Linux EXT4 FS development
 help / color / mirror / Atom feed
* [PATCH RFC v2 00/13] fs: reclaim inodes with I_METADATA_WRITEBACK
@ 2026-11-05 12:41 Christian Brauner
  2026-11-05 12:41 ` [PATCH RFC v2 01/13] ext2: add ext2_inode_block() helper Christian Brauner
                   ` (12 more replies)
  0 siblings, 13 replies; 27+ messages in thread
From: Christian Brauner @ 2026-11-05 12:41 UTC (permalink / raw)
  To: linux-fsdevel, Jan Kara
  Cc: Josef Bacik, Chris Mason, linux-ext4, OGAWA Hirofumi,
	Andreas Dilger, Baokun Li, Ojaswin Mujoo, Ritesh Harjani (IBM),
	Namjae Jeon, Christian Brauner (Amutable), stable

Since v7.3 ext2, ext4 without a journal, fat, udf and minix set
I_METADATA_WRITEBACK when they copy an inode into its buffer and only
fsync() and friends clear it again.

inode_lru_isolate() treats it like any other state bit and takes the
inode off the LRU, expecting something to put it back once the bit is
gone. Nothing ever does. So these inodes can't be reclaimed until
something fsyncs them or the filesystem is unmounted. That's a DoS.

On ext4 without a journal an atime update is enough to pin an inode, and
creating 60000 small files in a memory cgroup limited to 96M gets the
task OOM killed after about 43000 of them.

The original provided fix was quite ugly. It handed such inodes from
inode_lru_isolate() to a per-sb work item with a reference held, synced
them there and put them back on the LRU. We've had discussions in that
direction for unrelated reasons and we found that quite terrible. It's a
second inode reclaim offload mechanism next to Jan's deferred inode
reclaim, it needs a new inode state bit, and the reference shows up in
everything that looks for open deleted files.

So instead, let the shrinker reclaim these inodes like any other clean
inode and make the filesystems write out what I_METADATA_WRITEBACK
tracks in ->evict_inode() unless the inode is being deleted. That's
what they already do there for the metadata buffers they track.

The first twelve patches do that per filesystem. ->sync_inode_metadata()
of ext2, ext4, minix and udf looks the inode block up in the buffer
cache instead of reading it from disk, the way fat already does, so
that calling it from reclaim is fine. Then ->evict_inode() of all five
calls it for a linked inode that still has the bit set. The last patch
is the actual fix.

This still writes and waits from reclaim if the inode block is still
dirty. Once Jan's deferred inode reclaim lands these inodes can go to
his workers instead. I have that on top of his v3 (cf. [1]).

All of this is meant for v7.3 stable. v7.3 still has bfs which sets
I_METADATA_WRITEBACK as well, so the backport needs the same two
changes for bfs.

Tested on 65ba8f34ec88 with KASAN and lockdep: creating 5000 files,
sync(2) and two drop_caches leave about 5000 of 5000 inodes around on
ext2, ext4, vfat and minix without this series and at most one with it.
The memory cgroup run creates all 60000 files and nothing gets killed.
Blocks the flusher left dirty get written out on eviction on all five
filesystems. No splats.

udf inodes with their data in the ICB are still dirty after sync(2),
with and without this series. That's a separate issue I didn't care
about.

[1]: https://patch.msgid.link/20261029-work-inode-metadata_writeback-deferred-v1-1-7e49f6c12b60@kernel.org

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
Changes in v2:
- Drop the ext4_inode_loc_block() helper and use
  ext4_get_inode_loc_noio() with the sleeping buffer lookup instead
  (Jan).
- Write out what I_METADATA_WRITEBACK tracks from ->evict_inode() of
  each filesystem instead of from evict() (Jan).
- Drop "fat: sync the inode in fat_free_eofblocks()" (Jan, OGAWA).
- Move the reproducer out of the commit message.
- Link to v1: https://patch.msgid.link/20261029-work-inode-metadata_writeback-v1-0-7d6c678a585d@kernel.org

---
Christian Brauner (13):
      ext2: add ext2_inode_block() helper
      ext2: don't read the inode block in ext2_sync_inode_metadata()
      ext2: sync inode metadata in ext2_evict_inode()
      ext4: use sb_find_get_block_nonatomic() in ext4_get_inode_loc_noio()
      ext4: don't read the inode block in ext4_sync_inode_metadata()
      ext4: sync inode metadata in ext4_evict_inode()
      minix: add minix_inode_block() helper
      minix: don't read the inode block in minix_sync_inode_metadata()
      minix: sync inode metadata in minix_evict_inode()
      udf: don't allocate the inode block in udf_sync_inode_metadata()
      udf: sync inode metadata in udf_evict_inode()
      fat: sync inode metadata in fat_evict_inode()
      fs: don't strand I_METADATA_WRITEBACK inodes outside the LRU

 fs/ext2/inode.c   | 69 ++++++++++++++++++++++++++++++++++++-------------------
 fs/ext4/inode.c   | 33 ++++++++++++++++++--------
 fs/fat/inode.c    | 11 ++++++++-
 fs/inode.c        |  5 +++-
 fs/minix/bitmap.c | 37 ++++++++++++++++++-----------
 fs/minix/inode.c  | 24 ++++++++++++-------
 fs/minix/minix.h  |  1 +
 fs/udf/inode.c    | 45 +++++++++++++++++++++---------------
 8 files changed, 150 insertions(+), 75 deletions(-)
---
base-commit: 65ba8f34ec886ec72b2c07ddc8cf3d815c32869d
change-id: 20261029-work-inode-metadata_writeback-d880a0429e49


^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2026-11-05 13:06 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-05 12:41 [PATCH RFC v2 00/13] fs: reclaim inodes with I_METADATA_WRITEBACK Christian Brauner
2026-11-05 12:41 ` [PATCH RFC v2 01/13] ext2: add ext2_inode_block() helper Christian Brauner
2026-11-05 12:52   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 02/13] ext2: don't read the inode block in ext2_sync_inode_metadata() Christian Brauner
2026-11-05 12:47   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 03/13] ext2: sync inode metadata in ext2_evict_inode() Christian Brauner
2026-11-05 12:49   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 04/13] ext4: use sb_find_get_block_nonatomic() in ext4_get_inode_loc_noio() Christian Brauner
2026-11-05 12:46   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 05/13] ext4: don't read the inode block in ext4_sync_inode_metadata() Christian Brauner
2026-11-05 12:48   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 06/13] ext4: sync inode metadata in ext4_evict_inode() Christian Brauner
2026-11-05 12:54   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 07/13] minix: add minix_inode_block() helper Christian Brauner
2026-11-05 12:45   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 08/13] minix: don't read the inode block in minix_sync_inode_metadata() Christian Brauner
2026-11-05 12:46   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 09/13] minix: sync inode metadata in minix_evict_inode() Christian Brauner
2026-11-05 12:46   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 10/13] udf: don't allocate the inode block in udf_sync_inode_metadata() Christian Brauner
2026-11-05 12:49   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 11/13] udf: sync inode metadata in udf_evict_inode() Christian Brauner
2026-11-05 12:54   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 12/13] fat: sync inode metadata in fat_evict_inode() Christian Brauner
2026-11-05 13:06   ` sashiko-bot
2026-11-05 12:41 ` [PATCH RFC v2 13/13] fs: don't strand I_METADATA_WRITEBACK inodes outside the LRU Christian Brauner
2026-11-05 12:55   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox