writeback: allow the file system to override MIN_WRITEBACK_PAGES

The relatively low minimal writeback size of 4MiB means that written back
inodes on rotational media are switched a lot.  Besides introducing
additional seeks, this also can lead to extreme file fragmentation on
zoned devices when a lot of files are cached relative to the available
writeback bandwidth.

Add a superblock field that allows the file system to override the
default size.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20251017034611.651385-3-hch@lst.de
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christoph Hellwig 2025-10-17 05:45:48 +02:00 committed by Christian Brauner
parent 151d0922bf
commit 90db4d4441
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
4 changed files with 12 additions and 9 deletions

View File

@ -32,11 +32,6 @@
#include <linux/memcontrol.h> #include <linux/memcontrol.h>
#include "internal.h" #include "internal.h"
/*
* 4MB minimal write chunk size
*/
#define MIN_WRITEBACK_PAGES (4096UL >> (PAGE_SHIFT - 10))
/* /*
* Passed into wb_writeback(), essentially a subset of writeback_control * Passed into wb_writeback(), essentially a subset of writeback_control
*/ */
@ -1889,8 +1884,8 @@ static int writeback_single_inode(struct inode *inode,
return ret; return ret;
} }
static long writeback_chunk_size(struct bdi_writeback *wb, static long writeback_chunk_size(struct super_block *sb,
struct wb_writeback_work *work) struct bdi_writeback *wb, struct wb_writeback_work *work)
{ {
long pages; long pages;
@ -1913,7 +1908,8 @@ static long writeback_chunk_size(struct bdi_writeback *wb,
pages = min(wb->avg_write_bandwidth / 2, pages = min(wb->avg_write_bandwidth / 2,
global_wb_domain.dirty_limit / DIRTY_SCOPE); global_wb_domain.dirty_limit / DIRTY_SCOPE);
pages = min(pages, work->nr_pages); pages = min(pages, work->nr_pages);
return round_down(pages + MIN_WRITEBACK_PAGES, MIN_WRITEBACK_PAGES); return round_down(pages + sb->s_min_writeback_pages,
sb->s_min_writeback_pages);
} }
/* /*
@ -2015,7 +2011,7 @@ static long writeback_sb_inodes(struct super_block *sb,
inode->i_state |= I_SYNC; inode->i_state |= I_SYNC;
wbc_attach_and_unlock_inode(&wbc, inode); wbc_attach_and_unlock_inode(&wbc, inode);
write_chunk = writeback_chunk_size(wb, work); write_chunk = writeback_chunk_size(inode->i_sb, wb, work);
wbc.nr_to_write = write_chunk; wbc.nr_to_write = write_chunk;
wbc.pages_skipped = 0; wbc.pages_skipped = 0;

View File

@ -389,6 +389,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
goto fail; goto fail;
if (list_lru_init_memcg(&s->s_inode_lru, s->s_shrink)) if (list_lru_init_memcg(&s->s_inode_lru, s->s_shrink))
goto fail; goto fail;
s->s_min_writeback_pages = MIN_WRITEBACK_PAGES;
return s; return s;
fail: fail:

View File

@ -1583,6 +1583,7 @@ struct super_block {
spinlock_t s_inode_wblist_lock; spinlock_t s_inode_wblist_lock;
struct list_head s_inodes_wb; /* writeback inodes */ struct list_head s_inodes_wb; /* writeback inodes */
long s_min_writeback_pages;
} __randomize_layout; } __randomize_layout;
static inline struct user_namespace *i_user_ns(const struct inode *inode) static inline struct user_namespace *i_user_ns(const struct inode *inode)

View File

@ -374,4 +374,9 @@ bool redirty_page_for_writepage(struct writeback_control *, struct page *);
void sb_mark_inode_writeback(struct inode *inode); void sb_mark_inode_writeback(struct inode *inode);
void sb_clear_inode_writeback(struct inode *inode); void sb_clear_inode_writeback(struct inode *inode);
/*
* 4MB minimal write chunk size
*/
#define MIN_WRITEBACK_PAGES (4096UL >> (PAGE_SHIFT - 10))
#endif /* WRITEBACK_H */ #endif /* WRITEBACK_H */