bytenr, &length, &multi, 0, NULL)) {
device = multi->stripes[0].dev;
device->total_ios++;
- blocksize = min(blocksize, (u32)(64 * 1024));
+ blocksize = min(blocksize, (u32)SZ_64K);
readahead(device->fd, multi->stripes[0].physical, blocksize);
}
ret = 1;
out:
- clear_extent_buffer_uptodate(io_tree, eb);
+ clear_extent_buffer_uptodate(eb);
return ret;
}
* Such unaligned tree block will free overlapping extent buffer,
* causing use-after-free bugs for fuzzed images.
*/
- if (!IS_ALIGNED(bytenr, sectorsize)) {
+ if (bytenr < sectorsize || !IS_ALIGNED(bytenr, sectorsize)) {
error("tree block bytenr %llu is not aligned to sectorsize %u",
bytenr, sectorsize);
return ERR_PTR(-EIO);
}
- if (!IS_ALIGNED(blocksize, nodesize)) {
+ if (blocksize < nodesize || !IS_ALIGNED(blocksize, nodesize)) {
error("tree block size %u is not aligned to nodesize %u",
blocksize, nodesize);
return ERR_PTR(-EIO);
}
+
eb = btrfs_find_create_tree_block(fs_info, bytenr, blocksize);
if (!eb)
return ERR_PTR(-ENOMEM);
return write_and_map_eb(trans, root, eb);
}
-int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
+void btrfs_setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
u32 stripesize, struct btrfs_root *root,
struct btrfs_fs_info *fs_info, u64 objectid)
{
root->fs_info = fs_info;
root->objectid = objectid;
root->last_trans = 0;
- root->highest_inode = 0;
root->last_inode_alloc = 0;
INIT_LIST_HEAD(&root->dirty_list);
memset(&root->root_key, 0, sizeof(root->root_key));
memset(&root->root_item, 0, sizeof(root->root_item));
root->root_key.objectid = objectid;
- return 0;
}
static int update_cowonly_root(struct btrfs_trans_handle *trans,
u32 blocksize;
u64 generation;
- __setup_root(tree_root->nodesize, tree_root->leafsize,
+ btrfs_setup_root(tree_root->nodesize, tree_root->leafsize,
tree_root->sectorsize, tree_root->stripesize,
root, fs_info, objectid);
ret = btrfs_find_last_root(tree_root, objectid,
blocksize = tree_root->nodesize;
- __setup_root(tree_root->nodesize, tree_root->leafsize,
+ btrfs_setup_root(tree_root->nodesize, tree_root->leafsize,
tree_root->sectorsize, tree_root->stripesize,
log_root, fs_info, BTRFS_TREE_LOG_OBJECTID);
goto insert;
}
- __setup_root(tree_root->nodesize, tree_root->leafsize,
+ btrfs_setup_root(tree_root->nodesize, tree_root->leafsize,
tree_root->sectorsize, tree_root->stripesize,
root, fs_info, location->objectid);
return NULL;
}
-int btrfs_check_fs_compatibility(struct btrfs_super_block *sb, int writable)
+int btrfs_check_fs_compatibility(struct btrfs_super_block *sb,
+ unsigned int flags)
{
u64 features;
btrfs_set_super_incompat_flags(sb, features);
}
- features = btrfs_super_compat_ro_flags(sb) &
- ~BTRFS_FEATURE_COMPAT_RO_SUPP;
- if (writable && features) {
- printk("couldn't open RDWR because of unsupported "
- "option features (%Lx).\n",
- (unsigned long long)features);
- return -ENOTSUP;
+ features = btrfs_super_compat_ro_flags(sb);
+ if (flags & OPEN_CTREE_WRITES) {
+ if (flags & OPEN_CTREE_INVALIDATE_FST) {
+ /* Clear the FREE_SPACE_TREE_VALID bit on disk... */
+ features &= ~BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID;
+ btrfs_set_super_compat_ro_flags(sb, features);
+ /* ... and ignore the free space tree bit. */
+ features &= ~BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE;
+ }
+ if (features & ~BTRFS_FEATURE_COMPAT_RO_SUPP) {
+ printk("couldn't open RDWR because of unsupported "
+ "option features (%Lx).\n",
+ (unsigned long long)features);
+ return -ENOTSUP;
+ }
+
}
return 0;
}
btrfs_find_create_tree_block(fs_info, 0, nodesize);
if (!info_root->node)
return -ENOMEM;
- clear_extent_buffer_uptodate(NULL, info_root->node);
+ clear_extent_buffer_uptodate(info_root->node);
}
return 0;
stripesize = btrfs_super_stripesize(sb);
root = fs_info->tree_root;
- __setup_root(nodesize, leafsize, sectorsize, stripesize,
+ btrfs_setup_root(nodesize, leafsize, sectorsize, stripesize,
root, fs_info, BTRFS_ROOT_TREE_OBJECTID);
blocksize = root->nodesize;
generation = btrfs_super_generation(sb);
if (ret == 0)
fs_info->quota_enabled = 1;
- if (btrfs_fs_compat_ro(fs_info, BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE)) {
+ if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
ret = find_and_setup_root(root, fs_info, BTRFS_FREE_SPACE_TREE_OBJECTID,
fs_info->free_space_root);
if (ret) {
}
if (!skip_devices && total_devs != 1) {
- ret = btrfs_scan_lblkid();
+ ret = btrfs_scan_devices();
if (ret)
return ret;
}
sectorsize = btrfs_super_sectorsize(sb);
stripesize = btrfs_super_stripesize(sb);
- __setup_root(nodesize, leafsize, sectorsize, stripesize,
+ btrfs_setup_root(nodesize, leafsize, sectorsize, stripesize,
fs_info->chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID);
ret = btrfs_read_sys_array(fs_info->chunk_root);
memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE);
- ret = btrfs_check_fs_compatibility(fs_info->super_copy,
- flags & OPEN_CTREE_WRITES);
+ ret = btrfs_check_fs_compatibility(fs_info->super_copy, flags);
if (ret)
goto out_devices;
}
if (btrfs_super_sys_array_size(sb) < sizeof(struct btrfs_disk_key)
+ sizeof(struct btrfs_chunk)) {
- error("system chunk array too small %u < %lu",
+ error("system chunk array too small %u < %zu",
btrfs_super_sys_array_size(sb),
sizeof(struct btrfs_disk_key) +
sizeof(struct btrfs_chunk));
if (sb_bytenr != BTRFS_SUPER_INFO_OFFSET) {
ret = pread64(fd, buf, BTRFS_SUPER_INFO_SIZE, sb_bytenr);
+ /* real error */
+ if (ret < 0)
+ return -errno;
+
+ /* Not large enough sb, return -ENOENT instead of normal -EIO */
if (ret < BTRFS_SUPER_INFO_SIZE)
- return -1;
+ return -ENOENT;
if (btrfs_super_bytenr(buf) != sb_bytenr)
- return -1;
+ return -EIO;
- if (check_super(buf, sbflags))
- return -1;
+ ret = check_super(buf, sbflags);
+ if (ret < 0)
+ return ret;
memcpy(sb, buf, BTRFS_SUPER_INFO_SIZE);
return 0;
}