[PATCH v3 2/8] ovl: setup overlayfs' private bdi

From: Josef Bacik

Date: Wed Nov 04 2026 - 19:31:48 EST


From: Chengguang Xu <charliecgxu@xxxxxxxxxxx>

Setup overlayfs' private bdi so that we can collect
overlayfs' own dirty inodes.

Signed-off-by: Chengguang Xu <charliecgxu@xxxxxxxxxxx>
[josef: only for an overlay that tracks dirty inodes, add
ovl_tracks_dirty()]
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
---
fs/overlayfs/overlayfs.h | 18 ++++++++++++++++++
fs/overlayfs/super.c | 10 ++++++++++
2 files changed, 28 insertions(+)

diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 444e28c09145..0ef81c7a9701 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -7,6 +7,7 @@
#include <linux/kernel.h>
#include <linux/uuid.h>
#include <linux/fs.h>
+#include <linux/backing-dev.h>
#include <linux/fsverity.h>
#include <linux/namei.h>
#include <linux/posix_acl.h>
@@ -683,6 +684,23 @@ static inline bool ovl_should_sync_upper_fs(struct ovl_fs *ofs)
ofs->config.fsync_mode == OVL_FSYNC_STRICT;
}

+/*
+ * Does this overlay track the upper inodes that are modified through it, so
+ * that syncfs() and unmount only have to sync those?
+ *
+ * Only with fsync=relaxed. In the other modes the overlay never syncs, or it
+ * syncs the entire upper filesystem. fsync=auto does not count until it has
+ * been resolved. sync_filesystem() does not write any inodes of a filesystem
+ * that has no writeback, like tmpfs, and nothing ever clears their dirty flags.
+ */
+static inline bool ovl_tracks_dirty(struct ovl_fs *ofs)
+{
+ if (!ovl_upper_mnt(ofs) || ofs->config.fsync_mode != OVL_FSYNC_RELAXED)
+ return false;
+
+ return ovl_upper_mnt(ofs)->mnt_sb->s_bdi != &noop_backing_dev_info;
+}
+
/*
* To avoid regressions in existing setups with overlay lower offline changes,
* we allow lower changes only if none of the new features are used.
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 4500038d6941..efa4d862039c 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1479,6 +1479,16 @@ static int ovl_fill_super_creds(struct fs_context *fc, struct super_block *sb)
if (!ofs->workdir)
sb->s_flags |= SB_RDONLY;

+ /*
+ * Dirty overlay inodes go on the lists of this bdi.
+ * ovl_get_workdir() has resolved fsync=auto.
+ */
+ if (ovl_tracks_dirty(ofs)) {
+ err = super_setup_bdi(sb);
+ if (err)
+ return err;
+ }
+
sb->s_stack_depth = upper_sb->s_stack_depth;
sb->s_time_gran = upper_sb->s_time_gran;
}

--
2.55.0