Skip to content

Commit ac0c18f

Browse files
Kemeng Shibrauner
authored andcommitted
fs/writeback: avoid to writeback non-expired inode in kupdate writeback
In kupdate writeback, only expired inode (have been dirty for longer than dirty_expire_interval) is supposed to be written back. However, kupdate writeback will writeback non-expired inode left in b_io or b_more_io from last wb_writeback. As a result, writeback will keep being triggered unexpected when we keep dirtying pages even dirty memory is under threshold and inode is not expired. To be more specific: Assume dirty background threshold is > 1G and dirty_expire_centisecs is > 60s. When we running fio -size=1G -invalidate=0 -ioengine=libaio --time_based -runtime=60... (keep dirtying), the writeback will keep being triggered as following: wb_workfn wb_do_writeback wb_check_background_flush /* * Wb dirty background threshold starts at 0 if device was idle and * grows up when bandwidth of wb is updated. So a background * writeback is triggered. */ wb_over_bg_thresh /* * Dirtied inode will be written back and added to b_more_io list * after slice used up (because we keep dirtying the inode). */ wb_writeback Writeback is triggered per dirty_writeback_centisecs as following: wb_workfn wb_do_writeback wb_check_old_data_flush /* * Write back inode left in b_io and b_more_io from last wb_writeback * even the inode is non-expired and it will be added to b_more_io * again as slice will be used up (because we keep dirtying the * inode) */ wb_writeback Fix this by moving non-expired inode to dirty list instead of more io list for kupdate writeback in requeue_inode. Test as following: /* make it more easier to observe the issue */ echo 300000 > /proc/sys/vm/dirty_expire_centisecs echo 100 > /proc/sys/vm/dirty_writeback_centisecs /* create a idle device */ mkfs.ext4 -F /dev/vdb mount /dev/vdb /bdi1/ /* run buffer write with fio */ fio -name test -filename=/bdi1/file -size=800M -ioengine=libaio -bs=4K \ -iodepth=1 -rw=write -direct=0 --time_based -runtime=60 -invalidate=0 Fio result before fix (run three tests): 1360MB/s 1329MB/s 1455MB/s Fio result after fix (run three tests): 1737MB/s 1729MB/s 1789MB/s Writeback for non-expired inode is gone as expeted. Observe this with trace writeback_start and writeback_written as following: echo 1 > /sys/kernel/debug/tracing/events/writeback/writeback_start/enab echo 1 > /sys/kernel/debug/tracing/events/writeback/writeback_written/enable cat /sys/kernel/tracing/trace_pipe Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com> Link: https://lore.kernel.org/r/20240228091958.288260-2-shikemeng@huaweicloud.com Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent fc25321 commit ac0c18f

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

fs/fs-writeback.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,7 +1561,8 @@ static void inode_sleep_on_writeback(struct inode *inode)
15611561
* thread's back can have unexpected consequences.
15621562
*/
15631563
static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
1564-
struct writeback_control *wbc)
1564+
struct writeback_control *wbc,
1565+
unsigned long dirtied_before)
15651566
{
15661567
if (inode->i_state & I_FREEING)
15671568
return;
@@ -1594,7 +1595,8 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
15941595
* We didn't write back all the pages. nfs_writepages()
15951596
* sometimes bales out without doing anything.
15961597
*/
1597-
if (wbc->nr_to_write <= 0) {
1598+
if (wbc->nr_to_write <= 0 &&
1599+
!inode_dirtied_after(inode, dirtied_before)) {
15981600
/* Slice used up. Queue for next turn. */
15991601
requeue_io(inode, wb);
16001602
} else {
@@ -1862,6 +1864,11 @@ static long writeback_sb_inodes(struct super_block *sb,
18621864
unsigned long start_time = jiffies;
18631865
long write_chunk;
18641866
long total_wrote = 0; /* count both pages and inodes */
1867+
unsigned long dirtied_before = jiffies;
1868+
1869+
if (work->for_kupdate)
1870+
dirtied_before = jiffies -
1871+
msecs_to_jiffies(dirty_expire_interval * 10);
18651872

18661873
while (!list_empty(&wb->b_io)) {
18671874
struct inode *inode = wb_inode(wb->b_io.prev);
@@ -1967,7 +1974,7 @@ static long writeback_sb_inodes(struct super_block *sb,
19671974
spin_lock(&inode->i_lock);
19681975
if (!(inode->i_state & I_DIRTY_ALL))
19691976
total_wrote++;
1970-
requeue_inode(inode, tmp_wb, &wbc);
1977+
requeue_inode(inode, tmp_wb, &wbc, dirtied_before);
19711978
inode_sync_complete(inode);
19721979
spin_unlock(&inode->i_lock);
19731980

0 commit comments

Comments
 (0)