diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-11-17 21:02:50 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-11-17 21:02:50 -0500 |
commit | 3de4586c5278a28107030c336956381f69ff7a9d (patch) | |
tree | d636e3806cd5ecff71927d0300e46526fa23de1a /fs/btrfs/transaction.c | |
parent | 4ce4cb526f67775c1cce3e3fa01c292672ba874e (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/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 66 |
1 files changed, 53 insertions, 13 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 202c1b6df4a4..eec8b2465039 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -779,7 +779,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
779 | struct extent_buffer *tmp; | 779 | struct extent_buffer *tmp; |
780 | struct extent_buffer *old; | 780 | struct extent_buffer *old; |
781 | int ret; | 781 | int ret; |
782 | int namelen; | ||
783 | u64 objectid; | 782 | u64 objectid; |
784 | 783 | ||
785 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 784 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
@@ -816,28 +815,48 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
816 | if (ret) | 815 | if (ret) |
817 | goto fail; | 816 | goto fail; |
818 | 817 | ||
818 | key.offset = (u64)-1; | ||
819 | memcpy(&pending->root_key, &key, sizeof(key)); | ||
820 | fail: | ||
821 | kfree(new_root_item); | ||
822 | return ret; | ||
823 | } | ||
824 | |||
825 | static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, | ||
826 | struct btrfs_pending_snapshot *pending) | ||
827 | { | ||
828 | int ret; | ||
829 | int namelen; | ||
830 | u64 index = 0; | ||
831 | struct btrfs_trans_handle *trans; | ||
832 | struct inode *parent_inode; | ||
833 | struct inode *inode; | ||
834 | |||
835 | trans = btrfs_start_transaction(fs_info->fs_root, 1); | ||
836 | |||
819 | /* | 837 | /* |
820 | * insert the directory item | 838 | * insert the directory item |
821 | */ | 839 | */ |
822 | key.offset = (u64)-1; | ||
823 | namelen = strlen(pending->name); | 840 | namelen = strlen(pending->name); |
824 | ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, | 841 | parent_inode = pending->dentry->d_parent->d_inode; |
825 | pending->name, namelen, | 842 | ret = btrfs_set_inode_index(parent_inode, &index); |
826 | root->fs_info->sb->s_root->d_inode->i_ino, | 843 | ret = btrfs_insert_dir_item(trans, |
827 | &key, BTRFS_FT_DIR, 0); | 844 | BTRFS_I(parent_inode)->root, |
845 | pending->name, namelen, | ||
846 | parent_inode->i_ino, | ||
847 | &pending->root_key, BTRFS_FT_DIR, index); | ||
828 | 848 | ||
829 | if (ret) | 849 | if (ret) |
830 | goto fail; | 850 | goto fail; |
831 | 851 | #if 0 | |
832 | ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root, | 852 | ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root, |
833 | pending->name, strlen(pending->name), objectid, | 853 | pending->name, strlen(pending->name), objectid, |
834 | root->fs_info->sb->s_root->d_inode->i_ino, 0); | 854 | root->fs_info->sb->s_root->d_inode->i_ino, 0); |
835 | 855 | #endif | |
836 | /* Invalidate existing dcache entry for new snapshot. */ | 856 | inode = btrfs_lookup_dentry(parent_inode, pending->dentry); |
837 | btrfs_invalidate_dcache_root(root, pending->name, namelen); | 857 | d_instantiate(pending->dentry, inode); |
838 | |||
839 | fail: | 858 | fail: |
840 | kfree(new_root_item); | 859 | btrfs_end_transaction(trans, fs_info->fs_root); |
841 | return ret; | 860 | return ret; |
842 | } | 861 | } |
843 | 862 | ||
@@ -849,12 +868,28 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, | |||
849 | { | 868 | { |
850 | struct btrfs_pending_snapshot *pending; | 869 | struct btrfs_pending_snapshot *pending; |
851 | struct list_head *head = &trans->transaction->pending_snapshots; | 870 | struct list_head *head = &trans->transaction->pending_snapshots; |
871 | struct list_head *cur; | ||
872 | int ret; | ||
873 | |||
874 | list_for_each(cur, head) { | ||
875 | pending = list_entry(cur, struct btrfs_pending_snapshot, list); | ||
876 | ret = create_pending_snapshot(trans, fs_info, pending); | ||
877 | BUG_ON(ret); | ||
878 | } | ||
879 | return 0; | ||
880 | } | ||
881 | |||
882 | static noinline int finish_pending_snapshots(struct btrfs_trans_handle *trans, | ||
883 | struct btrfs_fs_info *fs_info) | ||
884 | { | ||
885 | struct btrfs_pending_snapshot *pending; | ||
886 | struct list_head *head = &trans->transaction->pending_snapshots; | ||
852 | int ret; | 887 | int ret; |
853 | 888 | ||
854 | while(!list_empty(head)) { | 889 | while(!list_empty(head)) { |
855 | pending = list_entry(head->next, | 890 | pending = list_entry(head->next, |
856 | struct btrfs_pending_snapshot, list); | 891 | struct btrfs_pending_snapshot, list); |
857 | ret = create_pending_snapshot(trans, fs_info, pending); | 892 | ret = finish_pending_snapshot(fs_info, pending); |
858 | BUG_ON(ret); | 893 | BUG_ON(ret); |
859 | list_del(&pending->list); | 894 | list_del(&pending->list); |
860 | kfree(pending->name); | 895 | kfree(pending->name); |
@@ -1033,11 +1068,15 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1033 | btrfs_drop_dead_reloc_roots(root); | 1068 | btrfs_drop_dead_reloc_roots(root); |
1034 | mutex_unlock(&root->fs_info->tree_reloc_mutex); | 1069 | mutex_unlock(&root->fs_info->tree_reloc_mutex); |
1035 | 1070 | ||
1071 | /* do the directory inserts of any pending snapshot creations */ | ||
1072 | finish_pending_snapshots(trans, root->fs_info); | ||
1073 | |||
1036 | mutex_lock(&root->fs_info->trans_mutex); | 1074 | mutex_lock(&root->fs_info->trans_mutex); |
1037 | 1075 | ||
1038 | cur_trans->commit_done = 1; | 1076 | cur_trans->commit_done = 1; |
1039 | root->fs_info->last_trans_committed = cur_trans->transid; | 1077 | root->fs_info->last_trans_committed = cur_trans->transid; |
1040 | wake_up(&cur_trans->commit_wait); | 1078 | wake_up(&cur_trans->commit_wait); |
1079 | |||
1041 | put_transaction(cur_trans); | 1080 | put_transaction(cur_trans); |
1042 | put_transaction(cur_trans); | 1081 | put_transaction(cur_trans); |
1043 | 1082 | ||
@@ -1046,6 +1085,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1046 | list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); | 1085 | list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); |
1047 | 1086 | ||
1048 | mutex_unlock(&root->fs_info->trans_mutex); | 1087 | mutex_unlock(&root->fs_info->trans_mutex); |
1088 | |||
1049 | kmem_cache_free(btrfs_trans_handle_cachep, trans); | 1089 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
1050 | 1090 | ||
1051 | if (root->fs_info->closing) { | 1091 | if (root->fs_info->closing) { |