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

From: Amir Goldstein

Date: Mon Nov 02 2026 - 05:15:00 EST


On Thu, Oct 29, 2026 at 2:09 AM Josef Bacik <josef@xxxxxxxxxxxxxx> wrote:
>
> v1: https://lore.kernel.org/all/20261027-b4-ovl-containerized-sync-v1-0-802e512379a6@xxxxxxxxxxxxxx/
>
> Jan, Amir suggested I ask you to look at the writeback and lazytime
> parts again, that's patches 4 to 6 and 9.
>
> v1->v2:
> - Dropped the superblock flag and the ext4, xfs and btrfs patches. This
> is all in overlayfs now and works the same on any upper file system.

I think this is over engineering.

What is our goal here?

Make overlayfs behave better for the (many) containers use case.

Who in their right mind uses a host filesystem which is not one of the
big three?

Most of the complexity and hackery in this patch set is because we don't want
to name the best behaving filesystems for overlayfs layers.

Please consider the attached patch.
It gives the mounter full control over how overlayfs behave.
It provides sane heuristic defaults for the filesystems that implement
RENAME_WHITEOUT, which is another way of saying "overlayfs compliant".
The RENAME_WHITEOUT heuristic of the default fsync=auto can be disabled
by distro/admin with the kconfig/module option fsync_auto.

The heuristics do not always get it right, for example, ext4 without
journal does
support RENAME_WHITEOUT, but it not safe for fsync=relaxed mode, but
this is an imaginary scenario that nobody uses and there is config/module/mount
options to force the legacy fsync=on mode in that case.

WDYT?

Thanks,
Amir.
From c45364e6ef447d2dd717eeed43a0ce069e84dde2 Mon Sep 17 00:00:00 2001
From: Amir Goldstein <amir73il@xxxxxxxxx>
Date: Mon, 2 Nov 2026 09:12:02 +0100
Subject: [PATCH] ovl: expand fsync mount options

The fsync mount option currently accepts three values:
"volatile", "strict" and "auto".

All other "enum" mount options have "on" and "off" values and this is
used by the generic _check_overlay_feature helper in fstests to probe
for support for enabling overlayfs features.

This commit adds supports for values "on", "off" and "relax" and makes
the value of "auto" depend on a kconfig/module option fsync_auto.

The value of "off" behaves almost the same the "volatile", not
persisting changes to upper layer, but it does not create the directory
"$workdir/work/incompat/volatile", which prevent mount cycle of a
volatile overlayfs. Some users requested to opt-out of this rail guard.

The new value "relaxed" is a preparation for not syncing the entire
upper fs on syncfs(2) and unmount and instead syncing only the upper
inodes modified by this overlayfs.

The value of "on" is the traditional overlayfs behavior and it behaves
the same as the current value "auto", releasing the value of "auto" to
differ by the kconfig/module option fsync_auto.

By default, with kconfig/module option fsync_auto=Y, the meaning of the
value "auto" is that filesystems that support RENAME_WHITEOUT default to
"relaxed" and filesystems that do not support RENAME_WHITEOUT default to
the traditional "fsync=on".

Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
---
Documentation/filesystems/overlayfs.rst | 32 +++++++++++++++++++++----
fs/overlayfs/Kconfig | 21 ++++++++++++++++
fs/overlayfs/overlayfs.h | 16 ++++++++++---
fs/overlayfs/params.c | 16 ++++++++++---
fs/overlayfs/params.h | 1 +
fs/overlayfs/super.c | 13 +++++++---
6 files changed, 85 insertions(+), 14 deletions(-)

diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst
index 16c35b491dad4..092806c620b64 100644
--- a/Documentation/filesystems/overlayfs.rst
+++ b/Documentation/filesystems/overlayfs.rst
@@ -826,27 +826,49 @@ The fsync during copy up only guarantees that if a copy up is observed
after a crash, the observed data is not zeroes or intermediate values
from the copy up staging area.

+Traditionally, syncfs(2) and unmount of an overlay sync the entire upper
+filesystem, including the dirty data of other overlays that share it.
+Overlayfs can be told to only write back the files that were modified
+through the overlay, and then ask the upper filesystem to commit its
+metadata.
+
On traditional local filesystems with a single journal (e.g. ext4, xfs),
fsync on a file also persists the parent directory changes, because they
are usually modified in the same transaction, so metadata durability during
-data copy up effectively comes for free. Overlayfs further limits risk by
-disallowing network filesystems as upper layer.
+data copy up and the persistence of other upper changes such as whiteouts
+effectively come for free.

Overlayfs can be tuned to prefer performance or durability when storing
to the underlying upper layer. This is controlled by the "fsync" mount
option, which supports these values:

-- "auto": (default)
+- "volatile": [*]
+ Prefer performance over durability (see `Volatile mount`_)
+- "off":
+ Same as "volatile", but does not prevent mounting the overlay again
+ after unmount (see `Volatile mount`_)
+- "relaxed":
Call fsync(2) on upper file before completion of data copy up.
No explicit fsync(2) on directory or metadata-only copy up.
+ syncfs(2) and unmount only write back the files that were modified
+ through the overlay.
+- "auto": (default)
+ "relaxed" if the upper filesystem supports RENAME_WHITEOUT,
+ otherwise "on".
+- "on":
+ syncfs(2) syncs the entire upper filesystem.
+ Copy up behaves like "relaxed".
- "strict":
+ syncfs(2) syncs the entire upper filesystem.
Call fsync(2) on upper file and directories before completion of any
copy up.
-- "volatile": [*]
- Prefer performance over durability (see `Volatile mount`_)

[*] The mount option "volatile" is an alias to "fsync=volatile".

+The default is "fsync=on" instead of "fsync=auto" with the module option
+"fsync_auto=N" or with the kernel config option
+CONFIG_OVERLAY_FS_FSYNC_AUTO=n.
+

Volatile mount
--------------
diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig
index 2ac67e04a6fbe..f1b2f3784c761 100644
--- a/fs/overlayfs/Kconfig
+++ b/fs/overlayfs/Kconfig
@@ -108,6 +108,27 @@ config OVERLAY_FS_XINO_AUTO

If unsure, say N.

+config OVERLAY_FS_FSYNC_AUTO
+ bool "Overlayfs: auto select the fsync mode by default"
+ default y
+ depends on OVERLAY_FS
+ help
+ If this config option is enabled then overlay filesystems will use
+ "fsync=auto" by default, which selects "fsync=relaxed" if the upper
+ filesystem supports RENAME_WHITEOUT and "fsync=on" otherwise.
+ With "fsync=relaxed", syncfs(2) and unmount of an overlay only write
+ back the files that were modified through the overlay, instead of
+ syncing the entire upper filesystem.
+
+ If this config option is disabled then overlay filesystems will use
+ "fsync=on" by default. It is still possible to change the default
+ with the "fsync_auto" module option or on a filesystem instance
+ basis with the "fsync" mount option.
+
+ For more information, see Documentation/filesystems/overlayfs.rst
+
+ If unsure, say Y.
+
config OVERLAY_FS_METACOPY
bool "Overlayfs: turn on metadata only copy up feature by default"
depends on OVERLAY_FS
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index b5a672e8e4764..c451b95c2bb4a 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -102,8 +102,11 @@ enum {
};

enum {
+ OVL_FSYNC_OFF,
OVL_FSYNC_VOLATILE,
+ OVL_FSYNC_RELAXED,
OVL_FSYNC_AUTO,
+ OVL_FSYNC_ON,
OVL_FSYNC_STRICT,
};

@@ -665,7 +668,8 @@ static inline bool ovl_xino_warn(struct ovl_fs *ofs)

static inline bool ovl_should_sync(struct ovl_fs *ofs)
{
- return ofs->config.fsync_mode != OVL_FSYNC_VOLATILE;
+ return ofs->config.fsync_mode != OVL_FSYNC_OFF &&
+ ofs->config.fsync_mode != OVL_FSYNC_VOLATILE;
}

static inline bool ovl_should_sync_metadata(struct ovl_fs *ofs)
@@ -673,9 +677,15 @@ static inline bool ovl_should_sync_metadata(struct ovl_fs *ofs)
return ofs->config.fsync_mode == OVL_FSYNC_STRICT;
}

-static inline bool ovl_is_volatile(struct ovl_config *config)
+/*
+ * With fsync=on or fsync=strict, syncfs(2) and unmount sync the entire upper
+ * filesystem. Otherwise they only write back the files that were modified
+ * through the overlay.
+ */
+static inline bool ovl_should_sync_upper_fs(struct ovl_fs *ofs)
{
- return config->fsync_mode == OVL_FSYNC_VOLATILE;
+ return ofs->config.fsync_mode == OVL_FSYNC_ON ||
+ ofs->config.fsync_mode == OVL_FSYNC_STRICT;
}

/*
diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c
index 5a15e5478a6b8..9ff266c38cd58 100644
--- a/fs/overlayfs/params.c
+++ b/fs/overlayfs/params.c
@@ -28,6 +28,11 @@ module_param_named(xino_auto, ovl_xino_auto_def, bool, 0644);
MODULE_PARM_DESC(xino_auto,
"Auto enable xino feature");

+static bool ovl_fsync_auto_def = IS_ENABLED(CONFIG_OVERLAY_FS_FSYNC_AUTO);
+module_param_named(fsync_auto, ovl_fsync_auto_def, bool, 0644);
+MODULE_PARM_DESC(fsync_auto,
+ "Default to fsync=auto instead of fsync=on");
+
static bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX);
module_param_named(index, ovl_index_def, bool, 0644);
MODULE_PARM_DESC(index,
@@ -142,8 +147,11 @@ static int ovl_verity_mode_def(void)
}

static const struct constant_table ovl_parameter_fsync[] = {
+ { "off", OVL_FSYNC_OFF },
{ "volatile", OVL_FSYNC_VOLATILE },
+ { "relaxed", OVL_FSYNC_RELAXED },
{ "auto", OVL_FSYNC_AUTO },
+ { "on", OVL_FSYNC_ON },
{ "strict", OVL_FSYNC_STRICT },
{}
};
@@ -155,7 +163,7 @@ static const char *ovl_fsync_mode(struct ovl_config *config)

static int ovl_fsync_mode_def(void)
{
- return OVL_FSYNC_AUTO;
+ return ovl_fsync_auto_def ? OVL_FSYNC_AUTO : OVL_FSYNC_ON;
}

const struct fs_parameter_spec ovl_parameter_spec[] = {
@@ -689,9 +697,11 @@ static int ovl_parse_param(struct fs_context *fc, struct fs_parameter *param)
break;
case Opt_fsync:
config->fsync_mode = result.uint_32;
+ ctx->set.fsync = true;
break;
case Opt_volatile:
config->fsync_mode = OVL_FSYNC_VOLATILE;
+ ctx->set.fsync = true;
break;
case Opt_userxattr:
config->userxattr = true;
@@ -896,8 +906,8 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx,
config->index = false;
}

- if (!config->upperdir && ovl_is_volatile(config)) {
- pr_info("option \"volatile\" is meaningless in a non-upper mount, ignoring it.\n");
+ if (!config->upperdir && set.fsync) {
+ pr_info("options \"fsync\" and \"volatile\" are meaningless in a non-upper mount, ignoring them.\n");
config->fsync_mode = ovl_fsync_mode_def();
}

diff --git a/fs/overlayfs/params.h b/fs/overlayfs/params.h
index ffd53cdd84827..3c864b874af25 100644
--- a/fs/overlayfs/params.h
+++ b/fs/overlayfs/params.h
@@ -15,6 +15,7 @@ struct ovl_opt_set {
bool redirect;
bool nfs_export;
bool index;
+ bool fsync;
};

#define OVL_MAX_STACK 500
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 8bc970748b96b..a44f6334feb69 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -755,8 +755,15 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
goto out;

rename_whiteout = err;
- if (!rename_whiteout)
+ if (!rename_whiteout) {
pr_warn("upper fs does not support RENAME_WHITEOUT.\n");
+ if (ofs->config.fsync_mode == OVL_FSYNC_AUTO)
+ pr_warn("...falling back to fsync=on.\n");
+ }
+
+ if (ofs->config.fsync_mode == OVL_FSYNC_AUTO)
+ ofs->config.fsync_mode = rename_whiteout ? OVL_FSYNC_RELAXED :
+ OVL_FSYNC_ON;

/*
* Check if upper/work fs supports (trusted|user).overlay.* xattr
@@ -810,9 +817,9 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,

/*
* For volatile mount, create a incompat/volatile/dirty file to keep
- * track of it.
+ * track of it. fsync=off allows mounting the overlay again.
*/
- if (ovl_is_volatile(&ofs->config)) {
+ if (ofs->config.fsync_mode == OVL_FSYNC_VOLATILE) {
err = ovl_create_volatile_dirty(ofs);
if (err < 0) {
pr_err("Failed to create volatile/dirty file.\n");
--
2.55.0