aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
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;