|
@@ -986,11 +986,13 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
|
|
|
int num;
|
|
|
u8 type;
|
|
|
|
|
|
- if (found_key->type == BTRFS_XATTR_ITEM_KEY)
|
|
|
- buf_len = BTRFS_MAX_XATTR_SIZE(root);
|
|
|
- else
|
|
|
- buf_len = PATH_MAX;
|
|
|
-
|
|
|
+ /*
|
|
|
+ * Start with a small buffer (1 page). If later we end up needing more
|
|
|
+ * space, which can happen for xattrs on a fs with a leaf size greater
|
|
|
+ * then the page size, attempt to increase the buffer. Typically xattr
|
|
|
+ * values are small.
|
|
|
+ */
|
|
|
+ buf_len = PATH_MAX;
|
|
|
buf = kmalloc(buf_len, GFP_NOFS);
|
|
|
if (!buf) {
|
|
|
ret = -ENOMEM;
|
|
@@ -1017,7 +1019,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
|
|
|
ret = -ENAMETOOLONG;
|
|
|
goto out;
|
|
|
}
|
|
|
- if (name_len + data_len > buf_len) {
|
|
|
+ if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)) {
|
|
|
ret = -E2BIG;
|
|
|
goto out;
|
|
|
}
|
|
@@ -1025,12 +1027,34 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
|
|
|
/*
|
|
|
* Path too long
|
|
|
*/
|
|
|
- if (name_len + data_len > buf_len) {
|
|
|
+ if (name_len + data_len > PATH_MAX) {
|
|
|
ret = -ENAMETOOLONG;
|
|
|
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),
|
|
|
name_len + data_len);
|
|
|
|
|
@@ -1051,7 +1075,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
- kfree(buf);
|
|
|
+ kvfree(buf);
|
|
|
return ret;
|
|
|
}
|
|
|
|