aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c140
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;
8extern struct kmem_cache *btrfs_trans_handle_cachep; 8extern struct kmem_cache *btrfs_trans_handle_cachep;
9extern struct kmem_cache *btrfs_transaction_cachep; 9extern 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
12static void put_transaction(struct btrfs_transaction *transaction) 14static 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
157struct 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
164int 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;
173printk("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;
198printk("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 }
209printk("add dirty done\n");
210 return 0;
211}
212
213int 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);
223printk("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
228printk("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
148int btrfs_commit_transaction(struct btrfs_trans_handle *trans, 238int 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