aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-11-17 21:02:50 -0500
committerChris Mason <chris.mason@oracle.com>2008-11-17 21:02:50 -0500
commit3de4586c5278a28107030c336956381f69ff7a9d (patch)
treed636e3806cd5ecff71927d0300e46526fa23de1a /fs/btrfs/ioctl.c
parent4ce4cb526f67775c1cce3e3fa01c292672ba874e (diff)
Btrfs: Allow subvolumes and snapshots anywhere in the directory tree
Before, all snapshots and subvolumes lived in a single flat directory. This was awkward and confusing because the single flat directory was only writable with the ioctls. This commit changes the ioctls to create subvols and snapshots at any point in the directory tree. This requires making separate ioctls for snapshot and subvol creation instead of a combining them into one. The subvol ioctl does: btrfsctl -S subvol_name parent_dir After the ioctl is done subvol_name lives inside parent_dir. The snapshot ioctl does: btrfsctl -s path_for_snapshot root_to_snapshot path_for_snapshot can be an absolute or relative path. btrfsctl breaks it up into directory and basename components. root_to_snapshot can be any file or directory in the FS. The snapshot is taken of the entire root where that file lives. Signed-off-by: Chris Mason <chris.mason@oracle.com>
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: