aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.c20
-rw-r--r--fs/btrfs/inode.c60
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
2303static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg) 2303static 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);
2360out:
2361 kfree(vol_args);
2362 return ret;
2339} 2363}
2340 2364
2341static int btrfs_ioctl_defrag(struct file *file) 2365static int btrfs_ioctl_defrag(struct file *file)