1 // SPDX-License-Identifier: GPL-2.0+
3 * BTRFS filesystem implementation for U-Boot
5 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
8 #include <linux/kernel.h>
15 u64 __btrfs_lookup_inode_ref(struct __btrfs_root *root, u64 inr,
16 struct btrfs_inode_ref *refp, char *name)
18 struct __btrfs_path path;
19 struct btrfs_key *key;
20 struct btrfs_inode_ref *ref;
23 key = btrfs_search_tree_key_type(root, inr, BTRFS_INODE_REF_KEY,
29 ref = btrfs_path_item_ptr(&path, struct btrfs_inode_ref);
30 btrfs_inode_ref_to_cpu(ref);
36 if (ref->name_len > BTRFS_NAME_LEN) {
37 printf("%s: inode name too long: %u\n", __func__,
42 memcpy(name, ref + 1, ref->name_len);
47 __btrfs_free_path(&path);
51 int __btrfs_lookup_inode(const struct __btrfs_root *root,
52 struct btrfs_key *location,
53 struct btrfs_inode_item *item,
54 struct __btrfs_root *new_root)
56 struct __btrfs_root tmp_root = *root;
57 struct __btrfs_path path;
60 if (location->type == BTRFS_ROOT_ITEM_KEY) {
61 if (btrfs_find_root(location->objectid, &tmp_root, NULL))
64 location->objectid = tmp_root.root_dirid;
65 location->type = BTRFS_INODE_ITEM_KEY;
69 if (btrfs_search_tree(&tmp_root, location, &path))
72 if (__btrfs_comp_keys(location, btrfs_path_leaf_key(&path)))
76 *item = *btrfs_path_item_ptr(&path, struct btrfs_inode_item);
77 btrfs_inode_item_to_cpu(item);
86 __btrfs_free_path(&path);
91 * Read the content of symlink inode @ino of @root, into @target.
92 * NOTE: @target will not be \0 termiated, caller should handle it properly.
94 * Return the number of read data.
95 * Return <0 for error.
97 int btrfs_readlink(struct btrfs_root *root, u64 ino, char *target)
99 struct btrfs_path path;
100 struct btrfs_key key;
101 struct btrfs_file_extent_item *fi;
105 key.type = BTRFS_EXTENT_DATA_KEY;
107 btrfs_init_path(&path);
109 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
116 fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
117 struct btrfs_file_extent_item);
118 if (btrfs_file_extent_type(path.nodes[0], fi) !=
119 BTRFS_FILE_EXTENT_INLINE) {
121 error("Extent for symlink %llu must be INLINE type!", ino);
124 if (btrfs_file_extent_compression(path.nodes[0], fi) !=
125 BTRFS_COMPRESS_NONE) {
127 error("Extent for symlink %llu must not be compressed!", ino);
130 if (btrfs_file_extent_ram_bytes(path.nodes[0], fi) >=
131 root->fs_info->sectorsize) {
133 error("Symlink %llu extent data too large (%llu)!\n",
134 ino, btrfs_file_extent_ram_bytes(path.nodes[0], fi));
137 read_extent_buffer(path.nodes[0], target,
138 btrfs_file_extent_inline_start(fi),
139 btrfs_file_extent_ram_bytes(path.nodes[0], fi));
140 ret = btrfs_file_extent_ram_bytes(path.nodes[0], fi);
142 btrfs_release_path(&path);
146 int __btrfs_readlink(const struct __btrfs_root *root, u64 inr, char *target)
148 struct btrfs_root *subvolume;
149 struct btrfs_fs_info *fs_info = current_fs_info;
150 struct btrfs_key key;
154 key.objectid = root->objectid;
155 key.type = BTRFS_ROOT_ITEM_KEY;
156 key.offset = (u64)-1;
157 subvolume = btrfs_read_fs_root(fs_info, &key);
158 if (IS_ERR(subvolume))
161 ret = btrfs_readlink(subvolume, inr, target);
168 static int lookup_root_ref(struct btrfs_fs_info *fs_info,
169 u64 rootid, u64 *root_ret, u64 *dir_ret)
171 struct btrfs_root *root = fs_info->tree_root;
172 struct btrfs_root_ref *root_ref;
173 struct btrfs_path path;
174 struct btrfs_key key;
177 btrfs_init_path(&path);
178 key.objectid = rootid;
179 key.type = BTRFS_ROOT_BACKREF_KEY;
180 key.offset = (u64)-1;
182 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
185 /* Should not happen */
190 ret = btrfs_previous_item(root, &path, rootid, BTRFS_ROOT_BACKREF_KEY);
197 btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
198 root_ref = btrfs_item_ptr(path.nodes[0], path.slots[0],
199 struct btrfs_root_ref);
200 *root_ret = key.offset;
201 *dir_ret = btrfs_root_ref_dirid(path.nodes[0], root_ref);
203 btrfs_release_path(&path);
208 * To get the parent inode of @ino of @root.
210 * @root_ret and @ino_ret will be filled.
212 * NOTE: This function is not reliable. It can only get one parent inode.
213 * The get the proper parent inode, we need a full VFS inodes stack to
216 static int get_parent_inode(struct btrfs_root *root, u64 ino,
217 struct btrfs_root **root_ret, u64 *ino_ret)
219 struct btrfs_fs_info *fs_info = root->fs_info;
220 struct btrfs_path path;
221 struct btrfs_key key;
224 if (ino == BTRFS_FIRST_FREE_OBJECTID) {
225 u64 parent_root = -1;
227 /* It's top level already, no more parent */
228 if (root->root_key.objectid == BTRFS_FS_TREE_OBJECTID) {
229 *root_ret = fs_info->fs_root;
230 *ino_ret = BTRFS_FIRST_FREE_OBJECTID;
234 ret = lookup_root_ref(fs_info, root->root_key.objectid,
235 &parent_root, ino_ret);
239 key.objectid = parent_root;
240 key.type = BTRFS_ROOT_ITEM_KEY;
241 key.offset = (u64)-1;
242 *root_ret = btrfs_read_fs_root(fs_info, &key);
243 if (IS_ERR(*root_ret))
244 return PTR_ERR(*root_ret);
249 btrfs_init_path(&path);
251 key.type = BTRFS_INODE_REF_KEY;
252 key.offset = (u64)-1;
254 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
257 /* Should not happen */
262 ret = btrfs_previous_item(root, &path, ino, BTRFS_INODE_REF_KEY);
269 btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
271 *ino_ret = key.offset;
273 btrfs_release_path(&path);
277 /* inr must be a directory (for regular files with multiple hard links this
278 function returns only one of the parents of the file) */
279 static u64 __get_parent_inode(struct __btrfs_root *root, u64 inr,
280 struct btrfs_inode_item *inode_item)
282 struct btrfs_key key;
285 if (inr == BTRFS_FIRST_FREE_OBJECTID) {
286 if (root->objectid != btrfs_info.fs_root.objectid) {
288 struct btrfs_root_ref ref;
290 parent = btrfs_lookup_root_ref(root->objectid, &ref,
295 if (btrfs_find_root(parent, root, NULL))
303 key.type = BTRFS_INODE_ITEM_KEY;
306 if (__btrfs_lookup_inode(root, &key, inode_item, NULL))
313 res = __btrfs_lookup_inode_ref(root, inr, NULL, NULL);
319 key.type = BTRFS_INODE_ITEM_KEY;
322 if (__btrfs_lookup_inode(root, &key, inode_item, NULL))
329 static inline int next_length(const char *path)
332 while (*path != '\0' && *path != '/') {
335 if (res > BTRFS_NAME_LEN)
341 static inline const char *skip_current_directories(const char *cur)
346 else if (cur[0] == '.' && cur[1] == '/')
356 * Resolve one filename of @ino of @root.
358 * key_ret: The child key (either INODE_ITEM or ROOT_ITEM type)
359 * type_ret: BTRFS_FT_* of the child inode.
361 * Return 0 with above members filled.
362 * Return <0 for error.
364 static int resolve_one_filename(struct btrfs_root *root, u64 ino,
365 const char *name, int namelen,
366 struct btrfs_key *key_ret, u8 *type_ret)
368 struct btrfs_dir_item *dir_item;
369 struct btrfs_path path;
372 btrfs_init_path(&path);
374 dir_item = btrfs_lookup_dir_item(NULL, root, &path, ino, name,
376 if (IS_ERR(dir_item)) {
377 ret = PTR_ERR(dir_item);
381 btrfs_dir_item_key_to_cpu(path.nodes[0], dir_item, key_ret);
382 *type_ret = btrfs_dir_type(path.nodes[0], dir_item);
384 btrfs_release_path(&path);
389 * Resolve a full path @filename. The start point is @ino of @root.
391 * The result will be filled into @root_ret, @ino_ret and @type_ret.
393 int btrfs_lookup_path(struct btrfs_root *root, u64 ino, const char *filename,
394 struct btrfs_root **root_ret, u64 *ino_ret,
395 u8 *type_ret, int symlink_limit)
397 struct btrfs_fs_info *fs_info = root->fs_info;
398 struct btrfs_root *next_root;
399 struct btrfs_key key;
400 const char *cur = filename;
407 /* If the path is absolute path, also search from fs root */
409 root = fs_info->fs_root;
410 ino = btrfs_root_dirid(&root->root_item);
414 while (*cur != '\0') {
415 cur = skip_current_directories(cur);
417 len = next_length(cur);
418 if (len > BTRFS_NAME_LEN) {
419 error("%s: Name too long at \"%.*s\"", __func__,
420 BTRFS_NAME_LEN, cur);
421 return -ENAMETOOLONG;
424 if (len == 1 && cur[0] == '.')
427 if (len == 2 && cur[0] == '.' && cur[1] == '.') {
428 /* Go one level up */
429 ret = get_parent_inode(root, ino, &next_root, &next_ino);
440 ret = resolve_one_filename(root, ino, cur, len, &key, &type);
444 if (key.type == BTRFS_ROOT_ITEM_KEY) {
445 /* Child inode is a subvolume */
447 next_root = btrfs_read_fs_root(fs_info, &key);
448 if (IS_ERR(next_root))
449 return PTR_ERR(next_root);
451 ino = btrfs_root_dirid(&root->root_item);
452 } else if (type == BTRFS_FT_SYMLINK && symlink_limit >= 0) {
453 /* Child inode is a symlink */
457 if (symlink_limit == 0) {
458 error("%s: Too much symlinks!", __func__);
461 target = malloc(fs_info->sectorsize);
464 ret = btrfs_readlink(root, key.objectid, target);
471 ret = btrfs_lookup_path(root, ino, target, &next_root,
472 &next_ino, &next_type,
480 /* Child inode is an inode */
496 u64 __btrfs_lookup_path(struct __btrfs_root *root, u64 inr, const char *path,
497 u8 *type_p, struct btrfs_inode_item *inode_item_p,
500 struct btrfs_dir_item item;
501 struct btrfs_inode_item inode_item;
502 u8 type = BTRFS_FT_DIR;
503 int len, have_inode = 0;
504 const char *cur = path;
508 inr = root->root_dirid;
512 cur = skip_current_directories(cur);
514 len = next_length(cur);
515 if (len > BTRFS_NAME_LEN) {
516 printf("%s: Name too long at \"%.*s\"\n", __func__,
517 BTRFS_NAME_LEN, cur);
521 if (len == 1 && cur[0] == '.')
524 if (len == 2 && cur[0] == '.' && cur[1] == '.') {
526 inr = __get_parent_inode(root, inr, &inode_item);
537 if (__btrfs_lookup_dir_item(root, inr, cur, len, &item))
542 if (__btrfs_lookup_inode(root, (struct btrfs_key *)&item.location,
546 if (item.type == BTRFS_FT_SYMLINK && symlink_limit >= 0) {
549 if (!symlink_limit) {
550 printf("%s: Too much symlinks!\n", __func__);
554 target = malloc(min(inode_item.size + 1,
555 (u64) btrfs_info.sb.sectorsize));
559 if (__btrfs_readlink(root, item.location.objectid,
565 inr = __btrfs_lookup_path(root, inr, target, &type,
566 &inode_item, symlink_limit - 1);
572 } else if (item.type != BTRFS_FT_DIR && cur[len]) {
573 printf("%s: \"%.*s\" not a directory\n", __func__,
574 (int) (cur - path + len), path);
577 inr = item.location.objectid;
588 struct btrfs_key key;
591 key.type = BTRFS_INODE_ITEM_KEY;
594 if (__btrfs_lookup_inode(root, &key, &inode_item, NULL))
598 *inode_item_p = inode_item;
604 u64 __btrfs_file_read(const struct __btrfs_root *root, u64 inr, u64 offset,
607 struct __btrfs_path path;
608 struct btrfs_key key;
609 struct btrfs_file_extent_item *extent;
611 u64 rd, rd_all = -1ULL;
614 key.type = BTRFS_EXTENT_DATA_KEY;
617 if (btrfs_search_tree(root, &key, &path))
620 if (__btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)) < 0) {
621 if (btrfs_prev_slot(&path))
624 if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))
631 if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))
634 extent = btrfs_path_item_ptr(&path,
635 struct btrfs_file_extent_item);
637 if (extent->type == BTRFS_FILE_EXTENT_INLINE) {
638 btrfs_file_extent_item_to_cpu_inl(extent);
639 rd = __btrfs_read_extent_inline(&path, extent, offset,
642 btrfs_file_extent_item_to_cpu(extent);
643 rd = __btrfs_read_extent_reg(&path, extent, offset, size,
648 printf("%s: Error reading extent\n", __func__);
660 } while (!(res = btrfs_next_slot(&path)));
666 __btrfs_free_path(&path);
671 * Read out inline extent.
673 * Since inline extent should only exist for offset 0, no need for extra
675 * Truncating should be handled by the caller.
677 * Return the number of bytes read.
678 * Return <0 for error.
680 int btrfs_read_extent_inline(struct btrfs_path *path,
681 struct btrfs_file_extent_item *fi, char *dest)
683 struct extent_buffer *leaf = path->nodes[0];
684 int slot = path->slots[0];
691 csize = btrfs_file_extent_inline_item_len(leaf, btrfs_item_nr(slot));
692 if (btrfs_file_extent_compression(leaf, fi) == BTRFS_COMPRESS_NONE) {
693 /* Uncompressed, just read it out */
694 read_extent_buffer(leaf, dest,
695 btrfs_file_extent_inline_start(fi),
700 /* Compressed extent, prepare the compressed and data buffer */
701 dsize = btrfs_file_extent_ram_bytes(leaf, fi);
702 cbuf = malloc(csize);
703 dbuf = malloc(dsize);
704 if (!cbuf || !dbuf) {
708 read_extent_buffer(leaf, cbuf, btrfs_file_extent_inline_start(fi),
710 ret = btrfs_decompress(btrfs_file_extent_compression(leaf, fi),
711 cbuf, csize, dbuf, dsize);
712 if (ret < 0 || ret != dsize) {
716 memcpy(dest, dbuf, dsize);
725 * Read out regular extent.
727 * Truncating should be handled by the caller.
729 * @offset and @len should not cross the extent boundary.
730 * Return the number of bytes read.
731 * Return <0 for error.
733 int btrfs_read_extent_reg(struct btrfs_path *path,
734 struct btrfs_file_extent_item *fi, u64 offset,
737 struct extent_buffer *leaf = path->nodes[0];
738 struct btrfs_fs_info *fs_info = leaf->fs_info;
739 struct btrfs_key key;
740 u64 extent_num_bytes;
747 bool finished = false;
750 int slot = path->slots[0];
753 btrfs_item_key_to_cpu(leaf, &key, slot);
754 extent_num_bytes = btrfs_file_extent_num_bytes(leaf, fi);
755 ASSERT(IS_ALIGNED(offset, fs_info->sectorsize) &&
756 IS_ALIGNED(len, fs_info->sectorsize));
757 ASSERT(offset >= key.offset &&
758 offset + len <= key.offset + extent_num_bytes);
760 /* Preallocated or hole , fill @dest with zero */
761 if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_PREALLOC ||
762 btrfs_file_extent_disk_bytenr(leaf, fi) == 0) {
763 memset(dest, 0, len);
767 if (btrfs_file_extent_compression(leaf, fi) == BTRFS_COMPRESS_NONE) {
770 logical = btrfs_file_extent_disk_bytenr(leaf, fi) +
771 btrfs_file_extent_offset(leaf, fi) +
775 num_copies = btrfs_num_copies(fs_info, logical, len);
776 for (i = 1; i <= num_copies; i++) {
777 ret = read_extent_data(fs_info, dest, logical, &read, i);
778 if (ret < 0 || read != len)
788 csize = btrfs_file_extent_disk_num_bytes(leaf, fi);
789 dsize = btrfs_file_extent_ram_bytes(leaf, fi);
790 disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
791 num_copies = btrfs_num_copies(fs_info, disk_bytenr, csize);
793 cbuf = malloc_cache_aligned(csize);
794 dbuf = malloc_cache_aligned(dsize);
795 if (!cbuf || !dbuf) {
799 /* For compressed extent, we must read the whole on-disk extent */
800 for (i = 1; i <= num_copies; i++) {
802 ret = read_extent_data(fs_info, cbuf, disk_bytenr,
804 if (ret < 0 || read != csize)
814 ret = btrfs_decompress(btrfs_file_extent_compression(leaf, fi), cbuf,
820 /* Then copy the needed part */
821 memcpy(dest, dbuf + btrfs_file_extent_offset(leaf, fi), len);