aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-07-28 15:32:19 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commit31153d81284934601d08110ac7698fd9a535e4c0 (patch)
tree38f873fea3012a58d2a8f4d439a9546443617878 /fs/btrfs/transaction.c
parent3a115f520f391b4ab14041bdd6eedb370d944fa6 (diff)
Btrfs: Add a leaf reference cache
Much of the IO done while dropping snapshots is done looking up leaves in the filesystem trees to see if they point to any extents and to drop the references on any extents found. This creates a cache so that IO isn't required. Signed-off-by: Chris Mason <chris.mason@oracle.com>
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