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

kmalloc a few large stack objects in the btrfs_ioctl path

parent 6da6abae
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -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;

+42 −18
Original line number Diff line number Diff line
@@ -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)