blob: 7bd12c2a1bc4b6016344f5b5e069a10000432d9c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Behún29387542017-09-03 17:00:28 +02002/*
3 * BTRFS filesystem implementation for U-Boot
4 *
5 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
Marek Behún29387542017-09-03 17:00:28 +02006 */
7
8#include "btrfs.h"
Simon Glass0f2af882020-05-10 11:40:05 -06009#include <log.h>
Marek Behún29387542017-09-03 17:00:28 +020010#include <malloc.h>
Marek Vasuta2f9cbf2018-09-22 04:13:35 +020011#include <memalign.h>
Marek Behún29387542017-09-03 17:00:28 +020012
Qu Wenruo1a618082020-06-24 18:02:49 +020013static 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
Qu Wenruod85f9592020-06-24 18:02:55 +020045int __btrfs_comp_keys(struct btrfs_key *a, struct btrfs_key *b)
Marek Behún29387542017-09-03 17:00:28 +020046{
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
Marek Behún29387542017-09-03 17:00:28 +020081 while (low < high) {
82 mid = (low + high) / 2;
83
84 tmp = (struct btrfs_key *) ((u8 *) addr + mid*item_size);
Qu Wenruod85f9592020-06-24 18:02:55 +020085 ret = __btrfs_comp_keys(tmp, key);
Marek Behún29387542017-09-03 17:00:28 +020086
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
Qu Wenruoddd0cb82020-06-24 18:02:56 +0200118static void clear_path(struct __btrfs_path *p)
Marek Behún29387542017-09-03 17:00:28 +0200119{
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
Qu Wenruoddd0cb82020-06-24 18:02:56 +0200128void __btrfs_free_path(struct __btrfs_path *p)
Marek Behún29387542017-09-03 17:00:28 +0200129{
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{
Marek Vasuta2f9cbf2018-09-22 04:13:35 +0200142 ALLOC_CACHE_ALIGN_BUFFER(struct btrfs_header, hdr,
143 sizeof(struct btrfs_header));
144 unsigned long size, offset = sizeof(*hdr);
Marek Behún29387542017-09-03 17:00:28 +0200145 union btrfs_tree_node *res;
146 u32 i;
147
Marek Vasuta2f9cbf2018-09-22 04:13:35 +0200148 if (!btrfs_devread(physical, sizeof(*hdr), hdr))
Marek Behún29387542017-09-03 17:00:28 +0200149 return -1;
150
Marek Vasuta2f9cbf2018-09-22 04:13:35 +0200151 btrfs_header_to_cpu(hdr);
Marek Behún29387542017-09-03 17:00:28 +0200152
Marek Vasuta2f9cbf2018-09-22 04:13:35 +0200153 if (hdr->level)
Marek Behún29387542017-09-03 17:00:28 +0200154 size = sizeof(struct btrfs_node)
Marek Vasuta2f9cbf2018-09-22 04:13:35 +0200155 + hdr->nritems * sizeof(struct btrfs_key_ptr);
Marek Behún29387542017-09-03 17:00:28 +0200156 else
157 size = btrfs_info.sb.nodesize;
158
Marek Vasuta2f9cbf2018-09-22 04:13:35 +0200159 res = malloc_cache_aligned(size);
Marek Behún29387542017-09-03 17:00:28 +0200160 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
Marek Vasuta2f9cbf2018-09-22 04:13:35 +0200171 memcpy(&res->header, hdr, sizeof(*hdr));
172 if (hdr->level)
173 for (i = 0; i < hdr->nritems; ++i)
Marek Behún29387542017-09-03 17:00:28 +0200174 btrfs_key_ptr_to_cpu(&res->node.ptrs[i]);
175 else
Marek Vasuta2f9cbf2018-09-22 04:13:35 +0200176 for (i = 0; i < hdr->nritems; ++i)
Marek Behún29387542017-09-03 17:00:28 +0200177 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,
Qu Wenruoddd0cb82020-06-24 18:02:56 +0200185 struct __btrfs_path *p)
Marek Behún29387542017-09-03 17:00:28 +0200186{
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
Pierre Bourdonb0ff60a2019-04-16 02:47:14 +0200221 if (lvl) {
Marek Behún29387542017-09-03 17:00:28 +0200222 logical = buf->node.ptrs[slot].blockptr;
Pierre Bourdonb0ff60a2019-04-16 02:47:14 +0200223 } 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;
Marek Behún29387542017-09-03 17:00:28 +0200233 break;
Pierre Bourdonb0ff60a2019-04-16 02:47:14 +0200234 }
Marek Behún29387542017-09-03 17:00:28 +0200235 }
236
237 return 0;
238err:
Qu Wenruoddd0cb82020-06-24 18:02:56 +0200239 __btrfs_free_path(p);
Marek Behún29387542017-09-03 17:00:28 +0200240 return -1;
241}
242
Qu Wenruoddd0cb82020-06-24 18:02:56 +0200243static int jump_leaf(struct __btrfs_path *path, int dir)
Marek Behún29387542017-09-03 17:00:28 +0200244{
Qu Wenruoddd0cb82020-06-24 18:02:56 +0200245 struct __btrfs_path p;
Marek Behún29387542017-09-03 17:00:28 +0200246 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
Qu Wenruoddd0cb82020-06-24 18:02:56 +0200305int btrfs_prev_slot(struct __btrfs_path *p)
Marek Behún29387542017-09-03 17:00:28 +0200306{
307 if (!p->slots[0])
308 return jump_leaf(p, -1);
309
310 p->slots[0]--;
311 return 0;
312}
313
Qu Wenruoddd0cb82020-06-24 18:02:56 +0200314int btrfs_next_slot(struct __btrfs_path *p)
Marek Behún29387542017-09-03 17:00:28 +0200315{
316 struct btrfs_leaf *leaf = &p->nodes[0]->leaf;
317
Yevgeny Popovychd537f862018-09-07 12:59:30 +0300318 if (p->slots[0] + 1 >= leaf->header.nritems)
Marek Behún29387542017-09-03 17:00:28 +0200319 return jump_leaf(p, 1);
320
321 p->slots[0]++;
322 return 0;
323}
Qu Wenruod85f9592020-06-24 18:02:55 +0200324
325int btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2)
326{
327 if (k1->objectid > k2->objectid)
328 return 1;
329 if (k1->objectid < k2->objectid)
330 return -1;
331 if (k1->type > k2->type)
332 return 1;
333 if (k1->type < k2->type)
334 return -1;
335 if (k1->offset > k2->offset)
336 return 1;
337 if (k1->offset < k2->offset)
338 return -1;
339 return 0;
340}
341
342static int btrfs_comp_keys(struct btrfs_disk_key *disk,
343 const struct btrfs_key *k2)
344{
345 struct btrfs_key k1;
346
347 btrfs_disk_key_to_cpu(&k1, disk);
348 return btrfs_comp_cpu_keys(&k1, k2);
349}
350
351enum btrfs_tree_block_status
352btrfs_check_node(struct btrfs_fs_info *fs_info,
353 struct btrfs_disk_key *parent_key, struct extent_buffer *buf)
354{
355 int i;
356 struct btrfs_key cpukey;
357 struct btrfs_disk_key key;
358 u32 nritems = btrfs_header_nritems(buf);
359 enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
360
361 if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(fs_info))
362 goto fail;
363
364 ret = BTRFS_TREE_BLOCK_INVALID_PARENT_KEY;
365 if (parent_key && parent_key->type) {
366 btrfs_node_key(buf, &key, 0);
367 if (memcmp(parent_key, &key, sizeof(key)))
368 goto fail;
369 }
370 ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
371 for (i = 0; nritems > 1 && i < nritems - 2; i++) {
372 btrfs_node_key(buf, &key, i);
373 btrfs_node_key_to_cpu(buf, &cpukey, i + 1);
374 if (btrfs_comp_keys(&key, &cpukey) >= 0)
375 goto fail;
376 }
377 return BTRFS_TREE_BLOCK_CLEAN;
378fail:
379 return ret;
380}
381
382enum btrfs_tree_block_status
383btrfs_check_leaf(struct btrfs_fs_info *fs_info,
384 struct btrfs_disk_key *parent_key, struct extent_buffer *buf)
385{
386 int i;
387 struct btrfs_key cpukey;
388 struct btrfs_disk_key key;
389 u32 nritems = btrfs_header_nritems(buf);
390 enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS;
391
392 if (nritems * sizeof(struct btrfs_item) > buf->len) {
393 fprintf(stderr, "invalid number of items %llu\n",
394 (unsigned long long)buf->start);
395 goto fail;
396 }
397
398 if (btrfs_header_level(buf) != 0) {
399 ret = BTRFS_TREE_BLOCK_INVALID_LEVEL;
400 fprintf(stderr, "leaf is not a leaf %llu\n",
401 (unsigned long long)btrfs_header_bytenr(buf));
402 goto fail;
403 }
404 if (btrfs_leaf_free_space(buf) < 0) {
405 ret = BTRFS_TREE_BLOCK_INVALID_FREE_SPACE;
406 fprintf(stderr, "leaf free space incorrect %llu %d\n",
407 (unsigned long long)btrfs_header_bytenr(buf),
408 btrfs_leaf_free_space(buf));
409 goto fail;
410 }
411
412 if (nritems == 0)
413 return BTRFS_TREE_BLOCK_CLEAN;
414
415 btrfs_item_key(buf, &key, 0);
416 if (parent_key && parent_key->type &&
417 memcmp(parent_key, &key, sizeof(key))) {
418 ret = BTRFS_TREE_BLOCK_INVALID_PARENT_KEY;
419 fprintf(stderr, "leaf parent key incorrect %llu\n",
420 (unsigned long long)btrfs_header_bytenr(buf));
421 goto fail;
422 }
423 for (i = 0; nritems > 1 && i < nritems - 1; i++) {
424 btrfs_item_key(buf, &key, i);
425 btrfs_item_key_to_cpu(buf, &cpukey, i + 1);
426 if (btrfs_comp_keys(&key, &cpukey) >= 0) {
427 ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER;
428 fprintf(stderr, "bad key ordering %d %d\n", i, i+1);
429 goto fail;
430 }
431 if (btrfs_item_offset_nr(buf, i) !=
432 btrfs_item_end_nr(buf, i + 1)) {
433 ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
434 fprintf(stderr, "incorrect offsets %u %u\n",
435 btrfs_item_offset_nr(buf, i),
436 btrfs_item_end_nr(buf, i + 1));
437 goto fail;
438 }
439 if (i == 0 && btrfs_item_end_nr(buf, i) !=
440 BTRFS_LEAF_DATA_SIZE(fs_info)) {
441 ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
442 fprintf(stderr, "bad item end %u wanted %u\n",
443 btrfs_item_end_nr(buf, i),
444 (unsigned)BTRFS_LEAF_DATA_SIZE(fs_info));
445 goto fail;
446 }
447 }
448
449 for (i = 0; i < nritems; i++) {
450 if (btrfs_item_end_nr(buf, i) >
451 BTRFS_LEAF_DATA_SIZE(fs_info)) {
452 btrfs_item_key(buf, &key, 0);
453 ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
454 fprintf(stderr, "slot end outside of leaf %llu > %llu\n",
455 (unsigned long long)btrfs_item_end_nr(buf, i),
456 (unsigned long long)BTRFS_LEAF_DATA_SIZE(
457 fs_info));
458 goto fail;
459 }
460 }
461
462 return BTRFS_TREE_BLOCK_CLEAN;
463fail:
464 return ret;
465}
466
467/*
468 * how many bytes are required to store the items in a leaf. start
469 * and nr indicate which items in the leaf to check. This totals up the
470 * space used both by the item structs and the item data
471 */
472static int leaf_space_used(struct extent_buffer *l, int start, int nr)
473{
474 int data_len;
475 int nritems = btrfs_header_nritems(l);
476 int end = min(nritems, start + nr) - 1;
477
478 if (!nr)
479 return 0;
480 data_len = btrfs_item_end_nr(l, start);
481 data_len = data_len - btrfs_item_offset_nr(l, end);
482 data_len += sizeof(struct btrfs_item) * nr;
483 WARN_ON(data_len < 0);
484 return data_len;
485}
486
487/*
488 * The space between the end of the leaf items and
489 * the start of the leaf data. IOW, how much room
490 * the leaf has left for both items and data
491 */
492int btrfs_leaf_free_space(struct extent_buffer *leaf)
493{
494 int nritems = btrfs_header_nritems(leaf);
495 u32 leaf_data_size;
496 int ret;
497
498 BUG_ON(leaf->fs_info && leaf->fs_info->nodesize != leaf->len);
499 leaf_data_size = __BTRFS_LEAF_DATA_SIZE(leaf->len);
500 ret = leaf_data_size - leaf_space_used(leaf, 0 ,nritems);
501 if (ret < 0) {
502 printk("leaf free space ret %d, leaf data size %u, used %d nritems %d\n",
503 ret, leaf_data_size, leaf_space_used(leaf, 0, nritems),
504 nritems);
505 }
506 return ret;
507}