Linux EXT4 FS development
 help / color / mirror / Atom feed
From: Jan Kara <jack@suse.cz>
To: <linux-fsdevel@vger.kernel.org>
Cc: Christian Brauner <brauner@kernel.org>,
	aivazian.tigran@gmail.com, Ted Tso <tytso@mit.edu>,
	<linux-ext4@vger.kernel.org>,
	OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>,
	Jan Kara <jack@suse.cz>
Subject: [PATCH v3 08/19] ext2: Fix data integrity writeout issues
Date: Thu,  2 Jul 2026 20:21:05 +0200	[thread overview]
Message-ID: <20260702182057.2832980-27-jack@suse.cz> (raw)
In-Reply-To: <20260702175436.12226-1-jack@suse.cz>

Ext2 could fail to properly write out inode on fsync(2) due to races
with WB_SYNC_NONE writeback. Several racing fsyncs could also result in
some fsync returning earlier than all metadata buffers were properly
persisted. Finally DIRSYNC handling was not properly persisting all
inode related metadata.

Fix all these issues by using new .sync_inode_metadata method which
makes sure all inode related metadata is written to disk during any
WB_SYNC_ALL writeback.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/ext2/dir.c   |  2 +-
 fs/ext2/ext2.h  |  3 +--
 fs/ext2/file.c  | 17 +----------------
 fs/ext2/inode.c | 35 +++++++++++++++++++++++------------
 fs/ext2/super.c |  1 +
 5 files changed, 27 insertions(+), 31 deletions(-)

diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 278d4be8ecbe..e17bbc7598c1 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -734,6 +734,6 @@ const struct file_operations ext2_dir_operations = {
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= ext2_compat_ioctl,
 #endif
-	.fsync		= ext2_fsync,
+	.fsync		= simple_fsync,
 	.setlease	= generic_setlease,
 };
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 79f7b395258c..5642451bf191 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -735,6 +735,7 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
 /* inode.c */
 extern struct inode *ext2_iget (struct super_block *, unsigned long);
 extern int ext2_write_inode (struct inode *, struct writeback_control *);
+extern int ext2_sync_inode_metadata(struct inode *, struct writeback_control *);
 extern void ext2_evict_inode(struct inode *);
 void ext2_write_failed(struct address_space *mapping, loff_t to);
 extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
@@ -772,8 +773,6 @@ extern void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es,
 extern const struct file_operations ext2_dir_operations;
 
 /* file.c */
-extern int ext2_fsync(struct file *file, loff_t start, loff_t end,
-		      int datasync);
 extern const struct inode_operations ext2_file_inode_operations;
 extern const struct file_operations ext2_file_operations;
 
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 8dca9ec4cacd..b9020df7d89e 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -47,21 +47,6 @@ static int ext2_release_file (struct inode * inode, struct file * filp)
 	return 0;
 }
 
-int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
-{
-	int ret;
-	struct inode *inode = file->f_mapping->host;
-	struct super_block *sb = inode->i_sb;
-
-	ret = mmb_fsync(file, &EXT2_I(inode)->i_metadata_bhs,
-			start, end, datasync);
-	if (ret == -EIO)
-		/* We don't really know where the IO error happened... */
-		ext2_error(sb, __func__,
-			   "detected IO error when writing metadata buffers");
-	return ret;
-}
-
 static ssize_t ext2_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
 	struct file *file = iocb->ki_filp;
@@ -213,7 +198,7 @@ const struct file_operations ext2_file_operations = {
 	.mmap_prepare	= generic_file_mmap_prepare,
 	.open		= ext2_file_open,
 	.release	= ext2_release_file,
-	.fsync		= ext2_fsync,
+	.fsync		= simple_fsync,
 	.get_unmapped_area = thp_get_unmapped_area,
 	.splice_read	= filemap_splice_read,
 	.splice_write	= iter_file_splice_write,
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 48862e73610c..51656641c4e5 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1563,20 +1563,31 @@ int ext2_write_inode(struct inode *inode, struct writeback_control *wbc)
 	} else for (n = 0; n < EXT2_N_BLOCKS; n++)
 		raw_inode->i_block[n] = ei->i_data[n];
 	mark_buffer_dirty(bh);
-	/*
-	 * For sync(2) the generic code will call sync_blockdev() to write
-	 * all metadata more efficiently.
-	 */
-	if (wbc->sync_mode == WB_SYNC_ALL && !wbc->for_sync) {
-		sync_dirty_buffer(bh);
-		if (buffer_req(bh) && !buffer_uptodate(bh)) {
-			printk ("IO error syncing ext2 inode [%s:%08lx]\n",
-				sb->s_id, (unsigned long) ino);
-			err = -EIO;
-		}
-	}
 	ei->i_state &= ~EXT2_STATE_NEW;
 	brelse (bh);
+	set_inode_metadata_writeback(inode);
+	return err;
+}
+
+int ext2_sync_inode_metadata(struct inode *inode, struct writeback_control *wbc)
+{
+	struct buffer_head *bh;
+	struct ext2_inode *raw_inode = ext2_get_inode(inode->i_sb, inode->i_ino,
+						      &bh);
+	int err = 0;
+
+	if (IS_ERR(raw_inode))
+		return -EIO;
+	sync_dirty_buffer(bh);
+	if (buffer_write_io_error(bh)) {
+		printk("IO error syncing ext2 inode [%s:%08lx]\n",
+		       inode->i_sb->s_id, (unsigned long)inode->i_ino);
+		err = -EIO;
+		goto out;
+	}
+	err = mmb_sync(&EXT2_I(inode)->i_metadata_bhs);
+out:
+	brelse(bh);
 	return err;
 }
 
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 3999f8f3b156..a40f530872a4 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -362,6 +362,7 @@ static const struct super_operations ext2_sops = {
 	.alloc_inode	= ext2_alloc_inode,
 	.free_inode	= ext2_free_in_core_inode,
 	.write_inode	= ext2_write_inode,
+	.sync_inode_metadata = ext2_sync_inode_metadata,
 	.evict_inode	= ext2_evict_inode,
 	.put_super	= ext2_put_super,
 	.sync_fs	= ext2_sync_fs,
-- 
2.51.0


  parent reply	other threads:[~2026-07-02 18:22 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-02 18:20 [PATCH v3 0/19] fs: Fix missed inode write during fsync Jan Kara
2026-07-02 18:20 ` [PATCH v3 01/19] affs: Drop support for metadata bh tracking Jan Kara
2026-07-02 18:20 ` [PATCH v3 02/19] fs: Fix possible UAF in mark_buffer_write_io_error() Jan Kara
2026-07-02 18:21 ` [PATCH v3 03/19] fs: Fix missed inode writeback when racing with __writeback_single_inode Jan Kara
2026-07-02 18:21 ` [PATCH v3 04/19] ext4: Allocate mapping_metadata_bhs struct on demand Jan Kara
2026-07-03 10:00   ` Christian Brauner
2026-07-03 16:10     ` Jan Kara
2026-07-02 18:21 ` [PATCH v3 05/19] ext2: Drop __ext2_write_inode() Jan Kara
2026-07-02 18:21 ` [PATCH v3 06/19] ext2: Avoid unnecessary inode buffer writeback for sync(2) Jan Kara
2026-07-02 18:21 ` [PATCH v3 07/19] fs: Provide way for filesystem to wait for metadata writeback Jan Kara
2026-07-03 10:06   ` Christian Brauner
2026-07-03 16:12     ` Jan Kara
2026-07-02 18:21 ` Jan Kara [this message]
2026-07-02 18:21 ` [PATCH v3 09/19] udf: Fix data integrity writeout issues Jan Kara
2026-07-02 18:21 ` [PATCH v3 10/19] udf: Use sync_inode_metadata() to writeout IS_SYNC inode Jan Kara
2026-07-02 18:21 ` [PATCH v3 11/19] udf: Write all metadata for IS_SYNC inodes Jan Kara
2026-07-02 18:21 ` [PATCH v3 12/19] udf: Fold udf_update_inode() into udf_write_inode() Jan Kara
2026-07-02 18:21 ` [PATCH v3 13/19] bfs: Fix data integrity writeout issues Jan Kara
2026-07-02 18:21 ` [PATCH v3 14/19] minix: " Jan Kara
2026-07-02 18:21 ` [PATCH v3 15/19] ext4: Fix data integrity writeout issues in nojournal mode Jan Kara
2026-07-02 18:21 ` [PATCH v3 16/19] fat: Fix missed inode writeback during fsync(2) Jan Kara
2026-07-02 18:21 ` [PATCH v3 17/19] fat: Remove some superfluous sync_dirty_buffer() calls Jan Kara
2026-07-02 18:21 ` [PATCH v3 18/19] fat: Replace fat_sync_inode() with sync_inode_metadata() Jan Kara
2026-07-02 18:21 ` [PATCH v3 19/19] vfs: Remove mmb_fsync() Jan Kara
2026-07-03 10:09 ` [PATCH v3 0/19] fs: Fix missed inode write during fsync Christian Brauner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260702182057.2832980-27-jack@suse.cz \
    --to=jack@suse.cz \
    --cc=aivazian.tigran@gmail.com \
    --cc=brauner@kernel.org \
    --cc=hirofumi@mail.parknet.co.jp \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox