[PATCH v6 2/9] fs: add sync_fs_and_bdev()
From: Josef Bacik
Date: Tue Nov 10 2026 - 11:00:05 EST
sync_filesystem() writes the inodes, calls ->sync_fs() and writes the block
device, first without waiting and then with.
overlayfs is about to write the inodes of its upper filesystem by itself,
only those that were modified through the overlay, and needs the other two
steps as they are. Move them to a helper so that overlayfs does not have
to know what they are.
sync_filesystem() calls the inner helper, so it still tests for a read-only
filesystem and for s_umount once. The exported function does both tests
for its callers.
No functional change intended.
Suggested-by: Christian Brauner <brauner@xxxxxxxxxx>
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
---
fs/sync.c | 52 +++++++++++++++++++++++++++++++++++++++-------------
include/linux/fs.h | 1 +
2 files changed, 40 insertions(+), 13 deletions(-)
diff --git a/fs/sync.c b/fs/sync.c
index 0681bfcb2da6..c5e49914918a 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -22,6 +22,42 @@
#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
SYNC_FILE_RANGE_WAIT_AFTER)
+static int __sync_fs_and_bdev(struct super_block *sb, bool wait)
+{
+ int ret;
+
+ if (sb->s_op->sync_fs) {
+ ret = sb->s_op->sync_fs(sb, wait);
+ if (ret)
+ return ret;
+ }
+ if (!wait)
+ return sync_blockdev_nowait(sb->s_bdev);
+ return sync_blockdev(sb->s_bdev);
+}
+
+/**
+ * sync_fs_and_bdev - call ->sync_fs() and write the block device
+ * @sb: the superblock, the caller holds s_umount
+ * @wait: wait for the I/O to complete
+ *
+ * These are the steps of sync_filesystem() that follow the writing of the
+ * inodes. This is for a caller that has already written the inodes it cares
+ * about. Like sync_filesystem() it does nothing on a read-only filesystem.
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int sync_fs_and_bdev(struct super_block *sb, bool wait)
+{
+ WARN_ON(!rwsem_is_locked(&sb->s_umount));
+
+ if (sb_rdonly(sb))
+ return 0;
+
+ return __sync_fs_and_bdev(sb, wait);
+}
+EXPORT_SYMBOL_GPL(sync_fs_and_bdev);
+
/*
* Write out and wait upon all dirty data associated with this
* superblock. Filesystem data as well as the underlying block
@@ -29,7 +65,7 @@
*/
int sync_filesystem(struct super_block *sb)
{
- int ret = 0;
+ int ret;
/*
* We need to be protected against the filesystem going from
@@ -52,22 +88,12 @@ int sync_filesystem(struct super_block *sb)
* at a time.
*/
writeback_inodes_sb(sb, WB_REASON_SYNC);
- if (sb->s_op->sync_fs) {
- ret = sb->s_op->sync_fs(sb, 0);
- if (ret)
- return ret;
- }
- ret = sync_blockdev_nowait(sb->s_bdev);
+ ret = __sync_fs_and_bdev(sb, false);
if (ret)
return ret;
sync_inodes_sb(sb);
- if (sb->s_op->sync_fs) {
- ret = sb->s_op->sync_fs(sb, 1);
- if (ret)
- return ret;
- }
- return sync_blockdev(sb->s_bdev);
+ return __sync_fs_and_bdev(sb, true);
}
EXPORT_SYMBOL(sync_filesystem);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b5485f2c1f2b..094a4be6828c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2617,6 +2617,7 @@ extern void __init vfs_caches_init(void);
void emergency_thaw_all(void);
extern int sync_filesystem(struct super_block *);
+int sync_fs_and_bdev(struct super_block *sb, bool wait);
extern const struct file_operations def_blk_fops;
extern const struct file_operations def_chr_fops;
--
2.55.0