diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/transaction.c | 97 |
1 files changed, 31 insertions, 66 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 43054285f638..01cebd661997 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -755,10 +755,17 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
755 | struct btrfs_root_item *new_root_item; | 755 | struct btrfs_root_item *new_root_item; |
756 | struct btrfs_root *tree_root = fs_info->tree_root; | 756 | struct btrfs_root *tree_root = fs_info->tree_root; |
757 | struct btrfs_root *root = pending->root; | 757 | struct btrfs_root *root = pending->root; |
758 | struct btrfs_root *parent_root; | ||
759 | struct inode *parent_inode; | ||
758 | struct extent_buffer *tmp; | 760 | struct extent_buffer *tmp; |
759 | struct extent_buffer *old; | 761 | struct extent_buffer *old; |
760 | int ret; | 762 | int ret; |
761 | u64 objectid; | 763 | u64 objectid; |
764 | int namelen; | ||
765 | u64 index = 0; | ||
766 | |||
767 | parent_inode = pending->dentry->d_parent->d_inode; | ||
768 | parent_root = BTRFS_I(parent_inode)->root; | ||
762 | 769 | ||
763 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 770 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
764 | if (!new_root_item) { | 771 | if (!new_root_item) { |
@@ -769,79 +776,59 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
769 | if (ret) | 776 | if (ret) |
770 | goto fail; | 777 | goto fail; |
771 | 778 | ||
772 | record_root_in_trans(trans, root); | ||
773 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | ||
774 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | ||
775 | |||
776 | key.objectid = objectid; | 779 | key.objectid = objectid; |
777 | /* record when the snapshot was created in key.offset */ | 780 | /* record when the snapshot was created in key.offset */ |
778 | key.offset = trans->transid; | 781 | key.offset = trans->transid; |
779 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 782 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); |
780 | 783 | ||
781 | old = btrfs_lock_root_node(root); | ||
782 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | ||
783 | btrfs_set_lock_blocking(old); | ||
784 | |||
785 | btrfs_copy_root(trans, root, old, &tmp, objectid); | ||
786 | btrfs_tree_unlock(old); | ||
787 | free_extent_buffer(old); | ||
788 | |||
789 | btrfs_set_root_node(new_root_item, tmp); | ||
790 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
791 | new_root_item); | ||
792 | btrfs_tree_unlock(tmp); | ||
793 | free_extent_buffer(tmp); | ||
794 | if (ret) | ||
795 | goto fail; | ||
796 | |||
797 | key.offset = (u64)-1; | ||
798 | memcpy(&pending->root_key, &key, sizeof(key)); | 784 | memcpy(&pending->root_key, &key, sizeof(key)); |
799 | fail: | 785 | pending->root_key.offset = (u64)-1; |
800 | kfree(new_root_item); | ||
801 | return ret; | ||
802 | } | ||
803 | |||
804 | static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, | ||
805 | struct btrfs_pending_snapshot *pending) | ||
806 | { | ||
807 | int ret; | ||
808 | int namelen; | ||
809 | u64 index = 0; | ||
810 | struct btrfs_trans_handle *trans; | ||
811 | struct inode *parent_inode; | ||
812 | struct btrfs_root *parent_root; | ||
813 | |||
814 | parent_inode = pending->dentry->d_parent->d_inode; | ||
815 | parent_root = BTRFS_I(parent_inode)->root; | ||
816 | trans = btrfs_join_transaction(parent_root, 1); | ||
817 | 786 | ||
787 | record_root_in_trans(trans, parent_root); | ||
818 | /* | 788 | /* |
819 | * insert the directory item | 789 | * insert the directory item |
820 | */ | 790 | */ |
821 | namelen = strlen(pending->name); | 791 | namelen = strlen(pending->name); |
822 | ret = btrfs_set_inode_index(parent_inode, &index); | 792 | ret = btrfs_set_inode_index(parent_inode, &index); |
793 | BUG_ON(ret); | ||
823 | ret = btrfs_insert_dir_item(trans, parent_root, | 794 | ret = btrfs_insert_dir_item(trans, parent_root, |
824 | pending->name, namelen, | 795 | pending->name, namelen, |
825 | parent_inode->i_ino, | 796 | parent_inode->i_ino, |
826 | &pending->root_key, BTRFS_FT_DIR, index); | 797 | &pending->root_key, BTRFS_FT_DIR, index); |
827 | 798 | BUG_ON(ret); | |
828 | if (ret) | ||
829 | goto fail; | ||
830 | 799 | ||
831 | btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); | 800 | btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); |
832 | ret = btrfs_update_inode(trans, parent_root, parent_inode); | 801 | ret = btrfs_update_inode(trans, parent_root, parent_inode); |
833 | BUG_ON(ret); | 802 | BUG_ON(ret); |
834 | 803 | ||
804 | record_root_in_trans(trans, root); | ||
805 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | ||
806 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | ||
807 | |||
808 | old = btrfs_lock_root_node(root); | ||
809 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | ||
810 | btrfs_set_lock_blocking(old); | ||
811 | |||
812 | btrfs_copy_root(trans, root, old, &tmp, objectid); | ||
813 | btrfs_tree_unlock(old); | ||
814 | free_extent_buffer(old); | ||
815 | |||
816 | btrfs_set_root_node(new_root_item, tmp); | ||
817 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
818 | new_root_item); | ||
819 | BUG_ON(ret); | ||
820 | btrfs_tree_unlock(tmp); | ||
821 | free_extent_buffer(tmp); | ||
822 | |||
835 | ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, | 823 | ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, |
836 | pending->root_key.objectid, | 824 | pending->root_key.objectid, |
837 | parent_root->root_key.objectid, | 825 | parent_root->root_key.objectid, |
838 | parent_inode->i_ino, index, pending->name, | 826 | parent_inode->i_ino, index, pending->name, |
839 | namelen); | 827 | namelen); |
840 | |||
841 | BUG_ON(ret); | 828 | BUG_ON(ret); |
842 | 829 | ||
843 | fail: | 830 | fail: |
844 | btrfs_end_transaction(trans, fs_info->fs_root); | 831 | kfree(new_root_item); |
845 | return ret; | 832 | return ret; |
846 | } | 833 | } |
847 | 834 | ||
@@ -862,25 +849,6 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, | |||
862 | return 0; | 849 | return 0; |
863 | } | 850 | } |
864 | 851 | ||
865 | static noinline int finish_pending_snapshots(struct btrfs_trans_handle *trans, | ||
866 | struct btrfs_fs_info *fs_info) | ||
867 | { | ||
868 | struct btrfs_pending_snapshot *pending; | ||
869 | struct list_head *head = &trans->transaction->pending_snapshots; | ||
870 | int ret; | ||
871 | |||
872 | while (!list_empty(head)) { | ||
873 | pending = list_entry(head->next, | ||
874 | struct btrfs_pending_snapshot, list); | ||
875 | ret = finish_pending_snapshot(fs_info, pending); | ||
876 | BUG_ON(ret); | ||
877 | list_del(&pending->list); | ||
878 | kfree(pending->name); | ||
879 | kfree(pending); | ||
880 | } | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | static void update_super_roots(struct btrfs_root *root) | 852 | static void update_super_roots(struct btrfs_root *root) |
885 | { | 853 | { |
886 | struct btrfs_root_item *root_item; | 854 | struct btrfs_root_item *root_item; |
@@ -1092,9 +1060,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1092 | 1060 | ||
1093 | btrfs_finish_extent_commit(trans, root); | 1061 | btrfs_finish_extent_commit(trans, root); |
1094 | 1062 | ||
1095 | /* do the directory inserts of any pending snapshot creations */ | ||
1096 | finish_pending_snapshots(trans, root->fs_info); | ||
1097 | |||
1098 | mutex_lock(&root->fs_info->trans_mutex); | 1063 | mutex_lock(&root->fs_info->trans_mutex); |
1099 | 1064 | ||
1100 | cur_trans->commit_done = 1; | 1065 | cur_trans->commit_done = 1; |