]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
fs: btrfs: Crossport btrfs_read_dev_super() from btrfs-progs
authorQu Wenruo <wqu@suse.com>
Wed, 24 Jun 2020 16:02:49 +0000 (18:02 +0200)
committerTom Rini <trini@konsulko.com>
Tue, 8 Sep 2020 00:57:27 +0000 (20:57 -0400)
This patch uses generic code from btrfs-progs to read one super block
from block device.

To support the btrfs-progs coding style, the following is also
crossported:
- BTRFS_SETGET_FUNC for btrfs_super_block
- btrfs_check_super() function
- Move btrfs_read_superblock() to disk-io.[ch]
  Since super.c only contains pretty small amount of code, and
  the extra check will be covered in later root read patches.

Differences between this implementation and btrfs-progs:
- No sbflags/sb_bytenr support
  Since we only need to read the primary super block (like kernel),
  sbflags/sb_bytenr used by super block recovery is not needed.

This also changes the following behavior of U-Boot btrfs:
- Only reads the primary super block
  The old implementation reads all 3 super blocks, and also one
  non-existing backup.
  This is not correct, especially if there is another filesystem created
  on the device but old superblocks are not rewritten.

  Just like kernel, we only check the primary super block.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: Marek BehĂșn <marek.behun@nic.cz>
[trini: Change error to be a define in compat.h]
Signed-off-by: Tom Rini <trini@konsulko.com>
fs/btrfs/Makefile
fs/btrfs/btrfs.c
fs/btrfs/compat.h [new file with mode: 0644]
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/super.c [deleted file]

index 84b3b5ec0e8aaff74f76b1b2e9844be5026c97d4..bd4b848d1b1f37ccf2a7c6d7b86a26b9006ef32d 100644 (file)
@@ -3,4 +3,4 @@
 # 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
 
 obj-y := btrfs.o chunk-map.o compression.o ctree.o dev.o dir-item.o \
-       extent-io.o inode.o root.o subvolume.o super.o crypto/hash.o disk-io.o
+       extent-io.o inode.o root.o subvolume.o crypto/hash.o disk-io.o
index d5a87c175c52bcee9bc56e2a299c9631370a7900..78a32497b58d5bd491b537b7c5e94cbb487fb107 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/time.h>
 #include "btrfs.h"
 #include "crypto/hash.h"
+#include "disk-io.h"
 
 struct btrfs_info btrfs_info;
 
diff --git a/fs/btrfs/compat.h b/fs/btrfs/compat.h
new file mode 100644 (file)
index 0000000..b354c17
--- /dev/null
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#ifndef __BTRFS_COMPAT_H__
+#define __BTRFS_COMPAT_H__
+
+#include <linux/errno.h>
+#include <fs_internal.h>
+#include <uuid.h>
+
+/* Provide a compatibility layer to make code syncing easier */
+
+/* A simple wraper to for error() used in btrfs-progs */
+#define error(fmt, ...)                pr_err("BTRFS: " fmt "\n", ##__VA_ARGS__)
+
+#define BTRFS_UUID_UNPARSED_SIZE       37
+
+/*
+ * Macros to generate set/get funcs for the struct fields
+ * assume there is a lefoo_to_cpu for every type, so lets make a simple
+ * one for u8:
+ */
+#define le8_to_cpu(v) (v)
+#define cpu_to_le8(v) (v)
+#define __le8 u8
+
+/*
+ * Read data from device specified by @desc and @part
+ *
+ * U-boot equivalent of pread().
+ *
+ * Return the bytes of data read.
+ * Return <0 for error.
+ */
+static inline int __btrfs_devread(struct blk_desc *desc,
+                                 struct disk_partition *part,
+                                 void *buf, size_t size, u64 offset)
+{
+       lbaint_t sector;
+       int byte_offset;
+       int ret;
+
+       sector = offset >> desc->log2blksz;
+       byte_offset = offset % desc->blksz;
+
+       /* fs_devread() return 0 for error, >0 for success */
+       ret = fs_devread(desc, part, sector, byte_offset, size, buf);
+       if (!ret)
+               return -EIO;
+       return size;
+}
+
+static inline void uuid_unparse(const u8 *uuid, char *out)
+{
+       return uuid_bin_to_str((unsigned char *)uuid, out, 0);
+}
+
+#endif
index 28f98d43ada42971165b4c048b48eba75d812cbb..1d8f7e168fe26dde90ab2482110e3491e835f2e3 100644 (file)
 #include <malloc.h>
 #include <memalign.h>
 
+static const struct btrfs_csum {
+       u16 size;
+       const char name[14];
+} btrfs_csums[] = {
+       [BTRFS_CSUM_TYPE_CRC32]         = {  4, "crc32c" },
+       [BTRFS_CSUM_TYPE_XXHASH]        = {  8, "xxhash64" },
+       [BTRFS_CSUM_TYPE_SHA256]        = { 32, "sha256" },
+       [BTRFS_CSUM_TYPE_BLAKE2]        = { 32, "blake2" },
+};
+
+u16 btrfs_super_csum_size(const struct btrfs_super_block *sb)
+{
+       const u16 csum_type = btrfs_super_csum_type(sb);
+
+       return btrfs_csums[csum_type].size;
+}
+
+const char *btrfs_super_csum_name(u16 csum_type)
+{
+       return btrfs_csums[csum_type].name;
+}
+
+size_t btrfs_super_num_csums(void)
+{
+       return ARRAY_SIZE(btrfs_csums);
+}
+
+u16 btrfs_csum_type_size(u16 csum_type)
+{
+       return btrfs_csums[csum_type].size;
+}
+
 int btrfs_comp_keys(struct btrfs_key *a, struct btrfs_key *b)
 {
        if (a->objectid > b->objectid)
index 156ce69ed02251fcbded6acc1aad23d6324af2b5..02125e5e100cb52403b54670125049a0474f45c4 100644 (file)
@@ -12,6 +12,7 @@
 #include <common.h>
 #include <compiler.h>
 #include "kernel-shared/btrfs_tree.h"
+#include "compat.h"
 
 #define BTRFS_MAX_MIRRORS 3
 
 #define BTRFS_FS_STATE_DEV_REPLACING   3
 #define BTRFS_FS_STATE_DUMMY_FS_INFO   4
 
+#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)             \
+static inline u##bits btrfs_##name(const type *s)                      \
+{                                                                      \
+       return le##bits##_to_cpu(s->member);                            \
+}                                                                      \
+static inline void btrfs_set_##name(type *s, u##bits val)              \
+{                                                                      \
+       s->member = cpu_to_le##bits(val);                               \
+}
+
 union btrfs_tree_node {
        struct btrfs_header header;
        struct btrfs_leaf leaf;
@@ -122,4 +133,60 @@ static inline void *btrfs_path_leaf_data(struct btrfs_path *p)
 #define btrfs_path_item_ptr(p,t)               \
        ((t *) btrfs_path_leaf_data((p)))
 
+u16 btrfs_super_csum_size(const struct btrfs_super_block *s);
+const char *btrfs_super_csum_name(u16 csum_type);
+u16 btrfs_csum_type_size(u16 csum_type);
+size_t btrfs_super_num_csums(void);
+
+/* struct btrfs_super_block */
+
+BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
+BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64);
+BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
+                        generation, 64);
+BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);
+BTRFS_SETGET_STACK_FUNCS(super_sys_array_size,
+                        struct btrfs_super_block, sys_chunk_array_size, 32);
+BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation,
+                        struct btrfs_super_block, chunk_root_generation, 64);
+BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block,
+                        root_level, 8);
+BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block,
+                        chunk_root, 64);
+BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block,
+                        chunk_root_level, 8);
+BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block,
+                        log_root, 64);
+BTRFS_SETGET_STACK_FUNCS(super_log_root_transid, struct btrfs_super_block,
+                        log_root_transid, 64);
+BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block,
+                        log_root_level, 8);
+BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block,
+                        total_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block,
+                        bytes_used, 64);
+BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block,
+                        sectorsize, 32);
+BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block,
+                        nodesize, 32);
+BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block,
+                        stripesize, 32);
+BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block,
+                        root_dir_objectid, 64);
+BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block,
+                        num_devices, 64);
+BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block,
+                        compat_flags, 64);
+BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block,
+                        compat_ro_flags, 64);
+BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block,
+                        incompat_flags, 64);
+BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block,
+                        csum_type, 16);
+BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block,
+                        cache_generation, 64);
+BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
+                        uuid_tree_generation, 64);
+BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64);
+
 #endif /* __BTRFS_CTREE_H__ */
index 58c32b548e504be0aae0c26c64c079414f838500..edebf741fd2d57861c00b8cff9093fa1902bc4c8 100644 (file)
@@ -1,7 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0+
 #include <common.h>
 #include <fs_internal.h>
+#include <uuid.h>
+#include <memalign.h>
+#include "kernel-shared/btrfs_tree.h"
 #include "disk-io.h"
+#include "ctree.h"
+#include "btrfs.h"
 #include "crypto/hash.h"
 
 int btrfs_csum_data(u16 csum_type, const u8 *data, u8 *out, size_t len)
@@ -20,3 +25,211 @@ int btrfs_csum_data(u16 csum_type, const u8 *data, u8 *out, size_t len)
                return -EINVAL;
        }
 }
+
+/*
+ * Check if the super is valid:
+ * - nodesize/sectorsize - minimum, maximum, alignment
+ * - tree block starts   - alignment
+ * - number of devices   - something sane
+ * - sys array size      - maximum
+ */
+static int btrfs_check_super(struct btrfs_super_block *sb)
+{
+       u8 result[BTRFS_CSUM_SIZE];
+       u16 csum_type;
+       int csum_size;
+       u8 *metadata_uuid;
+
+       if (btrfs_super_magic(sb) != BTRFS_MAGIC)
+               return -EIO;
+
+       csum_type = btrfs_super_csum_type(sb);
+       if (csum_type >= btrfs_super_num_csums()) {
+               error("unsupported checksum algorithm %u", csum_type);
+               return -EIO;
+       }
+       csum_size = btrfs_super_csum_size(sb);
+
+       btrfs_csum_data(csum_type, (u8 *)sb + BTRFS_CSUM_SIZE,
+                       result, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
+
+       if (memcmp(result, sb->csum, csum_size)) {
+               error("superblock checksum mismatch");
+               return -EIO;
+       }
+       if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) {
+               error("tree_root level too big: %d >= %d",
+                       btrfs_super_root_level(sb), BTRFS_MAX_LEVEL);
+               goto error_out;
+       }
+       if (btrfs_super_chunk_root_level(sb) >= BTRFS_MAX_LEVEL) {
+               error("chunk_root level too big: %d >= %d",
+                       btrfs_super_chunk_root_level(sb), BTRFS_MAX_LEVEL);
+               goto error_out;
+       }
+       if (btrfs_super_log_root_level(sb) >= BTRFS_MAX_LEVEL) {
+               error("log_root level too big: %d >= %d",
+                       btrfs_super_log_root_level(sb), BTRFS_MAX_LEVEL);
+               goto error_out;
+       }
+
+       if (!IS_ALIGNED(btrfs_super_root(sb), 4096)) {
+               error("tree_root block unaligned: %llu", btrfs_super_root(sb));
+               goto error_out;
+       }
+       if (!IS_ALIGNED(btrfs_super_chunk_root(sb), 4096)) {
+               error("chunk_root block unaligned: %llu",
+                       btrfs_super_chunk_root(sb));
+               goto error_out;
+       }
+       if (!IS_ALIGNED(btrfs_super_log_root(sb), 4096)) {
+               error("log_root block unaligned: %llu",
+                       btrfs_super_log_root(sb));
+               goto error_out;
+       }
+       if (btrfs_super_nodesize(sb) < 4096) {
+               error("nodesize too small: %u < 4096",
+                       btrfs_super_nodesize(sb));
+               goto error_out;
+       }
+       if (!IS_ALIGNED(btrfs_super_nodesize(sb), 4096)) {
+               error("nodesize unaligned: %u", btrfs_super_nodesize(sb));
+               goto error_out;
+       }
+       if (btrfs_super_sectorsize(sb) < 4096) {
+               error("sectorsize too small: %u < 4096",
+                       btrfs_super_sectorsize(sb));
+               goto error_out;
+       }
+       if (!IS_ALIGNED(btrfs_super_sectorsize(sb), 4096)) {
+               error("sectorsize unaligned: %u", btrfs_super_sectorsize(sb));
+               goto error_out;
+       }
+       if (btrfs_super_total_bytes(sb) == 0) {
+               error("invalid total_bytes 0");
+               goto error_out;
+       }
+       if (btrfs_super_bytes_used(sb) < 6 * btrfs_super_nodesize(sb)) {
+               error("invalid bytes_used %llu", btrfs_super_bytes_used(sb));
+               goto error_out;
+       }
+       if ((btrfs_super_stripesize(sb) != 4096)
+               && (btrfs_super_stripesize(sb) != btrfs_super_sectorsize(sb))) {
+               error("invalid stripesize %u", btrfs_super_stripesize(sb));
+               goto error_out;
+       }
+
+       if (btrfs_super_incompat_flags(sb) & BTRFS_FEATURE_INCOMPAT_METADATA_UUID)
+               metadata_uuid = sb->metadata_uuid;
+       else
+               metadata_uuid = sb->fsid;
+
+       if (memcmp(metadata_uuid, sb->dev_item.fsid, BTRFS_FSID_SIZE) != 0) {
+               char fsid[BTRFS_UUID_UNPARSED_SIZE];
+               char dev_fsid[BTRFS_UUID_UNPARSED_SIZE];
+
+               uuid_unparse(sb->metadata_uuid, fsid);
+               uuid_unparse(sb->dev_item.fsid, dev_fsid);
+               error("dev_item UUID does not match fsid: %s != %s",
+                       dev_fsid, fsid);
+               goto error_out;
+       }
+
+       /*
+        * Hint to catch really bogus numbers, bitflips or so
+        */
+       if (btrfs_super_num_devices(sb) > (1UL << 31)) {
+               error("suspicious number of devices: %llu",
+                       btrfs_super_num_devices(sb));
+       }
+
+       if (btrfs_super_num_devices(sb) == 0) {
+               error("number of devices is 0");
+               goto error_out;
+       }
+
+       /*
+        * Obvious sys_chunk_array corruptions, it must hold at least one key
+        * and one chunk
+        */
+       if (btrfs_super_sys_array_size(sb) > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) {
+               error("system chunk array too big %u > %u",
+                     btrfs_super_sys_array_size(sb),
+                     BTRFS_SYSTEM_CHUNK_ARRAY_SIZE);
+               goto error_out;
+       }
+       if (btrfs_super_sys_array_size(sb) < sizeof(struct btrfs_disk_key)
+                       + sizeof(struct btrfs_chunk)) {
+               error("system chunk array too small %u < %zu",
+                     btrfs_super_sys_array_size(sb),
+                     sizeof(struct btrfs_disk_key) +
+                     sizeof(struct btrfs_chunk));
+               goto error_out;
+       }
+
+       return 0;
+
+error_out:
+       error("superblock checksum matches but it has invalid members");
+       return -EIO;
+}
+
+/*
+ * btrfs_read_dev_super - read a valid primary superblock from a block device
+ * @desc,@part:        file descriptor of the device
+ * @sb:                buffer where the superblock is going to be read in
+ *
+ * Unlike the btrfs-progs/kernel version, here we ony care about the first
+ * super block, thus it's much simpler.
+ */
+int btrfs_read_dev_super(struct blk_desc *desc, struct disk_partition *part,
+                        struct btrfs_super_block *sb)
+{
+       char tmp[BTRFS_SUPER_INFO_SIZE];
+       struct btrfs_super_block *buf = (struct btrfs_super_block *)tmp;
+       int ret;
+
+       ret = __btrfs_devread(desc, part, tmp, BTRFS_SUPER_INFO_SIZE,
+                             BTRFS_SUPER_INFO_OFFSET);
+       if (ret < BTRFS_SUPER_INFO_SIZE)
+               return -EIO;
+
+       if (btrfs_super_bytenr(buf) != BTRFS_SUPER_INFO_OFFSET)
+               return -EIO;
+
+       if (btrfs_check_super(buf))
+               return -EIO;
+
+       memcpy(sb, buf, BTRFS_SUPER_INFO_SIZE);
+       return 0;
+}
+
+int btrfs_read_superblock(void)
+{
+       ALLOC_CACHE_ALIGN_BUFFER(char, raw_sb, BTRFS_SUPER_INFO_SIZE);
+       struct btrfs_super_block *sb = (struct btrfs_super_block *) raw_sb;
+       int ret;
+
+
+       btrfs_info.sb.generation = 0;
+
+       ret = btrfs_read_dev_super(btrfs_blk_desc, btrfs_part_info, sb);
+       if (ret < 0) {
+               pr_debug("%s: No valid BTRFS superblock found!\n", __func__);
+               return ret;
+       }
+       btrfs_super_block_to_cpu(sb);
+       memcpy(&btrfs_info.sb, sb, sizeof(*sb));
+
+       if (btrfs_info.sb.num_devices != 1) {
+               printf("%s: Unsupported number of devices (%lli). This driver "
+                      "only supports filesystem on one device.\n", __func__,
+                      btrfs_info.sb.num_devices);
+               return -1;
+       }
+
+       pr_debug("Chosen superblock with generation = %llu\n",
+             btrfs_info.sb.generation);
+
+       return 0;
+}
index efb715828cce7fc0e544ae69bc202b90111b9679..fe4093cbd8318d061246e26753ab9e56b1b3b4a4 100644 (file)
@@ -2,10 +2,14 @@
 #ifndef __BTRFS_DISK_IO_H__
 #define __BTRFS_DISK_IO_H__
 
+#include <linux/sizes.h>
+#include <fs_internal.h>
 #include "crypto/hash.h"
 #include "ctree.h"
 #include "disk-io.h"
 
+#define BTRFS_SUPER_INFO_OFFSET SZ_64K
+#define BTRFS_SUPER_INFO_SIZE  SZ_4K
 static inline u64 btrfs_name_hash(const char *name, int len)
 {
        u32 crc;
@@ -17,4 +21,7 @@ static inline u64 btrfs_name_hash(const char *name, int len)
 
 int btrfs_csum_data(u16 csum_type, const u8 *data, u8 *out, size_t len);
 
+int btrfs_read_dev_super(struct blk_desc *desc, struct disk_partition *part,
+                        struct btrfs_super_block *sb);
+int btrfs_read_superblock(void);
 #endif
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
deleted file mode 100644 (file)
index 101572b..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * BTRFS filesystem implementation for U-Boot
- *
- * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
- */
-
-#include <common.h>
-#include <log.h>
-#include <memalign.h>
-#include <part.h>
-#include <linux/compat.h>
-#include "btrfs.h"
-#include "disk-io.h"
-
-#define BTRFS_SUPER_FLAG_SUPP  (BTRFS_HEADER_FLAG_WRITTEN      \
-                                | BTRFS_HEADER_FLAG_RELOC      \
-                                | BTRFS_SUPER_FLAG_ERROR       \
-                                | BTRFS_SUPER_FLAG_SEEDING     \
-                                | BTRFS_SUPER_FLAG_METADUMP)
-
-#define BTRFS_SUPER_INFO_SIZE  4096
-
-/*
- * checks if a valid root backup is present.
- * considers the case when all root backups empty valid.
- * returns -1 in case of invalid root backup and 0 for valid.
- */
-static int btrfs_check_super_roots(struct btrfs_super_block *sb)
-{
-       struct btrfs_root_backup *root_backup;
-       int i, newest = -1;
-       int num_empty = 0;
-
-       for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; ++i) {
-               root_backup = sb->super_roots + i;
-
-               if (root_backup->tree_root == 0 && root_backup->tree_root_gen == 0)
-                       num_empty++;
-
-               if (root_backup->tree_root_gen == sb->generation)
-                       newest = i;
-       }
-
-       if (num_empty == BTRFS_NUM_BACKUP_ROOTS) {
-               return 0;
-       } else if (newest >= 0) {
-               return 0;
-       }
-
-       return -1;
-}
-
-static inline int is_power_of_2(u64 x)
-{
-       return !(x & (x - 1));
-}
-
-static int btrfs_check_super_csum(char *raw_disk_sb)
-{
-       struct btrfs_super_block *disk_sb =
-               (struct btrfs_super_block *) raw_disk_sb;
-       u16 csum_type = le16_to_cpu(disk_sb->csum_type);
-
-       if (csum_type == BTRFS_CSUM_TYPE_CRC32 ||
-           csum_type == BTRFS_CSUM_TYPE_SHA256 ||
-           csum_type == BTRFS_CSUM_TYPE_XXHASH) {
-               u8 result[BTRFS_CSUM_SIZE];
-
-               btrfs_csum_data(csum_type, (u8 *)raw_disk_sb + BTRFS_CSUM_SIZE,
-                       result, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
-
-               if (memcmp(raw_disk_sb, result, BTRFS_CSUM_SIZE))
-                       return -EIO;
-       } else if (csum_type == BTRFS_CSUM_TYPE_BLAKE2) {
-               printf("Blake2 csum type is not supported yet\n");
-               return -ENOTSUPP;
-       }
-
-       return 0;
-}
-
-static int btrfs_check_super(struct btrfs_super_block *sb)
-{
-       int ret = 0;
-
-       if (sb->flags & ~BTRFS_SUPER_FLAG_SUPP) {
-               printf("%s: Unsupported flags: %llu\n", __func__,
-                      sb->flags & ~BTRFS_SUPER_FLAG_SUPP);
-       }
-
-       if (sb->root_level > BTRFS_MAX_LEVEL) {
-               printf("%s: tree_root level too big: %d >= %d\n", __func__,
-                      sb->root_level, BTRFS_MAX_LEVEL);
-               ret = -1;
-       }
-
-       if (sb->chunk_root_level > BTRFS_MAX_LEVEL) {
-               printf("%s: chunk_root level too big: %d >= %d\n", __func__,
-                      sb->chunk_root_level, BTRFS_MAX_LEVEL);
-               ret = -1;
-       }
-
-       if (sb->log_root_level > BTRFS_MAX_LEVEL) {
-               printf("%s: log_root level too big: %d >= %d\n", __func__,
-                      sb->log_root_level, BTRFS_MAX_LEVEL);
-               ret = -1;
-       }
-
-       if (!is_power_of_2(sb->sectorsize) || sb->sectorsize < 4096 ||
-           sb->sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE) {
-               printf("%s: invalid sectorsize %u\n", __func__,
-                      sb->sectorsize);
-               ret = -1;
-       }
-
-       if (!is_power_of_2(sb->nodesize) || sb->nodesize < sb->sectorsize ||
-           sb->nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) {
-               printf("%s: invalid nodesize %u\n", __func__, sb->nodesize);
-               ret = -1;
-       }
-
-       if (sb->nodesize != sb->__unused_leafsize) {
-               printf("%s: invalid leafsize %u, should be %u\n", __func__,
-                      sb->__unused_leafsize, sb->nodesize);
-               ret = -1;
-       }
-
-       if (!IS_ALIGNED(sb->root, sb->sectorsize)) {
-               printf("%s: tree_root block unaligned: %llu\n", __func__,
-                      sb->root);
-               ret = -1;
-       }
-
-       if (!IS_ALIGNED(sb->chunk_root, sb->sectorsize)) {
-               printf("%s: chunk_root block unaligned: %llu\n", __func__,
-                      sb->chunk_root);
-               ret = -1;
-       }
-
-       if (!IS_ALIGNED(sb->log_root, sb->sectorsize)) {
-               printf("%s: log_root block unaligned: %llu\n", __func__,
-                      sb->log_root);
-               ret = -1;
-       }
-
-       if (memcmp(sb->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) {
-               printf("%s: dev_item UUID does not match fsid\n", __func__);
-               ret = -1;
-       }
-
-       if (sb->bytes_used < 6*sb->nodesize) {
-               printf("%s: bytes_used is too small %llu\n", __func__,
-                      sb->bytes_used);
-               ret = -1;
-       }
-
-       if (!is_power_of_2(sb->stripesize)) {
-               printf("%s: invalid stripesize %u\n", __func__, sb->stripesize);
-               ret = -1;
-       }
-
-       if (sb->sys_chunk_array_size > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) {
-               printf("%s: system chunk array too big %u > %u\n", __func__,
-                      sb->sys_chunk_array_size, BTRFS_SYSTEM_CHUNK_ARRAY_SIZE);
-               ret = -1;
-       }
-
-       if (sb->sys_chunk_array_size < sizeof(struct btrfs_key) +
-           sizeof(struct btrfs_chunk)) {
-               printf("%s: system chunk array too small %u < %zu\n", __func__,
-                      sb->sys_chunk_array_size, sizeof(struct btrfs_key)
-                      + sizeof(struct btrfs_chunk));
-               ret = -1;
-       }
-
-       return ret;
-}
-
-int btrfs_read_superblock(void)
-{
-       const u64 superblock_offsets[4] = {
-               0x10000ull,
-               0x4000000ull,
-               0x4000000000ull,
-               0x4000000000000ull
-       };
-       ALLOC_CACHE_ALIGN_BUFFER(char, raw_sb, BTRFS_SUPER_INFO_SIZE);
-       struct btrfs_super_block *sb = (struct btrfs_super_block *) raw_sb;
-       u64 dev_total_bytes;
-       int i;
-
-       dev_total_bytes = (u64) btrfs_part_info->size * btrfs_part_info->blksz;
-
-       btrfs_info.sb.generation = 0;
-
-       for (i = 0; i < 4; ++i) {
-               if (superblock_offsets[i] + sizeof(sb) > dev_total_bytes)
-                       break;
-
-               if (!btrfs_devread(superblock_offsets[i], BTRFS_SUPER_INFO_SIZE,
-                                  raw_sb))
-                       break;
-
-               if (btrfs_check_super_csum(raw_sb)) {
-                       debug("%s: invalid checksum at superblock mirror %i\n",
-                             __func__, i);
-                       continue;
-               }
-
-               btrfs_super_block_to_cpu(sb);
-
-               if (sb->magic != BTRFS_MAGIC) {
-                       debug("%s: invalid BTRFS magic 0x%016llX at "
-                             "superblock mirror %i\n", __func__, sb->magic, i);
-               } else if (sb->bytenr != superblock_offsets[i]) {
-                       printf("%s: invalid bytenr 0x%016llX (expected "
-                              "0x%016llX) at superblock mirror %i\n",
-                              __func__, sb->bytenr, superblock_offsets[i], i);
-               } else if (btrfs_check_super(sb)) {
-                       printf("%s: Checking superblock mirror %i failed\n",
-                              __func__, i);
-               } else if (sb->generation > btrfs_info.sb.generation) {
-                       memcpy(&btrfs_info.sb, sb, sizeof(*sb));
-               } else {
-                       /* Nothing */
-               }
-       }
-
-       if (!btrfs_info.sb.generation) {
-               debug("%s: No valid BTRFS superblock found!\n", __func__);
-               return -1;
-       }
-
-       if (btrfs_check_super_roots(&btrfs_info.sb)) {
-               printf("%s: No valid root_backup found!\n", __func__);
-               return -1;
-       }
-
-       if (sb->sectorsize != PAGE_SIZE) {
-               printf(
-       "%s: Unsupported sector size (%u), only supports %u as sector size\n",
-                       __func__, sb->sectorsize, PAGE_SIZE);
-               return -1;
-       }
-
-       if (btrfs_info.sb.num_devices != 1) {
-               printf("%s: Unsupported number of devices (%lli). This driver "
-                      "only supports filesystem on one device.\n", __func__,
-                      btrfs_info.sb.num_devices);
-               return -1;
-       }
-
-       debug("Chosen superblock with generation = %llu\n",
-             btrfs_info.sb.generation);
-
-       return 0;
-}