From: Christoph Hellwig <hch@xxxxxx> blkdev_put must not be called under sb->s_umount to avoid a lock order reversal with disk->open_mutex once call backs from block devices to the file system using the holder ops are supported. Move the call to btrfs_close_devices into btrfs_free_fs_info so that it is closed from ->kill_sb (which is also called from the mount failure handling path unlike ->put_super) as well as when an fs_info is freed because an existing superblock already exists. Signed-off-by: Christoph Hellwig <hch@xxxxxx> Reviewed-by: Christian Brauner <brauner@xxxxxxxxxx> Signed-off-by: Eric Biggers <ebiggers@xxxxxxxxxx> --- fs/btrfs/disk-io.c | 4 ++-- fs/btrfs/super.c | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index bbcc3df776461..fe98e6b1d9c61 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1237,20 +1237,22 @@ static void free_global_roots(struct btrfs_fs_info *fs_info) while ((node = rb_first_postorder(&fs_info->global_root_tree)) != NULL) { root = rb_entry(node, struct btrfs_root, rb_node); rb_erase(&root->rb_node, &fs_info->global_root_tree); btrfs_put_root(root); } } void btrfs_free_fs_info(struct btrfs_fs_info *fs_info) { + if (fs_info->fs_devices) + btrfs_close_devices(fs_info->fs_devices); percpu_counter_destroy(&fs_info->dirty_metadata_bytes); percpu_counter_destroy(&fs_info->delalloc_bytes); percpu_counter_destroy(&fs_info->ordered_bytes); percpu_counter_destroy(&fs_info->dev_replace.bio_counter); btrfs_free_csum_hash(fs_info); btrfs_free_stripe_hash_table(fs_info); btrfs_free_ref_cache(fs_info); kfree(fs_info->balance_ctl); kfree(fs_info->delayed_root); free_global_roots(fs_info); @@ -3605,21 +3607,20 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device invalidate_inode_pages2(fs_info->btree_inode->i_mapping); fail_sb_buffer: btrfs_stop_all_workers(fs_info); btrfs_free_block_groups(fs_info); fail_alloc: btrfs_mapping_tree_free(&fs_info->mapping_tree); iput(fs_info->btree_inode); fail: - btrfs_close_devices(fs_info->fs_devices); ASSERT(ret < 0); return ret; } ALLOW_ERROR_INJECTION(open_ctree, ERRNO); static void btrfs_end_super_write(struct bio *bio) { struct btrfs_device *device = bio->bi_private; struct bio_vec *bvec; struct bvec_iter_all iter_all; @@ -4385,21 +4386,20 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) * have had an IO error and have left over tree log blocks that aren't * cleaned up until the fs roots are freed. This makes the block group * accounting appear to be wrong because there's pending reserved bytes, * so make sure we do the block group cleanup afterwards. */ btrfs_free_block_groups(fs_info); iput(fs_info->btree_inode); btrfs_mapping_tree_free(&fs_info->mapping_tree); - btrfs_close_devices(fs_info->fs_devices); } void btrfs_mark_buffer_dirty(struct btrfs_trans_handle *trans, struct extent_buffer *buf) { struct btrfs_fs_info *fs_info = buf->fs_info; u64 transid = btrfs_header_generation(buf); #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS /* diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ef256b944c72a..9616ce63c5630 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1450,55 +1450,52 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, fs_devices = device->fs_devices; fs_info->fs_devices = fs_devices; error = btrfs_open_devices(fs_devices, mode, fs_type); mutex_unlock(&uuid_mutex); if (error) goto error_fs_info; if (!(flags & SB_RDONLY) && fs_devices->rw_devices == 0) { error = -EACCES; - goto error_close_devices; + goto error_fs_info; } bdev = fs_devices->latest_dev->bdev; s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | SB_NOSEC, fs_info); if (IS_ERR(s)) { error = PTR_ERR(s); - goto error_close_devices; + goto error_fs_info; } if (s->s_root) { - btrfs_close_devices(fs_devices); btrfs_free_fs_info(fs_info); if ((flags ^ s->s_flags) & SB_RDONLY) error = -EBUSY; } else { snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev); shrinker_debugfs_rename(s->s_shrink, "sb-%s:%s", fs_type->name, s->s_id); btrfs_sb(s)->bdev_holder = fs_type; error = btrfs_fill_super(s, fs_devices, data); } if (!error) error = security_sb_set_mnt_opts(s, new_sec_opts, 0, NULL); security_free_mnt_opts(&new_sec_opts); if (error) { deactivate_locked_super(s); return ERR_PTR(error); } return dget(s->s_root); -error_close_devices: - btrfs_close_devices(fs_devices); error_fs_info: btrfs_free_fs_info(fs_info); error_sec_opts: security_free_mnt_opts(&new_sec_opts); return ERR_PTR(error); } /* * Mount function which is called by VFS layer. * -- 2.43.0