aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorYan, Zheng <zheng.yan@oracle.com>2009-09-21 16:00:26 -0400
committerChris Mason <chris.mason@oracle.com>2009-09-21 16:00:26 -0400
commit76dda93c6ae2c1dc3e6cde34569d6aca26b0c918 (patch)
treef5ca46ec89d4ae2c762952d5f35e2c6f95ac046a /fs/btrfs/ioctl.c
parent4df27c4d5cc1dda54ed7d0a8389347f2df359cf9 (diff)
Btrfs: add snapshot/subvolume destroy ioctl
This patch adds snapshot/subvolume destroy ioctl. A subvolume that isn't being used and doesn't contains links to other subvolumes can be destroyed. Signed-off-by: Yan Zheng <zheng.yan@oracle.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c320
1 files changed, 184 insertions, 136 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 9b3a88755e51..a13fd556db74 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -230,8 +230,8 @@ static noinline int create_subvol(struct btrfs_root *root,
230 struct btrfs_root_item root_item; 230 struct btrfs_root_item root_item;
231 struct btrfs_inode_item *inode_item; 231 struct btrfs_inode_item *inode_item;
232 struct extent_buffer *leaf; 232 struct extent_buffer *leaf;
233 struct btrfs_root *new_root = root; 233 struct btrfs_root *new_root;
234 struct inode *dir; 234 struct inode *dir = dentry->d_parent->d_inode;
235 int ret; 235 int ret;
236 int err; 236 int err;
237 u64 objectid; 237 u64 objectid;
@@ -241,7 +241,7 @@ static noinline int create_subvol(struct btrfs_root *root,
241 241
242 ret = btrfs_check_metadata_free_space(root); 242 ret = btrfs_check_metadata_free_space(root);
243 if (ret) 243 if (ret)
244 goto fail_commit; 244 return ret;
245 245
246 trans = btrfs_start_transaction(root, 1); 246 trans = btrfs_start_transaction(root, 1);
247 BUG_ON(!trans); 247 BUG_ON(!trans);
@@ -304,11 +304,17 @@ static noinline int create_subvol(struct btrfs_root *root,
304 if (ret) 304 if (ret)
305 goto fail; 305 goto fail;
306 306
307 key.offset = (u64)-1;
308 new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
309 BUG_ON(IS_ERR(new_root));
310
311 btrfs_record_root_in_trans(trans, new_root);
312
313 ret = btrfs_create_subvol_root(trans, new_root, new_dirid,
314 BTRFS_I(dir)->block_group);
307 /* 315 /*
308 * insert the directory item 316 * insert the directory item
309 */ 317 */
310 key.offset = (u64)-1;
311 dir = dentry->d_parent->d_inode;
312 ret = btrfs_set_inode_index(dir, &index); 318 ret = btrfs_set_inode_index(dir, &index);
313 BUG_ON(ret); 319 BUG_ON(ret);
314 320
@@ -325,30 +331,15 @@ static noinline int create_subvol(struct btrfs_root *root,
325 ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, 331 ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
326 objectid, root->root_key.objectid, 332 objectid, root->root_key.objectid,
327 dir->i_ino, index, name, namelen); 333 dir->i_ino, index, name, namelen);
328 BUG_ON(ret);
329 334
330 ret = btrfs_commit_transaction(trans, root); 335 BUG_ON(ret);
331 if (ret)
332 goto fail_commit;
333
334 new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
335 BUG_ON(!new_root);
336
337 trans = btrfs_start_transaction(new_root, 1);
338 BUG_ON(!trans);
339
340 ret = btrfs_create_subvol_root(trans, new_root, dentry, new_dirid,
341 BTRFS_I(dir)->block_group);
342 if (ret)
343 goto fail;
344 336
337 d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
345fail: 338fail:
346 nr = trans->blocks_used; 339 nr = trans->blocks_used;
347 err = btrfs_commit_transaction(trans, new_root); 340 err = btrfs_commit_transaction(trans, root);
348 if (err && !ret) 341 if (err && !ret)
349 ret = err; 342 ret = err;
350fail_commit:
351 btrfs_btree_balance_dirty(root, nr);
352 return ret; 343 return ret;
353} 344}
354 345
@@ -409,14 +400,15 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
409 * sys_mkdirat and vfs_mkdir, but we only do a single component lookup 400 * sys_mkdirat and vfs_mkdir, but we only do a single component lookup
410 * inside this filesystem so it's quite a bit simpler. 401 * inside this filesystem so it's quite a bit simpler.
411 */ 402 */
412static noinline int btrfs_mksubvol(struct path *parent, char *name, 403static noinline int btrfs_mksubvol(struct path *parent,
413 int mode, int namelen, 404 char *name, int namelen,
414 struct btrfs_root *snap_src) 405 struct btrfs_root *snap_src)
415{ 406{
407 struct inode *dir = parent->dentry->d_inode;
416 struct dentry *dentry; 408 struct dentry *dentry;
417 int error; 409 int error;
418 410
419 mutex_lock_nested(&parent->dentry->d_inode->i_mutex, I_MUTEX_PARENT); 411 mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
420 412
421 dentry = lookup_one_len(name, parent->dentry, namelen); 413 dentry = lookup_one_len(name, parent->dentry, namelen);
422 error = PTR_ERR(dentry); 414 error = PTR_ERR(dentry);
@@ -427,99 +419,39 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name,
427 if (dentry->d_inode) 419 if (dentry->d_inode)
428 goto out_dput; 420 goto out_dput;
429 421
430 if (!IS_POSIXACL(parent->dentry->d_inode))
431 mode &= ~current_umask();
432
433 error = mnt_want_write(parent->mnt); 422 error = mnt_want_write(parent->mnt);
434 if (error) 423 if (error)
435 goto out_dput; 424 goto out_dput;
436 425
437 error = btrfs_may_create(parent->dentry->d_inode, dentry); 426 error = btrfs_may_create(dir, dentry);
438 if (error) 427 if (error)
439 goto out_drop_write; 428 goto out_drop_write;
440 429
441 /* 430 down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem);
442 * Actually perform the low-level subvolume creation after all 431
443 * this VFS fuzz. 432 if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0)
444 * 433 goto out_up_read;
445 * Eventually we want to pass in an inode under which we create this 434
446 * subvolume, but for now all are under the filesystem root.
447 *
448 * Also we should pass on the mode eventually to allow creating new
449 * subvolume with specific mode bits.
450 */
451 if (snap_src) { 435 if (snap_src) {
452 struct dentry *dir = dentry->d_parent; 436 error = create_snapshot(snap_src, dentry,
453 struct dentry *test = dir->d_parent; 437 name, namelen);
454 struct btrfs_path *path = btrfs_alloc_path();
455 int ret;
456 u64 test_oid;
457 u64 parent_oid = BTRFS_I(dir->d_inode)->root->root_key.objectid;
458
459 test_oid = snap_src->root_key.objectid;
460
461 ret = btrfs_find_root_ref(snap_src->fs_info->tree_root,
462 path, parent_oid, test_oid);
463 if (ret == 0)
464 goto create;
465 btrfs_release_path(snap_src->fs_info->tree_root, path);
466
467 /* we need to make sure we aren't creating a directory loop
468 * by taking a snapshot of something that has our current
469 * subvol in its directory tree. So, this loops through
470 * the dentries and checks the forward refs for each subvolume
471 * to see if is references the subvolume where we are
472 * placing this new snapshot.
473 */
474 while (1) {
475 if (!test ||
476 dir == snap_src->fs_info->sb->s_root ||
477 test == snap_src->fs_info->sb->s_root ||
478 test->d_inode->i_sb != snap_src->fs_info->sb) {
479 break;
480 }
481 if (S_ISLNK(test->d_inode->i_mode)) {
482 printk(KERN_INFO "Btrfs symlink in snapshot "
483 "path, failed\n");
484 error = -EMLINK;
485 btrfs_free_path(path);
486 goto out_drop_write;
487 }
488 test_oid =
489 BTRFS_I(test->d_inode)->root->root_key.objectid;
490 ret = btrfs_find_root_ref(snap_src->fs_info->tree_root,
491 path, test_oid, parent_oid);
492 if (ret == 0) {
493 printk(KERN_INFO "Btrfs snapshot creation "
494 "failed, looping\n");
495 error = -EMLINK;
496 btrfs_free_path(path);
497 goto out_drop_write;
498 }
499 btrfs_release_path(snap_src->fs_info->tree_root, path);
500 test = test->d_parent;
501 }
502create:
503 btrfs_free_path(path);
504 error = create_snapshot(snap_src, dentry, name, namelen);
505 } else { 438 } else {
506 error = create_subvol(BTRFS_I(parent->dentry->d_inode)->root, 439 error = create_subvol(BTRFS_I(dir)->root, dentry,
507 dentry, name, namelen); 440 name, namelen);
508 } 441 }
509 if (error) 442 if (!error)
510 goto out_drop_write; 443 fsnotify_mkdir(dir, dentry);
511 444out_up_read:
512 fsnotify_mkdir(parent->dentry->d_inode, dentry); 445 up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem);
513out_drop_write: 446out_drop_write:
514 mnt_drop_write(parent->mnt); 447 mnt_drop_write(parent->mnt);
515out_dput: 448out_dput:
516 dput(dentry); 449 dput(dentry);
517out_unlock: 450out_unlock:
518 mutex_unlock(&parent->dentry->d_inode->i_mutex); 451 mutex_unlock(&dir->i_mutex);
519 return error; 452 return error;
520} 453}
521 454
522
523static int btrfs_defrag_file(struct file *file) 455static int btrfs_defrag_file(struct file *file)
524{ 456{
525 struct inode *inode = fdentry(file)->d_inode; 457 struct inode *inode = fdentry(file)->d_inode;
@@ -597,7 +529,8 @@ out_unlock:
597 return 0; 529 return 0;
598} 530}
599 531
600static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg) 532static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
533 void __user *arg)
601{ 534{
602 u64 new_size; 535 u64 new_size;
603 u64 old_size; 536 u64 old_size;
@@ -706,10 +639,7 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
706{ 639{
707 struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; 640 struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
708 struct btrfs_ioctl_vol_args *vol_args; 641 struct btrfs_ioctl_vol_args *vol_args;
709 struct btrfs_dir_item *di;
710 struct btrfs_path *path;
711 struct file *src_file; 642 struct file *src_file;
712 u64 root_dirid;
713 int namelen; 643 int namelen;
714 int ret = 0; 644 int ret = 0;
715 645
@@ -727,32 +657,9 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
727 goto out; 657 goto out;
728 } 658 }
729 659
730 path = btrfs_alloc_path();
731 if (!path) {
732 ret = -ENOMEM;
733 goto out;
734 }
735
736 root_dirid = root->fs_info->sb->s_root->d_inode->i_ino,
737 di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root,
738 path, root_dirid,
739 vol_args->name, namelen, 0);
740 btrfs_free_path(path);
741
742 if (di && !IS_ERR(di)) {
743 ret = -EEXIST;
744 goto out;
745 }
746
747 if (IS_ERR(di)) {
748 ret = PTR_ERR(di);
749 goto out;
750 }
751
752 if (subvol) { 660 if (subvol) {
753 ret = btrfs_mksubvol(&file->f_path, vol_args->name, 661 ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen,
754 file->f_path.dentry->d_inode->i_mode, 662 NULL);
755 namelen, NULL);
756 } else { 663 } else {
757 struct inode *src_inode; 664 struct inode *src_inode;
758 src_file = fget(vol_args->fd); 665 src_file = fget(vol_args->fd);
@@ -769,17 +676,156 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
769 fput(src_file); 676 fput(src_file);
770 goto out; 677 goto out;
771 } 678 }
772 ret = btrfs_mksubvol(&file->f_path, vol_args->name, 679 ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen,
773 file->f_path.dentry->d_inode->i_mode, 680 BTRFS_I(src_inode)->root);
774 namelen, BTRFS_I(src_inode)->root);
775 fput(src_file); 681 fput(src_file);
776 } 682 }
777
778out: 683out:
779 kfree(vol_args); 684 kfree(vol_args);
780 return ret; 685 return ret;
781} 686}
782 687
688/*
689 * helper to check if the subvolume references other subvolumes
690 */
691static noinline int may_destroy_subvol(struct btrfs_root *root)
692{
693 struct btrfs_path *path;
694 struct btrfs_key key;
695 int ret;
696
697 path = btrfs_alloc_path();
698 if (!path)
699 return -ENOMEM;
700
701 key.objectid = root->root_key.objectid;
702 key.type = BTRFS_ROOT_REF_KEY;
703 key.offset = (u64)-1;
704
705 ret = btrfs_search_slot(NULL, root->fs_info->tree_root,
706 &key, path, 0, 0);
707 if (ret < 0)
708 goto out;
709 BUG_ON(ret == 0);
710
711 ret = 0;
712 if (path->slots[0] > 0) {
713 path->slots[0]--;
714 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
715 if (key.objectid == root->root_key.objectid &&
716 key.type == BTRFS_ROOT_REF_KEY)
717 ret = -ENOTEMPTY;
718 }
719out:
720 btrfs_free_path(path);
721 return ret;
722}
723
724static noinline int btrfs_ioctl_snap_destroy(struct file *file,
725 void __user *arg)
726{
727 struct dentry *parent = fdentry(file);
728 struct dentry *dentry;
729 struct inode *dir = parent->d_inode;
730 struct inode *inode;
731 struct btrfs_root *root = BTRFS_I(dir)->root;
732 struct btrfs_root *dest = NULL;
733 struct btrfs_ioctl_vol_args *vol_args;
734 struct btrfs_trans_handle *trans;
735 int namelen;
736 int ret;
737 int err = 0;
738
739 if (!capable(CAP_SYS_ADMIN))
740 return -EPERM;
741
742 vol_args = memdup_user(arg, sizeof(*vol_args));
743 if (IS_ERR(vol_args))
744 return PTR_ERR(vol_args);
745
746 vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
747 namelen = strlen(vol_args->name);
748 if (strchr(vol_args->name, '/') ||
749 strncmp(vol_args->name, "..", namelen) == 0) {
750 err = -EINVAL;
751 goto out;
752 }
753
754 err = mnt_want_write(file->f_path.mnt);
755 if (err)
756 goto out;
757
758 mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
759 dentry = lookup_one_len(vol_args->name, parent, namelen);
760 if (IS_ERR(dentry)) {
761 err = PTR_ERR(dentry);
762 goto out_unlock_dir;
763 }
764
765 if (!dentry->d_inode) {
766 err = -ENOENT;
767 goto out_dput;
768 }
769
770 inode = dentry->d_inode;
771 if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) {
772 err = -EINVAL;
773 goto out_dput;
774 }
775
776 dest = BTRFS_I(inode)->root;
777
778 mutex_lock(&inode->i_mutex);
779 err = d_invalidate(dentry);
780 if (err)
781 goto out_unlock;
782
783 down_write(&root->fs_info->subvol_sem);
784
785 err = may_destroy_subvol(dest);
786 if (err)
787 goto out_up_write;
788
789 trans = btrfs_start_transaction(root, 1);
790 ret = btrfs_unlink_subvol(trans, root, dir,
791 dest->root_key.objectid,
792 dentry->d_name.name,
793 dentry->d_name.len);
794 BUG_ON(ret);
795
796 btrfs_record_root_in_trans(trans, dest);
797
798 memset(&dest->root_item.drop_progress, 0,
799 sizeof(dest->root_item.drop_progress));
800 dest->root_item.drop_level = 0;
801 btrfs_set_root_refs(&dest->root_item, 0);
802
803 ret = btrfs_insert_orphan_item(trans,
804 root->fs_info->tree_root,
805 dest->root_key.objectid);
806 BUG_ON(ret);
807
808 ret = btrfs_commit_transaction(trans, root);
809 BUG_ON(ret);
810 inode->i_flags |= S_DEAD;
811out_up_write:
812 up_write(&root->fs_info->subvol_sem);
813out_unlock:
814 mutex_unlock(&inode->i_mutex);
815 if (!err) {
816 btrfs_invalidate_inodes(dest);
817 d_delete(dentry);
818 }
819out_dput:
820 dput(dentry);
821out_unlock_dir:
822 mutex_unlock(&dir->i_mutex);
823 mnt_drop_write(file->f_path.mnt);
824out:
825 kfree(vol_args);
826 return err;
827}
828
783static int btrfs_ioctl_defrag(struct file *file) 829static int btrfs_ioctl_defrag(struct file *file)
784{ 830{
785 struct inode *inode = fdentry(file)->d_inode; 831 struct inode *inode = fdentry(file)->d_inode;
@@ -853,8 +899,8 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
853 return ret; 899 return ret;
854} 900}
855 901
856static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, 902static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
857 u64 off, u64 olen, u64 destoff) 903 u64 off, u64 olen, u64 destoff)
858{ 904{
859 struct inode *inode = fdentry(file)->d_inode; 905 struct inode *inode = fdentry(file)->d_inode;
860 struct btrfs_root *root = BTRFS_I(inode)->root; 906 struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -1246,6 +1292,8 @@ long btrfs_ioctl(struct file *file, unsigned int
1246 return btrfs_ioctl_snap_create(file, argp, 0); 1292 return btrfs_ioctl_snap_create(file, argp, 0);
1247 case BTRFS_IOC_SUBVOL_CREATE: 1293 case BTRFS_IOC_SUBVOL_CREATE:
1248 return btrfs_ioctl_snap_create(file, argp, 1); 1294 return btrfs_ioctl_snap_create(file, argp, 1);
1295 case BTRFS_IOC_SNAP_DESTROY:
1296 return btrfs_ioctl_snap_destroy(file, argp);
1249 case BTRFS_IOC_DEFRAG: 1297 case BTRFS_IOC_DEFRAG:
1250 return btrfs_ioctl_defrag(file); 1298 return btrfs_ioctl_defrag(file);
1251 case BTRFS_IOC_RESIZE: 1299 case BTRFS_IOC_RESIZE: