diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 113 |
1 files changed, 37 insertions, 76 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 2d654c1c794d..2cb116099b90 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -17,6 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/slab.h> | ||
20 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
21 | #include <linux/writeback.h> | 22 | #include <linux/writeback.h> |
22 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> |
@@ -147,18 +148,13 @@ static void wait_current_trans(struct btrfs_root *root) | |||
147 | while (1) { | 148 | while (1) { |
148 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, | 149 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, |
149 | TASK_UNINTERRUPTIBLE); | 150 | TASK_UNINTERRUPTIBLE); |
150 | if (cur_trans->blocked) { | 151 | if (!cur_trans->blocked) |
151 | mutex_unlock(&root->fs_info->trans_mutex); | ||
152 | schedule(); | ||
153 | mutex_lock(&root->fs_info->trans_mutex); | ||
154 | finish_wait(&root->fs_info->transaction_wait, | ||
155 | &wait); | ||
156 | } else { | ||
157 | finish_wait(&root->fs_info->transaction_wait, | ||
158 | &wait); | ||
159 | break; | 152 | break; |
160 | } | 153 | mutex_unlock(&root->fs_info->trans_mutex); |
154 | schedule(); | ||
155 | mutex_lock(&root->fs_info->trans_mutex); | ||
161 | } | 156 | } |
157 | finish_wait(&root->fs_info->transaction_wait, &wait); | ||
162 | put_transaction(cur_trans); | 158 | put_transaction(cur_trans); |
163 | } | 159 | } |
164 | } | 160 | } |
@@ -760,10 +756,17 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
760 | struct btrfs_root_item *new_root_item; | 756 | struct btrfs_root_item *new_root_item; |
761 | struct btrfs_root *tree_root = fs_info->tree_root; | 757 | struct btrfs_root *tree_root = fs_info->tree_root; |
762 | struct btrfs_root *root = pending->root; | 758 | struct btrfs_root *root = pending->root; |
759 | struct btrfs_root *parent_root; | ||
760 | struct inode *parent_inode; | ||
763 | struct extent_buffer *tmp; | 761 | struct extent_buffer *tmp; |
764 | struct extent_buffer *old; | 762 | struct extent_buffer *old; |
765 | int ret; | 763 | int ret; |
766 | u64 objectid; | 764 | u64 objectid; |
765 | int namelen; | ||
766 | u64 index = 0; | ||
767 | |||
768 | parent_inode = pending->dentry->d_parent->d_inode; | ||
769 | parent_root = BTRFS_I(parent_inode)->root; | ||
767 | 770 | ||
768 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 771 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
769 | if (!new_root_item) { | 772 | if (!new_root_item) { |
@@ -774,79 +777,59 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
774 | if (ret) | 777 | if (ret) |
775 | goto fail; | 778 | goto fail; |
776 | 779 | ||
777 | record_root_in_trans(trans, root); | ||
778 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | ||
779 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | ||
780 | |||
781 | key.objectid = objectid; | 780 | key.objectid = objectid; |
782 | /* record when the snapshot was created in key.offset */ | 781 | /* record when the snapshot was created in key.offset */ |
783 | key.offset = trans->transid; | 782 | key.offset = trans->transid; |
784 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 783 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); |
785 | 784 | ||
786 | old = btrfs_lock_root_node(root); | ||
787 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | ||
788 | btrfs_set_lock_blocking(old); | ||
789 | |||
790 | btrfs_copy_root(trans, root, old, &tmp, objectid); | ||
791 | btrfs_tree_unlock(old); | ||
792 | free_extent_buffer(old); | ||
793 | |||
794 | btrfs_set_root_node(new_root_item, tmp); | ||
795 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
796 | new_root_item); | ||
797 | btrfs_tree_unlock(tmp); | ||
798 | free_extent_buffer(tmp); | ||
799 | if (ret) | ||
800 | goto fail; | ||
801 | |||
802 | key.offset = (u64)-1; | ||
803 | memcpy(&pending->root_key, &key, sizeof(key)); | 785 | memcpy(&pending->root_key, &key, sizeof(key)); |
804 | fail: | 786 | pending->root_key.offset = (u64)-1; |
805 | kfree(new_root_item); | ||
806 | return ret; | ||
807 | } | ||
808 | |||
809 | static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, | ||
810 | struct btrfs_pending_snapshot *pending) | ||
811 | { | ||
812 | int ret; | ||
813 | int namelen; | ||
814 | u64 index = 0; | ||
815 | struct btrfs_trans_handle *trans; | ||
816 | struct inode *parent_inode; | ||
817 | struct btrfs_root *parent_root; | ||
818 | |||
819 | parent_inode = pending->dentry->d_parent->d_inode; | ||
820 | parent_root = BTRFS_I(parent_inode)->root; | ||
821 | trans = btrfs_join_transaction(parent_root, 1); | ||
822 | 787 | ||
788 | record_root_in_trans(trans, parent_root); | ||
823 | /* | 789 | /* |
824 | * insert the directory item | 790 | * insert the directory item |
825 | */ | 791 | */ |
826 | namelen = strlen(pending->name); | 792 | namelen = strlen(pending->name); |
827 | ret = btrfs_set_inode_index(parent_inode, &index); | 793 | ret = btrfs_set_inode_index(parent_inode, &index); |
794 | BUG_ON(ret); | ||
828 | ret = btrfs_insert_dir_item(trans, parent_root, | 795 | ret = btrfs_insert_dir_item(trans, parent_root, |
829 | pending->name, namelen, | 796 | pending->name, namelen, |
830 | parent_inode->i_ino, | 797 | parent_inode->i_ino, |
831 | &pending->root_key, BTRFS_FT_DIR, index); | 798 | &pending->root_key, BTRFS_FT_DIR, index); |
832 | 799 | BUG_ON(ret); | |
833 | if (ret) | ||
834 | goto fail; | ||
835 | 800 | ||
836 | btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); | 801 | btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); |
837 | ret = btrfs_update_inode(trans, parent_root, parent_inode); | 802 | ret = btrfs_update_inode(trans, parent_root, parent_inode); |
838 | BUG_ON(ret); | 803 | BUG_ON(ret); |
839 | 804 | ||
805 | record_root_in_trans(trans, root); | ||
806 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | ||
807 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | ||
808 | |||
809 | old = btrfs_lock_root_node(root); | ||
810 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | ||
811 | btrfs_set_lock_blocking(old); | ||
812 | |||
813 | btrfs_copy_root(trans, root, old, &tmp, objectid); | ||
814 | btrfs_tree_unlock(old); | ||
815 | free_extent_buffer(old); | ||
816 | |||
817 | btrfs_set_root_node(new_root_item, tmp); | ||
818 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
819 | new_root_item); | ||
820 | BUG_ON(ret); | ||
821 | btrfs_tree_unlock(tmp); | ||
822 | free_extent_buffer(tmp); | ||
823 | |||
840 | ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, | 824 | ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, |
841 | pending->root_key.objectid, | 825 | pending->root_key.objectid, |
842 | parent_root->root_key.objectid, | 826 | parent_root->root_key.objectid, |
843 | parent_inode->i_ino, index, pending->name, | 827 | parent_inode->i_ino, index, pending->name, |
844 | namelen); | 828 | namelen); |
845 | |||
846 | BUG_ON(ret); | 829 | BUG_ON(ret); |
847 | 830 | ||
848 | fail: | 831 | fail: |
849 | btrfs_end_transaction(trans, fs_info->fs_root); | 832 | kfree(new_root_item); |
850 | return ret; | 833 | return ret; |
851 | } | 834 | } |
852 | 835 | ||
@@ -867,25 +850,6 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, | |||
867 | return 0; | 850 | return 0; |
868 | } | 851 | } |
869 | 852 | ||
870 | static noinline int finish_pending_snapshots(struct btrfs_trans_handle *trans, | ||
871 | struct btrfs_fs_info *fs_info) | ||
872 | { | ||
873 | struct btrfs_pending_snapshot *pending; | ||
874 | struct list_head *head = &trans->transaction->pending_snapshots; | ||
875 | int ret; | ||
876 | |||
877 | while (!list_empty(head)) { | ||
878 | pending = list_entry(head->next, | ||
879 | struct btrfs_pending_snapshot, list); | ||
880 | ret = finish_pending_snapshot(fs_info, pending); | ||
881 | BUG_ON(ret); | ||
882 | list_del(&pending->list); | ||
883 | kfree(pending->name); | ||
884 | kfree(pending); | ||
885 | } | ||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static void update_super_roots(struct btrfs_root *root) | 853 | static void update_super_roots(struct btrfs_root *root) |
890 | { | 854 | { |
891 | struct btrfs_root_item *root_item; | 855 | struct btrfs_root_item *root_item; |
@@ -1097,9 +1061,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1097 | 1061 | ||
1098 | btrfs_finish_extent_commit(trans, root); | 1062 | btrfs_finish_extent_commit(trans, root); |
1099 | 1063 | ||
1100 | /* do the directory inserts of any pending snapshot creations */ | ||
1101 | finish_pending_snapshots(trans, root->fs_info); | ||
1102 | |||
1103 | mutex_lock(&root->fs_info->trans_mutex); | 1064 | mutex_lock(&root->fs_info->trans_mutex); |
1104 | 1065 | ||
1105 | cur_trans->commit_done = 1; | 1066 | cur_trans->commit_done = 1; |