Message ID | 20230421174020.2994750-2-yosryahmed@google.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | cgroup: eliminate atomic rstat flushing | expand |
On Fri, Apr 21, 2023 at 10:40 AM Yosry Ahmed <yosryahmed@google.com> wrote: > > wb_over_bg_thresh() calls mem_cgroup_wb_stats() which invokes an rstat > flush, which can be expensive on large systems. Currently, > wb_writeback() calls wb_over_bg_thresh() within a lock section, so we > have to do the rstat flush atomically. On systems with a lot of > cpus and/or cgroups, this can cause us to disable irqs for a long time, > potentially causing problems. > > Move the call to wb_over_bg_thresh() outside the lock section in > preparation to make the rstat flush in mem_cgroup_wb_stats() non-atomic. > The list_empty(&wb->work_list) check should be okay outside the lock > section of wb->list_lock as it is protected by a separate lock > (wb->work_lock), and wb_over_bg_thresh() doesn't seem like it is > modifying any of wb->b_* lists the wb->list_lock is protecting. > Also, the loop seems to be already releasing and reacquring the > lock, so this refactoring looks safe. > > Signed-off-by: Yosry Ahmed <yosryahmed@google.com> > Reviewed-by: Michal Koutný <mkoutny@suse.com> > Reviewed-by: Jan Kara <jack@suse.cz> Acked-by: Shakeel Butt <shakeelb@google.com>
On Fri, Apr 21, 2023 at 05:40:16PM +0000, Yosry Ahmed wrote: > wb_over_bg_thresh() calls mem_cgroup_wb_stats() which invokes an rstat > flush, which can be expensive on large systems. Currently, > wb_writeback() calls wb_over_bg_thresh() within a lock section, so we > have to do the rstat flush atomically. On systems with a lot of > cpus and/or cgroups, this can cause us to disable irqs for a long time, > potentially causing problems. > > Move the call to wb_over_bg_thresh() outside the lock section in > preparation to make the rstat flush in mem_cgroup_wb_stats() non-atomic. > The list_empty(&wb->work_list) check should be okay outside the lock > section of wb->list_lock as it is protected by a separate lock > (wb->work_lock), and wb_over_bg_thresh() doesn't seem like it is > modifying any of wb->b_* lists the wb->list_lock is protecting. > Also, the loop seems to be already releasing and reacquring the > lock, so this refactoring looks safe. > > Signed-off-by: Yosry Ahmed <yosryahmed@google.com> > Reviewed-by: Michal Koutný <mkoutny@suse.com> > Reviewed-by: Jan Kara <jack@suse.cz> Acked-by: Tejun Heo <tj@kernel.org> Thanks.
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 1db3e3c24b43..11aa1652fb84 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -2024,7 +2024,6 @@ static long wb_writeback(struct bdi_writeback *wb, struct blk_plug plug; blk_start_plug(&plug); - spin_lock(&wb->list_lock); for (;;) { /* * Stop writeback when nr_pages has been consumed @@ -2049,6 +2048,9 @@ static long wb_writeback(struct bdi_writeback *wb, if (work->for_background && !wb_over_bg_thresh(wb)) break; + + spin_lock(&wb->list_lock); + /* * Kupdate and background works are special and we want to * include all inodes that need writing. Livelock avoidance is @@ -2078,13 +2080,19 @@ static long wb_writeback(struct bdi_writeback *wb, * mean the overall work is done. So we keep looping as long * as made some progress on cleaning pages or inodes. */ - if (progress) + if (progress) { + spin_unlock(&wb->list_lock); continue; + } + /* * No more inodes for IO, bail */ - if (list_empty(&wb->b_more_io)) + if (list_empty(&wb->b_more_io)) { + spin_unlock(&wb->list_lock); break; + } + /* * Nothing written. Wait for some inode to * become available for writeback. Otherwise @@ -2096,9 +2104,7 @@ static long wb_writeback(struct bdi_writeback *wb, spin_unlock(&wb->list_lock); /* This function drops i_lock... */ inode_sleep_on_writeback(inode); - spin_lock(&wb->list_lock); } - spin_unlock(&wb->list_lock); blk_finish_plug(&plug); return nr_pages - work->nr_pages;