2 * Copyright (C) 2015 Fujitsu. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
19 #include "kerncompat.h"
25 #include "find-root.h"
28 #include "extent-cache.h"
30 /* Return value is the same as btrfs_find_root_search(). */
31 static int add_eb_to_result(struct extent_buffer
*eb
,
32 struct cache_tree
*result
,
34 struct btrfs_find_root_filter
*filter
,
35 struct cache_extent
**match
)
37 u64 generation
= btrfs_header_generation(eb
);
38 u64 level
= btrfs_header_level(eb
);
39 u64 owner
= btrfs_header_owner(eb
);
40 u64 start
= eb
->start
;
41 struct cache_extent
*cache
;
42 struct btrfs_find_root_gen_cache
*gen_cache
= NULL
;
45 if (owner
!= filter
->objectid
|| level
< filter
->level
||
46 generation
< filter
->generation
)
50 * Get the generation cache or create one
52 * NOTE: search_cache_extent() may return cache that doesn't cover
53 * the range. So we need an extra check to make sure it's the right one.
55 cache
= search_cache_extent(result
, generation
);
56 if (!cache
|| cache
->start
!= generation
) {
57 gen_cache
= malloc(sizeof(*gen_cache
));
59 cache
= &gen_cache
->cache
;
60 cache
->start
= generation
;
63 gen_cache
->highest_level
= 0;
64 cache_tree_init(&gen_cache
->eb_tree
);
66 ret
= insert_cache_extent(result
, cache
);
70 gen_cache
= container_of(cache
, struct btrfs_find_root_gen_cache
,
73 /* Higher level, clean tree and insert the new one */
74 if (level
> gen_cache
->highest_level
) {
75 free_extent_cache_tree(&gen_cache
->eb_tree
);
76 gen_cache
->highest_level
= level
;
77 /* Fall into the insert routine */
80 /* Same level, insert it into the eb_tree */
81 if (level
== gen_cache
->highest_level
) {
82 ret
= add_cache_extent(&gen_cache
->eb_tree
,
84 if (ret
< 0 && ret
!= -EEXIST
)
88 if (generation
== filter
->match_gen
&&
89 level
== filter
->match_level
&&
90 !filter
->search_all
) {
93 *match
= search_cache_extent(&gen_cache
->eb_tree
,
100 * Return 0 if iterating all the metadata extents.
101 * Return 1 if found root with given gen/level and set *match to it.
102 * Return <0 if error happens
104 int btrfs_find_root_search(struct btrfs_fs_info
*fs_info
,
105 struct btrfs_find_root_filter
*filter
,
106 struct cache_tree
*result
,
107 struct cache_extent
**match
)
109 struct extent_buffer
*eb
;
110 u64 chunk_offset
= 0;
113 u32 nodesize
= btrfs_super_nodesize(fs_info
->super_copy
);
114 int suppress_errors
= 0;
117 suppress_errors
= fs_info
->suppress_check_block_errors
;
118 fs_info
->suppress_check_block_errors
= 1;
120 if (filter
->objectid
!= BTRFS_CHUNK_TREE_OBJECTID
)
121 ret
= btrfs_next_bg_metadata(&fs_info
->mapping_tree
,
125 ret
= btrfs_next_bg_system(&fs_info
->mapping_tree
,
133 for (offset
= chunk_offset
;
134 offset
< chunk_offset
+ chunk_size
;
135 offset
+= nodesize
) {
136 eb
= read_tree_block_fs_info(fs_info
, offset
, nodesize
,
138 if (!eb
|| IS_ERR(eb
))
140 ret
= add_eb_to_result(eb
, result
, nodesize
, filter
,
142 free_extent_buffer(eb
);
148 fs_info
->suppress_check_block_errors
= suppress_errors
;