mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 15:18:19 +00:00
kmalloc a few large stack objects in the btrfs_ioctl path
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
6da6abae02
commit
4aec2b5232
2 changed files with 56 additions and 24 deletions
|
@ -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,
|
||||||
} 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,
|
||||||
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) {
|
||||||
|
|
||||||
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)
|
||||||
|
|
Loading…
Reference in a new issue