OSDN Git Service

xattr: Avoid dynamically allocating memory in getxattr
authorSultan Alsawaf <sultan@kerneltoast.com>
Wed, 31 Jul 2019 07:04:01 +0000 (00:04 -0700)
committer0ranko0P <ranko0p@outlook.com>
Sat, 7 Dec 2019 10:22:18 +0000 (18:22 +0800)
Although the maximum xattr size is too big to fit on the stack (64 KiB),
we can still fulfill most getxattr requests with a 4 KiB stack
allocation, thereby improving performance. Such a large stack allocation
here is confirmed to be safe via stack usage measurements at runtime.

Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
fs/xattr.c

index 7444fb1..cd786d5 100644 (file)
@@ -430,6 +430,7 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
        void *kvalue = NULL;
        void *vvalue = NULL;
        char kname[XATTR_NAME_MAX + 1];
+       char kvalue_onstack[SZ_4K] __aligned(sizeof(long));
 
        error = strncpy_from_user(kname, name, sizeof(kname));
        if (error == 0 || error == sizeof(kname))
@@ -438,14 +439,19 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
                return error;
 
        if (size) {
-               if (size > XATTR_SIZE_MAX)
-                       size = XATTR_SIZE_MAX;
-               kvalue = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
-               if (!kvalue) {
-                       vvalue = vzalloc(size);
-                       if (!vvalue)
-                               return -ENOMEM;
-                       kvalue = vvalue;
+               if (size <= ARRAY_SIZE(kvalue_onstack)) {
+                       kvalue = kvalue_onstack;
+                       memset(kvalue, 0, size);
+               } else {
+                       if (size > XATTR_SIZE_MAX)
+                               size = XATTR_SIZE_MAX;
+                       kvalue = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+                       if (!kvalue) {
+                               vvalue = vzalloc(size);
+                               if (!vvalue)
+                                       return -ENOMEM;
+                               kvalue = vvalue;
+                       }
                }
        }
 
@@ -463,7 +469,7 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
        }
        if (vvalue)
                vfree(vvalue);
-       else
+       else if (kvalue != kvalue_onstack)
                kfree(kvalue);
        return error;
 }