diff options
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 120 | ||||
-rw-r--r-- | fs/btrfs/root-tree.c | 46 |
3 files changed, 156 insertions, 12 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 33ab165591c5..f4b4677bec77 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1459,6 +1459,8 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1459 | *item); | 1459 | *item); |
1460 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct | 1460 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct |
1461 | btrfs_root_item *item, struct btrfs_key *key); | 1461 | btrfs_root_item *item, struct btrfs_key *key); |
1462 | int btrfs_search_root(struct btrfs_root *root, u64 search_start, | ||
1463 | u64 *found_objectid); | ||
1462 | int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid, | 1464 | int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid, |
1463 | struct btrfs_root *latest_root); | 1465 | struct btrfs_root *latest_root); |
1464 | /* dir-item.c */ | 1466 | /* dir-item.c */ |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c0e67bde8428..8e69b5acfeff 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2422,6 +2422,85 @@ truncate_racing: | |||
2422 | } | 2422 | } |
2423 | 2423 | ||
2424 | /* | 2424 | /* |
2425 | * The back references tell us which tree holds a ref on a block, | ||
2426 | * but it is possible for the tree root field in the reference to | ||
2427 | * reflect the original root before a snapshot was made. In this | ||
2428 | * case we should search through all the children of a given root | ||
2429 | * to find potential holders of references on a block. | ||
2430 | * | ||
2431 | * Instead, we do something a little less fancy and just search | ||
2432 | * all the roots for a given key/block combination. | ||
2433 | */ | ||
2434 | static int find_root_for_ref(struct btrfs_root *root, | ||
2435 | struct btrfs_path *path, | ||
2436 | struct btrfs_key *key0, | ||
2437 | int level, | ||
2438 | int file_key, | ||
2439 | struct btrfs_root **found_root, | ||
2440 | u64 bytenr) | ||
2441 | { | ||
2442 | struct btrfs_key root_location; | ||
2443 | struct btrfs_root *cur_root = *found_root; | ||
2444 | struct btrfs_file_extent_item *file_extent; | ||
2445 | u64 root_search_start = BTRFS_FS_TREE_OBJECTID; | ||
2446 | u64 found_bytenr; | ||
2447 | int ret; | ||
2448 | int i; | ||
2449 | |||
2450 | root_location.offset = (u64)-1; | ||
2451 | root_location.type = BTRFS_ROOT_ITEM_KEY; | ||
2452 | path->lowest_level = level; | ||
2453 | path->reada = 0; | ||
2454 | while(1) { | ||
2455 | ret = btrfs_search_slot(NULL, cur_root, key0, path, 0, 0); | ||
2456 | found_bytenr = 0; | ||
2457 | if (ret == 0 && file_key) { | ||
2458 | struct extent_buffer *leaf = path->nodes[0]; | ||
2459 | file_extent = btrfs_item_ptr(leaf, path->slots[0], | ||
2460 | struct btrfs_file_extent_item); | ||
2461 | if (btrfs_file_extent_type(leaf, file_extent) == | ||
2462 | BTRFS_FILE_EXTENT_REG) { | ||
2463 | found_bytenr = | ||
2464 | btrfs_file_extent_disk_bytenr(leaf, | ||
2465 | file_extent); | ||
2466 | } | ||
2467 | } else if (ret == 0) { | ||
2468 | if (path->nodes[level]) | ||
2469 | found_bytenr = path->nodes[level]->start; | ||
2470 | } | ||
2471 | |||
2472 | for (i = level; i < BTRFS_MAX_LEVEL; i++) { | ||
2473 | if (!path->nodes[i]) | ||
2474 | break; | ||
2475 | free_extent_buffer(path->nodes[i]); | ||
2476 | path->nodes[i] = NULL; | ||
2477 | } | ||
2478 | btrfs_release_path(cur_root, path); | ||
2479 | |||
2480 | if (found_bytenr == bytenr) { | ||
2481 | *found_root = cur_root; | ||
2482 | ret = 0; | ||
2483 | goto out; | ||
2484 | } | ||
2485 | ret = btrfs_search_root(root->fs_info->tree_root, | ||
2486 | root_search_start, &root_search_start); | ||
2487 | if (ret) | ||
2488 | break; | ||
2489 | |||
2490 | root_location.objectid = root_search_start; | ||
2491 | cur_root = btrfs_read_fs_root_no_name(root->fs_info, | ||
2492 | &root_location); | ||
2493 | if (!cur_root) { | ||
2494 | ret = 1; | ||
2495 | break; | ||
2496 | } | ||
2497 | } | ||
2498 | out: | ||
2499 | path->lowest_level = 0; | ||
2500 | return ret; | ||
2501 | } | ||
2502 | |||
2503 | /* | ||
2425 | * note, this releases the path | 2504 | * note, this releases the path |
2426 | */ | 2505 | */ |
2427 | static int noinline relocate_one_reference(struct btrfs_root *extent_root, | 2506 | static int noinline relocate_one_reference(struct btrfs_root *extent_root, |
@@ -2430,13 +2509,15 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2430 | { | 2509 | { |
2431 | struct inode *inode; | 2510 | struct inode *inode; |
2432 | struct btrfs_root *found_root; | 2511 | struct btrfs_root *found_root; |
2433 | struct btrfs_key *root_location; | 2512 | struct btrfs_key root_location; |
2513 | struct btrfs_key found_key; | ||
2434 | struct btrfs_extent_ref *ref; | 2514 | struct btrfs_extent_ref *ref; |
2435 | u64 ref_root; | 2515 | u64 ref_root; |
2436 | u64 ref_gen; | 2516 | u64 ref_gen; |
2437 | u64 ref_objectid; | 2517 | u64 ref_objectid; |
2438 | u64 ref_offset; | 2518 | u64 ref_offset; |
2439 | int ret; | 2519 | int ret; |
2520 | int level; | ||
2440 | 2521 | ||
2441 | ref = btrfs_item_ptr(path->nodes[0], path->slots[0], | 2522 | ref = btrfs_item_ptr(path->nodes[0], path->slots[0], |
2442 | struct btrfs_extent_ref); | 2523 | struct btrfs_extent_ref); |
@@ -2446,20 +2527,30 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2446 | ref_offset = btrfs_ref_offset(path->nodes[0], ref); | 2527 | ref_offset = btrfs_ref_offset(path->nodes[0], ref); |
2447 | btrfs_release_path(extent_root, path); | 2528 | btrfs_release_path(extent_root, path); |
2448 | 2529 | ||
2449 | root_location = kmalloc(sizeof(*root_location), GFP_NOFS); | 2530 | root_location.objectid = ref_root; |
2450 | root_location->objectid = ref_root; | ||
2451 | if (ref_gen == 0) | 2531 | if (ref_gen == 0) |
2452 | root_location->offset = 0; | 2532 | root_location.offset = 0; |
2453 | else | 2533 | else |
2454 | root_location->offset = (u64)-1; | 2534 | root_location.offset = (u64)-1; |
2455 | root_location->type = BTRFS_ROOT_ITEM_KEY; | 2535 | root_location.type = BTRFS_ROOT_ITEM_KEY; |
2456 | 2536 | ||
2457 | found_root = btrfs_read_fs_root_no_name(extent_root->fs_info, | 2537 | found_root = btrfs_read_fs_root_no_name(extent_root->fs_info, |
2458 | root_location); | 2538 | &root_location); |
2459 | BUG_ON(!found_root); | 2539 | BUG_ON(!found_root); |
2460 | kfree(root_location); | ||
2461 | 2540 | ||
2462 | if (ref_objectid >= BTRFS_FIRST_FREE_OBJECTID) { | 2541 | if (ref_objectid >= BTRFS_FIRST_FREE_OBJECTID) { |
2542 | found_key.objectid = ref_objectid; | ||
2543 | found_key.type = BTRFS_EXTENT_DATA_KEY; | ||
2544 | found_key.offset = ref_offset; | ||
2545 | level = 0; | ||
2546 | |||
2547 | ret = find_root_for_ref(extent_root, path, &found_key, | ||
2548 | level, 1, &found_root, | ||
2549 | extent_key->objectid); | ||
2550 | |||
2551 | if (ret) | ||
2552 | goto out; | ||
2553 | |||
2463 | mutex_unlock(&extent_root->fs_info->fs_mutex); | 2554 | mutex_unlock(&extent_root->fs_info->fs_mutex); |
2464 | inode = btrfs_iget_locked(extent_root->fs_info->sb, | 2555 | inode = btrfs_iget_locked(extent_root->fs_info->sb, |
2465 | ref_objectid, found_root); | 2556 | ref_objectid, found_root); |
@@ -2485,12 +2576,9 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2485 | mutex_lock(&extent_root->fs_info->fs_mutex); | 2576 | mutex_lock(&extent_root->fs_info->fs_mutex); |
2486 | } else { | 2577 | } else { |
2487 | struct btrfs_trans_handle *trans; | 2578 | struct btrfs_trans_handle *trans; |
2488 | struct btrfs_key found_key; | ||
2489 | struct extent_buffer *eb; | 2579 | struct extent_buffer *eb; |
2490 | int level; | ||
2491 | int i; | 2580 | int i; |
2492 | 2581 | ||
2493 | trans = btrfs_start_transaction(found_root, 1); | ||
2494 | eb = read_tree_block(found_root, extent_key->objectid, | 2582 | eb = read_tree_block(found_root, extent_key->objectid, |
2495 | extent_key->offset); | 2583 | extent_key->offset); |
2496 | level = btrfs_header_level(eb); | 2584 | level = btrfs_header_level(eb); |
@@ -2502,6 +2590,15 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2502 | 2590 | ||
2503 | free_extent_buffer(eb); | 2591 | free_extent_buffer(eb); |
2504 | 2592 | ||
2593 | ret = find_root_for_ref(extent_root, path, &found_key, | ||
2594 | level, 0, &found_root, | ||
2595 | extent_key->objectid); | ||
2596 | |||
2597 | if (ret) | ||
2598 | goto out; | ||
2599 | |||
2600 | trans = btrfs_start_transaction(found_root, 1); | ||
2601 | |||
2505 | path->lowest_level = level; | 2602 | path->lowest_level = level; |
2506 | path->reada = 2; | 2603 | path->reada = 2; |
2507 | ret = btrfs_search_slot(trans, found_root, &found_key, path, | 2604 | ret = btrfs_search_slot(trans, found_root, &found_key, path, |
@@ -2578,6 +2675,7 @@ static int noinline relocate_one_extent(struct btrfs_root *extent_root, | |||
2578 | } | 2675 | } |
2579 | if (ret < 0) | 2676 | if (ret < 0) |
2580 | goto out; | 2677 | goto out; |
2678 | leaf = path->nodes[0]; | ||
2581 | } | 2679 | } |
2582 | 2680 | ||
2583 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 2681 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 08f19ec88092..8bf21ba0a43b 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -21,6 +21,51 @@ | |||
21 | #include "disk-io.h" | 21 | #include "disk-io.h" |
22 | #include "print-tree.h" | 22 | #include "print-tree.h" |
23 | 23 | ||
24 | /* | ||
25 | * returns 0 on finding something, 1 if no more roots are there | ||
26 | * and < 0 on error | ||
27 | */ | ||
28 | int btrfs_search_root(struct btrfs_root *root, u64 search_start, | ||
29 | u64 *found_objectid) | ||
30 | { | ||
31 | struct btrfs_path *path; | ||
32 | struct btrfs_key search_key; | ||
33 | int ret; | ||
34 | |||
35 | root = root->fs_info->tree_root; | ||
36 | search_key.objectid = search_start; | ||
37 | search_key.type = (u8)-1; | ||
38 | search_key.offset = (u64)-1; | ||
39 | |||
40 | path = btrfs_alloc_path(); | ||
41 | BUG_ON(!path); | ||
42 | again: | ||
43 | ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); | ||
44 | if (ret < 0) | ||
45 | goto out; | ||
46 | if (ret == 0) { | ||
47 | ret = 1; | ||
48 | goto out; | ||
49 | } | ||
50 | if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { | ||
51 | ret = btrfs_next_leaf(root, path); | ||
52 | if (ret) | ||
53 | goto out; | ||
54 | } | ||
55 | btrfs_item_key_to_cpu(path->nodes[0], &search_key, path->slots[0]); | ||
56 | if (search_key.type != BTRFS_ROOT_ITEM_KEY) { | ||
57 | search_key.offset++; | ||
58 | btrfs_release_path(root, path); | ||
59 | goto again; | ||
60 | } | ||
61 | ret = 0; | ||
62 | *found_objectid = search_key.objectid; | ||
63 | |||
64 | out: | ||
65 | btrfs_free_path(path); | ||
66 | return ret; | ||
67 | } | ||
68 | |||
24 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, | 69 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, |
25 | struct btrfs_root_item *item, struct btrfs_key *key) | 70 | struct btrfs_root_item *item, struct btrfs_key *key) |
26 | { | 71 | { |
@@ -55,7 +100,6 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, | |||
55 | memcpy(key, &found_key, sizeof(found_key)); | 100 | memcpy(key, &found_key, sizeof(found_key)); |
56 | ret = 0; | 101 | ret = 0; |
57 | out: | 102 | out: |
58 | btrfs_release_path(root, path); | ||
59 | btrfs_free_path(path); | 103 | btrfs_free_path(path); |
60 | return ret; | 104 | return ret; |
61 | } | 105 | } |