diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-05-08 13:26:18 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:02 -0400 |
commit | bf4ef67924d87b0addb32f084e83a9283496350e (patch) | |
tree | 2935d0395028d878e57df73e5fbd2182abc16c41 /fs/btrfs/extent-tree.c | |
parent | a061fc8da7b990faa41ca503e66faef3ecdeead0 (diff) |
Btrfs: Properly find the root for snapshotted blocks during chunk relocation
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 120 |
1 files changed, 109 insertions, 11 deletions
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]); |