]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
writeback: allow the file system to override MIN_WRITEBACK_PAGES
authorChristoph Hellwig <hch@lst.de>
Fri, 17 Oct 2025 03:45:48 +0000 (05:45 +0200)
committerChristian Brauner <brauner@kernel.org>
Wed, 29 Oct 2025 14:54:31 +0000 (15:54 +0100)
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>
fs/fs-writeback.c
fs/super.c
include/linux/fs.h
include/linux/writeback.h

index 30de37865fa12ae9dfe274efea7076602031b036..52763fa499d62446ed326932d96f6c109016cbd6 100644 (file)
 #include <linux/memcontrol.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
  */
@@ -1889,8 +1884,8 @@ out:
        return ret;
 }
 
-static long writeback_chunk_size(struct bdi_writeback *wb,
-                                struct wb_writeback_work *work)
+static long writeback_chunk_size(struct super_block *sb,
+               struct bdi_writeback *wb, struct wb_writeback_work *work)
 {
        long pages;
 
@@ -1913,7 +1908,8 @@ static long writeback_chunk_size(struct bdi_writeback *wb,
        pages = min(wb->avg_write_bandwidth / 2,
                    global_wb_domain.dirty_limit / DIRTY_SCOPE);
        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;
                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.pages_skipped = 0;
 
index 5bab94fb7e0358a59aeda0c0985d875e4463ade1..599c1d2641feb0f59b8b6757ae23c26ad6eb70b2 100644 (file)
@@ -389,6 +389,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
                goto fail;
        if (list_lru_init_memcg(&s->s_inode_lru, s->s_shrink))
                goto fail;
+       s->s_min_writeback_pages = MIN_WRITEBACK_PAGES;
        return s;
 
 fail:
index a5dbfa20f8d74cc105e3cb7dbc35751f72aca606..6bf369095d2e1b36201eecc38785d20c9280b678 100644 (file)
@@ -1583,6 +1583,7 @@ struct super_block {
 
        spinlock_t              s_inode_wblist_lock;
        struct list_head        s_inodes_wb;    /* writeback inodes */
+       long                    s_min_writeback_pages;
 } __randomize_layout;
 
 static inline struct user_namespace *i_user_ns(const struct inode *inode)
index 22dd4adc5667d952f1baf7fff14d8525f5e3b28e..49e1dd96f43e53d4d7ae01ab47030076ad4f797a 100644 (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_clear_inode_writeback(struct inode *inode);
 
+/*
+ * 4MB minimal write chunk size
+ */
+#define MIN_WRITEBACK_PAGES    (4096UL >> (PAGE_SHIFT - 10))
+
 #endif         /* WRITEBACK_H */