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