diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 60 |
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: | |||
2302 | 2302 | ||
2303 | static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg) | 2303 | static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg) |
2304 | { | 2304 | { |
2305 | struct btrfs_ioctl_vol_args vol_args; | 2305 | struct btrfs_ioctl_vol_args *vol_args; |
2306 | struct btrfs_dir_item *di; | 2306 | struct btrfs_dir_item *di; |
2307 | struct btrfs_path *path; | 2307 | struct btrfs_path *path; |
2308 | int namelen; | ||
2309 | u64 root_dirid; | 2308 | u64 root_dirid; |
2309 | int namelen; | ||
2310 | int ret; | ||
2310 | 2311 | ||
2311 | if (copy_from_user(&vol_args, arg, sizeof(vol_args))) | 2312 | vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS); |
2312 | return -EFAULT; | ||
2313 | 2313 | ||
2314 | namelen = strlen(vol_args.name); | 2314 | if (!vol_args) |
2315 | if (namelen > BTRFS_VOL_NAME_MAX) | 2315 | return -ENOMEM; |
2316 | return -EINVAL; | 2316 | |
2317 | if (strchr(vol_args.name, '/')) | 2317 | if (copy_from_user(vol_args, arg, sizeof(*vol_args))) { |
2318 | return -EINVAL; | 2318 | ret = -EFAULT; |
2319 | goto out; | ||
2320 | } | ||
2321 | |||
2322 | namelen = strlen(vol_args->name); | ||
2323 | if (namelen > BTRFS_VOL_NAME_MAX) { | ||
2324 | ret = -EINVAL; | ||
2325 | goto out; | ||
2326 | } | ||
2327 | if (strchr(vol_args->name, '/')) { | ||
2328 | ret = -EINVAL; | ||
2329 | goto out; | ||
2330 | } | ||
2319 | 2331 | ||
2320 | path = btrfs_alloc_path(); | 2332 | path = btrfs_alloc_path(); |
2321 | if (!path) | 2333 | if (!path) { |
2322 | return -ENOMEM; | 2334 | ret = -ENOMEM; |
2335 | goto out; | ||
2336 | } | ||
2323 | 2337 | ||
2324 | root_dirid = root->fs_info->sb->s_root->d_inode->i_ino, | 2338 | root_dirid = root->fs_info->sb->s_root->d_inode->i_ino, |
2325 | mutex_lock(&root->fs_info->fs_mutex); | 2339 | mutex_lock(&root->fs_info->fs_mutex); |
2326 | di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, | 2340 | di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, |
2327 | path, root_dirid, | 2341 | path, root_dirid, |
2328 | vol_args.name, namelen, 0); | 2342 | vol_args->name, namelen, 0); |
2329 | mutex_unlock(&root->fs_info->fs_mutex); | 2343 | mutex_unlock(&root->fs_info->fs_mutex); |
2330 | btrfs_free_path(path); | 2344 | btrfs_free_path(path); |
2331 | if (di && !IS_ERR(di)) | 2345 | |
2332 | return -EEXIST; | 2346 | if (di && !IS_ERR(di)) { |
2333 | if (IS_ERR(di)) | 2347 | ret = -EEXIST; |
2334 | return PTR_ERR(di); | 2348 | goto out; |
2349 | } | ||
2350 | |||
2351 | if (IS_ERR(di)) { | ||
2352 | ret = PTR_ERR(di); | ||
2353 | goto out; | ||
2354 | } | ||
2335 | 2355 | ||
2336 | if (root == root->fs_info->tree_root) | 2356 | if (root == root->fs_info->tree_root) |
2337 | return create_subvol(root, vol_args.name, namelen); | 2357 | ret = create_subvol(root, vol_args->name, namelen); |
2338 | return create_snapshot(root, vol_args.name, namelen); | 2358 | else |
2359 | ret = create_snapshot(root, vol_args->name, namelen); | ||
2360 | out: | ||
2361 | kfree(vol_args); | ||
2362 | return ret; | ||
2339 | } | 2363 | } |
2340 | 2364 | ||
2341 | static int btrfs_ioctl_defrag(struct file *file) | 2365 | static int btrfs_ioctl_defrag(struct file *file) |