Re: [PATCH v3 0/8] ovl: only sync what was written through the overlay
From: Christian Brauner
Date: Fri Nov 06 2026 - 10:42:56 EST
On Wed, Nov 04, 2026 at 08:44:57PM +0000, Josef Bacik wrote:
> sync_filesystem() writes every inode on a dirty list, calls ->sync_fs()
> and writes the block device. Only the first step is expensive, because
> of other people's data. With fsync=relaxed overlayfs writes the upper
> inodes whose overlay inode was marked dirty and does the other two steps
> as they are.
I think that makes sense.
The thing that's a bit ugly is that overlayfs open-codes the tail of
sync_filesystems(): ovl_sync_fs() calling upper_sb->s_op->sync_fs() and
sync_blockdev() itself is one more place that needs to know what
sync_filesystem() does.
So we should probably add a helper to fs/sync.c for the ->sync_fs() and
block device part and use that.
> fsync=auto, the default, picks relaxed if the upper file system supports
> RENAME_WHITEOUT.
Eheeeem, isn't that kind of a bad proxy for this? What ->sync_fs() +
block device do is a property of the upper filesystems and how is that
related to RENAME_WHITEOUT? There's a few counter examples you even
give:
> - f2fs, ubifs, fuse and tmpfs get relaxed as well and I didn't test
> them. ubifs_sync_fs() doesn't write dirty inodes, so a chmod of the
> work directory at mount time waits for the flusher there.
So on ubifs a syncfs() in relaxed mode returns with metadata still in
memory. Meh. I know the flag got droppped but that was an overlayfs
speicfic thing. A generic property of ->sync_fs() is a different thing?
> Now an overlay inode is marked dirty when the upper inode is changed,
> mostly from ovl_copyattr() as Amir and Miklos suggested.
Afaict, creation isn't covered. ovl_instantiate() ends up in
ovl_inode_init() which now uses __ovl_copyattr(). So a new file,
directory, symlink or hardlink only dirties the parent but not the new
overlay inode.
Fine for metadata, but a long symlink isn't metadata. We should mark the
new inode dirty where it's instantiated.
> lazytime on the upper file system needs its own handling. The flusher
> leaves the timestamps in memory for up to 12 hours, so the overlay inode
> can't be clean, but it can't stay dirty and pinned for that long either.
> Patch 9 gives it I_DIRTY_TIME like the upper inode has, and forwards
> ->sync_lazytime() to the upper inode.
Parking the overlay inode with I_DIRTY_TIME is fine?
So from what I could research:
* ovl_park_inode() calls mark_inode_dirty_sync(). Jan's deferred inode
reclaim (cf. [1]) removes exactly that from iput() because it does IO
from dentry reclaim.
He replaces it with queue_dirtytime_writeback(). That moves the inode
to the head of b_dirty_time and wakes the flusher.
So it would be nice if we could base your thing on top of Jan's series
(I hope he'll send v2 soon!) and call queue_dirtytime_writeback() thing.
> An overlay inode that loses its last reference while it is dirty is
> kept until it has been written and then sits on the LRU, like with
> any other file system.
Hm, Jan's series fixes that as well afaict. :)
There's some Sashiko thing btw you should look into?
[1]: https://lore.kernel.org/r/20261009133253.20102-1-jack@xxxxxxx
--