aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.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/extent-tree.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/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c115
1 files changed, 104 insertions, 11 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index cdfb4ff4b459..7b24f1511654 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -26,6 +26,7 @@
26#include "transaction.h" 26#include "transaction.h"
27#include "volumes.h" 27#include "volumes.h"
28#include "locking.h" 28#include "locking.h"
29#include "ref-cache.h"
29 30
30#define BLOCK_GROUP_DATA EXTENT_WRITEBACK 31#define BLOCK_GROUP_DATA EXTENT_WRITEBACK
31#define BLOCK_GROUP_METADATA EXTENT_UPTODATE 32#define BLOCK_GROUP_METADATA EXTENT_UPTODATE
@@ -927,7 +928,7 @@ out:
927} 928}
928 929
929int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, 930int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
930 struct extent_buffer *buf) 931 struct extent_buffer *buf, int cache_ref)
931{ 932{
932 u64 bytenr; 933 u64 bytenr;
933 u32 nritems; 934 u32 nritems;
@@ -937,6 +938,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
937 int level; 938 int level;
938 int ret; 939 int ret;
939 int faili; 940 int faili;
941 int nr_file_extents = 0;
940 942
941 if (!root->ref_cows) 943 if (!root->ref_cows)
942 return 0; 944 return 0;
@@ -959,6 +961,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
959 if (disk_bytenr == 0) 961 if (disk_bytenr == 0)
960 continue; 962 continue;
961 963
964 if (buf != root->commit_root)
965 nr_file_extents++;
966
962 mutex_lock(&root->fs_info->alloc_mutex); 967 mutex_lock(&root->fs_info->alloc_mutex);
963 ret = __btrfs_inc_extent_ref(trans, root, disk_bytenr, 968 ret = __btrfs_inc_extent_ref(trans, root, disk_bytenr,
964 btrfs_file_extent_disk_num_bytes(buf, fi), 969 btrfs_file_extent_disk_num_bytes(buf, fi),
@@ -988,6 +993,53 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
988 } 993 }
989 } 994 }
990 } 995 }
996 /* cache orignal leaf block's references */
997 if (level == 0 && cache_ref && buf != root->commit_root) {
998 struct btrfs_leaf_ref *ref;
999 struct btrfs_extent_info *info;
1000
1001 ref = btrfs_alloc_leaf_ref(nr_file_extents);
1002 if (!ref) {
1003 WARN_ON(1);
1004 goto out;
1005 }
1006
1007 btrfs_item_key_to_cpu(buf, &ref->key, 0);
1008
1009 ref->bytenr = buf->start;
1010 ref->owner = btrfs_header_owner(buf);
1011 ref->generation = btrfs_header_generation(buf);
1012 ref->nritems = nr_file_extents;
1013 info = ref->extents;
1014
1015 for (i = 0; nr_file_extents > 0 && i < nritems; i++) {
1016 u64 disk_bytenr;
1017 btrfs_item_key_to_cpu(buf, &key, i);
1018 if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
1019 continue;
1020 fi = btrfs_item_ptr(buf, i,
1021 struct btrfs_file_extent_item);
1022 if (btrfs_file_extent_type(buf, fi) ==
1023 BTRFS_FILE_EXTENT_INLINE)
1024 continue;
1025 disk_bytenr = btrfs_file_extent_disk_bytenr(buf, fi);
1026 if (disk_bytenr == 0)
1027 continue;
1028
1029 info->bytenr = disk_bytenr;
1030 info->num_bytes =
1031 btrfs_file_extent_disk_num_bytes(buf, fi);
1032 info->objectid = key.objectid;
1033 info->offset = key.offset;
1034 info++;
1035 }
1036
1037 BUG_ON(!root->ref_tree);
1038 ret = btrfs_add_leaf_ref(root, ref);
1039 WARN_ON(ret);
1040 btrfs_free_leaf_ref(ref);
1041 }
1042out:
991 return 0; 1043 return 0;
992fail: 1044fail:
993 WARN_ON(1); 1045 WARN_ON(1);
@@ -2215,9 +2267,9 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
2215 return buf; 2267 return buf;
2216} 2268}
2217 2269
2218static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans, 2270static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans,
2219 struct btrfs_root *root, 2271 struct btrfs_root *root,
2220 struct extent_buffer *leaf) 2272 struct extent_buffer *leaf)
2221{ 2273{
2222 u64 leaf_owner; 2274 u64 leaf_owner;
2223 u64 leaf_generation; 2275 u64 leaf_generation;
@@ -2266,6 +2318,30 @@ static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans,
2266 return 0; 2318 return 0;
2267} 2319}
2268 2320
2321static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans,
2322 struct btrfs_root *root,
2323 struct btrfs_leaf_ref *ref)
2324{
2325 int i;
2326 int ret;
2327 struct btrfs_extent_info *info = ref->extents;
2328
2329 mutex_unlock(&root->fs_info->alloc_mutex);
2330 for (i = 0; i < ref->nritems; i++) {
2331 mutex_lock(&root->fs_info->alloc_mutex);
2332 ret = __btrfs_free_extent(trans, root,
2333 info->bytenr, info->num_bytes,
2334 ref->owner, ref->generation,
2335 info->objectid, info->offset, 0);
2336 mutex_unlock(&root->fs_info->alloc_mutex);
2337 BUG_ON(ret);
2338 info++;
2339 }
2340 mutex_lock(&root->fs_info->alloc_mutex);
2341
2342 return 0;
2343}
2344
2269static void noinline reada_walk_down(struct btrfs_root *root, 2345static void noinline reada_walk_down(struct btrfs_root *root,
2270 struct extent_buffer *node, 2346 struct extent_buffer *node,
2271 int slot) 2347 int slot)
@@ -2341,6 +2417,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
2341 struct extent_buffer *next; 2417 struct extent_buffer *next;
2342 struct extent_buffer *cur; 2418 struct extent_buffer *cur;
2343 struct extent_buffer *parent; 2419 struct extent_buffer *parent;
2420 struct btrfs_leaf_ref *ref;
2344 u32 blocksize; 2421 u32 blocksize;
2345 int ret; 2422 int ret;
2346 u32 refs; 2423 u32 refs;
@@ -2370,7 +2447,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
2370 btrfs_header_nritems(cur)) 2447 btrfs_header_nritems(cur))
2371 break; 2448 break;
2372 if (*level == 0) { 2449 if (*level == 0) {
2373 ret = drop_leaf_ref(trans, root, cur); 2450 ret = drop_leaf_ref_no_cache(trans, root, cur);
2374 BUG_ON(ret); 2451 BUG_ON(ret);
2375 break; 2452 break;
2376 } 2453 }
@@ -2391,6 +2468,21 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
2391 BUG_ON(ret); 2468 BUG_ON(ret);
2392 continue; 2469 continue;
2393 } 2470 }
2471
2472 if (*level == 1) {
2473 struct btrfs_key key;
2474 btrfs_node_key_to_cpu(cur, &key, path->slots[*level]);
2475 ref = btrfs_lookup_leaf_ref(root, &key);
2476 if (ref) {
2477 ret = drop_leaf_ref(trans, root, ref);
2478 BUG_ON(ret);
2479 btrfs_remove_leaf_ref(root, ref);
2480 btrfs_free_leaf_ref(ref);
2481 *level = 0;
2482 break;
2483 }
2484 }
2485
2394 next = btrfs_find_tree_block(root, bytenr, blocksize); 2486 next = btrfs_find_tree_block(root, bytenr, blocksize);
2395 if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) { 2487 if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) {
2396 free_extent_buffer(next); 2488 free_extent_buffer(next);
@@ -2398,7 +2490,6 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
2398 2490
2399 if (path->slots[*level] == 0) 2491 if (path->slots[*level] == 0)
2400 reada_walk_down(root, cur, path->slots[*level]); 2492 reada_walk_down(root, cur, path->slots[*level]);
2401
2402 next = read_tree_block(root, bytenr, blocksize, 2493 next = read_tree_block(root, bytenr, blocksize,
2403 ptr_gen); 2494 ptr_gen);
2404 cond_resched(); 2495 cond_resched();
@@ -2435,17 +2526,19 @@ out:
2435 WARN_ON(*level >= BTRFS_MAX_LEVEL); 2526 WARN_ON(*level >= BTRFS_MAX_LEVEL);
2436 2527
2437 if (path->nodes[*level] == root->node) { 2528 if (path->nodes[*level] == root->node) {
2438 root_owner = root->root_key.objectid;
2439 parent = path->nodes[*level]; 2529 parent = path->nodes[*level];
2530 bytenr = path->nodes[*level]->start;
2440 } else { 2531 } else {
2441 parent = path->nodes[*level + 1]; 2532 parent = path->nodes[*level + 1];
2442 root_owner = btrfs_header_owner(parent); 2533 bytenr = btrfs_node_blockptr(parent, path->slots[*level + 1]);
2443 } 2534 }
2444 2535
2536 blocksize = btrfs_level_size(root, *level);
2537 root_owner = btrfs_header_owner(parent);
2445 root_gen = btrfs_header_generation(parent); 2538 root_gen = btrfs_header_generation(parent);
2446 ret = __btrfs_free_extent(trans, root, path->nodes[*level]->start, 2539
2447 path->nodes[*level]->len, 2540 ret = __btrfs_free_extent(trans, root, bytenr, blocksize,
2448 root_owner, root_gen, 0, 0, 1); 2541 root_owner, root_gen, 0, 0, 1);
2449 free_extent_buffer(path->nodes[*level]); 2542 free_extent_buffer(path->nodes[*level]);
2450 path->nodes[*level] = NULL; 2543 path->nodes[*level] = NULL;
2451 *level += 1; 2544 *level += 1;