aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c71
1 files changed, 52 insertions, 19 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index f43df72b0e17..ec45b3086136 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -67,6 +67,7 @@ static noinline int create_subvol(struct btrfs_root *root,
67 int err; 67 int err;
68 u64 objectid; 68 u64 objectid;
69 u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; 69 u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
70 u64 index = 0;
70 unsigned long nr = 1; 71 unsigned long nr = 1;
71 72
72 ret = btrfs_check_free_space(root, 1, 0); 73 ret = btrfs_check_free_space(root, 1, 0);
@@ -126,6 +127,7 @@ static noinline int create_subvol(struct btrfs_root *root,
126 key.objectid = objectid; 127 key.objectid = objectid;
127 key.offset = 1; 128 key.offset = 1;
128 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); 129 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
130printk("inserting root objectid %Lu\n", objectid);
129 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, 131 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
130 &root_item); 132 &root_item);
131 if (ret) 133 if (ret)
@@ -135,24 +137,27 @@ static noinline int create_subvol(struct btrfs_root *root,
135 * insert the directory item 137 * insert the directory item
136 */ 138 */
137 key.offset = (u64)-1; 139 key.offset = (u64)-1;
138 dir = root->fs_info->sb->s_root->d_inode; 140 dir = dentry->d_parent->d_inode;
139 ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, 141 ret = btrfs_set_inode_index(dir, &index);
142 BUG_ON(ret);
143
144 ret = btrfs_insert_dir_item(trans, root,
140 name, namelen, dir->i_ino, &key, 145 name, namelen, dir->i_ino, &key,
141 BTRFS_FT_DIR, 0); 146 BTRFS_FT_DIR, index);
142 if (ret) 147 if (ret)
143 goto fail; 148 goto fail;
144 149#if 0
145 ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root, 150 ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root,
146 name, namelen, objectid, 151 name, namelen, objectid,
147 root->fs_info->sb->s_root->d_inode->i_ino, 0); 152 root->fs_info->sb->s_root->d_inode->i_ino, 0);
148 if (ret) 153 if (ret)
149 goto fail; 154 goto fail;
150 155#endif
151 ret = btrfs_commit_transaction(trans, root); 156 ret = btrfs_commit_transaction(trans, root);
152 if (ret) 157 if (ret)
153 goto fail_commit; 158 goto fail_commit;
154 159
155 new_root = btrfs_read_fs_root(root->fs_info, &key, name, namelen); 160 new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
156 BUG_ON(!new_root); 161 BUG_ON(!new_root);
157 162
158 trans = btrfs_start_transaction(new_root, 1); 163 trans = btrfs_start_transaction(new_root, 1);
@@ -170,14 +175,16 @@ fail:
170 ret = err; 175 ret = err;
171fail_commit: 176fail_commit:
172 btrfs_btree_balance_dirty(root, nr); 177 btrfs_btree_balance_dirty(root, nr);
178printk("all done ret %d\n", ret);
173 return ret; 179 return ret;
174} 180}
175 181
176static int create_snapshot(struct btrfs_root *root, char *name, int namelen) 182static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
183 char *name, int namelen)
177{ 184{
178 struct btrfs_pending_snapshot *pending_snapshot; 185 struct btrfs_pending_snapshot *pending_snapshot;
179 struct btrfs_trans_handle *trans; 186 struct btrfs_trans_handle *trans;
180 int ret; 187 int ret = 0;
181 int err; 188 int err;
182 unsigned long nr = 0; 189 unsigned long nr = 0;
183 190
@@ -188,7 +195,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
188 if (ret) 195 if (ret)
189 goto fail_unlock; 196 goto fail_unlock;
190 197
191 pending_snapshot = kmalloc(sizeof(*pending_snapshot), GFP_NOFS); 198 pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
192 if (!pending_snapshot) { 199 if (!pending_snapshot) {
193 ret = -ENOMEM; 200 ret = -ENOMEM;
194 goto fail_unlock; 201 goto fail_unlock;
@@ -201,12 +208,12 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
201 } 208 }
202 memcpy(pending_snapshot->name, name, namelen); 209 memcpy(pending_snapshot->name, name, namelen);
203 pending_snapshot->name[namelen] = '\0'; 210 pending_snapshot->name[namelen] = '\0';
211 pending_snapshot->dentry = dentry;
204 trans = btrfs_start_transaction(root, 1); 212 trans = btrfs_start_transaction(root, 1);
205 BUG_ON(!trans); 213 BUG_ON(!trans);
206 pending_snapshot->root = root; 214 pending_snapshot->root = root;
207 list_add(&pending_snapshot->list, 215 list_add(&pending_snapshot->list,
208 &trans->transaction->pending_snapshots); 216 &trans->transaction->pending_snapshots);
209 ret = btrfs_update_inode(trans, root, root->inode);
210 err = btrfs_commit_transaction(trans, root); 217 err = btrfs_commit_transaction(trans, root);
211 218
212fail_unlock: 219fail_unlock:
@@ -230,7 +237,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
230 * inside this filesystem so it's quite a bit simpler. 237 * inside this filesystem so it's quite a bit simpler.
231 */ 238 */
232static noinline int btrfs_mksubvol(struct path *parent, char *name, 239static noinline int btrfs_mksubvol(struct path *parent, char *name,
233 int mode, int namelen) 240 int mode, int namelen,
241 struct btrfs_root *snap_src)
234{ 242{
235 struct dentry *dentry; 243 struct dentry *dentry;
236 int error; 244 int error;
@@ -248,6 +256,7 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name,
248 256
249 if (!IS_POSIXACL(parent->dentry->d_inode)) 257 if (!IS_POSIXACL(parent->dentry->d_inode))
250 mode &= ~current->fs->umask; 258 mode &= ~current->fs->umask;
259
251 error = mnt_want_write(parent->mnt); 260 error = mnt_want_write(parent->mnt);
252 if (error) 261 if (error)
253 goto out_dput; 262 goto out_dput;
@@ -266,8 +275,12 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name,
266 * Also we should pass on the mode eventually to allow creating new 275 * Also we should pass on the mode eventually to allow creating new
267 * subvolume with specific mode bits. 276 * subvolume with specific mode bits.
268 */ 277 */
269 error = create_subvol(BTRFS_I(parent->dentry->d_inode)->root, dentry, 278 if (snap_src) {
270 name, namelen); 279 error = create_snapshot(snap_src, dentry, name, namelen);
280 } else {
281 error = create_subvol(BTRFS_I(parent->dentry->d_inode)->root,
282 dentry, name, namelen);
283 }
271 if (error) 284 if (error)
272 goto out_drop_write; 285 goto out_drop_write;
273 286
@@ -471,15 +484,16 @@ out:
471} 484}
472 485
473static noinline int btrfs_ioctl_snap_create(struct file *file, 486static noinline int btrfs_ioctl_snap_create(struct file *file,
474 void __user *arg) 487 void __user *arg, int subvol)
475{ 488{
476 struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; 489 struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
477 struct btrfs_ioctl_vol_args *vol_args; 490 struct btrfs_ioctl_vol_args *vol_args;
478 struct btrfs_dir_item *di; 491 struct btrfs_dir_item *di;
479 struct btrfs_path *path; 492 struct btrfs_path *path;
493 struct file *src_file;
480 u64 root_dirid; 494 u64 root_dirid;
481 int namelen; 495 int namelen;
482 int ret; 496 int ret = 0;
483 497
484 if (root->fs_info->sb->s_flags & MS_RDONLY) 498 if (root->fs_info->sb->s_flags & MS_RDONLY)
485 return -EROFS; 499 return -EROFS;
@@ -523,12 +537,29 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
523 goto out; 537 goto out;
524 } 538 }
525 539
526 if (root == root->fs_info->tree_root) { 540 if (subvol) {
527 ret = btrfs_mksubvol(&file->f_path, vol_args->name, 541 ret = btrfs_mksubvol(&file->f_path, vol_args->name,
528 file->f_path.dentry->d_inode->i_mode, 542 file->f_path.dentry->d_inode->i_mode,
529 namelen); 543 namelen, NULL);
530 } else { 544 } else {
531 ret = create_snapshot(root, vol_args->name, namelen); 545 struct inode *src_inode;
546 src_file = fget(vol_args->fd);
547 if (!src_file) {
548 ret = -EINVAL;
549 goto out;
550 }
551
552 src_inode = src_file->f_path.dentry->d_inode;
553 if (src_inode->i_sb != file->f_path.dentry->d_inode->i_sb) {
554 printk("btrfs: Snapshot src from another FS\n");
555 ret = -EINVAL;
556 fput(src_file);
557 goto out;
558 }
559 ret = btrfs_mksubvol(&file->f_path, vol_args->name,
560 file->f_path.dentry->d_inode->i_mode,
561 namelen, BTRFS_I(src_inode)->root);
562 fput(src_file);
532 } 563 }
533 564
534out: 565out:
@@ -1030,7 +1061,9 @@ long btrfs_ioctl(struct file *file, unsigned int
1030 1061
1031 switch (cmd) { 1062 switch (cmd) {
1032 case BTRFS_IOC_SNAP_CREATE: 1063 case BTRFS_IOC_SNAP_CREATE:
1033 return btrfs_ioctl_snap_create(file, (void __user *)arg); 1064 return btrfs_ioctl_snap_create(file, (void __user *)arg, 0);
1065 case BTRFS_IOC_SUBVOL_CREATE:
1066 return btrfs_ioctl_snap_create(file, (void __user *)arg, 1);
1034 case BTRFS_IOC_DEFRAG: 1067 case BTRFS_IOC_DEFRAG:
1035 return btrfs_ioctl_defrag(file); 1068 return btrfs_ioctl_defrag(file);
1036 case BTRFS_IOC_RESIZE: 1069 case BTRFS_IOC_RESIZE: