]> git.ipfire.org Git - thirdparty/u-boot.git/blame - fs/btrfs/ctree.c
fs: btrfs: Crossport volumes.[ch] from btrfs-progs
[thirdparty/u-boot.git] / fs / btrfs / ctree.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
21a14fac
MB
2/*
3 * BTRFS filesystem implementation for U-Boot
4 *
5 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
21a14fac
MB
6 */
7
8#include "btrfs.h"
f7ae49fc 9#include <log.h>
21a14fac 10#include <malloc.h>
c9795396 11#include <memalign.h>
21a14fac 12
4aebb994
QW
13static const struct btrfs_csum {
14 u16 size;
15 const char name[14];
16} btrfs_csums[] = {
17 [BTRFS_CSUM_TYPE_CRC32] = { 4, "crc32c" },
18 [BTRFS_CSUM_TYPE_XXHASH] = { 8, "xxhash64" },
19 [BTRFS_CSUM_TYPE_SHA256] = { 32, "sha256" },
20 [BTRFS_CSUM_TYPE_BLAKE2] = { 32, "blake2" },
21};
22
23u16 btrfs_super_csum_size(const struct btrfs_super_block *sb)
24{
25 const u16 csum_type = btrfs_super_csum_type(sb);
26
27 return btrfs_csums[csum_type].size;
28}
29
30const char *btrfs_super_csum_name(u16 csum_type)
31{
32 return btrfs_csums[csum_type].name;
33}
34
35size_t btrfs_super_num_csums(void)
36{
37 return ARRAY_SIZE(btrfs_csums);
38}
39
40u16 btrfs_csum_type_size(u16 csum_type)
41{
42 return btrfs_csums[csum_type].size;
43}
44
21a14fac
MB
45int btrfs_comp_keys(struct btrfs_key *a, struct btrfs_key *b)
46{
47 if (a->objectid > b->objectid)
48 return 1;
49 if (a->objectid < b->objectid)
50 return -1;
51 if (a->type > b->type)
52 return 1;
53 if (a->type < b->type)
54 return -1;
55 if (a->offset > b->offset)
56 return 1;
57 if (a->offset < b->offset)
58 return -1;
59 return 0;
60}
61
62int btrfs_comp_keys_type(struct btrfs_key *a, struct btrfs_key *b)
63{
64 if (a->objectid > b->objectid)
65 return 1;
66 if (a->objectid < b->objectid)
67 return -1;
68 if (a->type > b->type)
69 return 1;
70 if (a->type < b->type)
71 return -1;
72 return 0;
73}
74
75static int generic_bin_search(void *addr, int item_size, struct btrfs_key *key,
76 int max, int *slot)
77{
78 int low = 0, high = max, mid, ret;
79 struct btrfs_key *tmp;
80
21a14fac
MB
81 while (low < high) {
82 mid = (low + high) / 2;
83
84 tmp = (struct btrfs_key *) ((u8 *) addr + mid*item_size);
85 ret = btrfs_comp_keys(tmp, key);
86
87 if (ret < 0) {
88 low = mid + 1;
89 } else if (ret > 0) {
90 high = mid;
91 } else {
92 *slot = mid;
93 return 0;
94 }
95 }
96
97 *slot = low;
98 return 1;
99}
100
101int btrfs_bin_search(union btrfs_tree_node *p, struct btrfs_key *key,
102 int *slot)
103{
104 void *addr;
105 unsigned long size;
106
107 if (p->header.level) {
108 addr = p->node.ptrs;
109 size = sizeof(struct btrfs_key_ptr);
110 } else {
111 addr = p->leaf.items;
112 size = sizeof(struct btrfs_item);
113 }
114
115 return generic_bin_search(addr, size, key, p->header.nritems, slot);
116}
117
118static void clear_path(struct btrfs_path *p)
119{
120 int i;
121
122 for (i = 0; i < BTRFS_MAX_LEVEL; ++i) {
123 p->nodes[i] = NULL;
124 p->slots[i] = 0;
125 }
126}
127
128void btrfs_free_path(struct btrfs_path *p)
129{
130 int i;
131
132 for (i = 0; i < BTRFS_MAX_LEVEL; ++i) {
133 if (p->nodes[i])
134 free(p->nodes[i]);
135 }
136
137 clear_path(p);
138}
139
140static int read_tree_node(u64 physical, union btrfs_tree_node **buf)
141{
c9795396
MV
142 ALLOC_CACHE_ALIGN_BUFFER(struct btrfs_header, hdr,
143 sizeof(struct btrfs_header));
144 unsigned long size, offset = sizeof(*hdr);
21a14fac
MB
145 union btrfs_tree_node *res;
146 u32 i;
147
c9795396 148 if (!btrfs_devread(physical, sizeof(*hdr), hdr))
21a14fac
MB
149 return -1;
150
c9795396 151 btrfs_header_to_cpu(hdr);
21a14fac 152
c9795396 153 if (hdr->level)
21a14fac 154 size = sizeof(struct btrfs_node)
c9795396 155 + hdr->nritems * sizeof(struct btrfs_key_ptr);
21a14fac
MB
156 else
157 size = btrfs_info.sb.nodesize;
158
c9795396 159 res = malloc_cache_aligned(size);
21a14fac
MB
160 if (!res) {
161 debug("%s: malloc failed\n", __func__);
162 return -1;
163 }
164
165 if (!btrfs_devread(physical + offset, size - offset,
166 ((u8 *) res) + offset)) {
167 free(res);
168 return -1;
169 }
170
c9795396
MV
171 memcpy(&res->header, hdr, sizeof(*hdr));
172 if (hdr->level)
173 for (i = 0; i < hdr->nritems; ++i)
21a14fac
MB
174 btrfs_key_ptr_to_cpu(&res->node.ptrs[i]);
175 else
c9795396 176 for (i = 0; i < hdr->nritems; ++i)
21a14fac
MB
177 btrfs_item_to_cpu(&res->leaf.items[i]);
178
179 *buf = res;
180
181 return 0;
182}
183
184int btrfs_search_tree(const struct btrfs_root *root, struct btrfs_key *key,
185 struct btrfs_path *p)
186{
187 u8 lvl, prev_lvl;
188 int i, slot, ret;
189 u64 logical, physical;
190 union btrfs_tree_node *buf;
191
192 clear_path(p);
193
194 logical = root->bytenr;
195
196 for (i = 0; i < BTRFS_MAX_LEVEL; ++i) {
197 physical = btrfs_map_logical_to_physical(logical);
198 if (physical == -1ULL)
199 goto err;
200
201 if (read_tree_node(physical, &buf))
202 goto err;
203
204 lvl = buf->header.level;
205 if (i && prev_lvl != lvl + 1) {
206 printf("%s: invalid level in header at %llu\n",
207 __func__, logical);
208 goto err;
209 }
210 prev_lvl = lvl;
211
212 ret = btrfs_bin_search(buf, key, &slot);
213 if (ret < 0)
214 goto err;
215 if (ret && slot > 0 && lvl)
216 slot -= 1;
217
218 p->slots[lvl] = slot;
219 p->nodes[lvl] = buf;
220
1627e5e5 221 if (lvl) {
21a14fac 222 logical = buf->node.ptrs[slot].blockptr;
1627e5e5
PB
223 } else {
224 /*
225 * The path might be invalid if:
226 * cur leaf max < searched value < next leaf min
227 *
228 * Jump to the next valid element if it exists.
229 */
230 if (slot >= buf->header.nritems)
231 if (btrfs_next_slot(p) < 0)
232 goto err;
21a14fac 233 break;
1627e5e5 234 }
21a14fac
MB
235 }
236
237 return 0;
238err:
239 btrfs_free_path(p);
240 return -1;
241}
242
243static int jump_leaf(struct btrfs_path *path, int dir)
244{
245 struct btrfs_path p;
246 u32 slot;
247 int level = 1, from_level, i;
248
249 dir = dir >= 0 ? 1 : -1;
250
251 p = *path;
252
253 while (level < BTRFS_MAX_LEVEL) {
254 if (!p.nodes[level])
255 return 1;
256
257 slot = p.slots[level];
258 if ((dir > 0 && slot + dir >= p.nodes[level]->header.nritems)
259 || (dir < 0 && !slot))
260 level++;
261 else
262 break;
263 }
264
265 if (level == BTRFS_MAX_LEVEL)
266 return 1;
267
268 p.slots[level] = slot + dir;
269 level--;
270 from_level = level;
271
272 while (level >= 0) {
273 u64 logical, physical;
274
275 slot = p.slots[level + 1];
276 logical = p.nodes[level + 1]->node.ptrs[slot].blockptr;
277 physical = btrfs_map_logical_to_physical(logical);
278 if (physical == -1ULL)
279 goto err;
280
281 if (read_tree_node(physical, &p.nodes[level]))
282 goto err;
283
284 if (dir > 0)
285 p.slots[level] = 0;
286 else
287 p.slots[level] = p.nodes[level]->header.nritems - 1;
288 level--;
289 }
290
291 /* Free rewritten nodes in path */
292 for (i = 0; i <= from_level; ++i)
293 free(path->nodes[i]);
294
295 *path = p;
296 return 0;
297
298err:
299 /* Free rewritten nodes in p */
300 for (i = level + 1; i <= from_level; ++i)
301 free(p.nodes[i]);
302 return -1;
303}
304
305int btrfs_prev_slot(struct btrfs_path *p)
306{
307 if (!p->slots[0])
308 return jump_leaf(p, -1);
309
310 p->slots[0]--;
311 return 0;
312}
313
314int btrfs_next_slot(struct btrfs_path *p)
315{
316 struct btrfs_leaf *leaf = &p->nodes[0]->leaf;
317
5b781cf0 318 if (p->slots[0] + 1 >= leaf->header.nritems)
21a14fac
MB
319 return jump_leaf(p, 1);
320
321 p->slots[0]++;
322 return 0;
323}