t() will + * trigger writeback again, and may even cause extra works queued + * into workqueue. + */ + if (unlikely(BTRFS_FS_ERROR(fs_info))) + filemap_write_and_wait(fs_info->btree_inode->i_mapping); + /* * we must make sure there is not any read request to * submit after we stopping all workers. */ invalidate_inode_pages2(fs_info->btree_inode->i_mapping); + btrfs_stop_all_workers(fs_info); /* We shouldn't have any transaction open at this point */ diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 870584dde575..a8a53409bb3f 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2246,6 +2246,17 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb, wbc_account_cgroup_owner(wbc, folio, range_len); folio_unlock(folio); } + /* + * If the fs is already in error status, do not submit any writeback + * but immediately finish it. + * This is to avoid iput() triggering dirty folio writeback for + * transaction aborted fses, which can cause extra works into + * already stopped workqueues. + */ + if (unlikely(BTRFS_FS_ERROR(fs_info))) { + btrfs_bio_end_io(bbio, errno_to_blk_status(-EROFS)); + return; + } btrfs_submit_bbio(bbio, 0); } -- 2.51.0[PATCH] btrfs: make sure no dirty metadata write is submitted after btrfs_stop_all_workers()Qu Wenruo undefinedlinux-btrfs@vger.kernel.org undefined undefinedÉ