aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/send.c
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2014-08-20 05:45:45 -0400
committerChris Mason <clm@fb.com>2014-09-17 16:38:16 -0400
commit4395e0c4da486f007dcb45b0336427be7ec08ab1 (patch)
tree3396fecc7f51ee2947133df851bc2a6c8c1cd15c /fs/btrfs/send.c
parentf87c4318af8bd5daec361e436c69f9d71a43b261 (diff)
Btrfs: send, lower mem requirements for processing xattrs
Maximum xattr size can be up to nearly the leaf size. For an fs with a leaf size larger than the page size, using kmalloc requires allocating multiple pages that are contiguous, which might not be possible if there's heavy memory fragmentation. Therefore fallback to vmalloc if we fail to allocate with kmalloc. Also start with a smaller buffer size, since xattr values typically are smaller than a page. Reported-by: Chris Murphy <lists@colorremedies.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r--fs/btrfs/send.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index b67e12eb7ca9..7edfc7cebda4 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -986,11 +986,13 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
986 int num; 986 int num;
987 u8 type; 987 u8 type;
988 988
989 if (found_key->type == BTRFS_XATTR_ITEM_KEY) 989 /*
990 buf_len = BTRFS_MAX_XATTR_SIZE(root); 990 * Start with a small buffer (1 page). If later we end up needing more
991 else 991 * space, which can happen for xattrs on a fs with a leaf size greater
992 buf_len = PATH_MAX; 992 * then the page size, attempt to increase the buffer. Typically xattr
993 993 * values are small.
994 */
995 buf_len = PATH_MAX;
994 buf = kmalloc(buf_len, GFP_NOFS); 996 buf = kmalloc(buf_len, GFP_NOFS);
995 if (!buf) { 997 if (!buf) {
996 ret = -ENOMEM; 998 ret = -ENOMEM;
@@ -1017,7 +1019,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
1017 ret = -ENAMETOOLONG; 1019 ret = -ENAMETOOLONG;
1018 goto out; 1020 goto out;
1019 } 1021 }
1020 if (name_len + data_len > buf_len) { 1022 if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)) {
1021 ret = -E2BIG; 1023 ret = -E2BIG;
1022 goto out; 1024 goto out;
1023 } 1025 }
@@ -1025,12 +1027,34 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
1025 /* 1027 /*
1026 * Path too long 1028 * Path too long
1027 */ 1029 */
1028 if (name_len + data_len > buf_len) { 1030 if (name_len + data_len > PATH_MAX) {
1029 ret = -ENAMETOOLONG; 1031 ret = -ENAMETOOLONG;
1030 goto out; 1032 goto out;
1031 } 1033 }
1032 } 1034 }
1033 1035
1036 if (name_len + data_len > buf_len) {
1037 buf_len = name_len + data_len;
1038 if (is_vmalloc_addr(buf)) {
1039 vfree(buf);
1040 buf = NULL;
1041 } else {
1042 char *tmp = krealloc(buf, buf_len,
1043 GFP_NOFS | __GFP_NOWARN);
1044
1045 if (!tmp)
1046 kfree(buf);
1047 buf = tmp;
1048 }
1049 if (!buf) {
1050 buf = vmalloc(buf_len);
1051 if (!buf) {
1052 ret = -ENOMEM;
1053 goto out;
1054 }
1055 }
1056 }
1057
1034 read_extent_buffer(eb, buf, (unsigned long)(di + 1), 1058 read_extent_buffer(eb, buf, (unsigned long)(di + 1),
1035 name_len + data_len); 1059 name_len + data_len);
1036 1060
@@ -1051,7 +1075,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
1051 } 1075 }
1052 1076
1053out: 1077out:
1054 kfree(buf); 1078 kvfree(buf);
1055 return ret; 1079 return ret;
1056} 1080}
1057 1081