diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 82b03afcbd92..1791c6e3d834 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -56,48 +56,49 @@ static noinline void switch_commit_root(struct btrfs_root *root) | |||
56 | static noinline int join_transaction(struct btrfs_root *root, int nofail) | 56 | static noinline int join_transaction(struct btrfs_root *root, int nofail) |
57 | { | 57 | { |
58 | struct btrfs_transaction *cur_trans; | 58 | struct btrfs_transaction *cur_trans; |
59 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
59 | 60 | ||
60 | spin_lock(&root->fs_info->trans_lock); | 61 | spin_lock(&fs_info->trans_lock); |
61 | loop: | 62 | loop: |
62 | /* The file system has been taken offline. No new transactions. */ | 63 | /* The file system has been taken offline. No new transactions. */ |
63 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { | 64 | if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { |
64 | spin_unlock(&root->fs_info->trans_lock); | 65 | spin_unlock(&fs_info->trans_lock); |
65 | return -EROFS; | 66 | return -EROFS; |
66 | } | 67 | } |
67 | 68 | ||
68 | if (root->fs_info->trans_no_join) { | 69 | if (fs_info->trans_no_join) { |
69 | if (!nofail) { | 70 | if (!nofail) { |
70 | spin_unlock(&root->fs_info->trans_lock); | 71 | spin_unlock(&fs_info->trans_lock); |
71 | return -EBUSY; | 72 | return -EBUSY; |
72 | } | 73 | } |
73 | } | 74 | } |
74 | 75 | ||
75 | cur_trans = root->fs_info->running_transaction; | 76 | cur_trans = fs_info->running_transaction; |
76 | if (cur_trans) { | 77 | if (cur_trans) { |
77 | if (cur_trans->aborted) { | 78 | if (cur_trans->aborted) { |
78 | spin_unlock(&root->fs_info->trans_lock); | 79 | spin_unlock(&fs_info->trans_lock); |
79 | return cur_trans->aborted; | 80 | return cur_trans->aborted; |
80 | } | 81 | } |
81 | atomic_inc(&cur_trans->use_count); | 82 | atomic_inc(&cur_trans->use_count); |
82 | atomic_inc(&cur_trans->num_writers); | 83 | atomic_inc(&cur_trans->num_writers); |
83 | cur_trans->num_joined++; | 84 | cur_trans->num_joined++; |
84 | spin_unlock(&root->fs_info->trans_lock); | 85 | spin_unlock(&fs_info->trans_lock); |
85 | return 0; | 86 | return 0; |
86 | } | 87 | } |
87 | spin_unlock(&root->fs_info->trans_lock); | 88 | spin_unlock(&fs_info->trans_lock); |
88 | 89 | ||
89 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); | 90 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); |
90 | if (!cur_trans) | 91 | if (!cur_trans) |
91 | return -ENOMEM; | 92 | return -ENOMEM; |
92 | 93 | ||
93 | spin_lock(&root->fs_info->trans_lock); | 94 | spin_lock(&fs_info->trans_lock); |
94 | if (root->fs_info->running_transaction) { | 95 | if (fs_info->running_transaction) { |
95 | /* | 96 | /* |
96 | * someone started a transaction after we unlocked. Make sure | 97 | * someone started a transaction after we unlocked. Make sure |
97 | * to redo the trans_no_join checks above | 98 | * to redo the trans_no_join checks above |
98 | */ | 99 | */ |
99 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); | 100 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); |
100 | cur_trans = root->fs_info->running_transaction; | 101 | cur_trans = fs_info->running_transaction; |
101 | goto loop; | 102 | goto loop; |
102 | } | 103 | } |
103 | 104 | ||
@@ -122,20 +123,38 @@ loop: | |||
122 | cur_trans->delayed_refs.flushing = 0; | 123 | cur_trans->delayed_refs.flushing = 0; |
123 | cur_trans->delayed_refs.run_delayed_start = 0; | 124 | cur_trans->delayed_refs.run_delayed_start = 0; |
124 | cur_trans->delayed_refs.seq = 1; | 125 | cur_trans->delayed_refs.seq = 1; |
126 | |||
127 | /* | ||
128 | * although the tree mod log is per file system and not per transaction, | ||
129 | * the log must never go across transaction boundaries. | ||
130 | */ | ||
131 | smp_mb(); | ||
132 | if (!list_empty(&fs_info->tree_mod_seq_list)) { | ||
133 | printk(KERN_ERR "btrfs: tree_mod_seq_list not empty when " | ||
134 | "creating a fresh transaction\n"); | ||
135 | WARN_ON(1); | ||
136 | } | ||
137 | if (!RB_EMPTY_ROOT(&fs_info->tree_mod_log)) { | ||
138 | printk(KERN_ERR "btrfs: tree_mod_log rb tree not empty when " | ||
139 | "creating a fresh transaction\n"); | ||
140 | WARN_ON(1); | ||
141 | } | ||
142 | atomic_set(&fs_info->tree_mod_seq, 0); | ||
143 | |||
125 | init_waitqueue_head(&cur_trans->delayed_refs.seq_wait); | 144 | init_waitqueue_head(&cur_trans->delayed_refs.seq_wait); |
126 | spin_lock_init(&cur_trans->commit_lock); | 145 | spin_lock_init(&cur_trans->commit_lock); |
127 | spin_lock_init(&cur_trans->delayed_refs.lock); | 146 | spin_lock_init(&cur_trans->delayed_refs.lock); |
128 | INIT_LIST_HEAD(&cur_trans->delayed_refs.seq_head); | 147 | INIT_LIST_HEAD(&cur_trans->delayed_refs.seq_head); |
129 | 148 | ||
130 | INIT_LIST_HEAD(&cur_trans->pending_snapshots); | 149 | INIT_LIST_HEAD(&cur_trans->pending_snapshots); |
131 | list_add_tail(&cur_trans->list, &root->fs_info->trans_list); | 150 | list_add_tail(&cur_trans->list, &fs_info->trans_list); |
132 | extent_io_tree_init(&cur_trans->dirty_pages, | 151 | extent_io_tree_init(&cur_trans->dirty_pages, |
133 | root->fs_info->btree_inode->i_mapping); | 152 | fs_info->btree_inode->i_mapping); |
134 | root->fs_info->generation++; | 153 | fs_info->generation++; |
135 | cur_trans->transid = root->fs_info->generation; | 154 | cur_trans->transid = fs_info->generation; |
136 | root->fs_info->running_transaction = cur_trans; | 155 | fs_info->running_transaction = cur_trans; |
137 | cur_trans->aborted = 0; | 156 | cur_trans->aborted = 0; |
138 | spin_unlock(&root->fs_info->trans_lock); | 157 | spin_unlock(&fs_info->trans_lock); |
139 | 158 | ||
140 | return 0; | 159 | return 0; |
141 | } | 160 | } |