diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 140 |
1 files changed, 103 insertions, 37 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 20d84bd03223..83a0194ab163 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -8,6 +8,8 @@ static int total_trans = 0; | |||
8 | extern struct kmem_cache *btrfs_trans_handle_cachep; | 8 | extern struct kmem_cache *btrfs_trans_handle_cachep; |
9 | extern struct kmem_cache *btrfs_transaction_cachep; | 9 | extern struct kmem_cache *btrfs_transaction_cachep; |
10 | 10 | ||
11 | #define BTRFS_ROOT_TRANS_TAG 0 | ||
12 | |||
11 | #define TRANS_MAGIC 0xE1E10E | 13 | #define TRANS_MAGIC 0xE1E10E |
12 | static void put_transaction(struct btrfs_transaction *transaction) | 14 | static void put_transaction(struct btrfs_transaction *transaction) |
13 | { | 15 | { |
@@ -31,9 +33,10 @@ static int join_transaction(struct btrfs_root *root) | |||
31 | GFP_NOFS); | 33 | GFP_NOFS); |
32 | total_trans++; | 34 | total_trans++; |
33 | BUG_ON(!cur_trans); | 35 | BUG_ON(!cur_trans); |
36 | root->fs_info->generation++; | ||
34 | root->fs_info->running_transaction = cur_trans; | 37 | root->fs_info->running_transaction = cur_trans; |
35 | cur_trans->num_writers = 0; | 38 | cur_trans->num_writers = 0; |
36 | cur_trans->transid = root->root_key.offset + 1; | 39 | cur_trans->transid = root->fs_info->generation; |
37 | init_waitqueue_head(&cur_trans->writer_wait); | 40 | init_waitqueue_head(&cur_trans->writer_wait); |
38 | init_waitqueue_head(&cur_trans->commit_wait); | 41 | init_waitqueue_head(&cur_trans->commit_wait); |
39 | cur_trans->magic = TRANS_MAGIC; | 42 | cur_trans->magic = TRANS_MAGIC; |
@@ -51,13 +54,22 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | |||
51 | struct btrfs_trans_handle *h = | 54 | struct btrfs_trans_handle *h = |
52 | kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | 55 | kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); |
53 | int ret; | 56 | int ret; |
57 | u64 running_trans_id; | ||
54 | 58 | ||
55 | /* FIXME, use the right root */ | ||
56 | root = root->fs_info->fs_root; | ||
57 | mutex_lock(&root->fs_info->trans_mutex); | 59 | mutex_lock(&root->fs_info->trans_mutex); |
58 | ret = join_transaction(root); | 60 | ret = join_transaction(root); |
59 | BUG_ON(ret); | 61 | BUG_ON(ret); |
60 | h->transid = root->fs_info->running_transaction->transid; | 62 | running_trans_id = root->fs_info->running_transaction->transid; |
63 | |||
64 | if (root != root->fs_info->tree_root && root->last_trans < | ||
65 | running_trans_id) { | ||
66 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, | ||
67 | (unsigned long)root, BTRFS_ROOT_TRANS_TAG); | ||
68 | root->commit_root = root->node; | ||
69 | get_bh(root->node); | ||
70 | } | ||
71 | root->last_trans = running_trans_id; | ||
72 | h->transid = running_trans_id; | ||
61 | h->transaction = root->fs_info->running_transaction; | 73 | h->transaction = root->fs_info->running_transaction; |
62 | h->blocks_reserved = num_blocks; | 74 | h->blocks_reserved = num_blocks; |
63 | h->blocks_used = 0; | 75 | h->blocks_used = 0; |
@@ -72,9 +84,6 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
72 | { | 84 | { |
73 | struct btrfs_transaction *cur_trans; | 85 | struct btrfs_transaction *cur_trans; |
74 | 86 | ||
75 | /* FIXME, use the right root */ | ||
76 | root = root->fs_info->fs_root; | ||
77 | |||
78 | WARN_ON(trans->magic != TRANS_MAGIC); | 87 | WARN_ON(trans->magic != TRANS_MAGIC); |
79 | WARN_ON(trans->magic2 != TRANS_MAGIC); | 88 | WARN_ON(trans->magic2 != TRANS_MAGIC); |
80 | mutex_lock(&root->fs_info->trans_mutex); | 89 | mutex_lock(&root->fs_info->trans_mutex); |
@@ -145,17 +154,96 @@ static int wait_for_commit(struct btrfs_root *root, | |||
145 | return 0; | 154 | return 0; |
146 | } | 155 | } |
147 | 156 | ||
157 | struct dirty_root { | ||
158 | struct list_head list; | ||
159 | struct btrfs_key snap_key; | ||
160 | struct buffer_head *commit_root; | ||
161 | struct btrfs_root *root; | ||
162 | }; | ||
163 | |||
164 | int add_dirty_roots(struct btrfs_trans_handle *trans, | ||
165 | struct radix_tree_root *radix, struct list_head *list) | ||
166 | { | ||
167 | struct dirty_root *dirty; | ||
168 | struct btrfs_root *gang[8]; | ||
169 | struct btrfs_root *root; | ||
170 | int i; | ||
171 | int ret; | ||
172 | int err; | ||
173 | printk("add dirty\n"); | ||
174 | while(1) { | ||
175 | ret = radix_tree_gang_lookup_tag(radix, (void **)gang, 0, | ||
176 | ARRAY_SIZE(gang), | ||
177 | BTRFS_ROOT_TRANS_TAG); | ||
178 | if (ret == 0) | ||
179 | break; | ||
180 | for (i = 0; i < ret; i++) { | ||
181 | root = gang[i]; | ||
182 | radix_tree_tag_clear(radix, (unsigned long)root, | ||
183 | BTRFS_ROOT_TRANS_TAG); | ||
184 | if (root->commit_root == root->node) { | ||
185 | WARN_ON(root->node->b_blocknr != | ||
186 | btrfs_root_blocknr(&root->root_item)); | ||
187 | brelse(root->commit_root); | ||
188 | root->commit_root = NULL; | ||
189 | continue; | ||
190 | } | ||
191 | dirty = kmalloc(sizeof(*dirty), GFP_NOFS); | ||
192 | BUG_ON(!dirty); | ||
193 | memcpy(&dirty->snap_key, &root->root_key, | ||
194 | sizeof(root->root_key)); | ||
195 | dirty->commit_root = root->commit_root; | ||
196 | root->commit_root = NULL; | ||
197 | dirty->root = root; | ||
198 | printk("adding dirty root %Lu gen %Lu blocknr %Lu\n", root->root_key.objectid, root->root_key.offset, dirty->commit_root->b_blocknr); | ||
199 | root->root_key.offset = root->fs_info->generation; | ||
200 | btrfs_set_root_blocknr(&root->root_item, | ||
201 | root->node->b_blocknr); | ||
202 | err = btrfs_insert_root(trans, root->fs_info->tree_root, | ||
203 | &root->root_key, | ||
204 | &root->root_item); | ||
205 | BUG_ON(err); | ||
206 | list_add(&dirty->list, list); | ||
207 | } | ||
208 | } | ||
209 | printk("add dirty done\n"); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | int drop_dirty_roots(struct btrfs_root *tree_root, struct list_head *list) | ||
214 | { | ||
215 | struct dirty_root *dirty; | ||
216 | struct btrfs_trans_handle *trans; | ||
217 | int ret; | ||
218 | |||
219 | while(!list_empty(list)) { | ||
220 | dirty = list_entry(list->next, struct dirty_root, list); | ||
221 | list_del_init(&dirty->list); | ||
222 | trans = btrfs_start_transaction(tree_root, 1); | ||
223 | printk("drop snapshot root %p, commit_root blocknr %Lu generation %Lu\n", dirty->root, dirty->commit_root->b_blocknr, dirty->snap_key.offset); | ||
224 | ret = btrfs_drop_snapshot(trans, dirty->root, | ||
225 | dirty->commit_root); | ||
226 | BUG_ON(ret); | ||
227 | |||
228 | printk("del root objectid %Lu, offset %Lu\n", dirty->snap_key.objectid, dirty->snap_key.offset); | ||
229 | ret = btrfs_del_root(trans, tree_root, &dirty->snap_key); | ||
230 | BUG_ON(ret); | ||
231 | ret = btrfs_end_transaction(trans, tree_root); | ||
232 | BUG_ON(ret); | ||
233 | kfree(dirty); | ||
234 | } | ||
235 | return 0; | ||
236 | } | ||
237 | |||
148 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 238 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
149 | struct btrfs_root *root) | 239 | struct btrfs_root *root) |
150 | { | 240 | { |
151 | int ret = 0; | 241 | int ret = 0; |
152 | struct buffer_head *snap; | ||
153 | struct btrfs_key snap_key; | ||
154 | struct btrfs_transaction *cur_trans; | 242 | struct btrfs_transaction *cur_trans; |
243 | struct list_head dirty_fs_roots; | ||
155 | DEFINE_WAIT(wait); | 244 | DEFINE_WAIT(wait); |
156 | 245 | ||
157 | /* FIXME, use the right root */ | 246 | INIT_LIST_HEAD(&dirty_fs_roots); |
158 | root = root->fs_info->fs_root; | ||
159 | 247 | ||
160 | mutex_lock(&root->fs_info->trans_mutex); | 248 | mutex_lock(&root->fs_info->trans_mutex); |
161 | if (trans->transaction->in_commit) { | 249 | if (trans->transaction->in_commit) { |
@@ -184,22 +272,13 @@ printk("already in commit!, waiting\n"); | |||
184 | } | 272 | } |
185 | finish_wait(&trans->transaction->writer_wait, &wait); | 273 | finish_wait(&trans->transaction->writer_wait, &wait); |
186 | WARN_ON(cur_trans != trans->transaction); | 274 | WARN_ON(cur_trans != trans->transaction); |
187 | if (root->node != root->commit_root) { | 275 | add_dirty_roots(trans, &root->fs_info->fs_roots_radix, &dirty_fs_roots); |
188 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); | ||
189 | root->root_key.offset++; | ||
190 | } | ||
191 | |||
192 | if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) { | ||
193 | btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); | ||
194 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, | ||
195 | &root->root_key, &root->root_item); | ||
196 | BUG_ON(ret); | ||
197 | } | ||
198 | |||
199 | ret = btrfs_commit_tree_roots(trans, root); | 276 | ret = btrfs_commit_tree_roots(trans, root); |
200 | BUG_ON(ret); | 277 | BUG_ON(ret); |
201 | cur_trans = root->fs_info->running_transaction; | 278 | cur_trans = root->fs_info->running_transaction; |
202 | root->fs_info->running_transaction = NULL; | 279 | root->fs_info->running_transaction = NULL; |
280 | btrfs_set_super_generation(root->fs_info->disk_super, | ||
281 | root->fs_info->generation + 1); | ||
203 | mutex_unlock(&root->fs_info->trans_mutex); | 282 | mutex_unlock(&root->fs_info->trans_mutex); |
204 | ret = btrfs_write_and_wait_transaction(trans, root); | 283 | ret = btrfs_write_and_wait_transaction(trans, root); |
205 | BUG_ON(ret); | 284 | BUG_ON(ret); |
@@ -213,21 +292,8 @@ printk("already in commit!, waiting\n"); | |||
213 | put_transaction(cur_trans); | 292 | put_transaction(cur_trans); |
214 | mutex_unlock(&root->fs_info->trans_mutex); | 293 | mutex_unlock(&root->fs_info->trans_mutex); |
215 | kmem_cache_free(btrfs_trans_handle_cachep, trans); | 294 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
216 | if (root->node != root->commit_root) { | ||
217 | trans = btrfs_start_transaction(root, 1); | ||
218 | snap = root->commit_root; | ||
219 | root->commit_root = root->node; | ||
220 | get_bh(root->node); | ||
221 | ret = btrfs_drop_snapshot(trans, root, snap); | ||
222 | BUG_ON(ret); | ||
223 | 295 | ||
224 | ret = btrfs_del_root(trans, root->fs_info->tree_root, | 296 | drop_dirty_roots(root->fs_info->tree_root, &dirty_fs_roots); |
225 | &snap_key); | ||
226 | BUG_ON(ret); | ||
227 | root->fs_info->generation = root->root_key.offset + 1; | ||
228 | ret = btrfs_end_transaction(trans, root); | ||
229 | BUG_ON(ret); | ||
230 | } | ||
231 | return ret; | 297 | return ret; |
232 | } | 298 | } |
233 | 299 | ||