/* 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)
{
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;
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;
}
}
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)
{
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);
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),
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,
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;
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;
}
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;
}