Merge branch 'qu/find-root-v3-part1' into v3.19.x
[platform/upstream/btrfs-progs.git] / find-root.c
1 /*
2  * Copyright (C) 2015 Fujitsu.  All rights reserved.
3  *
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.
7  *
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.
12  *
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.
17  */
18
19 #include "kerncompat.h"
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include "ctree.h"
24 #include "utils.h"
25 #include "find-root.h"
26 #include "volumes.h"
27 #include "disk-io.h"
28 #include "extent-cache.h"
29
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,
33                             u32 leafsize,
34                             struct btrfs_find_root_filter *filter,
35                             struct cache_extent **match)
36 {
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;
43         int ret = 0;
44
45         if (owner != filter->objectid || level < filter->level ||
46             generation < filter->generation)
47                 return ret;
48
49         /* Get the generation cache or create one */
50         cache = search_cache_extent(result, generation);
51         if (!cache) {
52                 gen_cache = malloc(sizeof(*gen_cache));
53                 BUG_ON(!gen_cache);
54                 cache = &gen_cache->cache;
55                 cache->start = generation;
56                 cache->size = 1;
57                 cache->objectid = 0;
58                 gen_cache->highest_level = 0;
59                 cache_tree_init(&gen_cache->eb_tree);
60
61                 ret = insert_cache_extent(result, cache);
62                 if (ret < 0)
63                         return ret;
64         }
65         gen_cache = container_of(cache, struct btrfs_find_root_gen_cache,
66                                  cache);
67
68         /* Higher level, clean tree and insert the new one */
69         if (level > gen_cache->highest_level) {
70                 free_extent_cache_tree(&gen_cache->eb_tree);
71                 gen_cache->highest_level = level;
72                 /* Fall into the insert routine */
73         }
74
75         /* Same level, insert it into the eb_tree */
76         if (level == gen_cache->highest_level) {
77                 ret = add_cache_extent(&gen_cache->eb_tree,
78                                        start, leafsize);
79                 if (ret < 0 && ret != -EEXIST)
80                         return ret;
81                 ret = 0;
82         }
83         if (generation == filter->match_gen &&
84             level == filter->match_level &&
85             !filter->search_all) {
86                 ret = 1;
87                 if (match)
88                         *match = search_cache_extent(&gen_cache->eb_tree,
89                                                      start);
90         }
91         return ret;
92 }
93
94 /*
95  * Return 0 if iterating all the metadata extents.
96  * Return 1 if found root with given gen/level and set *match to it.
97  * Return <0 if error happens
98  */
99 int btrfs_find_root_search(struct btrfs_root *chunk_root,
100                            struct btrfs_find_root_filter *filter,
101                            struct cache_tree *result,
102                            struct cache_extent **match)
103 {
104         struct btrfs_fs_info *fs_info = chunk_root->fs_info;
105         struct extent_buffer *eb;
106         u64 metadata_offset = 0;
107         u64 metadata_size = 0;
108         u64 offset = 0;
109         u32 leafsize = chunk_root->leafsize;
110         int suppress_errors = 0;
111         int ret = 0;
112
113         suppress_errors = fs_info->suppress_check_block_errors;
114         fs_info->suppress_check_block_errors = 1;
115         while (1) {
116                 ret = btrfs_next_metadata(&fs_info->mapping_tree,
117                                           &metadata_offset, &metadata_size);
118                 if (ret) {
119                         if (ret == -ENOENT)
120                                 ret = 0;
121                         break;
122                 }
123                 for (offset = metadata_offset;
124                      offset < metadata_offset + metadata_size;
125                      offset += chunk_root->leafsize) {
126                         eb = read_tree_block(chunk_root, offset, leafsize, 0);
127                         if (!eb || IS_ERR(eb))
128                                 continue;
129                         ret = add_eb_to_result(eb, result, leafsize, filter,
130                                                match);
131                         free_extent_buffer(eb);
132                         if (ret)
133                                 goto out;
134                 }
135         }
136 out:
137         fs_info->suppress_check_block_errors = suppress_errors;
138         return ret;
139 }