diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 115 |
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 | ||
929 | int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 930 | int 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 | } | ||
1042 | out: | ||
991 | return 0; | 1043 | return 0; |
992 | fail: | 1044 | fail: |
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 | ||
2218 | static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans, | 2270 | static 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 | ||
2321 | static 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 | |||
2269 | static void noinline reada_walk_down(struct btrfs_root *root, | 2345 | static 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; |