kmalloc a few large stack objects in the btrfs_ioctl path

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 585f279..7f76445 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -80,10 +80,14 @@
 	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 @@
 	} 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 @@
 	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;
 
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 6a7d916..1e725a4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2302,40 +2302,64 @@
 
 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)