X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=disk-io.c;h=6aa6d98a880ecd6af501441c8f623a5e4db434be;hb=c1c987503412a8e98e40da2548c6b78888535641;hp=854c285569f87d29c9f5c518f6a40b8a6e50f11a;hpb=ff9ee51677818b7e6ea5caacb03dbbc45f5be706;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/disk-io.c b/disk-io.c index 854c285..6aa6d98 100644 --- a/disk-io.c +++ b/disk-io.c @@ -118,7 +118,7 @@ static void print_tree_block_error(struct btrfs_fs_info *fs_info, } } -u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len) +u32 btrfs_csum_data(char *data, u32 seed, size_t len) { return crc32c(seed, data, len); } @@ -207,7 +207,7 @@ void readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, 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); } @@ -241,7 +241,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree, ret = 1; out: - clear_extent_buffer_uptodate(io_tree, eb); + clear_extent_buffer_uptodate(eb); return ret; } @@ -326,16 +326,17 @@ struct extent_buffer* read_tree_block_fs_info( * 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); @@ -425,9 +426,7 @@ err: return ret; } -int write_and_map_eb(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *eb) +int write_and_map_eb(struct btrfs_root *root, struct extent_buffer *eb) { int ret; int dev_nr; @@ -474,10 +473,10 @@ int write_tree_block(struct btrfs_trans_handle *trans, btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); csum_tree_block(root, eb, 0); - return write_and_map_eb(trans, root, eb); + return write_and_map_eb(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) { @@ -493,7 +492,6 @@ int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, 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); @@ -501,7 +499,6 @@ int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, 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, @@ -618,7 +615,7 @@ commit_tree: write_ctree_super(trans, root); btrfs_finish_extent_commit(trans, fs_info->extent_root, &fs_info->pinned_extents); - btrfs_free_transaction(root, trans); + kfree(trans); free_extent_buffer(root->commit_root); root->commit_root = NULL; fs_info->running_transaction = NULL; @@ -634,7 +631,7 @@ static int find_and_setup_root(struct btrfs_root *tree_root, 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, @@ -670,7 +667,7 @@ static int find_and_setup_log_root(struct btrfs_root *tree_root, 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); @@ -734,7 +731,7 @@ struct btrfs_root *btrfs_read_fs_root_no_cache(struct btrfs_fs_info *fs_info, 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); @@ -818,7 +815,8 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, if (location->objectid == BTRFS_CSUM_TREE_OBJECTID) return fs_info->csum_root; if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID) - return fs_info->quota_root; + return fs_info->quota_enabled ? fs_info->quota_root : + ERR_PTR(-ENOENT); BUG_ON(location->objectid == BTRFS_TREE_RELOC_OBJECTID || location->offset != (u64)-1); @@ -840,12 +838,14 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, void btrfs_free_fs_info(struct btrfs_fs_info *fs_info) { + if (fs_info->quota_root) + free(fs_info->quota_root); + free(fs_info->tree_root); free(fs_info->extent_root); free(fs_info->chunk_root); free(fs_info->dev_root); free(fs_info->csum_root); - free(fs_info->quota_root); free(fs_info->free_space_root); free(fs_info->super_copy); free(fs_info->log_root_tree); @@ -904,7 +904,8 @@ free_all: 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; @@ -923,13 +924,22 @@ int btrfs_check_fs_compatibility(struct btrfs_super_block *sb, int writable) 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; } @@ -976,7 +986,7 @@ static int setup_root_or_create_block(struct btrfs_fs_info *fs_info, 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; @@ -1002,7 +1012,7 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr, 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); @@ -1050,10 +1060,14 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr, ret = find_and_setup_root(root, fs_info, BTRFS_QUOTA_TREE_OBJECTID, fs_info->quota_root); - if (ret == 0) + if (ret) { + free(fs_info->quota_root); + fs_info->quota_root = NULL; + } else { 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) { @@ -1167,7 +1181,7 @@ int btrfs_scan_fs_devices(int fd, const char *path, } if (!skip_devices && total_devs != 1) { - ret = btrfs_scan_lblkid(); + ret = btrfs_scan_devices(); if (ret) return ret; } @@ -1191,7 +1205,7 @@ int btrfs_setup_chunk_tree_and_device_map(struct btrfs_fs_info *fs_info, 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); @@ -1320,8 +1334,7 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, 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; @@ -1455,7 +1468,7 @@ static int check_super(struct btrfs_super_block *sb, unsigned sbflags) csum_size = btrfs_csum_sizes[csum_type]; crc = ~(u32)0; - crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, + crc = btrfs_csum_data((char *)sb + BTRFS_CSUM_SIZE, crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); btrfs_csum_final(crc, result); @@ -1561,7 +1574,7 @@ static int check_super(struct btrfs_super_block *sb, unsigned sbflags) } 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)); @@ -1590,14 +1603,20 @@ int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr, 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; } @@ -1655,7 +1674,7 @@ static int write_dev_supers(struct btrfs_root *root, if (root->fs_info->super_bytenr != BTRFS_SUPER_INFO_OFFSET) { btrfs_set_super_bytenr(sb, root->fs_info->super_bytenr); crc = ~(u32)0; - crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, + crc = btrfs_csum_data((char *)sb + BTRFS_CSUM_SIZE, crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); btrfs_csum_final(crc, &sb->csum[0]); @@ -1679,7 +1698,7 @@ static int write_dev_supers(struct btrfs_root *root, btrfs_set_super_bytenr(sb, bytenr); crc = ~(u32)0; - crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, + crc = btrfs_csum_data((char *)sb + BTRFS_CSUM_SIZE, crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); btrfs_csum_final(crc, &sb->csum[0]); @@ -1787,7 +1806,7 @@ int close_ctree_fs_info(struct btrfs_fs_info *fs_info) ret = __commit_transaction(trans, root); BUG_ON(ret); write_ctree_super(trans, root); - btrfs_free_transaction(root, trans); + kfree(trans); } if (fs_info->finalize_on_close) { @@ -1803,10 +1822,10 @@ int close_ctree_fs_info(struct btrfs_fs_info *fs_info) free_fs_roots_tree(&fs_info->fs_root_tree); btrfs_release_all_roots(fs_info); - btrfs_close_devices(fs_info->fs_devices); + ret = btrfs_close_devices(fs_info->fs_devices); btrfs_cleanup_all_caches(fs_info); btrfs_free_fs_info(fs_info); - return 0; + return ret; } int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -1815,12 +1834,6 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, return clear_extent_buffer_dirty(eb); } -int wait_on_tree_block_writeback(struct btrfs_root *root, - struct extent_buffer *eb) -{ - return 0; -} - void btrfs_mark_buffer_dirty(struct extent_buffer *eb) { set_extent_buffer_dirty(eb);