kmalloc a few large stack objects in the btrfs_ioctl path
authorChris Mason <chris.mason@oracle.com>
Tue, 18 Dec 2007 21:25:45 +0000 (16:25 -0500)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:03:58 +0000 (11:03 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.c
fs/btrfs/inode.c

index 585f279d1112338b1e14782ff1048fd7e355e760..7f764455f26e9a2b18237e27fc98bb6dd1d636d6 100644 (file)
@@ -80,10 +80,14 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
        int ret = 0;
        int level;
        struct btrfs_key first_key;
-       struct btrfs_root new_root;
+       struct btrfs_root *new_root;
 
-       memcpy(&new_root, root, sizeof(new_root));
-       new_root.root_key.objectid = new_root_objectid;
+       new_root = kmalloc(sizeof(*new_root), GFP_NOFS);
+       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 !=
                root->fs_info->running_transaction->transid);
@@ -99,12 +103,14 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
        } else {
                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,
                                       trans->transid, first_key.objectid,
                                       level, buf->start, 0);
-       if (IS_ERR(cow))
+       if (IS_ERR(cow)) {
+               kfree(new_root);
                return PTR_ERR(cow);
+       }
 
        copy_extent_buffer(cow, buf, 0, 0, cow->len);
        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);
 
        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)
                return ret;
 
index 6a7d9160df276a91229b6f633ab2b6289ecb4e8a..1e725a48467cf17454a35fd7678f1fa5e184baf1 100644 (file)
@@ -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)