{
struct btrfs_fs_devices *fs_devices;
- u32 leafsize = btrfs_super_leafsize(fs_info->super_copy);
+ u32 nodesize = btrfs_super_nodesize(fs_info->super_copy);
int ret = BTRFS_BAD_FSID;
if (buf->start != btrfs_header_bytenr(buf))
if (btrfs_header_level(buf) >= BTRFS_MAX_LEVEL)
return BTRFS_BAD_LEVEL;
if (btrfs_header_nritems(buf) > max_nritems(btrfs_header_level(buf),
- leafsize))
+ nodesize))
+ return BTRFS_BAD_NRITEMS;
+
+ /* Only leaf can be empty */
+ if (btrfs_header_nritems(buf) == 0 &&
+ btrfs_header_level(buf) != 0)
return BTRFS_BAD_NRITEMS;
fs_devices = fs_info->fs_devices;
void btrfs_csum_final(u32 crc, char *result)
{
- *(__le32 *)result = ~cpu_to_le32(crc);
+ put_unaligned_le32(~crc, result);
}
static int __csum_tree_block_size(struct extent_buffer *buf, u16 csum_size,
if (ret)
return ret;
- blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
+ blocksize = root->nodesize;
generation = btrfs_root_generation(&root->root_item);
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation);
return 0;
}
- blocksize = btrfs_level_size(tree_root,
- btrfs_super_log_root_level(disk_super));
+ blocksize = tree_root->nodesize;
__setup_root(tree_root->nodesize, tree_root->leafsize,
tree_root->sectorsize, tree_root->stripesize,
return ERR_PTR(ret);
}
generation = btrfs_root_generation(&root->root_item);
- blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
+ blocksize = root->nodesize;
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation);
if (!extent_buffer_uptodate(root->node)) {
{
struct btrfs_super_block *sb = fs_info->super_copy;
struct btrfs_root *root = fs_info->tree_root;
- u32 leafsize = btrfs_super_leafsize(sb);
+ u32 nodesize = btrfs_super_nodesize(sb);
int ret;
ret = find_and_setup_root(root, fs_info, objectid, info_root);
* million of places that assume a root has a valid ->node
*/
info_root->node =
- btrfs_find_create_tree_block(fs_info, 0, leafsize);
+ btrfs_find_create_tree_block(fs_info, 0, nodesize);
if (!info_root->node)
return -ENOMEM;
clear_extent_buffer_uptodate(NULL, info_root->node);
root = fs_info->tree_root;
__setup_root(nodesize, leafsize, sectorsize, stripesize,
root, fs_info, BTRFS_ROOT_TREE_OBJECTID);
- blocksize = btrfs_level_size(root, btrfs_super_root_level(sb));
+ blocksize = root->nodesize;
generation = btrfs_super_generation(sb);
if (!root_tree_bytenr && !(flags & OPEN_CTREE_BACKUP_ROOT)) {
if (ret)
return ret;
- blocksize = btrfs_level_size(fs_info->chunk_root,
- btrfs_super_chunk_root_level(sb));
+ blocksize = fs_info->chunk_root->nodesize;
generation = btrfs_super_chunk_root_generation(sb);
if (chunk_root_bytenr && !IS_ALIGNED(chunk_root_bytenr,
goto out;
disk_super = fs_info->super_copy;
- if (!(flags & OPEN_CTREE_RECOVER_SUPER))
+ if (flags & OPEN_CTREE_RECOVER_SUPER)
ret = btrfs_read_dev_super(fs_devices->latest_bdev,
disk_super, sb_bytenr, 1);
else
int fp;
int ret;
struct btrfs_fs_info *info;
- int oflags = O_CREAT | O_RDWR;
+ int oflags = O_RDWR;
struct stat st;
ret = stat(filename, &st);
if (!(flags & OPEN_CTREE_WRITES))
oflags = O_RDONLY;
- fp = open(filename, oflags, 0600);
+ fp = open(filename, oflags);
if (fp < 0) {
error("cannot open '%s': %s", filename, strerror(errno));
return NULL;
int csum_size;
if (btrfs_super_magic(sb) != BTRFS_MAGIC) {
- fprintf(stderr, "ERROR: superblock magic doesn't match\n");
+ error("superblock magic doesn't match");
return -EIO;
}
csum_type = btrfs_super_csum_type(sb);
if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) {
- fprintf(stderr, "ERROR: unsupported checksum algorithm %u\n",
- csum_type);
+ error("unsupported checksum algorithm %u\n", csum_type);
return -EIO;
}
csum_size = btrfs_csum_sizes[csum_type];
btrfs_csum_final(crc, result);
if (memcmp(result, sb->csum, csum_size)) {
- fprintf(stderr, "ERROR: superblock checksum mismatch\n");
+ error("superblock checksum mismatch");
return -EIO;
}
if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) {
- fprintf(stderr, "ERROR: tree_root level too big: %d >= %d\n",
+ error("tree_root level too big: %d >= %d",
btrfs_super_root_level(sb), BTRFS_MAX_LEVEL);
- return -EIO;
+ goto error_out;
}
if (btrfs_super_chunk_root_level(sb) >= BTRFS_MAX_LEVEL) {
- fprintf(stderr, "ERROR: chunk_root level too big: %d >= %d\n",
+ error("chunk_root level too big: %d >= %d",
btrfs_super_chunk_root_level(sb), BTRFS_MAX_LEVEL);
- return -EIO;
+ goto error_out;
}
if (btrfs_super_log_root_level(sb) >= BTRFS_MAX_LEVEL) {
- fprintf(stderr, "ERROR: log_root level too big: %d >= %d\n",
+ error("log_root level too big: %d >= %d",
btrfs_super_log_root_level(sb), BTRFS_MAX_LEVEL);
- return -EIO;
+ goto error_out;
}
if (!IS_ALIGNED(btrfs_super_root(sb), 4096)) {
- fprintf(stderr, "ERROR: tree_root block unaligned: %llu\n",
- btrfs_super_root(sb));
- return -EIO;
+ error("tree_root block unaligned: %llu", btrfs_super_root(sb));
+ goto error_out;
}
if (!IS_ALIGNED(btrfs_super_chunk_root(sb), 4096)) {
- fprintf(stderr, "ERROR: chunk_root block unaligned: %llu\n",
+ error("chunk_root block unaligned: %llu",
btrfs_super_chunk_root(sb));
- return -EIO;
+ goto error_out;
}
if (!IS_ALIGNED(btrfs_super_log_root(sb), 4096)) {
- fprintf(stderr, "ERROR: log_root block unaligned: %llu\n",
+ error("log_root block unaligned: %llu",
btrfs_super_log_root(sb));
- return -EIO;
+ goto error_out;
}
if (btrfs_super_nodesize(sb) < 4096) {
- fprintf(stderr, "ERROR: nodesize too small: %u < 4096\n",
+ error("nodesize too small: %u < 4096",
btrfs_super_nodesize(sb));
- return -EIO;
+ goto error_out;
}
if (!IS_ALIGNED(btrfs_super_nodesize(sb), 4096)) {
- fprintf(stderr, "ERROR: nodesize unaligned: %u\n",
- btrfs_super_nodesize(sb));
- return -EIO;
+ error("nodesize unaligned: %u", btrfs_super_nodesize(sb));
+ goto error_out;
}
if (btrfs_super_sectorsize(sb) < 4096) {
- fprintf(stderr, "ERROR: sectorsize too small: %u < 4096\n",
+ error("sectorsize too small: %u < 4096",
btrfs_super_sectorsize(sb));
- return -EIO;
+ goto error_out;
}
if (!IS_ALIGNED(btrfs_super_sectorsize(sb), 4096)) {
- fprintf(stderr, "ERROR: sectorsize unaligned: %u\n",
- btrfs_super_sectorsize(sb));
- return -EIO;
+ 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 (memcmp(sb->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) {
uuid_unparse(sb->fsid, fsid);
uuid_unparse(sb->dev_item.fsid, dev_fsid);
- printk(KERN_ERR
- "ERROR: dev_item UUID does not match fsid: %s != %s\n",
+ error("dev_item UUID does not match fsid: %s != %s",
dev_fsid, fsid);
- return -EIO;
+ goto error_out;
}
/*
* Hint to catch really bogus numbers, bitflips or so
*/
if (btrfs_super_num_devices(sb) > (1UL << 31)) {
- fprintf(stderr, "WARNING: suspicious number of devices: %llu\n",
+ warning("suspicious number of devices: %llu",
btrfs_super_num_devices(sb));
}
if (btrfs_super_num_devices(sb) == 0) {
- fprintf(stderr, "ERROR: number of devices is 0\n");
- return -EIO;
+ error("number of devices is 0");
+ goto error_out;
}
/*
* and one chunk
*/
if (btrfs_super_sys_array_size(sb) > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) {
- fprintf(stderr, "BTRFS: system chunk array too big %u > %u\n",
- btrfs_super_sys_array_size(sb),
- BTRFS_SYSTEM_CHUNK_ARRAY_SIZE);
- return -EIO;
+ 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)) {
- fprintf(stderr, "BTRFS: system chunk array too small %u < %lu\n",
- btrfs_super_sys_array_size(sb),
- sizeof(struct btrfs_disk_key) +
- sizeof(struct btrfs_chunk));
- return -EIO;
+ error("system chunk array too small %u < %lu",
+ 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;
}
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr,