Re: [PATCH 00/10] ovl: only sync what was written through the overlay

From: Amir Goldstein

Date: Wed Oct 28 2026 - 11:18:58 EST


On Tue, Oct 27, 2026 at 11:09 PM Josef Bacik <josef@xxxxxxxxxxxxxx> wrote:
>
> Hello,
>
> This picks up Chengguang Xu's "implement containerized syncfs for
> overlayfs", last posted as RFC V6 in November 2021 [1].
>

Thanks for picking this up!
This looks like a very useful improvement.

> syncfs() on an overlay and unmounting one call sync_filesystem() on the
> upper file system, so they write every dirty inode on it no matter who
> dirtied it. We run a lot of containers on one upper file system, and
> stopping one of them writes out the dirty data of all the others. That
> can take a very long time, and s_umount of the upper file system is held
> the whole time, so anything that wants it exclusively queues up and then
> everybody else queues up behind that.
>
> With this an overlay only writes the upper inodes that were changed
> through it, and then has the upper file system commit its metadata.
>
> The V6 discussion ended with a direction but no V7, so that's what I
> tried to follow:
>
> - V6 kept every overlay inode with an upper inode dirty for good. Jan
> and Amir didn't like the cost of walking them. Now an overlay inode
> is marked dirty when the upper inode is changed, mostly from
> ovl_copyattr() as Amir and Miklos suggested.
> - It never looks at the dirty flags of the upper inode, Miklos pointed
> out that they're cleared when writeback starts.
> - ->write_inode() goes through write_inode_now() on the upper inode,
> and keeps the overlay inode dirty while the upper inode is open for
> writing, which covers shared mappings.
> - V6 marked the inodes DONTCACHE, which Jan was worried about. This
> goes back to the v5 patch that keeps dirty overlay inodes cached.
>
> One thing is new. V6 called wait_sb_inodes() on the upper file system to
> catch writeback that was started but not finished, which waits for
> everybody's writeback. Instead ->write_inode() keeps the overlay inode
> dirty while the upper inode has pages tagged dirty or under writeback.
> The tags don't have the problem the inode flags have, the writeback tag
> is set before the dirty tag is cleared. So a clean overlay inode means
> its data is on disk, and syncfs() only waits for its own inodes.
>
> That takes care of the data. Metadata is harder, a lot of what is
> changed on the upper file system has no overlay inode that could be on
> the dirty list: the root of the overlay isn't hashed, and whiteouts,
> index entries, the work directories and their parent have none. File
> systems that log their metadata don't care, ->sync_fs() commits it. ext2
> does, there a whiteout was gone after a crash. I first had overlayfs
> write all of those itself and kept finding more of them, the last one
> was the link count of the shared whiteout when a whiteout is removed.
>
> So patch 1 adds a superblock flag, SB_I_OVL_USE_SYNC_FS, by which a file
> system says that ->sync_fs() commits all of its metadata,

I have some reservations about the flag name (how could I not)
but mostly because I am considering if this flag could serve something else
as well (more on patch 1 review).

> and patches 2
> to 4 set it for ext4 with a journal, xfs and btrfs. Without the flag on
> the upper file system nothing changes, no inode is marked dirty and
> syncfs() and unmount call sync_filesystem() like they always did.
>
> Patches 5, 7, 8 and 10 are Chengguang's with changes noted in them,
> patches 6 and 9 are new. I dropped Jan's Reviewed-by tags from V6 since
> the patches changed.
>
> 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.
>

I suggest asking review from Jan again for those writeback and lazytime
bits. Would be hard for me to validate those.

Thanks,
Amir.

> Things I know about:
>
> - 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. Clean and unlinked ones are still freed right
> away.
> - Every overlay on such an upper file system gets a bdi.
> - I haven't measured syncfs() with a very large number of dirty inodes.
>
> For testing I put several overlays on one upper file system and dirty
> 192M next to the overlay under test, through another overlay and
> directly. Then syncfs() or unmount the one overlay, copy the block
> device as it is at that moment, mount the copy, and check that
> everything that was changed through the overlay is in it and that the
> 192M aren't. That passes with ext4, xfs and btrfs as the upper file
> system. With KASAN and lockdep on, syncfs() goes from 239-284ms to
> 45-48ms and unmount from 126-234ms to 39-44ms. With ext2 and ext4
> without a journal the 192M are written as before.
>
> fstests with -overlay, the auto groups of generic and overlay, gives the
> same results with and without the series on ext4 and on xfs.
>
> [1] https://lore.kernel.org/r/20211122030038.1938875-1-cgxu519@xxxxxxxxxxxx
>
> Thanks,
>
> Josef
>
> ---
> Chengguang Xu (4):
> ovl: setup overlayfs' private bdi
> ovl: implement overlayfs' own ->write_inode operation
> ovl: cache dirty overlayfs' inode
> ovl: implement containerized syncfs for overlayfs
>
> Josef Bacik (6):
> fs: add SB_I_OVL_USE_SYNC_FS
> ext4: set SB_I_OVL_USE_SYNC_FS if there is a journal
> xfs: set SB_I_OVL_USE_SYNC_FS
> btrfs: set SB_I_OVL_USE_SYNC_FS
> ovl: mark the overlay inode dirty on modification
> ovl: handle lazytime on the upper filesystem
>
> fs/btrfs/super.c | 2 +-
> fs/ext4/super.c | 1 +
> fs/overlayfs/copy_up.c | 2 +
> fs/overlayfs/dir.c | 1 +
> fs/overlayfs/file.c | 8 ++-
> fs/overlayfs/inode.c | 21 +++++-
> fs/overlayfs/overlayfs.h | 28 ++++++++
> fs/overlayfs/super.c | 145 ++++++++++++++++++++++++++++++++++++++---
> fs/overlayfs/util.c | 14 +++-
> fs/xfs/xfs_super.c | 2 +-
> include/linux/fs/super_types.h | 1 +
> 11 files changed, 211 insertions(+), 14 deletions(-)
> ---
> base-commit: 2c8a968b488c134d05ccefff890270ac8ab899a8
> change-id: 20261026-b4-ovl-containerized-sync-149bed1afe9a
>