diff options
author | Dave Chinner <dchinner@redhat.com> | 2012-03-06 23:50:21 -0500 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2012-03-15 15:14:33 -0400 |
commit | ad650f5b27bc9858360b42aaa0d9204d16115316 (patch) | |
tree | 9f21fe0fe1589c7cbcbc422f7d4ffcc4cf57bb74 /fs/xfs/xfs_ioctl.c | |
parent | 6eb2466036358078aed9a65d702cbc97baf0ce65 (diff) |
xfs: fallback to vmalloc for large buffers in xfs_attrmulti_attr_get
xfsdump uses for a large buffer for extended attributes, which has a
kmalloc'd shadow buffer in the kernel. This can fail after the
system has been running for some time as it is a high order
allocation. Add a fallback to vmalloc so that it doesn't require
contiguous memory and so won't randomly fail while xfsdump is
running.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_ioctl.c')
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 76f3ca5cfc36..f588320dc4b9 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
@@ -450,9 +450,12 @@ xfs_attrmulti_attr_get( | |||
450 | 450 | ||
451 | if (*len > XATTR_SIZE_MAX) | 451 | if (*len > XATTR_SIZE_MAX) |
452 | return EINVAL; | 452 | return EINVAL; |
453 | kbuf = kmalloc(*len, GFP_KERNEL); | 453 | kbuf = kmem_zalloc(*len, KM_SLEEP | KM_MAYFAIL); |
454 | if (!kbuf) | 454 | if (!kbuf) { |
455 | return ENOMEM; | 455 | kbuf = kmem_zalloc_large(*len); |
456 | if (!kbuf) | ||
457 | return ENOMEM; | ||
458 | } | ||
456 | 459 | ||
457 | error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags); | 460 | error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags); |
458 | if (error) | 461 | if (error) |
@@ -462,7 +465,10 @@ xfs_attrmulti_attr_get( | |||
462 | error = EFAULT; | 465 | error = EFAULT; |
463 | 466 | ||
464 | out_kfree: | 467 | out_kfree: |
465 | kfree(kbuf); | 468 | if (is_vmalloc_addr(kbuf)) |
469 | kmem_free_large(kbuf); | ||
470 | else | ||
471 | kmem_free(kbuf); | ||
466 | return error; | 472 | return error; |
467 | } | 473 | } |
468 | 474 | ||