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.c67
1 files changed, 49 insertions, 18 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 768b0d223e68..543e5ee4033a 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -24,6 +24,7 @@
24#include "disk-io.h" 24#include "disk-io.h"
25#include "transaction.h" 25#include "transaction.h"
26#include "locking.h" 26#include "locking.h"
27#include "ref-cache.h"
27 28
28static int total_trans = 0; 29static int total_trans = 0;
29extern struct kmem_cache *btrfs_trans_handle_cachep; 30extern struct kmem_cache *btrfs_trans_handle_cachep;
@@ -31,6 +32,13 @@ extern struct kmem_cache *btrfs_transaction_cachep;
31 32
32#define BTRFS_ROOT_TRANS_TAG 0 33#define BTRFS_ROOT_TRANS_TAG 0
33 34
35struct dirty_root {
36 struct list_head list;
37 struct btrfs_root *root;
38 struct btrfs_root *latest_root;
39 struct btrfs_leaf_ref_tree ref_tree;
40};
41
34static noinline void put_transaction(struct btrfs_transaction *transaction) 42static noinline void put_transaction(struct btrfs_transaction *transaction)
35{ 43{
36 WARN_ON(transaction->use_count == 0); 44 WARN_ON(transaction->use_count == 0);
@@ -84,6 +92,7 @@ static noinline int join_transaction(struct btrfs_root *root)
84 92
85static noinline int record_root_in_trans(struct btrfs_root *root) 93static noinline int record_root_in_trans(struct btrfs_root *root)
86{ 94{
95 struct dirty_root *dirty;
87 u64 running_trans_id = root->fs_info->running_transaction->transid; 96 u64 running_trans_id = root->fs_info->running_transaction->transid;
88 if (root->ref_cows && root->last_trans < running_trans_id) { 97 if (root->ref_cows && root->last_trans < running_trans_id) {
89 WARN_ON(root == root->fs_info->extent_root); 98 WARN_ON(root == root->fs_info->extent_root);
@@ -91,7 +100,25 @@ static noinline int record_root_in_trans(struct btrfs_root *root)
91 radix_tree_tag_set(&root->fs_info->fs_roots_radix, 100 radix_tree_tag_set(&root->fs_info->fs_roots_radix,
92 (unsigned long)root->root_key.objectid, 101 (unsigned long)root->root_key.objectid,
93 BTRFS_ROOT_TRANS_TAG); 102 BTRFS_ROOT_TRANS_TAG);
103
104 dirty = kmalloc(sizeof(*dirty), GFP_NOFS);
105 BUG_ON(!dirty);
106 dirty->root = kmalloc(sizeof(*dirty->root), GFP_NOFS);
107 BUG_ON(!dirty->root);
108
109 dirty->latest_root = root;
110 INIT_LIST_HEAD(&dirty->list);
111 btrfs_leaf_ref_tree_init(&dirty->ref_tree);
112 dirty->ref_tree.generation = running_trans_id;
113
94 root->commit_root = btrfs_root_node(root); 114 root->commit_root = btrfs_root_node(root);
115 root->ref_tree = &dirty->ref_tree;
116
117 memcpy(dirty->root, root, sizeof(*root));
118 spin_lock_init(&dirty->root->node_lock);
119 mutex_init(&dirty->root->objectid_mutex);
120 dirty->root->node = root->commit_root;
121 dirty->root->commit_root = NULL;
95 } else { 122 } else {
96 WARN_ON(1); 123 WARN_ON(1);
97 } 124 }
@@ -310,12 +337,6 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
310 return 0; 337 return 0;
311} 338}
312 339
313struct dirty_root {
314 struct list_head list;
315 struct btrfs_root *root;
316 struct btrfs_root *latest_root;
317};
318
319int btrfs_add_dead_root(struct btrfs_root *root, 340int btrfs_add_dead_root(struct btrfs_root *root,
320 struct btrfs_root *latest, 341 struct btrfs_root *latest,
321 struct list_head *dead_list) 342 struct list_head *dead_list)
@@ -325,8 +346,10 @@ int btrfs_add_dead_root(struct btrfs_root *root,
325 dirty = kmalloc(sizeof(*dirty), GFP_NOFS); 346 dirty = kmalloc(sizeof(*dirty), GFP_NOFS);
326 if (!dirty) 347 if (!dirty)
327 return -ENOMEM; 348 return -ENOMEM;
349 btrfs_leaf_ref_tree_init(&dirty->ref_tree);
328 dirty->root = root; 350 dirty->root = root;
329 dirty->latest_root = latest; 351 dirty->latest_root = latest;
352 root->ref_tree = NULL;
330 list_add(&dirty->list, dead_list); 353 list_add(&dirty->list, dead_list);
331 return 0; 354 return 0;
332} 355}
@@ -354,11 +377,23 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
354 radix_tree_tag_clear(radix, 377 radix_tree_tag_clear(radix,
355 (unsigned long)root->root_key.objectid, 378 (unsigned long)root->root_key.objectid,
356 BTRFS_ROOT_TRANS_TAG); 379 BTRFS_ROOT_TRANS_TAG);
380
381 BUG_ON(!root->ref_tree);
382 dirty = container_of(root->ref_tree, struct dirty_root,
383 ref_tree);
384
357 if (root->commit_root == root->node) { 385 if (root->commit_root == root->node) {
358 WARN_ON(root->node->start != 386 WARN_ON(root->node->start !=
359 btrfs_root_bytenr(&root->root_item)); 387 btrfs_root_bytenr(&root->root_item));
388
389 BUG_ON(!btrfs_leaf_ref_tree_empty(
390 root->ref_tree));
360 free_extent_buffer(root->commit_root); 391 free_extent_buffer(root->commit_root);
361 root->commit_root = NULL; 392 root->commit_root = NULL;
393 root->ref_tree = NULL;
394
395 kfree(dirty->root);
396 kfree(dirty);
362 397
363 /* make sure to update the root on disk 398 /* make sure to update the root on disk
364 * so we get any updates to the block used 399 * so we get any updates to the block used
@@ -370,23 +405,12 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
370 &root->root_item); 405 &root->root_item);
371 continue; 406 continue;
372 } 407 }
373 dirty = kmalloc(sizeof(*dirty), GFP_NOFS);
374 BUG_ON(!dirty);
375 dirty->root = kmalloc(sizeof(*dirty->root), GFP_NOFS);
376 BUG_ON(!dirty->root);
377 408
378 memset(&root->root_item.drop_progress, 0, 409 memset(&root->root_item.drop_progress, 0,
379 sizeof(struct btrfs_disk_key)); 410 sizeof(struct btrfs_disk_key));
380 root->root_item.drop_level = 0; 411 root->root_item.drop_level = 0;
381
382 memcpy(dirty->root, root, sizeof(*root));
383 dirty->root->node = root->commit_root;
384 dirty->latest_root = root;
385 spin_lock_init(&dirty->root->node_lock);
386 mutex_init(&dirty->root->objectid_mutex);
387
388 root->commit_root = NULL; 412 root->commit_root = NULL;
389 413 root->ref_tree = NULL;
390 root->root_key.offset = root->fs_info->generation; 414 root->root_key.offset = root->fs_info->generation;
391 btrfs_set_root_bytenr(&root->root_item, 415 btrfs_set_root_bytenr(&root->root_item,
392 root->node->start); 416 root->node->start);
@@ -409,6 +433,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
409 list_add(&dirty->list, list); 433 list_add(&dirty->list, list);
410 } else { 434 } else {
411 WARN_ON(1); 435 WARN_ON(1);
436 free_extent_buffer(dirty->root->node);
412 kfree(dirty->root); 437 kfree(dirty->root);
413 kfree(dirty); 438 kfree(dirty);
414 } 439 }
@@ -514,6 +539,8 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
514 ret = btrfs_end_transaction(trans, tree_root); 539 ret = btrfs_end_transaction(trans, tree_root);
515 BUG_ON(ret); 540 BUG_ON(ret);
516 541
542 btrfs_remove_leaf_refs(dirty->root);
543
517 free_extent_buffer(dirty->root->node); 544 free_extent_buffer(dirty->root->node);
518 kfree(dirty->root); 545 kfree(dirty->root);
519 kfree(dirty); 546 kfree(dirty);
@@ -698,6 +725,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
698 &dirty_fs_roots); 725 &dirty_fs_roots);
699 BUG_ON(ret); 726 BUG_ON(ret);
700 727
728 spin_lock(&root->fs_info->ref_cache_lock);
729 root->fs_info->running_ref_cache_size = 0;
730 spin_unlock(&root->fs_info->ref_cache_lock);
731
701 ret = btrfs_commit_tree_roots(trans, root); 732 ret = btrfs_commit_tree_roots(trans, root);
702 BUG_ON(ret); 733 BUG_ON(ret);
703 734