linux-next: manual merge of the btrfs tree with the btrfs-fixes tree
Subsystems (2)
Mark Brown
maintainerHi all,
Today's linux-next merge of the btrfs tree got a conflict in:
fs/btrfs/disk-io.c
between commit:
50242828700f0 ("btrfs: check for NULL root after calls to btrfs_extent_root()")
from the btrfs-fixes tree and commits:
6960a23c3d592 ("btrfs: check for NULL root after calls to btrfs_extent_root()") a1f82939d6410 ("btrfs: remove max_mirrors argument from write_all_supers()")
from the btrfs tree.
I fixed it up (see below) and can carry the fix as necessary. This is now fixed as far as linux-next is concerned, but any non trivial conflicts should be mentioned to your upstream maintainer when your tree is submitted for merging. You may also want to consider cooperating with the maintainer of the conflicting tree to minimise any particularly complex conflicts.
fs/btrfs/disk-io.c +0 -0
@@@ -50,7 -50,6 +50,6 @@@#include "relocation.h" #include "scrub.h" #include "super.h" -#include "delayed-inode.h" #define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN |\ BTRFS_HEADER_FLAG_RELOC |\ * detect blocks that either didn't get written at all or got written * in the wrong place. */ -int btrfs_buffer_uptodate (struct extent_buffer *eb,u64 parent_transid,bool atomic) +int btrfs_buffer_uptodate (struct extent_buffer *eb,u64 parent_transid,bool atomic, +const struct btrfs_tree_parent_check *check) {if (!extent_buffer_uptodate (eb))return 0 ; -if (!parent_transid ||btrfs_header_generation (eb) == parent_transid) +if (!parent_transid ||btrfs_header_generation (eb) == parent_transid) { +/* +* On a cache hit, the caller may still need tree parent +* verification before reusing the buffer. +*/ +if (unlikely (check &&btrfs_verify_level_key (eb, check))) +return -EUCLEAN ;return 1 ; + }if (atomic)return -EAGAIN ; -if (!extent_buffer_uptodate (eb) || -btrfs_header_generation (eb) != parent_transid) { +if (btrfs_header_generation (eb) != parent_transid) { btrfs_err_rl(eb->fs_info, "parent transid verify failed on logical %llu mirror %u wanted %llu found %llu", eb->start, eb->read_mirror, } struct btrfs_root *btrfs_global_root(struct btrfs_fs_info *fs_info, - struct btrfs_key *key) + const struct btrfs_key *key) { struct rb_node *node; struct btrfs_root *root = NULL; struct btrfs_root *btrfs_csum_root(struct btrfs_fs_info *fs_info, u64 bytenr) { -struct btrfs_key key = { + const struct btrfs_key key = { .objectid = BTRFS_CSUM_TREE_OBJECTID, .type = BTRFS_ROOT_ITEM_KEY, .offset = btrfs_global_root_id(fs_info, bytenr), struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info, u64 bytenr) { - struct btrfs_key key = { + const struct btrfs_key key = { .objectid = BTRFS_EXTENT_TREE_OBJECTID, .type = BTRFS_ROOT_ITEM_KEY, .offset = btrfs_global_root_id(fs_info, bytenr), root->node = NULL; goto fail; } - if (unlikely(!btrfs_buffer_uptodate(root->node, generation, false))) { - ret = -EIO; + + ret = btrfs_buffer_uptodate(root->node, generation, false, &check); + if (unlikely(ret <= 0)) { + if (ret == 0) + ret = -EIO; goto fail; } btrfs_put_root(log_tree_root); return ret; } -if (unlikely (!extent_buffer_uptodate (log_tree_root->node))) { -btrfs_err (fs_info,"failed to read log tree" ); -btrfs_put_root (log_tree_root); -return -EIO ; - } /* returns with log_tree_root freed on success */ ret = btrfs_recover_log_trees(log_tree_root); return -EUCLEAN; } + /* It must hold at least one key and one chunk. */ + if (unlikely(sys_array_size < sizeof(struct btrfs_disk_key) + + sizeof(struct btrfs_chunk))) { + btrfs_err(fs_info, "system chunk array too small %u < %zu", + sys_array_size, + sizeof(struct btrfs_disk_key) + sizeof(struct btrfs_chunk)); + return -EUCLEAN; + } + while (cur < sys_array_size) { struct btrfs_disk_key *disk_key; struct btrfs_chunk *chunk; int ret = 0; const bool ignore_flags = btrfs_test_opt(fs_info, IGNORESUPERFLAGS); -if (btrfs_super_magic (sb) !=BTRFS_MAGIC ) { + if (unlikely(btrfs_super_magic(sb) != BTRFS_MAGIC)) { btrfs_err(fs_info, "no valid FS found"); ret = -EINVAL; } -if ((btrfs_super_flags (sb) & ~BTRFS_SUPER_FLAG_SUPP )) { + if (unlikely(btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP)) { if (!ignore_flags) { btrfs_err(fs_info, "unrecognized or unsupported super flag 0x%llx", btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP); } } -if (btrfs_super_root_level (sb) >=BTRFS_MAX_LEVEL ) { + if (unlikely(btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL)) { btrfs_err(fs_info, "tree_root level too big: %d >= %d", btrfs_super_root_level(sb), BTRFS_MAX_LEVEL); ret = -EINVAL; } -if (btrfs_super_chunk_root_level (sb) >=BTRFS_MAX_LEVEL ) { + if (unlikely(btrfs_super_chunk_root_level(sb) >= BTRFS_MAX_LEVEL)) { btrfs_err(fs_info, "chunk_root level too big: %d >= %d", btrfs_super_chunk_root_level(sb), BTRFS_MAX_LEVEL); ret = -EINVAL; } -if (btrfs_super_log_root_level (sb) >=BTRFS_MAX_LEVEL ) { + if (unlikely(btrfs_super_log_root_level(sb) >= BTRFS_MAX_LEVEL)) { btrfs_err(fs_info, "log_root level too big: %d >= %d", btrfs_super_log_root_level(sb), BTRFS_MAX_LEVEL); ret = -EINVAL; * Check sectorsize and nodesize first, other check will need it. * Check all possible sectorsize(4K, 8K, 16K, 32K, 64K) here. */ - if (!is_power_of_2(sectorsize) || sectorsize < BTRFS_MIN_BLOCKSIZE || - sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE) { + if (unlikely(!is_power_of_2(sectorsize) || sectorsize < BTRFS_MIN_BLOCKSIZE || + sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE)) { btrfs_err(fs_info, "invalid sectorsize %llu", sectorsize); ret = -EINVAL; } -if (!btrfs_supported_blocksize (sectorsize)) { + if (unlikely(!btrfs_supported_blocksize(sectorsize))) { btrfs_err(fs_info, "sectorsize %llu not yet supported for page size %lu", sectorsize, PAGE_SIZE); ret = -EINVAL; } -if (!is_power_of_2 (nodesize) || nodesize < sectorsize || - nodesize >BTRFS_MAX_METADATA_BLOCKSIZE ) { + if (unlikely(!is_power_of_2(nodesize) || nodesize < sectorsize || + nodesize > BTRFS_MAX_METADATA_BLOCKSIZE)) { btrfs_err(fs_info, "invalid nodesize %llu", nodesize); ret = -EINVAL; } -if (nodesize !=le32_to_cpu (sb->__unused_leafsize)) { + if (unlikely(nodesize != le32_to_cpu(sb->__unused_leafsize))) { btrfs_err(fs_info, "invalid leafsize %u, should be %llu", le32_to_cpu(sb->__unused_leafsize), nodesize); ret = -EINVAL; } /* Root alignment check */ -if (!IS_ALIGNED (btrfs_super_root (sb), sectorsize)) { + if (unlikely(!IS_ALIGNED(btrfs_super_root(sb), sectorsize))) { btrfs_err(fs_info, "tree_root block unaligned: %llu", btrfs_super_root(sb)); ret = -EINVAL; } -if (!IS_ALIGNED (btrfs_super_chunk_root (sb), sectorsize)) { + if (unlikely(!IS_ALIGNED(btrfs_super_chunk_root(sb), sectorsize))) { btrfs_err(fs_info, "chunk_root block unaligned: %llu", btrfs_super_chunk_root(sb)); ret = -EINVAL; } -if (!IS_ALIGNED (btrfs_super_log_root (sb), sectorsize)) { + if (unlikely(!IS_ALIGNED(btrfs_super_log_root(sb), sectorsize))) { btrfs_err(fs_info, "log_root block unaligned: %llu", btrfs_super_log_root(sb)); ret = -EINVAL; } -if (!fs_info->fs_devices->temp_fsid && -memcmp (fs_info->fs_devices->fsid, sb->fsid,BTRFS_FSID_SIZE ) !=0 ) { + if (unlikely(!fs_info->fs_devices->temp_fsid && + memcmp(fs_info->fs_devices->fsid, sb->fsid, BTRFS_FSID_SIZE) != 0)) { btrfs_err(fs_info, "superblock fsid doesn't match fsid of fs_devices: %pU != %pU", sb->fsid, fs_info->fs_devices->fsid); ret = -EINVAL; } -if (memcmp (fs_info->fs_devices->metadata_uuid,btrfs_sb_fsid_ptr (sb), -BTRFS_FSID_SIZE ) !=0 ) { + if (unlikely(memcmp(fs_info->fs_devices->metadata_uuid, btrfs_sb_fsid_ptr(sb), + BTRFS_FSID_SIZE) != 0)) { btrfs_err(fs_info, "superblock metadata_uuid doesn't match metadata uuid of fs_devices: %pU != %pU", btrfs_sb_fsid_ptr(sb), fs_info->fs_devices->metadata_uuid); ret = -EINVAL; } -if (memcmp (fs_info->fs_devices->metadata_uuid, sb->dev_item.fsid, -BTRFS_FSID_SIZE ) !=0 ) { + if (unlikely(memcmp(fs_info->fs_devices->metadata_uuid, sb->dev_item.fsid, + BTRFS_FSID_SIZE) != 0)) { btrfs_err(fs_info, "dev_item UUID does not match metadata fsid: %pU != %pU", fs_info->fs_devices->metadata_uuid, sb->dev_item.fsid); * Artificial requirement for block-group-tree to force newer features * (free-space-tree, no-holes) so the test matrix is smaller. */ - if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE) && - (!btrfs_fs_compat_ro (fs_info,FREE_SPACE_TREE_VALID ) || - !btrfs_fs_incompat(fs_info, NO_HOLES))) { + if (unlikely(btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE) && + (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID) || + !btrfs_fs_incompat(fs_info, NO_HOLES)))) { btrfs_err(fs_info, "block-group-tree feature requires free-space-tree and no-holes"); ret = -EINVAL; * Reduce test matrix for remap tree by requiring block-group-tree * and no-holes. Free-space-tree is a hard requirement. */ -if (!btrfs_fs_compat_ro (fs_info,FREE_SPACE_TREE_VALID ) || - !btrfs_fs_incompat (fs_info,NO_HOLES ) || - !btrfs_fs_compat_ro (fs_info,BLOCK_GROUP_TREE )) { + if (unlikely(!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID) || + !btrfs_fs_incompat(fs_info, NO_HOLES) || + !btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE))) { btrfs_err(fs_info, "remap-tree feature requires free-space-tree, no-holes, and block-group-tree"); ret = -EINVAL; } -if (btrfs_fs_incompat (fs_info,MIXED_GROUPS )) { + if (unlikely(btrfs_fs_incompat(fs_info, MIXED_GROUPS))) { btrfs_err(fs_info, "remap-tree not supported with mixed-bg"); ret = -EINVAL; } -if (btrfs_fs_incompat (fs_info,ZONED )) { + if (unlikely(btrfs_fs_incompat(fs_info, ZONED))) { btrfs_err(fs_info, "remap-tree not supported with zoned devices"); ret = -EINVAL; } -if (sectorsize >PAGE_SIZE ) { + if (unlikely(sectorsize > PAGE_SIZE)) { btrfs_err(fs_info, "remap-tree not supported when block size > page size"); ret = -EINVAL; } * Hint to catch really bogus numbers, bitflips or so, more exact checks are * done later */ - if (btrfs_super_bytes_used(sb) < 6 * btrfs_super_nodesize(sb)) { + if (unlikely(btrfs_super_bytes_used(sb) < 6 * btrfs_super_nodesize(sb))) { btrfs_err(fs_info, "bytes_used is too small %llu", btrfs_super_bytes_used(sb)); ret = -EINVAL; } -if (!is_power_of_2 (btrfs_super_stripesize (sb))) { + if (unlikely(!is_power_of_2(btrfs_super_stripesize(sb)))) { btrfs_err(fs_info, "invalid stripesize %u", btrfs_super_stripesize(sb)); ret = -EINVAL; } -if (btrfs_super_num_devices (sb) > (1UL <<31 )) + if (unlikely(btrfs_super_num_devices(sb) > (1UL << 31))) btrfs_warn(fs_info, "suspicious number of devices: %llu", btrfs_super_num_devices(sb)); -if (btrfs_super_num_devices (sb) ==0 ) { + if (unlikely(btrfs_super_num_devices(sb) == 0)) { btrfs_err(fs_info, "number of devices is 0"); ret = -EINVAL; } -if (mirror_num >=0 && -btrfs_super_bytenr (sb) !=btrfs_sb_offset (mirror_num)) { -btrfs_err (fs_info,"super offset mismatch %llu != %u" , -btrfs_super_bytenr (sb),BTRFS_SUPER_INFO_OFFSET ); + if (unlikely(mirror_num >= 0 && + btrfs_super_bytenr(sb) != btrfs_sb_offset(mirror_num))) { + btrfs_err(fs_info, "super offset mismatch %llu != %llu", + btrfs_super_bytenr(sb), btrfs_sb_offset(mirror_num)); ret = -EINVAL; } -if (ret) + if (unlikely(ret)) return ret; ret = validate_sys_chunk_array(fs_info, sb); -/* -* Obvious sys_chunk_array corruptions, it must hold at least one key -* and one chunk -*/ -if (btrfs_super_sys_array_size (sb) >BTRFS_SYSTEM_CHUNK_ARRAY_SIZE ) { -btrfs_err (fs_info,"system chunk array too big %u > %u" , -btrfs_super_sys_array_size (sb), -BTRFS_SYSTEM_CHUNK_ARRAY_SIZE ); - ret = -EINVAL ; - } -if (btrfs_super_sys_array_size (sb) <sizeof (struct btrfs_disk_key ) - +sizeof (struct btrfs_chunk )) { -btrfs_err (fs_info,"system chunk array too small %u < %zu" , -btrfs_super_sys_array_size (sb), -sizeof (struct btrfs_disk_key ) - +sizeof (struct btrfs_chunk )); - ret = -EINVAL ; - } - /* * The generation is a global counter, we'll trust it more than the others * but it's still possible that it's the one that's wrong. */ -if (btrfs_super_generation (sb) <btrfs_super_chunk_root_generation (sb)) + if (unlikely(btrfs_super_generation(sb) < btrfs_super_chunk_root_generation(sb))) btrfs_warn(fs_info, "suspicious: generation < chunk_root_generation: %llu < %llu", btrfs_super_generation(sb), btrfs_super_chunk_root_generation(sb)); -if (btrfs_super_generation (sb) <btrfs_super_cache_generation (sb) - &&btrfs_super_cache_generation (sb) != (u64)-1 ) + if (unlikely(btrfs_super_generation(sb) < btrfs_super_cache_generation(sb) && + btrfs_super_cache_generation(sb) != (u64)-1)) btrfs_warn(fs_info, "suspicious: generation < cache_generation: %llu < %llu", btrfs_super_generation(sb), int ret; ret = btrfs_validate_super(fs_info, sb, -1); -if (ret <0 ) + if (unlikely(ret < 0)) goto out; if (unlikely(!btrfs_supported_super_csum(btrfs_super_csum_type(sb)))) { ret = -EUCLEAN; goto out; } out: -if (ret <0 ) + if (unlikely(ret < 0)) btrfs_err(fs_info, "super block corruption detected before writing it to disk"); return ret; root->node = NULL; return ret; } -if (unlikely (!extent_buffer_uptodate (root->node))) { -free_extent_buffer (root->node); - root->node =NULL ; -return -EIO ; - } btrfs_set_root_node(&root->root_item, root->node); root->commit_root = btrfs_root_node(root); * Write superblock @sb to the @device. Do not wait for completion, all the * folios we use for writing are locked. * - * Write @max_mirrors copies of the superblock, where 0 means default that fit - * the expected device size at commit time. Note that max_mirrors must be + * Write @max_mirrors copies of the superblock. Note that max_mirrors must be * same for write and wait phases. * * Return number of errors when folio is not found or submission fails. atomic_set(&device->sb_write_errors, 0); -if (max_mirrors ==0 ) - max_mirrors =BTRFS_SUPER_MIRROR_MAX ; - for (i = 0; i < max_mirrors; i++) { struct folio *folio; struct bio *bio; int ret; u64 bytenr; -if (max_mirrors ==0 ) - max_mirrors =BTRFS_SUPER_MIRROR_MAX ; - for (i = 0; i < max_mirrors; i++) { struct folio *folio; ret = btrfs_sb_log_location(device, i, READ, &bytenr); if (ret == -ENOENT) { break; - }else if (ret <0 ) { + } else if (unlikely(ret < 0)) { errors++; if (i == 0) primary_failed = true; } errors += atomic_read(&device->sb_write_errors); -if (errors >=BTRFS_SUPER_PRIMARY_WRITE_ERROR ) - primary_failed = true; -if (primary_failed) { + + if (unlikely(primary_failed || errors >= BTRFS_SUPER_PRIMARY_WRITE_ERROR)) { btrfs_err(device->fs_info, "error writing primary super block to device %llu", device->devid); return -1; wait_for_completion_io(&device->flush_wait); -if (bio->bi_status) { + if (unlikely(bio->bi_status)) { set_bit(BTRFS_DEV_STATE_FLUSH_FAILED, &device->dev_state); btrfs_dev_stat_inc_and_print(device, BTRFS_DEV_STAT_FLUSH_ERRS); return true; list_for_each_entry(dev, head, dev_list) { if (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state)) continue; -if (!dev->bdev) { + if (unlikely(!dev->bdev)) { errors_wait++; continue; } !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) continue; -if (wait_dev_flush (dev)) + if (unlikely(wait_dev_flush(dev))) errors_wait++; } return min_tolerated; } -int write_all_supers (struct btrfs_fs_info *fs_info,int max_mirrors) + int write_all_supers(struct btrfs_trans_handle *trans) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct list_head *head; struct btrfs_device *dev; struct btrfs_super_block *sb; struct btrfs_dev_item *dev_item; + int max_mirrors; int ret; int do_barriers; int max_errors; int total_errors = 0; -u64 flags; do_barriers = !btrfs_test_opt(fs_info, NOBARRIER); -/* -* max_mirrors == 0 indicates we're from commit_transaction, -* not from fsync where the tree roots in fs_info have not -* been consistent on disk. -*/ -if (max_mirrors ==0 ) { + if (trans->transaction->state < TRANS_STATE_UNBLOCKED) { + /* We are called from fsync. */ + max_mirrors = 1; + } else { + /* We are called from transaction commit. */ + max_mirrors = BTRFS_SUPER_MIRROR_MAX; ret = backup_super_roots(fs_info); if (ret < 0) return ret; if (do_barriers) { ret = barrier_all_devices(fs_info); -if (ret) { + if (unlikely(ret)) { mutex_unlock( &fs_info->fs_devices->device_list_mutex); -btrfs_handle_fs_error (fs_info, ret, -"errors while submitting device barriers." ); + btrfs_abort_transaction(trans, ret); + btrfs_err(fs_info, "error while submitting device barriers"); return ret; } } + btrfs_set_super_flags(sb, btrfs_super_flags(sb) | BTRFS_HEADER_FLAG_WRITTEN); + list_for_each_entry(dev, head, dev_list) { -if (!dev->bdev) { + if (unlikely(!dev->bdev)) { total_errors++; continue; } memcpy(dev_item->fsid, dev->fs_devices->metadata_uuid, BTRFS_FSID_SIZE); - flags =btrfs_super_flags (sb); -btrfs_set_super_flags (sb, flags |BTRFS_HEADER_FLAG_WRITTEN ); - ret = btrfs_validate_write_super(fs_info, sb); if (unlikely(ret < 0)) { mutex_unlock(&fs_info->fs_devices->device_list_mutex); -btrfs_handle_fs_error (fs_info, -EUCLEAN , -"unexpected superblock corruption detected" ); -return -EUCLEAN ; + btrfs_abort_transaction(trans, ret); + btrfs_err(fs_info, + "unexpected superblock corruption before writing it"); + return ret; } ret = write_dev_supers(dev, sb, max_mirrors); -if (ret) + if (unlikely(ret)) total_errors++; } if (unlikely(total_errors > max_errors)) { mutex_unlock(&fs_info->fs_devices->device_list_mutex); /* FUA is masked off if unsupported and can't be the reason */ -btrfs_handle_fs_error (fs_info, -EIO , -"%d errors while writing supers" , - total_errors); + btrfs_abort_transaction(trans, -EIO); + btrfs_err(fs_info, "%d errors while writing supers", total_errors); return -EIO; } total_errors = 0; list_for_each_entry(dev, head, dev_list) { -if (!dev->bdev) + if (unlikely(!dev->bdev)) continue; if (!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &dev->dev_state) || !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) continue; ret = wait_dev_supers(dev, max_mirrors); -if (ret) + if (unlikely(ret)) total_errors++; } mutex_unlock(&fs_info->fs_devices->device_list_mutex); if (unlikely(total_errors > max_errors)) { -btrfs_handle_fs_error (fs_info, -EIO , -"%d errors while writing supers" , - total_errors); + btrfs_abort_transaction(trans, -EIO); + btrfs_err(fs_info, "%d errors while writing supers", total_errors); return -EIO; } return 0;