aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xattr.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@linux-foundation.org>2012-04-05 17:25:07 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-04-05 18:25:50 -0400
commit0d08d7b7e13b5060181b11ecdde82d8fda322123 (patch)
tree21f938ad3adafb2902358a5a234169229b3bcc16 /fs/xattr.c
parent703bf2d122c95412a30f72658c53ad6292867b0b (diff)
fs/xattr.c:listxattr(): fall back to vmalloc() if kmalloc() failed
This allocation can be as large as 64k. As David points out, "falling back to vmalloc here is much better solution than failing to retreive the attribute - it will work no matter how fragmented memory gets. That means we don't get incomplete backups occurring after days or months of uptime and successful backups". Cc: Dave Chinner <david@fromorbit.com> Cc: Dave Jones <davej@codemonkey.org.uk> Cc: David Rientjes <rientjes@google.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/xattr.c')
-rw-r--r--fs/xattr.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/fs/xattr.c b/fs/xattr.c
index a14d842ccb21..d14afbae3c13 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -19,8 +19,9 @@
19#include <linux/export.h> 19#include <linux/export.h>
20#include <linux/fsnotify.h> 20#include <linux/fsnotify.h>
21#include <linux/audit.h> 21#include <linux/audit.h>
22#include <asm/uaccess.h> 22#include <linux/vmalloc.h>
23 23
24#include <asm/uaccess.h>
24 25
25/* 26/*
26 * Check permissions for extended attribute access. This is a bit complicated 27 * Check permissions for extended attribute access. This is a bit complicated
@@ -492,13 +493,18 @@ listxattr(struct dentry *d, char __user *list, size_t size)
492{ 493{
493 ssize_t error; 494 ssize_t error;
494 char *klist = NULL; 495 char *klist = NULL;
496 char *vlist = NULL; /* If non-NULL, we used vmalloc() */
495 497
496 if (size) { 498 if (size) {
497 if (size > XATTR_LIST_MAX) 499 if (size > XATTR_LIST_MAX)
498 size = XATTR_LIST_MAX; 500 size = XATTR_LIST_MAX;
499 klist = kmalloc(size, __GFP_NOWARN | GFP_KERNEL); 501 klist = kmalloc(size, __GFP_NOWARN | GFP_KERNEL);
500 if (!klist) 502 if (!klist) {
501 return -ENOMEM; 503 vlist = vmalloc(size);
504 if (!vlist)
505 return -ENOMEM;
506 klist = vlist;
507 }
502 } 508 }
503 509
504 error = vfs_listxattr(d, klist, size); 510 error = vfs_listxattr(d, klist, size);
@@ -510,7 +516,10 @@ listxattr(struct dentry *d, char __user *list, size_t size)
510 than XATTR_LIST_MAX bytes. Not possible. */ 516 than XATTR_LIST_MAX bytes. Not possible. */
511 error = -E2BIG; 517 error = -E2BIG;
512 } 518 }
513 kfree(klist); 519 if (vlist)
520 vfree(vlist);
521 else
522 kfree(klist);
514 return error; 523 return error;
515} 524}
516 525