Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fs: don't flush in-flight wb switches for superblocks without cgroup writeback

When deactivating any type of superblock, it had to wait for the in-flight
wb switches to be completed. wb switches are executed in inode_switch_wbs_work_fn()
which needs to acquire the wb_switch_rwsem and races against sync_inodes_sb().
If there are too much dirty data in the superblock, the waiting time may increase
significantly.

For superblocks without cgroup writeback such as tmpfs, they have nothing to
do with the wb swithes, so the flushing can be avoided.

Signed-off-by: Haifeng Xu <haifeng.xu@shopee.com>
Link: https://lore.kernel.org/r/20240726030525.180330-1-haifeng.xu@shopee.com
Reviewed-by: Jan Kara <jack@suse.cz>
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Haifeng Xu and committed by
Christian Brauner
c393eaa8 e02bdb72

+9 -4
+6 -1
fs/fs-writeback.c
··· 1132 1132 1133 1133 /** 1134 1134 * cgroup_writeback_umount - flush inode wb switches for umount 1135 + * @sb: target super_block 1135 1136 * 1136 1137 * This function is called when a super_block is about to be destroyed and 1137 1138 * flushes in-flight inode wb switches. An inode wb switch goes through ··· 1141 1140 * rare occurrences and synchronize_rcu() can take a while, perform 1142 1141 * flushing iff wb switches are in flight. 1143 1142 */ 1144 - void cgroup_writeback_umount(void) 1143 + void cgroup_writeback_umount(struct super_block *sb) 1145 1144 { 1145 + 1146 + if (!(sb->s_bdi->capabilities & BDI_CAP_WRITEBACK)) 1147 + return; 1148 + 1146 1149 /* 1147 1150 * SB_ACTIVE should be reliably cleared before checking 1148 1151 * isw_nr_in_flight, see generic_shutdown_super().
+1 -1
fs/super.c
··· 621 621 sync_filesystem(sb); 622 622 sb->s_flags &= ~SB_ACTIVE; 623 623 624 - cgroup_writeback_umount(); 624 + cgroup_writeback_umount(sb); 625 625 626 626 /* Evict all inodes with zero refcount. */ 627 627 evict_inodes(sb);
+2 -2
include/linux/writeback.h
··· 217 217 size_t bytes); 218 218 int cgroup_writeback_by_id(u64 bdi_id, int memcg_id, 219 219 enum wb_reason reason, struct wb_completion *done); 220 - void cgroup_writeback_umount(void); 220 + void cgroup_writeback_umount(struct super_block *sb); 221 221 bool cleanup_offline_cgwb(struct bdi_writeback *wb); 222 222 223 223 /** ··· 324 324 { 325 325 } 326 326 327 - static inline void cgroup_writeback_umount(void) 327 + static inline void cgroup_writeback_umount(struct super_block *sb) 328 328 { 329 329 } 330 330