Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/809315/?format=api
{ "id": 809315, "url": "http://patchwork.ozlabs.org/api/patches/809315/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20170903150031.18179-7-marek.behun@nic.cz/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170903150031.18179-7-marek.behun@nic.cz>", "list_archive_url": null, "date": "2017-09-03T15:00:28", "name": "[U-Boot,6/9] fs: btrfs: Add single-device read-only BTRFS implementation", "commit_ref": "21a14facb1494592c3ad4874c6a00539d15a29cf", "pull_url": null, "state": "accepted", "archived": false, "hash": "cf25dcdc2597dadbeee7b434b030812a7d05c745", "submitter": { "id": 71605, "url": "http://patchwork.ozlabs.org/api/people/71605/?format=api", "name": "Marek Behún", "email": "marek.behun@nic.cz" }, "delegate": { "id": 3651, "url": "http://patchwork.ozlabs.org/api/users/3651/?format=api", "username": "trini", "first_name": "Tom", "last_name": "Rini", "email": "trini@ti.com" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20170903150031.18179-7-marek.behun@nic.cz/mbox/", "series": [ { "id": 1246, "url": "http://patchwork.ozlabs.org/api/series/1246/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=1246", "date": "2017-09-03T15:00:25", "name": "Add single-device read-only BTRFS support", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/1246/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/809315/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/809315/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": [ "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.denx.de\n\t(client-ip=81.169.180.215; helo=lists.denx.de;\n\tenvelope-from=u-boot-bounces@lists.denx.de;\n\treceiver=<UNKNOWN>)", "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tsecure) header.d=nic.cz header.i=@nic.cz header.b=\"fj1SgFm1\"; \n\tdkim-atps=neutral" ], "Received": [ "from lists.denx.de (dione.denx.de [81.169.180.215])\n\tby ozlabs.org (Postfix) with ESMTP id 3xlbtX3L2rz9t2y\n\tfor <incoming@patchwork.ozlabs.org>;\n\tMon, 4 Sep 2017 01:07:16 +1000 (AEST)", "by lists.denx.de (Postfix, from userid 105)\n\tid 2D03CC21EF6; Sun, 3 Sep 2017 15:05:30 +0000 (UTC)", "from lists.denx.de (localhost [IPv6:::1])\n\tby lists.denx.de (Postfix) with ESMTP id 9F8DFC21F67;\n\tSun, 3 Sep 2017 15:01:43 +0000 (UTC)", "by lists.denx.de (Postfix, from userid 105)\n\tid 9D026C21D65; Sun, 3 Sep 2017 15:01:34 +0000 (UTC)", "from mail.nic.cz (mail.nic.cz [217.31.204.67])\n\tby lists.denx.de (Postfix) with ESMTPS id 9A012C21DAA\n\tfor <u-boot@lists.denx.de>; Sun, 3 Sep 2017 15:01:33 +0000 (UTC)", "from dellmb.labs.office.nic.cz (unknown\n\t[IPv6:2001:1488:fffe:6:8982:ed8c:62b1:c0c8])\n\tby mail.nic.cz (Postfix) with ESMTP id 49A0362401;\n\tSun, 3 Sep 2017 17:01:33 +0200 (CEST)" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=-5.0 required=5.0 tests=RCVD_IN_DNSWL_HI,\n\tT_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=nic.cz; s=default;\n\tt=1504450893; bh=vw9A0DZnhEbYR2A/Ez59q/gMP4zjtTC3YWjL3sHOK9g=;\n\th=From:To:Date;\n\tb=fj1SgFm1At5zx3f8utgeMj97yu3UYNcz5s2jI3sk0majCl/waBOn3ONIoRCh1UFUA\n\t4ACvoiORPSyUV7KOuRlruJtcLXC+xi8c5q4yhFCsEJ0XSzKS1FTvUdX/OkvJCtb8do\n\tLSCXGL9AFMktAYbJIckaKVCJ/btbGZc+ayWBXqdI=", "From": "=?utf-8?q?Marek_Beh=C3=BAn?= <marek.behun@nic.cz>", "To": "u-boot@lists.denx.de", "Date": "Sun, 3 Sep 2017 17:00:28 +0200", "Message-Id": "<20170903150031.18179-7-marek.behun@nic.cz>", "X-Mailer": "git-send-email 2.13.5", "In-Reply-To": "<20170903150031.18179-1-marek.behun@nic.cz>", "References": "<20170903150031.18179-1-marek.behun@nic.cz>", "X-Virus-Scanned": "clamav-milter 0.99.2 at mail", "X-Virus-Status": "Clean", "Cc": "Tomas Hlavacek <tomas.hlavacek@nic.cz>, Stefan Roese <sr@denx.de>,\n\t=?utf-8?q?Andreas_F=C3=A4rber?= <afaerber@suse.de>", "Subject": "[U-Boot] [PATCH 6/9] fs: btrfs: Add single-device read-only BTRFS\n\timplementation", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.18", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<http://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=subscribe>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "base64", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>" }, "content": "This adds the proper implementation for the BTRFS filesystem.\nThe implementation currently supports only read-only mode and\nthe filesystem can be only on a single device.\n\nChecksums of data chunks is unimplemented.\n\nCompression is implemented (ZLIB + LZO).\n\nSigned-off-by: Marek Behun <marek.behun@nic.cz>\n\n create mode 100644 fs/btrfs/btrfs.h\n create mode 100644 fs/btrfs/chunk-map.c\n create mode 100644 fs/btrfs/compression.c\n create mode 100644 fs/btrfs/ctree.c\n create mode 100644 fs/btrfs/dev.c\n create mode 100644 fs/btrfs/dir-item.c\n create mode 100644 fs/btrfs/extent-io.c\n create mode 100644 fs/btrfs/hash.c\n create mode 100644 fs/btrfs/inode.c\n create mode 100644 fs/btrfs/root.c\n create mode 100644 fs/btrfs/subvolume.c\n create mode 100644 fs/btrfs/super.c", "diff": "diff --git a/fs/btrfs/btrfs.h b/fs/btrfs/btrfs.h\nnew file mode 100644\nindex 0000000000..4247cbbb09\n--- /dev/null\n+++ b/fs/btrfs/btrfs.h\n@@ -0,0 +1,89 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#ifndef __BTRFS_BTRFS_H__\n+#define __BTRFS_BTRFS_H__\n+\n+#include <linux/rbtree.h>\n+#include \"conv-funcs.h\"\n+\n+struct btrfs_info {\n+\tstruct btrfs_super_block sb;\n+\tstruct btrfs_root_backup *root_backup;\n+\n+\tstruct btrfs_root tree_root;\n+\tstruct btrfs_root fs_root;\n+\tstruct btrfs_root chunk_root;\n+\n+\tstruct rb_root chunks_root;\n+};\n+\n+extern struct btrfs_info btrfs_info;\n+\n+/* hash.c */\n+void btrfs_hash_init(void);\n+u32 btrfs_crc32c(u32, const void *, size_t);\n+u32 btrfs_csum_data(char *, u32, size_t);\n+void btrfs_csum_final(u32, void *);\n+\n+static inline u64 btrfs_name_hash(const char *name, int len)\n+{\n+\treturn btrfs_crc32c((u32) ~1, name, len);\n+}\n+\n+/* dev.c */\n+extern struct blk_desc *btrfs_blk_desc;\n+extern disk_partition_t *btrfs_part_info;\n+\n+int btrfs_devread(u64, int, void *);\n+\n+/* chunk-map.c */\n+u64 btrfs_map_logical_to_physical(u64);\n+int btrfs_chunk_map_init(void);\n+void btrfs_chunk_map_exit(void);\n+int btrfs_read_chunk_tree(void);\n+\n+/* compression.c */\n+u32 btrfs_decompress(u8 type, const char *, u32, char *, u32);\n+\n+/* super.c */\n+int btrfs_read_superblock(void);\n+\n+/* dir-item.c */\n+typedef int (*btrfs_readdir_callback_t)(const struct btrfs_root *,\n+\t\t\t\t\tstruct btrfs_dir_item *);\n+\n+int btrfs_lookup_dir_item(const struct btrfs_root *, u64, const char *, int,\n+\t\t\t struct btrfs_dir_item *);\n+int btrfs_readdir(const struct btrfs_root *, u64, btrfs_readdir_callback_t);\n+\n+/* root.c */\n+int btrfs_find_root(u64, struct btrfs_root *, struct btrfs_root_item *);\n+u64 btrfs_lookup_root_ref(u64, struct btrfs_root_ref *, char *);\n+\n+/* inode.c */\n+u64 btrfs_lookup_inode_ref(struct btrfs_root *, u64, struct btrfs_inode_ref *,\n+\t\t\t char *);\n+int btrfs_lookup_inode(const struct btrfs_root *, struct btrfs_key *,\n+\t\t struct btrfs_inode_item *, struct btrfs_root *);\n+int btrfs_readlink(const struct btrfs_root *, u64, char *);\n+u64 btrfs_lookup_path(struct btrfs_root *, u64, const char *, u8 *,\n+\t\t struct btrfs_inode_item *, int);\n+u64 btrfs_file_read(const struct btrfs_root *, u64, u64, u64, char *);\n+\n+/* subvolume.c */\n+u64 btrfs_get_default_subvol_objectid(void);\n+\n+/* extent-io.c */\n+u64 btrfs_read_extent_inline(struct btrfs_path *,\n+\t\t\t struct btrfs_file_extent_item *, u64, u64,\n+\t\t\t char *);\n+u64 btrfs_read_extent_reg(struct btrfs_path *, struct btrfs_file_extent_item *,\n+\t\t\t u64, u64, char *);\n+\n+#endif /* !__BTRFS_BTRFS_H__ */\ndiff --git a/fs/btrfs/chunk-map.c b/fs/btrfs/chunk-map.c\nnew file mode 100644\nindex 0000000000..48407f3331\n--- /dev/null\n+++ b/fs/btrfs/chunk-map.c\n@@ -0,0 +1,178 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+#include <malloc.h>\n+\n+struct chunk_map_item {\n+\tstruct rb_node node;\n+\tu64 logical;\n+\tu64 length;\n+\tu64 physical;\n+};\n+\n+static int add_chunk_mapping(struct btrfs_key *key, struct btrfs_chunk *chunk)\n+{\n+\tstruct btrfs_stripe *stripe;\n+\tu64 block_profile = chunk->type & BTRFS_BLOCK_GROUP_PROFILE_MASK;\n+\tstruct rb_node **new = &(btrfs_info.chunks_root.rb_node), *prnt = NULL;\n+\tstruct chunk_map_item *map_item;\n+\n+\tif (block_profile && block_profile != BTRFS_BLOCK_GROUP_DUP) {\n+\t\tprintf(\"%s: unsupported chunk profile %llu\\n\", __func__,\n+\t\t block_profile);\n+\t\treturn -1;\n+\t} else if (!chunk->length) {\n+\t\tprintf(\"%s: zero length chunk\\n\", __func__);\n+\t\treturn -1;\n+\t}\n+\n+\tstripe = &chunk->stripe;\n+\tbtrfs_stripe_to_cpu(stripe);\n+\n+\twhile (*new) {\n+\t\tstruct chunk_map_item *this;\n+\n+\t\tthis = rb_entry(*new, struct chunk_map_item, node);\n+\n+\t\tprnt = *new;\n+\t\tif (key->offset < this->logical) {\n+\t\t\tnew = &((*new)->rb_left);\n+\t\t} else if (key->offset > this->logical) {\n+\t\t\tnew = &((*new)->rb_right);\n+\t\t} else {\n+\t\t\tdebug(\"%s: Logical address %llu already in map!\\n\",\n+\t\t\t __func__, key->offset);\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\tmap_item = malloc(sizeof(struct chunk_map_item));\n+\tif (!map_item)\n+\t\treturn -1;\n+\n+\tmap_item->logical = key->offset;\n+\tmap_item->length = chunk->length;\n+\tmap_item->physical = le64_to_cpu(chunk->stripe.offset);\n+\trb_link_node(&map_item->node, prnt, new);\n+\trb_insert_color(&map_item->node, &btrfs_info.chunks_root);\n+\n+\tdebug(\"%s: Mapping %llu to %llu\\n\", __func__, map_item->logical,\n+\t map_item->physical);\n+\n+\treturn 0;\n+}\n+\n+u64 btrfs_map_logical_to_physical(u64 logical)\n+{\n+\tstruct rb_node *node = btrfs_info.chunks_root.rb_node;\n+\n+\twhile (node) {\n+\t\tstruct chunk_map_item *item;\n+\n+\t\titem = rb_entry(node, struct chunk_map_item, node);\n+\n+\t\tif (item->logical > logical)\n+\t\t\tnode = node->rb_left;\n+\t\telse if (logical > item->logical + item->length)\n+\t\t\tnode = node->rb_right;\n+\t\telse\n+\t\t\treturn item->physical + logical - item->logical;\n+\t}\n+\n+\tprintf(\"%s: Cannot map logical address %llu to physical\\n\", __func__,\n+\t logical);\n+\n+\treturn -1ULL;\n+}\n+\n+void btrfs_chunk_map_exit(void)\n+{\n+\tstruct rb_node *now, *next;\n+\tstruct chunk_map_item *item;\n+\n+\tfor (now = rb_first_postorder(&btrfs_info.chunks_root); now; now = next)\n+\t{\n+\t\titem = rb_entry(now, struct chunk_map_item, node);\n+\t\tnext = rb_next_postorder(now);\n+\t\tfree(item);\n+\t}\n+}\n+\n+int btrfs_chunk_map_init(void)\n+{\n+\tu8 sys_chunk_array_copy[sizeof(btrfs_info.sb.sys_chunk_array)];\n+\tu8 * const start = sys_chunk_array_copy;\n+\tu8 * const end = start + btrfs_info.sb.sys_chunk_array_size;\n+\tu8 *cur;\n+\tstruct btrfs_key *key;\n+\tstruct btrfs_chunk *chunk;\n+\n+\tbtrfs_info.chunks_root = RB_ROOT;\n+\n+\tmemcpy(sys_chunk_array_copy, btrfs_info.sb.sys_chunk_array,\n+\t sizeof(sys_chunk_array_copy));\n+\n+\tfor (cur = start; cur < end;) {\n+\t\tkey = (struct btrfs_key *) cur;\n+\t\tcur += sizeof(struct btrfs_key);\n+\t\tchunk = (struct btrfs_chunk *) cur;\n+\n+\t\tbtrfs_key_to_cpu(key);\n+\t\tbtrfs_chunk_to_cpu(chunk);\n+\n+\t\tif (key->type != BTRFS_CHUNK_ITEM_KEY) {\n+\t\t\tprintf(\"%s: invalid key type %u\\n\", __func__,\n+\t\t\t key->type);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (add_chunk_mapping(key, chunk))\n+\t\t\treturn -1;\n+\n+\t\tcur += sizeof(struct btrfs_chunk);\n+\t\tcur += sizeof(struct btrfs_stripe) * (chunk->num_stripes - 1);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int btrfs_read_chunk_tree(void)\n+{\n+\tstruct btrfs_path path;\n+\tstruct btrfs_key key, *found_key;\n+\tstruct btrfs_chunk *chunk;\n+\tint res;\n+\n+\tkey.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;\n+\tkey.type = BTRFS_CHUNK_ITEM_KEY;\n+\tkey.offset = 0;\n+\n+\tif (btrfs_search_tree(&btrfs_info.chunk_root, &key, &path))\n+\t\treturn -1;\n+\n+\tdo {\n+\t\tfound_key = btrfs_path_leaf_key(&path);\n+\t\tif (btrfs_comp_keys_type(&key, found_key))\n+\t\t\tbreak;\n+\n+\t\tchunk = btrfs_path_item_ptr(&path, struct btrfs_chunk);\n+\t\tbtrfs_chunk_to_cpu(chunk);\n+\t\tif (add_chunk_mapping(found_key, chunk)) {\n+\t\t\tres = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t} while (!(res = btrfs_next_slot(&path)));\n+\n+\tbtrfs_free_path(&path);\n+\n+\tif (res < 0)\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\ndiff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c\nnew file mode 100644\nindex 0000000000..a59ff5a8bb\n--- /dev/null\n+++ b/fs/btrfs/compression.c\n@@ -0,0 +1,134 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+#include <linux/lzo.h>\n+#include <u-boot/zlib.h>\n+\n+static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)\n+{\n+\tu32 tot_len, in_len, res;\n+\tsize_t out_len;\n+\tint ret;\n+\n+\tif (clen < 4)\n+\t\treturn -1;\n+\n+\ttot_len = le32_to_cpu(*(u32 *) cbuf);\n+\tcbuf += 4;\n+\tclen -= 4;\n+\ttot_len -= 4;\n+\n+\tif (tot_len == 0 && dlen)\n+\t\treturn -1;\n+\tif (tot_len < 4)\n+\t\treturn -1;\n+\n+\tres = 0;\n+\n+\twhile (tot_len > 4) {\n+\t\tin_len = le32_to_cpu(*(u32 *) cbuf);\n+\t\tcbuf += 4;\n+\t\tclen -= 4;\n+\n+\t\tif (in_len > clen || tot_len < 4 + in_len)\n+\t\t\treturn -1;\n+\n+\t\ttot_len -= 4 + in_len;\n+\n+\t\tout_len = dlen;\n+\t\tret = lzo1x_decompress_safe(cbuf, in_len, dbuf, &out_len);\n+\t\tif (ret != LZO_E_OK)\n+\t\t\treturn -1;\n+\n+\t\tcbuf += in_len;\n+\t\tclen -= in_len;\n+\t\tdbuf += out_len;\n+\t\tdlen -= out_len;\n+\n+\t\tres += out_len;\n+\t}\n+\n+\treturn res;\n+}\n+\n+/* from zutil.h */\n+#define PRESET_DICT 0x20\n+\n+static u32 decompress_zlib(const u8 *_cbuf, u32 clen, u8 *dbuf, u32 dlen)\n+{\n+\tint wbits = MAX_WBITS, ret = -1;\n+\tz_stream stream;\n+\tu8 *cbuf;\n+\tu32 res;\n+\n+\tmemset(&stream, 0, sizeof(stream));\n+\n+\tcbuf = (u8 *) _cbuf;\n+\n+\tstream.total_in = 0;\n+\n+\tstream.next_out = dbuf;\n+\tstream.avail_out = dlen;\n+\tstream.total_out = 0;\n+\n+\t/* skip adler32 check if deflate and no dictionary */\n+\tif (clen > 2 && !(cbuf[1] & PRESET_DICT) &&\n+\t ((cbuf[0] & 0x0f) == Z_DEFLATED) &&\n+\t !(((cbuf[0] << 8) + cbuf[1]) % 31)) {\n+\t\twbits = -((cbuf[0] >> 4) + 8);\n+\t\tcbuf += 2;\n+\t\tclen -= 2;\n+\t}\n+\n+\tif (Z_OK != inflateInit2(&stream, wbits))\n+\t\treturn -1;\n+\n+\twhile (stream.total_in < clen) {\n+\t\tstream.next_in = cbuf + stream.total_in;\n+\t\tstream.avail_in = min((u32) (clen - stream.total_in),\n+\t\t\t\t (u32) btrfs_info.sb.sectorsize);\n+\n+\t\tret = inflate(&stream, Z_NO_FLUSH);\n+\t\tif (ret != Z_OK)\n+\t\t\tbreak;\n+\t}\n+\n+\tres = stream.total_out;\n+\tinflateEnd(&stream);\n+\n+\tif (ret != Z_STREAM_END)\n+\t\treturn -1;\n+\n+\treturn res;\n+}\n+\n+u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen)\n+{\n+\tu32 res;\n+\tconst u8 *cbuf;\n+\tu8 *dbuf;\n+\n+\tcbuf = (const u8 *) c;\n+\tdbuf = (u8 *) d;\n+\n+\tswitch (type) {\n+\tcase BTRFS_COMPRESS_NONE:\n+\t\tres = dlen < clen ? dlen : clen;\n+\t\tmemcpy(dbuf, cbuf, res);\n+\t\treturn res;\n+\tcase BTRFS_COMPRESS_ZLIB:\n+\t\treturn decompress_zlib(cbuf, clen, dbuf, dlen);\n+\tcase BTRFS_COMPRESS_LZO:\n+\t\treturn decompress_lzo(cbuf, clen, dbuf, dlen);\n+\tdefault:\n+\t\tprintf(\"%s: Unsupported compression in extent: %i\\n\", __func__,\n+\t\t type);\n+\t\treturn -1;\n+\t}\n+}\ndiff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c\nnew file mode 100644\nindex 0000000000..b13ecb9376\n--- /dev/null\n+++ b/fs/btrfs/ctree.c\n@@ -0,0 +1,289 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+#include <malloc.h>\n+\n+int btrfs_comp_keys(struct btrfs_key *a, struct btrfs_key *b)\n+{\n+\tif (a->objectid > b->objectid)\n+\t\treturn 1;\n+\tif (a->objectid < b->objectid)\n+\t\treturn -1;\n+\tif (a->type > b->type)\n+\t\treturn 1;\n+\tif (a->type < b->type)\n+\t\treturn -1;\n+\tif (a->offset > b->offset)\n+\t\treturn 1;\n+\tif (a->offset < b->offset)\n+\t\treturn -1;\n+\treturn 0;\n+}\n+\n+int btrfs_comp_keys_type(struct btrfs_key *a, struct btrfs_key *b)\n+{\n+\tif (a->objectid > b->objectid)\n+\t\treturn 1;\n+\tif (a->objectid < b->objectid)\n+\t\treturn -1;\n+\tif (a->type > b->type)\n+\t\treturn 1;\n+\tif (a->type < b->type)\n+\t\treturn -1;\n+\treturn 0;\n+}\n+\n+static int generic_bin_search(void *addr, int item_size, struct btrfs_key *key,\n+\t\t\t int max, int *slot)\n+{\n+\tint low = 0, high = max, mid, ret;\n+\tstruct btrfs_key *tmp;\n+\n+\tif (0) {\n+\t\tint i;\n+\t\tprintf(\"\\tsearching %llu %i\\n\", key->objectid, key->type);\n+\t\tfor (i = 0; i < max; ++i) {\n+\t\t\ttmp = (struct btrfs_key *) ((u8 *) addr + i*item_size);\n+\t\t\tprintf(\"\\t\\t%llu %i\\n\", tmp->objectid, tmp->type);\n+\t\t}\n+\t\tprintf(\"\\n\");\n+\t}\n+\n+\twhile (low < high) {\n+\t\tmid = (low + high) / 2;\n+\n+\t\ttmp = (struct btrfs_key *) ((u8 *) addr + mid*item_size);\n+\t\tret = btrfs_comp_keys(tmp, key);\n+\n+\t\tif (ret < 0) {\n+\t\t\tlow = mid + 1;\n+\t\t} else if (ret > 0) {\n+\t\t\thigh = mid;\n+\t\t} else {\n+\t\t\t*slot = mid;\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\t*slot = low;\n+\treturn 1;\n+}\n+\n+int btrfs_bin_search(union btrfs_tree_node *p, struct btrfs_key *key,\n+\t\t int *slot)\n+{\n+\tvoid *addr;\n+\tunsigned long size;\n+\n+\tif (p->header.level) {\n+\t\taddr = p->node.ptrs;\n+\t\tsize = sizeof(struct btrfs_key_ptr);\n+\t} else {\n+\t\taddr = p->leaf.items;\n+\t\tsize = sizeof(struct btrfs_item);\n+\t}\n+\n+\treturn generic_bin_search(addr, size, key, p->header.nritems, slot);\n+}\n+\n+static void clear_path(struct btrfs_path *p)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < BTRFS_MAX_LEVEL; ++i) {\n+\t\tp->nodes[i] = NULL;\n+\t\tp->slots[i] = 0;\n+\t}\n+}\n+\n+void btrfs_free_path(struct btrfs_path *p)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < BTRFS_MAX_LEVEL; ++i) {\n+\t\tif (p->nodes[i])\n+\t\t\tfree(p->nodes[i]);\n+\t}\n+\n+\tclear_path(p);\n+}\n+\n+static int read_tree_node(u64 physical, union btrfs_tree_node **buf)\n+{\n+\tstruct btrfs_header hdr;\n+\tunsigned long size, offset = sizeof(hdr);\n+\tunion btrfs_tree_node *res;\n+\tu32 i;\n+\n+\tif (!btrfs_devread(physical, sizeof(hdr), &hdr))\n+\t\treturn -1;\n+\n+\tbtrfs_header_to_cpu(&hdr);\n+\n+\tif (hdr.level)\n+\t\tsize = sizeof(struct btrfs_node)\n+\t\t + hdr.nritems * sizeof(struct btrfs_key_ptr);\n+\telse\n+\t\tsize = btrfs_info.sb.nodesize;\n+\n+\tres = malloc(size);\n+\tif (!res) {\n+\t\tdebug(\"%s: malloc failed\\n\", __func__);\n+\t\treturn -1;\n+\t}\n+\n+\tif (!btrfs_devread(physical + offset, size - offset,\n+\t\t\t ((u8 *) res) + offset)) {\n+\t\tfree(res);\n+\t\treturn -1;\n+\t}\n+\n+\tres->header = hdr;\n+\tif (hdr.level)\n+\t\tfor (i = 0; i < hdr.nritems; ++i)\n+\t\t\tbtrfs_key_ptr_to_cpu(&res->node.ptrs[i]);\n+\telse\n+\t\tfor (i = 0; i < hdr.nritems; ++i)\n+\t\t\tbtrfs_item_to_cpu(&res->leaf.items[i]);\n+\n+\t*buf = res;\n+\n+\treturn 0;\n+}\n+\n+int btrfs_search_tree(const struct btrfs_root *root, struct btrfs_key *key,\n+\t\t struct btrfs_path *p)\n+{\n+\tu8 lvl, prev_lvl;\n+\tint i, slot, ret;\n+\tu64 logical, physical;\n+\tunion btrfs_tree_node *buf;\n+\n+\tclear_path(p);\n+\n+\tlogical = root->bytenr;\n+\n+\tfor (i = 0; i < BTRFS_MAX_LEVEL; ++i) {\n+\t\tphysical = btrfs_map_logical_to_physical(logical);\n+\t\tif (physical == -1ULL)\n+\t\t\tgoto err;\n+\n+\t\tif (read_tree_node(physical, &buf))\n+\t\t\tgoto err;\n+\n+\t\tlvl = buf->header.level;\n+\t\tif (i && prev_lvl != lvl + 1) {\n+\t\t\tprintf(\"%s: invalid level in header at %llu\\n\",\n+\t\t\t __func__, logical);\n+\t\t\tgoto err;\n+\t\t}\n+\t\tprev_lvl = lvl;\n+\n+\t\tret = btrfs_bin_search(buf, key, &slot);\n+\t\tif (ret < 0)\n+\t\t\tgoto err;\n+\t\tif (ret && slot > 0 && lvl)\n+\t\t\tslot -= 1;\n+\n+\t\tp->slots[lvl] = slot;\n+\t\tp->nodes[lvl] = buf;\n+\n+\t\tif (lvl)\n+\t\t\tlogical = buf->node.ptrs[slot].blockptr;\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+err:\n+\tbtrfs_free_path(p);\n+\treturn -1;\n+}\n+\n+static int jump_leaf(struct btrfs_path *path, int dir)\n+{\n+\tstruct btrfs_path p;\n+\tu32 slot;\n+\tint level = 1, from_level, i;\n+\n+\tdir = dir >= 0 ? 1 : -1;\n+\n+\tp = *path;\n+\n+\twhile (level < BTRFS_MAX_LEVEL) {\n+\t\tif (!p.nodes[level])\n+\t\t\treturn 1;\n+\n+\t\tslot = p.slots[level];\n+\t\tif ((dir > 0 && slot + dir >= p.nodes[level]->header.nritems)\n+\t\t || (dir < 0 && !slot))\n+\t\t\tlevel++;\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\n+\tif (level == BTRFS_MAX_LEVEL)\n+\t\treturn 1;\n+\n+\tp.slots[level] = slot + dir;\n+\tlevel--;\n+\tfrom_level = level;\n+\n+\twhile (level >= 0) {\n+\t\tu64 logical, physical;\n+\n+\t\tslot = p.slots[level + 1];\n+\t\tlogical = p.nodes[level + 1]->node.ptrs[slot].blockptr;\n+\t\tphysical = btrfs_map_logical_to_physical(logical);\n+\t\tif (physical == -1ULL)\n+\t\t\tgoto err;\n+\n+\t\tif (read_tree_node(physical, &p.nodes[level]))\n+\t\t\tgoto err;\n+\n+\t\tif (dir > 0)\n+\t\t\tp.slots[level] = 0;\n+\t\telse\n+\t\t\tp.slots[level] = p.nodes[level]->header.nritems - 1;\n+\t\tlevel--;\n+\t}\n+\n+\t/* Free rewritten nodes in path */\n+\tfor (i = 0; i <= from_level; ++i)\n+\t\tfree(path->nodes[i]);\n+\n+\t*path = p;\n+\treturn 0;\n+\n+err:\n+\t/* Free rewritten nodes in p */\n+\tfor (i = level + 1; i <= from_level; ++i)\n+\t\tfree(p.nodes[i]);\n+\treturn -1;\n+}\n+\n+int btrfs_prev_slot(struct btrfs_path *p)\n+{\n+\tif (!p->slots[0])\n+\t\treturn jump_leaf(p, -1);\n+\n+\tp->slots[0]--;\n+\treturn 0;\n+}\n+\n+int btrfs_next_slot(struct btrfs_path *p)\n+{\n+\tstruct btrfs_leaf *leaf = &p->nodes[0]->leaf;\n+\n+\tif (p->slots[0] >= leaf->header.nritems)\n+\t\treturn jump_leaf(p, 1);\n+\n+\tp->slots[0]++;\n+\treturn 0;\n+}\ndiff --git a/fs/btrfs/dev.c b/fs/btrfs/dev.c\nnew file mode 100644\nindex 0000000000..fd2e9b6127\n--- /dev/null\n+++ b/fs/btrfs/dev.c\n@@ -0,0 +1,26 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include <common.h>\n+#include <compiler.h>\n+#include <fs_internal.h>\n+\n+struct blk_desc *btrfs_blk_desc;\n+disk_partition_t *btrfs_part_info;\n+\n+int btrfs_devread(u64 address, int byte_len, void *buf)\n+{\n+\tlbaint_t sector;\n+\tint byte_offset;\n+\n+\tsector = address >> btrfs_blk_desc->log2blksz;\n+\tbyte_offset = address % btrfs_blk_desc->blksz;\n+\n+\treturn fs_devread(btrfs_blk_desc, btrfs_part_info, sector, byte_offset,\n+\t\t\t byte_len, buf);\n+}\ndiff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c\nnew file mode 100644\nindex 0000000000..decf86eb53\n--- /dev/null\n+++ b/fs/btrfs/dir-item.c\n@@ -0,0 +1,125 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+\n+static int verify_dir_item(struct btrfs_dir_item *item, u32 start, u32 total)\n+{\n+\tu16 max_len = BTRFS_NAME_LEN;\n+\tu32 end;\n+\n+\tif (item->type >= BTRFS_FT_MAX) {\n+\t\tprintf(\"%s: invalid dir item type: %i\\n\", __func__, item->type);\n+\t\treturn 1;\n+\t}\n+\n+\tif (item->type == BTRFS_FT_XATTR)\n+\t\tmax_len = 255; /* XATTR_NAME_MAX */\n+\n+\tend = start + sizeof(*item) + item->name_len;\n+\tif (item->name_len > max_len || end > total) {\n+\t\tprintf(\"%s: invalid dir item name len: %u\\n\", __func__,\n+\t\t item->name_len);\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static struct btrfs_dir_item *\n+btrfs_match_dir_item_name(struct btrfs_path *path, const char *name,\n+\t\t\t int name_len)\n+{\n+\tstruct btrfs_dir_item *item;\n+\tu32 total_len, cur = 0, this_len;\n+\tconst char *name_ptr;\n+\n+\titem = btrfs_path_item_ptr(path, struct btrfs_dir_item);\n+\n+\ttotal_len = btrfs_path_item_size(path);\n+\n+\twhile (cur < total_len) {\n+\t\tbtrfs_dir_item_to_cpu(item);\n+\t\tthis_len = sizeof(*item) + item->name_len + item->data_len;\n+\t\tname_ptr = (const char *) (item + 1);\n+\n+\t\tif (verify_dir_item(item, cur, total_len))\n+\t\t\treturn NULL;\n+\t\tif (item->name_len == name_len && !memcmp(name_ptr, name,\n+\t\t\t\t\t\t\t name_len))\n+\t\t\treturn item;\n+\n+\t\tcur += this_len;\n+\t\titem = (struct btrfs_dir_item *) ((u8 *) item + this_len);\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+int btrfs_lookup_dir_item(const struct btrfs_root *root, u64 dir,\n+\t\t\t const char *name, int name_len,\n+\t\t\t struct btrfs_dir_item *item)\n+{\n+\tstruct btrfs_path path;\n+\tstruct btrfs_key key;\n+\tstruct btrfs_dir_item *res = NULL;\n+\n+\tkey.objectid = dir;\n+\tkey.type = BTRFS_DIR_ITEM_KEY;\n+\tkey.offset = btrfs_name_hash(name, name_len);\n+\n+\tif (btrfs_search_tree(root, &key, &path))\n+\t\treturn -1;\n+\n+\tif (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))\n+\t\tgoto out;\n+\n+\tres = btrfs_match_dir_item_name(&path, name, name_len);\n+\tif (res)\n+\t\t*item = *res;\n+out:\n+\tbtrfs_free_path(&path);\n+\treturn res ? 0 : -1;\n+}\n+\n+int btrfs_readdir(const struct btrfs_root *root, u64 dir,\n+\t\t btrfs_readdir_callback_t callback)\n+{\n+\tstruct btrfs_path path;\n+\tstruct btrfs_key key, *found_key;\n+\tstruct btrfs_dir_item *item;\n+\tint res;\n+\n+\tkey.objectid = dir;\n+\tkey.type = BTRFS_DIR_INDEX_KEY;\n+\tkey.offset = 0;\n+\n+\tif (btrfs_search_tree(root, &key, &path))\n+\t\treturn -1;\n+\n+\tdo {\n+\t\tfound_key = btrfs_path_leaf_key(&path);\n+\t\tif (btrfs_comp_keys_type(&key, found_key))\n+\t\t\tbreak;\n+\n+\t\titem = btrfs_path_item_ptr(&path, struct btrfs_dir_item);\n+\t\tbtrfs_dir_item_to_cpu(item);\n+\n+\t\tif (verify_dir_item(item, 0, sizeof(*item) + item->name_len))\n+\t\t\tcontinue;\n+\t\tif (item->type == BTRFS_FT_XATTR)\n+\t\t\tcontinue;\n+\n+\t\tif (callback(root, item))\n+\t\t\tbreak;\n+\t} while (!(res = btrfs_next_slot(&path)));\n+\n+\tbtrfs_free_path(&path);\n+\n+\treturn res < 0 ? -1 : 0;\n+}\ndiff --git a/fs/btrfs/extent-io.c b/fs/btrfs/extent-io.c\nnew file mode 100644\nindex 0000000000..feb91432e9\n--- /dev/null\n+++ b/fs/btrfs/extent-io.c\n@@ -0,0 +1,120 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+#include <malloc.h>\n+\n+u64 btrfs_read_extent_inline(struct btrfs_path *path,\n+\t\t\t struct btrfs_file_extent_item *extent, u64 offset,\n+\t\t\t u64 size, char *out)\n+{\n+\tu32 clen, dlen, orig_size = size, res;\n+\tconst char *cbuf;\n+\tchar *dbuf;\n+\tconst int data_off = offsetof(struct btrfs_file_extent_item,\n+\t\t\t\t disk_bytenr);\n+\n+\tclen = btrfs_path_item_size(path) - data_off;\n+\tcbuf = (const char *) extent + data_off;\n+\tdlen = extent->ram_bytes;\n+\n+\tif (offset > dlen)\n+\t\treturn -1ULL;\n+\n+\tif (size > dlen - offset)\n+\t\tsize = dlen - offset;\n+\n+\tif (extent->compression == BTRFS_COMPRESS_NONE) {\n+\t\tmemcpy(out, cbuf + offset, size);\n+\t\treturn size;\n+\t}\n+\n+\tif (dlen > orig_size) {\n+\t\tdbuf = malloc(dlen);\n+\t\tif (!dbuf)\n+\t\t\treturn -1ULL;\n+\t} else {\n+\t\tdbuf = out;\n+\t}\n+\n+\tres = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen);\n+\tif (res == -1 || res != dlen)\n+\t\tgoto err;\n+\n+\tif (dlen > orig_size) {\n+\t\tmemcpy(out, dbuf + offset, size);\n+\t\tfree(dbuf);\n+\t} else if (offset) {\n+\t\tmemmove(out, dbuf + offset, size);\n+\t}\n+\n+\treturn size;\n+\n+err:\n+\tif (dlen > orig_size)\n+\t\tfree(dbuf);\n+\treturn -1ULL;\n+}\n+\n+u64 btrfs_read_extent_reg(struct btrfs_path *path,\n+\t\t\t struct btrfs_file_extent_item *extent, u64 offset,\n+\t\t\t u64 size, char *out)\n+{\n+\tu64 physical, clen, dlen, orig_size = size;\n+\tu32 res;\n+\tchar *cbuf, *dbuf;\n+\n+\tclen = extent->disk_num_bytes;\n+\tdlen = extent->num_bytes;\n+\n+\tif (offset > dlen)\n+\t\treturn -1ULL;\n+\n+\tif (size > dlen - offset)\n+\t\tsize = dlen - offset;\n+\n+\tphysical = btrfs_map_logical_to_physical(extent->disk_bytenr);\n+\tif (physical == -1ULL)\n+\t\treturn -1ULL;\n+\n+\tif (extent->compression == BTRFS_COMPRESS_NONE) {\n+\t\tphysical += extent->offset + offset;\n+\t\tif (!btrfs_devread(physical, size, out))\n+\t\t\treturn -1ULL;\n+\n+\t\treturn size;\n+\t}\n+\n+\tcbuf = malloc(dlen > size ? clen + dlen : clen);\n+\tif (!cbuf)\n+\t\treturn -1ULL;\n+\n+\tif (dlen > orig_size)\n+\t\tdbuf = cbuf + clen;\n+\telse\n+\t\tdbuf = out;\n+\n+\tif (!btrfs_devread(physical, clen, cbuf))\n+\t\tgoto err;\n+\n+\tres = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen);\n+\tif (res == -1)\n+\t\tgoto err;\n+\n+\tif (dlen > orig_size)\n+\t\tmemcpy(out, dbuf + offset, size);\n+\telse\n+\t\tmemmove(out, dbuf + offset, size);\n+\n+\tfree(cbuf);\n+\treturn res;\n+\n+err:\n+\tfree(cbuf);\n+\treturn -1ULL;\n+}\ndiff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c\nnew file mode 100644\nindex 0000000000..f8a50e532a\n--- /dev/null\n+++ b/fs/btrfs/hash.c\n@@ -0,0 +1,38 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+#include <u-boot/crc.h>\n+\n+static u32 btrfs_crc32c_table[256];\n+\n+void btrfs_hash_init(void)\n+{\n+\tstatic int inited = 0;\n+\n+\tif (!inited) {\n+\t\tcrc32c_init(btrfs_crc32c_table, 0x82F63B78);\n+\t\tinited = 1;\n+\t}\n+}\n+\n+u32 btrfs_crc32c(u32 crc, const void *data, size_t length)\n+{\n+\treturn crc32c_cal(crc, (const char *) data, length,\n+\t\t\t btrfs_crc32c_table);\n+}\n+\n+u32 btrfs_csum_data(char *data, u32 seed, size_t len)\n+{\n+\treturn btrfs_crc32c(seed, data, len);\n+}\n+\n+void btrfs_csum_final(u32 crc, void *result)\n+{\n+\t*((u32 *) result) = cpu_to_le32(~crc);\n+}\ndiff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c\nnew file mode 100644\nindex 0000000000..0d3da28296\n--- /dev/null\n+++ b/fs/btrfs/inode.c\n@@ -0,0 +1,385 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+#include <malloc.h>\n+\n+u64 btrfs_lookup_inode_ref(struct btrfs_root *root, u64 inr,\n+\t\t\t struct btrfs_inode_ref *refp, char *name)\n+{\n+\tstruct btrfs_path path;\n+\tstruct btrfs_key *key;\n+\tstruct btrfs_inode_ref *ref;\n+\tu64 res = -1ULL;\n+\n+\tkey = btrfs_search_tree_key_type(root, inr, BTRFS_INODE_REF_KEY,\n+\t\t\t\t\t &path);\n+\n+\tif (!key)\n+\t\treturn -1ULL;\n+\n+\tref = btrfs_path_item_ptr(&path, struct btrfs_inode_ref);\n+\tbtrfs_inode_ref_to_cpu(ref);\n+\n+\tif (refp)\n+\t\t*refp = *ref;\n+\n+\tif (name) {\n+\t\tif (ref->name_len > BTRFS_NAME_MAX) {\n+\t\t\tprintf(\"%s: inode name too long: %u\\n\", __func__,\n+\t\t\t ref->name_len);\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tmemcpy(name, ref + 1, ref->name_len);\n+\t}\n+\n+\tres = key->offset;\n+out:\n+\tbtrfs_free_path(&path);\n+\treturn res;\n+}\n+\n+int btrfs_lookup_inode(const struct btrfs_root *root,\n+\t\t struct btrfs_key *location,\n+\t\t struct btrfs_inode_item *item,\n+\t\t struct btrfs_root *new_root)\n+{\n+\tstruct btrfs_root tmp_root = *root;\n+\tstruct btrfs_path path;\n+\tint res = -1;\n+\n+\tif (location->type == BTRFS_ROOT_ITEM_KEY) {\n+\t\tif (btrfs_find_root(location->objectid, &tmp_root, NULL))\n+\t\t\treturn -1;\n+\n+\t\tlocation->objectid = tmp_root.root_dirid;\n+\t\tlocation->type = BTRFS_INODE_ITEM_KEY;\n+\t\tlocation->offset = 0;\n+\t}\n+\n+\tif (btrfs_search_tree(&tmp_root, location, &path))\n+\t\treturn res;\n+\n+\tif (btrfs_comp_keys(location, btrfs_path_leaf_key(&path)))\n+\t\tgoto out;\n+\n+\tif (item) {\n+\t\t*item = *btrfs_path_item_ptr(&path, struct btrfs_inode_item);\n+\t\tbtrfs_inode_item_to_cpu(item);\n+\t}\n+\n+\tif (new_root)\n+\t\t*new_root = tmp_root;\n+\n+\tres = 0;\n+\n+out:\n+\tbtrfs_free_path(&path);\n+\treturn res;\n+}\n+\n+int btrfs_readlink(const struct btrfs_root *root, u64 inr, char *target)\n+{\n+\tstruct btrfs_path path;\n+\tstruct btrfs_key key;\n+\tstruct btrfs_file_extent_item *extent;\n+\tconst char *data_ptr;\n+\tint res = -1;\n+\n+\tkey.objectid = inr;\n+\tkey.type = BTRFS_EXTENT_DATA_KEY;\n+\tkey.offset = 0;\n+\n+\tif (btrfs_search_tree(root, &key, &path))\n+\t\treturn -1;\n+\n+\tif (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)))\n+\t\tgoto out;\n+\n+\textent = btrfs_path_item_ptr(&path, struct btrfs_file_extent_item);\n+\tif (extent->type != BTRFS_FILE_EXTENT_INLINE) {\n+\t\tprintf(\"%s: Extent for symlink %llu not of INLINE type\\n\",\n+\t\t __func__, inr);\n+\t\tgoto out;\n+\t}\n+\n+\tbtrfs_file_extent_item_to_cpu_inl(extent);\n+\n+\tif (extent->compression != BTRFS_COMPRESS_NONE) {\n+\t\tprintf(\"%s: Symlink %llu extent data compressed!\\n\", __func__,\n+\t\t inr);\n+\t\tgoto out;\n+\t} else if (extent->encryption != 0) {\n+\t\tprintf(\"%s: Symlink %llu extent data encrypted!\\n\", __func__,\n+\t\t inr);\n+\t\tgoto out;\n+\t} else if (extent->ram_bytes >= btrfs_info.sb.sectorsize) {\n+\t\tprintf(\"%s: Symlink %llu extent data too long (%llu)!\\n\",\n+\t\t __func__, inr, extent->ram_bytes);\n+\t\tgoto out;\n+\t}\n+\n+\tdata_ptr = (const char *) extent\n+\t\t + offsetof(struct btrfs_file_extent_item, disk_bytenr);\n+\n+\tmemcpy(target, data_ptr, extent->ram_bytes);\n+\ttarget[extent->ram_bytes] = '\\0';\n+\tres = 0;\n+out:\n+\tbtrfs_free_path(&path);\n+\treturn res;\n+}\n+\n+/* inr must be a directory (for regular files with multiple hard links this\n+ function returns only one of the parents of the file) */\n+static u64 get_parent_inode(struct btrfs_root *root, u64 inr,\n+\t\t\t struct btrfs_inode_item *inode_item)\n+{\n+\tstruct btrfs_key key;\n+\tu64 res;\n+\n+\tif (inr == BTRFS_FIRST_FREE_OBJECTID) {\n+\t\tif (root->objectid != btrfs_info.fs_root.objectid) {\n+\t\t\tu64 parent;\n+\t\t\tstruct btrfs_root_ref ref;\n+\n+\t\t\tparent = btrfs_lookup_root_ref(root->objectid, &ref,\n+\t\t\t\t\t\t NULL);\n+\t\t\tif (parent == -1ULL)\n+\t\t\t\treturn -1ULL;\n+\n+\t\t\tif (btrfs_find_root(parent, root, NULL))\n+\t\t\t\treturn -1ULL;\n+\n+\t\t\tinr = ref.dirid;\n+\t\t}\n+\n+\t\tif (inode_item) {\n+\t\t\tkey.objectid = inr;\n+\t\t\tkey.type = BTRFS_INODE_ITEM_KEY;\n+\t\t\tkey.offset = 0;\n+\n+\t\t\tif (btrfs_lookup_inode(root, &key, inode_item, NULL))\n+\t\t\t\treturn -1ULL;\n+\t\t}\n+\n+\t\treturn inr;\n+\t}\n+\n+\tres = btrfs_lookup_inode_ref(root, inr, NULL, NULL);\n+\tif (res == -1ULL)\n+\t\treturn -1ULL;\n+\n+\tif (inode_item) {\n+\t\tkey.objectid = res;\n+\t\tkey.type = BTRFS_INODE_ITEM_KEY;\n+\t\tkey.offset = 0;\n+\n+\t\tif (btrfs_lookup_inode(root, &key, inode_item, NULL))\n+\t\t\treturn -1ULL;\n+\t}\n+\n+\treturn res;\n+}\n+\n+static inline int next_length(const char *path)\n+{\n+\tint res = 0;\n+\twhile (*path != '\\0' && *path != '/' && res <= BTRFS_NAME_LEN)\n+\t\t++res, ++path;\n+\treturn res;\n+}\n+\n+static inline const char *skip_current_directories(const char *cur)\n+{\n+\twhile (1) {\n+\t\tif (cur[0] == '/')\n+\t\t\t++cur;\n+\t\telse if (cur[0] == '.' && cur[1] == '/')\n+\t\t\tcur += 2;\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\n+\treturn cur;\n+}\n+\n+/* inode.c, musi vratit aj root stromu kde sa inoda najde */\n+u64 btrfs_lookup_path(struct btrfs_root *root, u64 inr, const char *path,\n+\t\t u8 *type_p, struct btrfs_inode_item *inode_item_p,\n+\t\t int symlink_limit)\n+{\n+\tstruct btrfs_dir_item item;\n+\tstruct btrfs_inode_item inode_item;\n+\tu8 type = BTRFS_FT_DIR;\n+\tint len, have_inode = 0;\n+\tconst char *cur = path;\n+\n+\tif (*cur == '/') {\n+\t\t++cur;\n+\t\tinr = root->root_dirid;\n+\t}\n+\n+\tdo {\n+\t\tcur = skip_current_directories(cur);\n+\n+\t\tlen = next_length(cur);\n+\t\tif (len > BTRFS_NAME_LEN) {\n+\t\t\tprintf(\"%s: Name too long at \\\"%.*s\\\"\\n\", __func__,\n+\t\t\t BTRFS_NAME_LEN, cur);\n+\t\t\treturn -1ULL;\n+\t\t}\n+\n+\t\tif (len == 1 && cur[0] == '.')\n+\t\t\tbreak;\n+\n+\t\tif (len == 2 && cur[0] == '.' && cur[1] == '.') {\n+\t\t\tcur += 2;\n+\t\t\tinr = get_parent_inode(root, inr, &inode_item);\n+\t\t\tif (inr == -1ULL)\n+\t\t\t\treturn -1ULL;\n+\n+\t\t\ttype = BTRFS_FT_DIR;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!*cur)\n+\t\t\tbreak;\n+\t\t\n+\t\tif (btrfs_lookup_dir_item(root, inr, cur, len, &item))\n+\t\t\treturn -1ULL;\n+\n+\t\ttype = item.type;\n+\t\thave_inode = 1;\n+\t\tif (btrfs_lookup_inode(root, &item.location, &inode_item, root))\n+\t\t\treturn -1ULL;\n+\n+\t\tif (item.type == BTRFS_FT_SYMLINK && symlink_limit >= 0) {\n+\t\t\tchar *target;\n+\n+\t\t\tif (!symlink_limit) {\n+\t\t\t\tprintf(\"%s: Too much symlinks!\\n\", __func__);\n+\t\t\t\treturn -1ULL;\n+\t\t\t}\n+\n+\t\t\ttarget = malloc(min(inode_item.size + 1,\n+\t\t\t\t\t (u64) btrfs_info.sb.sectorsize));\n+\t\t\tif (!target)\n+\t\t\t\treturn -1ULL;\n+\n+\t\t\tif (btrfs_readlink(root, item.location.objectid,\n+\t\t\t\t\t target)) {\n+\t\t\t\tfree(target);\n+\t\t\t\treturn -1ULL;\n+\t\t\t}\n+\n+\t\t\tinr = btrfs_lookup_path(root, inr, target, &type,\n+\t\t\t\t\t\t&inode_item, symlink_limit - 1);\n+\n+\t\t\tfree(target);\n+\n+\t\t\tif (inr == -1ULL)\n+\t\t\t\treturn -1ULL;\n+\t\t} else if (item.type != BTRFS_FT_DIR && cur[len]) {\n+\t\t\tprintf(\"%s: \\\"%.*s\\\" not a directory\\n\", __func__,\n+\t\t\t (int) (cur - path + len), path);\n+\t\t\treturn -1ULL;\n+\t\t} else {\n+\t\t\tinr = item.location.objectid;\n+\t\t}\n+\n+\t\tcur += len;\n+\t} while (*cur);\n+\n+\tif (type_p)\n+\t\t*type_p = type;\n+\n+\tif (inode_item_p) {\n+\t\tif (!have_inode) {\n+\t\t\tstruct btrfs_key key;\n+\n+\t\t\tkey.objectid = inr;\n+\t\t\tkey.type = BTRFS_INODE_ITEM_KEY;\n+\t\t\tkey.offset = 0;\n+\n+\t\t\tif (btrfs_lookup_inode(root, &key, &inode_item, NULL))\n+\t\t\t\treturn -1ULL;\n+\t\t}\n+\n+\t\t*inode_item_p = inode_item;\n+\t}\n+\n+\treturn inr;\n+}\n+\n+u64 btrfs_file_read(const struct btrfs_root *root, u64 inr, u64 offset,\n+\t\t u64 size, char *buf)\n+{\n+\tstruct btrfs_path path;\n+\tstruct btrfs_key key;\n+\tstruct btrfs_file_extent_item *extent;\n+\tint res;\n+\tu64 rd, rd_all = -1ULL;\n+\n+\tkey.objectid = inr;\n+\tkey.type = BTRFS_EXTENT_DATA_KEY;\n+\tkey.offset = offset;\n+\n+\tif (btrfs_search_tree(root, &key, &path))\n+\t\treturn -1ULL;\n+\n+\tif (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)) < 0) {\n+\t\tif (btrfs_prev_slot(&path))\n+\t\t\tgoto out;\n+\n+\t\tif (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))\n+\t\t\tgoto out;\n+\t}\n+\n+\trd_all = 0;\n+\n+\tdo {\n+\t\tif (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))\n+\t\t\tbreak;\n+\n+\t\textent = btrfs_path_item_ptr(&path,\n+\t\t\t\t\t struct btrfs_file_extent_item);\n+\n+\t\tif (extent->type == BTRFS_FILE_EXTENT_INLINE) {\n+\t\t\tbtrfs_file_extent_item_to_cpu_inl(extent);\n+\t\t\trd = btrfs_read_extent_inline(&path, extent, offset,\n+\t\t\t\t\t\t size, buf);\n+\t\t} else {\n+\t\t\tbtrfs_file_extent_item_to_cpu(extent);\n+\t\t\trd = btrfs_read_extent_reg(&path, extent, offset, size,\n+\t\t\t\t\t\t buf);\n+\t\t}\n+\n+\t\tif (rd == -1ULL) {\n+\t\t\tprintf(\"%s: Error reading extent\\n\", __func__);\n+\t\t\trd_all = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\toffset = 0;\n+\t\tbuf += rd;\n+\t\trd_all += rd;\n+\t\tsize -= rd;\n+\n+\t\tif (!size)\n+\t\t\tbreak;\n+\t} while (!(res = btrfs_next_slot(&path)));\n+\n+\tif (res)\n+\t\treturn -1ULL;\n+\n+out:\n+\tbtrfs_free_path(&path);\n+\treturn rd_all;\n+}\ndiff --git a/fs/btrfs/root.c b/fs/btrfs/root.c\nnew file mode 100644\nindex 0000000000..c405813b69\n--- /dev/null\n+++ b/fs/btrfs/root.c\n@@ -0,0 +1,93 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+\n+static void read_root_item(struct btrfs_path *p, struct btrfs_root_item *item)\n+{\n+\tu32 len;\n+\tint reset = 0;\n+\n+\tlen = btrfs_path_item_size(p);\n+\tmemcpy(item, btrfs_path_item_ptr(p, struct btrfs_root_item), len);\n+\tbtrfs_root_item_to_cpu(item);\n+\n+\tif (len < sizeof(*item))\n+\t\treset = 1;\n+\tif (!reset && item->generation != item->generation_v2) {\n+\t\tif (item->generation_v2 != 0)\n+\t\t\tprintf(\"%s: generation != generation_v2 in root item\",\n+\t\t\t __func__);\n+\t\treset = 1;\n+\t}\n+\tif (reset) {\n+\t\tmemset(&item->generation_v2, 0,\n+\t\t sizeof(*item) - offsetof(struct btrfs_root_item,\n+\t\t\t\t\t\tgeneration_v2));\n+\t}\n+}\n+\n+int btrfs_find_root(u64 objectid, struct btrfs_root *root,\n+\t\t struct btrfs_root_item *root_item)\n+{\n+\tstruct btrfs_path path;\n+\tstruct btrfs_root_item my_root_item;\n+\n+\tif (!btrfs_search_tree_key_type(&btrfs_info.tree_root, objectid,\n+\t\t\t\t\tBTRFS_ROOT_ITEM_KEY, &path))\n+\t\treturn -1;\n+\n+\tif (!root_item)\n+\t\troot_item = &my_root_item;\n+\tread_root_item(&path, root_item);\n+\n+\tif (root) {\n+\t\troot->objectid = objectid;\n+\t\troot->bytenr = root_item->bytenr;\n+\t\troot->root_dirid = root_item->root_dirid;\n+\t}\n+\n+\tbtrfs_free_path(&path);\n+\treturn 0;\n+}\n+\n+u64 btrfs_lookup_root_ref(u64 subvolid, struct btrfs_root_ref *refp, char *name)\n+{\n+\tstruct btrfs_path path;\n+\tstruct btrfs_key *key;\n+\tstruct btrfs_root_ref *ref;\n+\tu64 res = -1ULL;\n+\n+\tkey = btrfs_search_tree_key_type(&btrfs_info.tree_root, subvolid,\n+\t\t\t\t\t BTRFS_ROOT_BACKREF_KEY, &path);\n+\n+\tif (!key)\n+\t\treturn -1ULL;\n+\n+\tref = btrfs_path_item_ptr(&path, struct btrfs_root_ref);\n+\tbtrfs_root_ref_to_cpu(ref);\n+\n+\tif (refp)\n+\t\t*refp = *ref;\n+\n+\tif (name) {\n+\t\tif (ref->name_len > BTRFS_VOL_NAME_MAX) {\n+\t\t\tprintf(\"%s: volume name too long: %u\\n\", __func__,\n+\t\t\t ref->name_len);\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tmemcpy(name, ref + 1, ref->name_len);\n+\t}\n+\n+\tres = key->offset;\n+out:\n+\tbtrfs_free_path(&path);\n+\treturn res;\n+}\n+\ndiff --git a/fs/btrfs/subvolume.c b/fs/btrfs/subvolume.c\nnew file mode 100644\nindex 0000000000..54e0ab4546\n--- /dev/null\n+++ b/fs/btrfs/subvolume.c\n@@ -0,0 +1,131 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+#include <malloc.h>\n+\n+static int get_subvol_name(u64 subvolid, char *name, int max_len)\n+{\n+\tstruct btrfs_root_ref rref;\n+\tstruct btrfs_inode_ref iref;\n+\tstruct btrfs_root root;\n+\tu64 dir;\n+\tchar tmp[max(BTRFS_VOL_NAME_MAX, BTRFS_NAME_MAX)];\n+\tchar *ptr;\n+\n+\tptr = name + max_len - 1;\n+\t*ptr = '\\0';\n+\n+\twhile (subvolid != BTRFS_FS_TREE_OBJECTID) {\n+\t\tsubvolid = btrfs_lookup_root_ref(subvolid, &rref, tmp);\n+\n+\t\tif (subvolid == -1ULL)\n+\t\t\treturn -1;\n+\n+\t\tptr -= rref.name_len + 1;\n+\t\tif (ptr < name)\n+\t\t\tgoto too_long;\n+\n+\t\tmemcpy(ptr + 1, tmp, rref.name_len);\n+\t\t*ptr = '/';\n+\n+\t\tif (btrfs_find_root(subvolid, &root, NULL))\n+\t\t\treturn -1;\n+\n+\t\tdir = rref.dirid;\n+\n+\t\twhile (dir != BTRFS_FIRST_FREE_OBJECTID) {\n+\t\t\tdir = btrfs_lookup_inode_ref(&root, dir, &iref, tmp);\n+\n+\t\t\tif (dir == -1ULL)\n+\t\t\t\treturn -1;\n+\n+\t\t\tptr -= iref.name_len + 1;\n+\t\t\tif (ptr < name)\n+\t\t\t\tgoto too_long;\n+\n+\t\t\tmemcpy(ptr + 1, tmp, iref.name_len);\n+\t\t\t*ptr = '/';\n+\t\t}\n+\t}\n+\n+\tif (ptr == name + max_len - 1) {\n+\t\tname[0] = '/';\n+\t\tname[1] = '\\0';\n+\t} else {\n+\t\tmemmove(name, ptr, name + max_len - ptr);\n+\t}\n+\n+\treturn 0;\n+\n+too_long:\n+\tprintf(\"%s: subvolume name too long\\n\", __func__);\n+\treturn -1;\n+}\n+\n+u64 btrfs_get_default_subvol_objectid(void)\n+{\n+\tstruct btrfs_dir_item item;\n+\n+\tif (btrfs_lookup_dir_item(&btrfs_info.tree_root,\n+\t\t\t\t btrfs_info.sb.root_dir_objectid, \"default\", 7,\n+\t\t\t\t &item))\n+\t\treturn BTRFS_FS_TREE_OBJECTID;\n+\treturn item.location.objectid;\n+}\n+\n+static void list_subvols(u64 tree, char *nameptr, int max_name_len, int level)\n+{\n+\tstruct btrfs_key key, *found_key;\n+\tstruct btrfs_path path;\n+\tstruct btrfs_root_ref *ref;\n+\tint res;\n+\n+\tkey.objectid = tree;\n+\tkey.type = BTRFS_ROOT_REF_KEY;\n+\tkey.offset = 0;\n+\n+\tif (btrfs_search_tree(&btrfs_info.tree_root, &key, &path))\n+\t\treturn;\n+\n+\tdo {\n+\t\tfound_key = btrfs_path_leaf_key(&path);\n+\t\tif (btrfs_comp_keys_type(&key, found_key))\n+\t\t\tbreak;\n+\n+\t\tref = btrfs_path_item_ptr(&path, struct btrfs_root_ref);\n+\t\tbtrfs_root_ref_to_cpu(ref);\n+\n+\t\tprintf(\"ID %llu parent %llu name \", found_key->offset, tree);\n+\t\tif (nameptr && !get_subvol_name(found_key->offset, nameptr,\n+\t\t\t\t\t\tmax_name_len))\n+\t\t\tprintf(\"%s\\n\", nameptr);\n+\t\telse\n+\t\t\tprintf(\"%.*s\\n\", (int) ref->name_len,\n+\t\t\t (const char *) (ref + 1));\n+\n+\t\tif (level > 0)\n+\t\t\tlist_subvols(found_key->offset, nameptr, max_name_len,\n+\t\t\t\t level - 1);\n+\t\telse\n+\t\t\tprintf(\"%s: Too much recursion, maybe skipping some \"\n+\t\t\t \"subvolumes\\n\", __func__);\n+\t} while (!(res = btrfs_next_slot(&path)));\n+\n+\tbtrfs_free_path(&path);\n+}\n+\n+void btrfs_list_subvols(void)\n+{\n+\tchar *nameptr = malloc(4096);\n+\n+\tlist_subvols(BTRFS_FS_TREE_OBJECTID, nameptr, nameptr ? 4096 : 0, 40);\n+\n+\tif (nameptr)\n+\t\tfree(nameptr);\n+}\ndiff --git a/fs/btrfs/super.c b/fs/btrfs/super.c\nnew file mode 100644\nindex 0000000000..706286ee2d\n--- /dev/null\n+++ b/fs/btrfs/super.c\n@@ -0,0 +1,233 @@\n+/*\n+ * BTRFS filesystem implementation for U-Boot\n+ *\n+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include \"btrfs.h\"\n+\n+#define BTRFS_SUPER_FLAG_SUPP\t(BTRFS_HEADER_FLAG_WRITTEN\t\\\n+\t\t\t\t | BTRFS_HEADER_FLAG_RELOC\t\\\n+\t\t\t\t | BTRFS_SUPER_FLAG_ERROR\t\\\n+\t\t\t\t | BTRFS_SUPER_FLAG_SEEDING\t\\\n+\t\t\t\t | BTRFS_SUPER_FLAG_METADUMP)\n+\n+#define BTRFS_SUPER_INFO_SIZE\t4096\n+\n+static int btrfs_newest_root_backup(struct btrfs_super_block *sb)\n+{\n+\tstruct btrfs_root_backup *root_backup;\n+\tint i, newest = -1;\n+\n+\tfor (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; ++i) {\n+\t\troot_backup = sb->super_roots + i;\n+\t\tif (root_backup->tree_root_gen == sb->generation)\n+\t\t\tnewest = i;\n+\t}\n+\n+\treturn newest;\n+}\n+\n+static inline int is_power_of_2(u64 x)\n+{\n+\treturn !(x & (x - 1));\n+}\n+\n+static int btrfs_check_super_csum(char *raw_disk_sb)\n+{\n+\tstruct btrfs_super_block *disk_sb =\n+\t\t(struct btrfs_super_block *) raw_disk_sb;\n+\tu16 csum_type = le16_to_cpu(disk_sb->csum_type);\n+\n+\tif (csum_type == BTRFS_CSUM_TYPE_CRC32) {\n+\t\tu32 crc = ~(u32) 0;\n+\t\tconst int csum_size = sizeof(crc);\n+\t\tchar result[csum_size];\n+\n+\t\tcrc = btrfs_csum_data(raw_disk_sb + BTRFS_CSUM_SIZE, crc,\n+\t\t\t\t BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);\n+\t\tbtrfs_csum_final(crc, result);\n+\n+\t\tif (memcmp(raw_disk_sb, result, csum_size))\n+\t\t\treturn -1;\n+\t} else {\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int btrfs_check_super(struct btrfs_super_block *sb)\n+{\n+\tint ret = 0;\n+\n+\tif (sb->flags & ~BTRFS_SUPER_FLAG_SUPP) {\n+\t\tprintf(\"%s: Unsupported flags: %llu\\n\", __func__,\n+\t\t sb->flags & ~BTRFS_SUPER_FLAG_SUPP);\n+\t}\n+\n+\tif (sb->root_level > BTRFS_MAX_LEVEL) {\n+\t\tprintf(\"%s: tree_root level too big: %d >= %d\\n\", __func__,\n+\t\t sb->root_level, BTRFS_MAX_LEVEL);\n+\t\tret = -1;\n+\t}\n+\n+\tif (sb->chunk_root_level > BTRFS_MAX_LEVEL) {\n+\t\tprintf(\"%s: chunk_root level too big: %d >= %d\\n\", __func__,\n+\t\t sb->chunk_root_level, BTRFS_MAX_LEVEL);\n+\t\tret = -1;\n+\t}\n+\n+\tif (sb->log_root_level > BTRFS_MAX_LEVEL) {\n+\t\tprintf(\"%s: log_root level too big: %d >= %d\\n\", __func__,\n+\t\t sb->log_root_level, BTRFS_MAX_LEVEL);\n+\t\tret = -1;\n+\t}\n+\n+\tif (!is_power_of_2(sb->sectorsize) || sb->sectorsize < 4096 ||\n+\t sb->sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE) {\n+\t\tprintf(\"%s: invalid sectorsize %u\\n\", __func__,\n+\t\t sb->sectorsize);\n+\t\tret = -1;\n+\t}\n+\n+\tif (!is_power_of_2(sb->nodesize) || sb->nodesize < sb->sectorsize ||\n+\t sb->nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) {\n+\t\tprintf(\"%s: invalid nodesize %u\\n\", __func__, sb->nodesize);\n+\t\tret = -1;\n+\t}\n+\n+\tif (sb->nodesize != sb->__unused_leafsize) {\n+\t\tprintf(\"%s: invalid leafsize %u, should be %u\\n\", __func__,\n+\t\t sb->__unused_leafsize, sb->nodesize);\n+\t\tret = -1;\n+\t}\n+\n+\tif (!IS_ALIGNED(sb->root, sb->sectorsize)) {\n+\t\tprintf(\"%s: tree_root block unaligned: %llu\\n\", __func__,\n+\t\t sb->root);\n+\t\tret = -1;\n+\t}\n+\n+\tif (!IS_ALIGNED(sb->chunk_root, sb->sectorsize)) {\n+\t\tprintf(\"%s: chunk_root block unaligned: %llu\\n\", __func__,\n+\t\t sb->chunk_root);\n+\t\tret = -1;\n+\t}\n+\n+\tif (!IS_ALIGNED(sb->log_root, sb->sectorsize)) {\n+\t\tprintf(\"%s: log_root block unaligned: %llu\\n\", __func__,\n+\t\t sb->log_root);\n+\t\tret = -1;\n+\t}\n+\n+\tif (memcmp(sb->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) {\n+\t\tprintf(\"%s: dev_item UUID does not match fsid\\n\", __func__);\n+\t\tret = -1;\n+\t}\n+\n+\tif (sb->bytes_used < 6*sb->nodesize) {\n+\t\tprintf(\"%s: bytes_used is too small %llu\\n\", __func__,\n+\t\t sb->bytes_used);\n+\t\tret = -1;\n+\t}\n+\n+\tif (!is_power_of_2(sb->stripesize)) {\n+\t\tprintf(\"%s: invalid stripesize %u\\n\", __func__, sb->stripesize);\n+\t\tret = -1;\n+\t}\n+\n+\tif (sb->sys_chunk_array_size > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) {\n+\t\tprintf(\"%s: system chunk array too big %u > %u\\n\", __func__,\n+\t\t sb->sys_chunk_array_size, BTRFS_SYSTEM_CHUNK_ARRAY_SIZE);\n+\t\tret = -1;\n+\t}\n+\n+\tif (sb->sys_chunk_array_size < sizeof(struct btrfs_key) +\n+\t sizeof(struct btrfs_chunk)) {\n+\t\tprintf(\"%s: system chunk array too small %u < %u\\n\", __func__,\n+\t\t sb->sys_chunk_array_size, (u32) sizeof(struct btrfs_key)\n+\t\t + sizeof(struct btrfs_chunk));\n+\t\tret = -1;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int btrfs_read_superblock(void)\n+{\n+\tconst u64 superblock_offsets[4] = {\n+\t\t0x10000ull,\n+\t\t0x4000000ull,\n+\t\t0x4000000000ull,\n+\t\t0x4000000000000ull\n+\t};\n+\tchar raw_sb[BTRFS_SUPER_INFO_SIZE];\n+\tstruct btrfs_super_block *sb = (struct btrfs_super_block *) raw_sb;\n+\tu64 dev_total_bytes;\n+\tint i, root_backup_idx;\n+\n+\tdev_total_bytes = (u64) btrfs_part_info->size * btrfs_part_info->blksz;\n+\n+\tbtrfs_info.sb.generation = 0;\n+\n+\tfor (i = 0; i < 4; ++i) {\n+\t\tif (superblock_offsets[i] + sizeof(sb) > dev_total_bytes)\n+\t\t\tbreak;\n+\n+\t\tif (!btrfs_devread(superblock_offsets[i], BTRFS_SUPER_INFO_SIZE,\n+\t\t\t\t raw_sb))\n+\t\t\tbreak;\n+\n+\t\tif (btrfs_check_super_csum(raw_sb)) {\n+\t\t\tprintf(\"%s: invalid checksum at superblock mirror %i\\n\",\n+\t\t\t __func__, i);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tbtrfs_super_block_to_cpu(sb);\n+\n+\t\tif (sb->magic != BTRFS_MAGIC) {\n+\t\t\tprintf(\"%s: invalid BTRFS magic 0x%016llX at \"\n+\t\t\t \"superblock mirror %i\\n\", __func__, sb->magic,\n+\t\t\t i);\n+\t\t} else if (sb->bytenr != superblock_offsets[i]) {\n+\t\t\tprintf(\"%s: invalid bytenr 0x%016llX (expected \"\n+\t\t\t \"0x%016llX) at superblock mirror %i\\n\",\n+\t\t\t __func__, sb->bytenr, superblock_offsets[i], i);\n+\t\t} else if (btrfs_check_super(sb)) {\n+\t\t\tprintf(\"%s: Checking superblock mirror %i failed\\n\",\n+\t\t\t __func__, i);\n+\t\t} else if (sb->generation > btrfs_info.sb.generation) {\n+\t\t\tmemcpy(&btrfs_info.sb, sb, sizeof(*sb));\n+\t\t} else {\n+\t\t\t/* Nothing */\n+\t\t}\n+\t}\n+\n+\tif (!btrfs_info.sb.generation) {\n+\t\tprintf(\"%s: No valid BTRFS superblock found!\\n\", __func__);\n+\t\treturn -1;\n+\t}\n+\n+\troot_backup_idx = btrfs_newest_root_backup(&btrfs_info.sb);\n+\tif (root_backup_idx < 0) {\n+\t\tprintf(\"%s: No valid root_backup found!\\n\", __func__);\n+\t\treturn -1;\n+\t}\n+\tbtrfs_info.root_backup = btrfs_info.sb.super_roots + root_backup_idx;\n+\n+\tif (btrfs_info.root_backup->num_devices != 1) {\n+\t\tprintf(\"%s: Unsupported number of devices (%lli). This driver \"\n+\t\t \"only supports filesystem on one device.\\n\", __func__,\n+\t\t btrfs_info.root_backup->num_devices);\n+\t\treturn -1;\n+\t}\n+\n+\tdebug(\"Chosen superblock with generation = %llu\\n\",\n+\t btrfs_info.sb.generation);\n+\n+\treturn 0;\n+}\n", "prefixes": [ "U-Boot", "6/9" ] }