aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/extent-tree.c120
-rw-r--r--fs/btrfs/root-tree.c46
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);
1460int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct 1460int 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);
1462int btrfs_search_root(struct btrfs_root *root, u64 search_start,
1463 u64 *found_objectid);
1462int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid, 1464int 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 */
2434static 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 }
2498out:
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 */
2427static int noinline relocate_one_reference(struct btrfs_root *extent_root, 2506static 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 */
28int 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);
42again:
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
64out:
65 btrfs_free_path(path);
66 return ret;
67}
68
24int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, 69int 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;
57out: 102out:
58 btrfs_release_path(root, path);
59 btrfs_free_path(path); 103 btrfs_free_path(path);
60 return ret; 104 return ret;
61} 105}