diff options
-rw-r--r-- | fs/btrfs/ctree.c | 20 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 60 |
2 files changed, 56 insertions, 24 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 585f279d1112..7f764455f26e 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -80,10 +80,14 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, | |||
80 | int ret = 0; | 80 | int ret = 0; |
81 | int level; | 81 | int level; |
82 | struct btrfs_key first_key; | 82 | struct btrfs_key first_key; |
83 | struct btrfs_root new_root; | 83 | struct btrfs_root *new_root; |
84 | 84 | ||
85 | memcpy(&new_root, root, sizeof(new_root)); | 85 | new_root = kmalloc(sizeof(*new_root), GFP_NOFS); |
86 | new_root.root_key.objectid = new_root_objectid; | 86 | if (!new_root) |
87 | return -ENOMEM; | ||
88 | |||
89 | memcpy(new_root, root, sizeof(*new_root)); | ||
90 | new_root->root_key.objectid = new_root_objectid; | ||
87 | 91 | ||
88 | WARN_ON(root->ref_cows && trans->transid != | 92 | WARN_ON(root->ref_cows && trans->transid != |
89 | root->fs_info->running_transaction->transid); | 93 | root->fs_info->running_transaction->transid); |
@@ -99,12 +103,14 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, | |||
99 | } else { | 103 | } else { |
100 | first_key.objectid = 0; | 104 | first_key.objectid = 0; |
101 | } | 105 | } |
102 | cow = __btrfs_alloc_free_block(trans, &new_root, buf->len, | 106 | cow = __btrfs_alloc_free_block(trans, new_root, buf->len, |
103 | new_root_objectid, | 107 | new_root_objectid, |
104 | trans->transid, first_key.objectid, | 108 | trans->transid, first_key.objectid, |
105 | level, buf->start, 0); | 109 | level, buf->start, 0); |
106 | if (IS_ERR(cow)) | 110 | if (IS_ERR(cow)) { |
111 | kfree(new_root); | ||
107 | return PTR_ERR(cow); | 112 | return PTR_ERR(cow); |
113 | } | ||
108 | 114 | ||
109 | copy_extent_buffer(cow, buf, 0, 0, cow->len); | 115 | copy_extent_buffer(cow, buf, 0, 0, cow->len); |
110 | btrfs_set_header_bytenr(cow, cow->start); | 116 | btrfs_set_header_bytenr(cow, cow->start); |
@@ -112,7 +118,9 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, | |||
112 | btrfs_set_header_owner(cow, new_root_objectid); | 118 | btrfs_set_header_owner(cow, new_root_objectid); |
113 | 119 | ||
114 | WARN_ON(btrfs_header_generation(buf) > trans->transid); | 120 | WARN_ON(btrfs_header_generation(buf) > trans->transid); |
115 | ret = btrfs_inc_ref(trans, &new_root, buf); | 121 | ret = btrfs_inc_ref(trans, new_root, buf); |
122 | kfree(new_root); | ||
123 | |||
116 | if (ret) | 124 | if (ret) |
117 | return ret; | 125 | return ret; |
118 | 126 | ||
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) |