diff options
author | Christian Brauner <brauner@kernel.org> | 2025-09-15 14:50:03 +0200 |
---|---|---|
committer | Christian Brauner <brauner@kernel.org> | 2025-09-19 13:11:06 +0200 |
commit | 9426414f0d42f824892ecd4dccfebf8987084a41 (patch) | |
tree | 8ef299818292d567a88da80cf69905a7956a9712 /mm/backing-dev.c | |
parent | 8f5ae30d69d7543eee0d70083daf4de8fe15d585 (diff) | |
parent | 0cee64c547e3c9cda646af3e075a64f445ee8148 (diff) |
Merge patch series "writeback: Avoid lockups when switching inodes"
Jan Kara <jack@suse.cz> says:
This patch series addresses lockups reported by users when systemd unit reading
lots of files from a filesystem mounted with lazytime mount option exits. See
patch 3 for more details about the reproducer.
There are two main issues why switching many inodes between wbs:
1) Multiple workers will be spawned to do the switching but they all contend
on the same wb->list_lock making all the parallelism pointless and just
wasting time.
2) Sorting of wb->b_dirty list by dirtied_time_when is inherently slow.
Patches 1-3 address these problems, patch 4 adds a tracepoint for better
observability of inode writeback switching.
* patches from https://lore.kernel.org/20250912103522.2935-1-jack@suse.cz:
writeback: Add tracepoint to track pending inode switches
writeback: Avoid excessively long inode switching times
writeback: Avoid softlockup when switching many inodes
writeback: Avoid contention on wb->list_lock when switching inodes
Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'mm/backing-dev.c')
-rw-r--r-- | mm/backing-dev.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 783904d8c5ef..0beaca6bacf7 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -633,6 +633,7 @@ static void cgwb_release_workfn(struct work_struct *work) wb_exit(wb); bdi_put(bdi); WARN_ON_ONCE(!list_empty(&wb->b_attached)); + WARN_ON_ONCE(work_pending(&wb->switch_work)); call_rcu(&wb->rcu, cgwb_free_rcu); } @@ -709,6 +710,8 @@ static int cgwb_create(struct backing_dev_info *bdi, wb->memcg_css = memcg_css; wb->blkcg_css = blkcg_css; INIT_LIST_HEAD(&wb->b_attached); + INIT_WORK(&wb->switch_work, inode_switch_wbs_work_fn); + init_llist_head(&wb->switch_wbs_ctxs); INIT_WORK(&wb->release_work, cgwb_release_workfn); set_bit(WB_registered, &wb->state); bdi_get(bdi); @@ -839,6 +842,8 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi) if (!ret) { bdi->wb.memcg_css = &root_mem_cgroup->css; bdi->wb.blkcg_css = blkcg_root_css; + INIT_WORK(&bdi->wb.switch_work, inode_switch_wbs_work_fn); + init_llist_head(&bdi->wb.switch_wbs_ctxs); } return ret; } |