summaryrefslogtreecommitdiff
path: root/fs/btrfs/root.c
blob: 127b67fd1c89fef11c52b92215f11decb1c12f44 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// SPDX-License-Identifier: GPL-2.0+
/*
 * BTRFS filesystem implementation for U-Boot
 *
 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
 */

#include "btrfs.h"

static void read_root_item(struct btrfs_path *p, struct btrfs_root_item *item)
{
	u32 len;
	int reset = 0;

	len = btrfs_path_item_size(p);
	memcpy(item, btrfs_path_item_ptr(p, struct btrfs_root_item), len);
	btrfs_root_item_to_cpu(item);

	if (len < sizeof(*item))
		reset = 1;
	if (!reset && item->generation != item->generation_v2) {
		if (item->generation_v2 != 0)
			printf("%s: generation != generation_v2 in root item",
			       __func__);
		reset = 1;
	}
	if (reset) {
		memset(&item->generation_v2, 0,
		       sizeof(*item) - offsetof(struct btrfs_root_item,
						generation_v2));
	}
}

int btrfs_find_root(u64 objectid, struct btrfs_root *root,
		    struct btrfs_root_item *root_item)
{
	struct btrfs_path path;
	struct btrfs_root_item my_root_item;

	if (!btrfs_search_tree_key_type(&btrfs_info.tree_root, objectid,
					BTRFS_ROOT_ITEM_KEY, &path))
		return -1;

	if (!root_item)
		root_item = &my_root_item;
	read_root_item(&path, root_item);

	if (root) {
		root->objectid = objectid;
		root->bytenr = root_item->bytenr;
		root->root_dirid = root_item->root_dirid;
	}

	btrfs_free_path(&path);
	return 0;
}

u64 btrfs_lookup_root_ref(u64 subvolid, struct btrfs_root_ref *refp, char *name)
{
	struct btrfs_path path;
	struct btrfs_key *key;
	struct btrfs_root_ref *ref;
	u64 res = -1ULL;

	key = btrfs_search_tree_key_type(&btrfs_info.tree_root, subvolid,
					       BTRFS_ROOT_BACKREF_KEY, &path);

	if (!key)
		return -1ULL;

	ref = btrfs_path_item_ptr(&path, struct btrfs_root_ref);
	btrfs_root_ref_to_cpu(ref);

	if (refp)
		*refp = *ref;

	if (name) {
		if (ref->name_len > BTRFS_VOL_NAME_MAX) {
			printf("%s: volume name too long: %u\n", __func__,
			       ref->name_len);
			goto out;
		}

		memcpy(name, ref + 1, ref->name_len);
	}

	res = key->offset;
out:
	btrfs_free_path(&path);
	return res;
}