btrfs-progs: subvol show: print received uuid
[platform/upstream/btrfs-progs.git] / disk-io.c
index 6c1961e..a6e6056 100644 (file)
--- a/disk-io.c
+++ b/disk-io.c
 /* specified errno for check_tree_block */
 #define BTRFS_BAD_BYTENR               (-1)
 #define BTRFS_BAD_FSID                 (-2)
+#define BTRFS_BAD_LEVEL                        (-3)
+#define BTRFS_BAD_NRITEMS              (-4)
+
+/* Calculate max possible nritems for a leaf/node */
+static u32 max_nritems(u8 level, u32 nodesize)
+{
+
+       if (level == 0)
+               return ((nodesize - sizeof(struct btrfs_header)) /
+                       sizeof(struct btrfs_item));
+       return ((nodesize - sizeof(struct btrfs_header)) /
+               sizeof(struct btrfs_key_ptr));
+}
 
 static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
 {
@@ -46,10 +59,16 @@ static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
 
        if (buf->start != btrfs_header_bytenr(buf))
                return BTRFS_BAD_BYTENR;
+       if (btrfs_header_level(buf) >= BTRFS_MAX_LEVEL)
+               return BTRFS_BAD_LEVEL;
+       if (btrfs_header_nritems(buf) > max_nritems(btrfs_header_level(buf),
+                                                   root->nodesize))
+               return BTRFS_BAD_NRITEMS;
 
        fs_devices = root->fs_info->fs_devices;
        while (fs_devices) {
-               if (!memcmp_extent_buffer(buf, fs_devices->fsid,
+               if (root->fs_info->ignore_fsid_mismatch ||
+                   !memcmp_extent_buffer(buf, fs_devices->fsid,
                                          btrfs_header_fsid(),
                                          BTRFS_FSID_SIZE)) {
                        ret = 0;
@@ -81,6 +100,14 @@ static void print_tree_block_error(struct btrfs_root *root,
                fprintf(stderr, "bytenr mismatch, want=%llu, have=%llu\n",
                        eb->start, btrfs_header_bytenr(eb));
                break;
+       case BTRFS_BAD_LEVEL:
+               fprintf(stderr, "bad level, %u > %u\n",
+                       btrfs_header_level(eb), BTRFS_MAX_LEVEL);
+               break;
+       case BTRFS_BAD_NRITEMS:
+               fprintf(stderr, "invalid nr_items: %u\n",
+                       btrfs_header_nritems(eb));
+               break;
        }
 }
 
@@ -371,7 +398,7 @@ int write_and_map_eb(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-static int write_tree_block(struct btrfs_trans_handle *trans,
+int write_tree_block(struct btrfs_trans_handle *trans,
                     struct btrfs_root *root,
                     struct extent_buffer *eb)
 {
@@ -380,7 +407,7 @@ static int write_tree_block(struct btrfs_trans_handle *trans,
                BUG();
        }
 
-       if (!btrfs_buffer_uptodate(eb, trans->transid))
+       if (trans && !btrfs_buffer_uptodate(eb, trans->transid))
                BUG();
 
        btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
@@ -1149,6 +1176,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
                fs_info->on_restoring = 1;
        if (flags & OPEN_CTREE_SUPPRESS_CHECK_BLOCK_ERRORS)
                fs_info->suppress_check_block_errors = 1;
+       if (flags & OPEN_CTREE_IGNORE_FSID_MISMATCH)
+               fs_info->ignore_fsid_mismatch = 1;
 
        ret = btrfs_scan_fs_devices(fp, path, &fs_devices, sb_bytenr,
                                    (flags & OPEN_CTREE_RECOVER_SUPER),
@@ -1180,6 +1209,12 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
                goto out_devices;
        }
 
+       if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_CHANGING_FSID &&
+           !fs_info->ignore_fsid_mismatch) {
+               fprintf(stderr, "ERROR: Filesystem UUID change in progress\n");
+               goto out_devices;
+       }
+
        memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE);
 
        ret = btrfs_check_fs_compatibility(fs_info->super_copy,
@@ -1197,7 +1232,7 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
                           BTRFS_UUID_SIZE);
 
        ret = btrfs_setup_all_roots(fs_info, root_tree_bytenr, flags);
-       if (ret)
+       if (ret && !(flags & __OPEN_CTREE_RETURN_CHUNK_ROOT))
                goto out_chunk;
 
        return fs_info;
@@ -1242,6 +1277,8 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr,
        info = open_ctree_fs_info(filename, sb_bytenr, 0, flags);
        if (!info)
                return NULL;
+       if (flags & __OPEN_CTREE_RETURN_CHUNK_ROOT)
+               return info->chunk_root;
        return info->fs_root;
 }
 
@@ -1252,6 +1289,8 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
        info = __open_ctree_fd(fp, path, sb_bytenr, 0, flags);
        if (!info)
                return NULL;
+       if (flags & __OPEN_CTREE_RETURN_CHUNK_ROOT)
+               return info->chunk_root;
        return info->fs_root;
 }