提交 4395e0c4 编写于 作者: F Filipe Manana 提交者: Chris Mason

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: NChris Murphy <lists@colorremedies.com>
Signed-off-by: NFilipe Manana <fdmanana@suse.com>
Signed-off-by: NChris Mason <clm@fb.com>
上级 f87c4318
...@@ -986,11 +986,13 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, ...@@ -986,11 +986,13 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
int num; int num;
u8 type; u8 type;
if (found_key->type == BTRFS_XATTR_ITEM_KEY) /*
buf_len = BTRFS_MAX_XATTR_SIZE(root); * Start with a small buffer (1 page). If later we end up needing more
else * space, which can happen for xattrs on a fs with a leaf size greater
buf_len = PATH_MAX; * then the page size, attempt to increase the buffer. Typically xattr
* values are small.
*/
buf_len = PATH_MAX;
buf = kmalloc(buf_len, GFP_NOFS); buf = kmalloc(buf_len, GFP_NOFS);
if (!buf) { if (!buf) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -1017,7 +1019,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, ...@@ -1017,7 +1019,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
ret = -ENAMETOOLONG; ret = -ENAMETOOLONG;
goto out; goto out;
} }
if (name_len + data_len > buf_len) { if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)) {
ret = -E2BIG; ret = -E2BIG;
goto out; goto out;
} }
...@@ -1025,12 +1027,34 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, ...@@ -1025,12 +1027,34 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
/* /*
* Path too long * Path too long
*/ */
if (name_len + data_len > buf_len) { if (name_len + data_len > PATH_MAX) {
ret = -ENAMETOOLONG; ret = -ENAMETOOLONG;
goto out; goto out;
} }
} }
if (name_len + data_len > buf_len) {
buf_len = name_len + data_len;
if (is_vmalloc_addr(buf)) {
vfree(buf);
buf = NULL;
} else {
char *tmp = krealloc(buf, buf_len,
GFP_NOFS | __GFP_NOWARN);
if (!tmp)
kfree(buf);
buf = tmp;
}
if (!buf) {
buf = vmalloc(buf_len);
if (!buf) {
ret = -ENOMEM;
goto out;
}
}
}
read_extent_buffer(eb, buf, (unsigned long)(di + 1), read_extent_buffer(eb, buf, (unsigned long)(di + 1),
name_len + data_len); name_len + data_len);
...@@ -1051,7 +1075,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, ...@@ -1051,7 +1075,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
} }
out: out:
kfree(buf); kvfree(buf);
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册