Commit 4aec2b52 authored by Chris Mason's avatar Chris Mason

kmalloc a few large stack objects in the btrfs_ioctl path

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 6da6abae
...@@ -80,10 +80,14 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, ...@@ -80,10 +80,14 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
int ret = 0; int ret = 0;
int level; int level;
struct btrfs_key first_key; struct btrfs_key first_key;
struct btrfs_root new_root; struct btrfs_root *new_root;
memcpy(&new_root, root, sizeof(new_root)); new_root = kmalloc(sizeof(*new_root), GFP_NOFS);
new_root.root_key.objectid = new_root_objectid; if (!new_root)
return -ENOMEM;
memcpy(new_root, root, sizeof(*new_root));
new_root->root_key.objectid = new_root_objectid;
WARN_ON(root->ref_cows && trans->transid != WARN_ON(root->ref_cows && trans->transid !=
root->fs_info->running_transaction->transid); root->fs_info->running_transaction->transid);
...@@ -99,12 +103,14 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, ...@@ -99,12 +103,14 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
} else { } else {
first_key.objectid = 0; first_key.objectid = 0;
} }
cow = __btrfs_alloc_free_block(trans, &new_root, buf->len, cow = __btrfs_alloc_free_block(trans, new_root, buf->len,
new_root_objectid, new_root_objectid,
trans->transid, first_key.objectid, trans->transid, first_key.objectid,
level, buf->start, 0); level, buf->start, 0);
if (IS_ERR(cow)) if (IS_ERR(cow)) {
kfree(new_root);
return PTR_ERR(cow); return PTR_ERR(cow);
}
copy_extent_buffer(cow, buf, 0, 0, cow->len); copy_extent_buffer(cow, buf, 0, 0, cow->len);
btrfs_set_header_bytenr(cow, cow->start); btrfs_set_header_bytenr(cow, cow->start);
...@@ -112,7 +118,9 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, ...@@ -112,7 +118,9 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
btrfs_set_header_owner(cow, new_root_objectid); btrfs_set_header_owner(cow, new_root_objectid);
WARN_ON(btrfs_header_generation(buf) > trans->transid); WARN_ON(btrfs_header_generation(buf) > trans->transid);
ret = btrfs_inc_ref(trans, &new_root, buf); ret = btrfs_inc_ref(trans, new_root, buf);
kfree(new_root);
if (ret) if (ret)
return ret; return ret;
......
...@@ -2302,40 +2302,64 @@ int btrfs_defrag_file(struct file *file) { ...@@ -2302,40 +2302,64 @@ int btrfs_defrag_file(struct file *file) {
static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg) static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg)
{ {
struct btrfs_ioctl_vol_args vol_args; struct btrfs_ioctl_vol_args *vol_args;
struct btrfs_dir_item *di; struct btrfs_dir_item *di;
struct btrfs_path *path; struct btrfs_path *path;
int namelen;
u64 root_dirid; u64 root_dirid;
int namelen;
int ret;
if (copy_from_user(&vol_args, arg, sizeof(vol_args))) vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
return -EFAULT;
namelen = strlen(vol_args.name); if (!vol_args)
if (namelen > BTRFS_VOL_NAME_MAX) return -ENOMEM;
return -EINVAL;
if (strchr(vol_args.name, '/')) if (copy_from_user(vol_args, arg, sizeof(*vol_args))) {
return -EINVAL; ret = -EFAULT;
goto out;
}
namelen = strlen(vol_args->name);
if (namelen > BTRFS_VOL_NAME_MAX) {
ret = -EINVAL;
goto out;
}
if (strchr(vol_args->name, '/')) {
ret = -EINVAL;
goto out;
}
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path) {
return -ENOMEM; ret = -ENOMEM;
goto out;
}
root_dirid = root->fs_info->sb->s_root->d_inode->i_ino, root_dirid = root->fs_info->sb->s_root->d_inode->i_ino,
mutex_lock(&root->fs_info->fs_mutex); mutex_lock(&root->fs_info->fs_mutex);
di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root,
path, root_dirid, path, root_dirid,
vol_args.name, namelen, 0); vol_args->name, namelen, 0);
mutex_unlock(&root->fs_info->fs_mutex); mutex_unlock(&root->fs_info->fs_mutex);
btrfs_free_path(path); btrfs_free_path(path);
if (di && !IS_ERR(di))
return -EEXIST; if (di && !IS_ERR(di)) {
if (IS_ERR(di)) ret = -EEXIST;
return PTR_ERR(di); goto out;
}
if (IS_ERR(di)) {
ret = PTR_ERR(di);
goto out;
}
if (root == root->fs_info->tree_root) if (root == root->fs_info->tree_root)
return create_subvol(root, vol_args.name, namelen); ret = create_subvol(root, vol_args->name, namelen);
return create_snapshot(root, vol_args.name, namelen); else
ret = create_snapshot(root, vol_args->name, namelen);
out:
kfree(vol_args);
return ret;
} }
static int btrfs_ioctl_defrag(struct file *file) static int btrfs_ioctl_defrag(struct file *file)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment