Buffered writeback to a block device submits one bio per dirty buffer_head. For
contiguous dirty data this creates many small bios that the block layer then has
to merge again, or does not merge at all. Large folios make this worse, since a
2 MB folio with 4 KiB blocks is up to 512 bios, although the buffers of a folio,
and consecutive folios, are often contiguous on disk.

To aggregate data into a bio, keep one bio open while writing back and
append each dirty buffer to it as long as it directly continues the
data already in the bio and can share its properties. Once a buffer
does not fit, submit the bio and start a new one. The open bio is kept
across the buffers of a folio and across consecutive folios, so
contiguous dirty data ends up in one large bio, which is then also
completed in one pass instead of buffer by buffer.

A similar approach was posted before [1]. Since then folios, and large
folios in particular, make it much more attractive: a single folio can
now carry many buffers, and a run of folios can fill a bio with
hundreds of megabytes. With 2 MB folios I see bios of up to 512 MB
(256 segments).

[1] https://lore.kernel.org/all/[email protected]/

Lukas Sichert (4):
  buffer: writeback: extract shared bio build/complete helpers
  buffer: writeback: batch contiguous async-write buffers per folio
  block: coalesce bios across folios in blkdev_writepages
  selftests: filesystems: add blkdev writeback coalescing test

 block/fops.c                                  |   9 +-
 fs/buffer.c                                   | 236 +++++++++++++---
 include/linux/buffer_head.h                   |   3 +
 .../testing/selftests/filesystems/.gitignore  |   1 +
 tools/testing/selftests/filesystems/Makefile  |   2 +-
 .../filesystems/blkdev_writeback_test.c       | 259 ++++++++++++++++++
 6 files changed, 463 insertions(+), 47 deletions(-)
 create mode 100644 tools/testing/selftests/filesystems/blkdev_writeback_test.c


base-commit: 0c2669a9f4a1d607e7591ae50ccf3c432a0aff08


Reply via email to