summaryrefslogtreecommitdiff
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-12-18 16:25:45 -0500
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:58 -0400
commit4aec2b52327b3a3a20faa3f1af3102c0d97c7c92 (patch)
treef17d84355d64dd42c17462069b00f271f920e4a0 /fs/btrfs/inode.c
parent6da6abae027e2dbc59bca5f4168b0760f25068c7 (diff)
downloadlwn-4aec2b52327b3a3a20faa3f1af3102c0d97c7c92.tar.gz
lwn-4aec2b52327b3a3a20faa3f1af3102c0d97c7c92.zip
kmalloc a few large stack objects in the btrfs_ioctl path
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c60
1 files changed, 42 insertions, 18 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 6a7d9160df27..1e725a48467c 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2302,40 +2302,64 @@ out_unlock:
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_path *path;
- int namelen;
u64 root_dirid;
+ int namelen;
+ int ret;
- if (copy_from_user(&vol_args, arg, sizeof(vol_args)))
- return -EFAULT;
+ vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
- namelen = strlen(vol_args.name);
- if (namelen > BTRFS_VOL_NAME_MAX)
- return -EINVAL;
- if (strchr(vol_args.name, '/'))
- return -EINVAL;
+ if (!vol_args)
+ return -ENOMEM;
+
+ if (copy_from_user(vol_args, arg, sizeof(*vol_args))) {
+ 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();
- if (!path)
- return -ENOMEM;
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
root_dirid = root->fs_info->sb->s_root->d_inode->i_ino,
mutex_lock(&root->fs_info->fs_mutex);
di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root,
path, root_dirid,
- vol_args.name, namelen, 0);
+ vol_args->name, namelen, 0);
mutex_unlock(&root->fs_info->fs_mutex);
btrfs_free_path(path);
- if (di && !IS_ERR(di))
- return -EEXIST;
- if (IS_ERR(di))
- return PTR_ERR(di);
+
+ if (di && !IS_ERR(di)) {
+ ret = -EEXIST;
+ goto out;
+ }
+
+ if (IS_ERR(di)) {
+ ret = PTR_ERR(di);
+ goto out;
+ }
if (root == root->fs_info->tree_root)
- return create_subvol(root, vol_args.name, namelen);
- return create_snapshot(root, vol_args.name, namelen);
+ ret = create_subvol(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)