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 16/19] fat: Fix missed inode writeback during fsync(2)
Date: Thu, 2 Jul 2026 20:21:13 +0200 [thread overview]
Message-ID: <20260702182057.2832980-35-jack@suse.cz> (raw)
In-Reply-To: <20260702175436.12226-1-jack@suse.cz>
FAT 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.
Fix 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. The slight disadvantage of this approach is that
when fsync(2) of an inode races with rename(2) of the inode, the window
during which inode isn't properly persisted becomes wider.
Signed-off-by: Jan Kara <jack@suse.cz>
---
fs/fat/file.c | 3 +--
fs/fat/inode.c | 63 ++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 54 insertions(+), 12 deletions(-)
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 37e7049b4c8c..8a7585c25207 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -190,8 +190,7 @@ int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
struct inode *fat_inode = MSDOS_SB(inode->i_sb)->fat_inode;
int err;
- err = mmb_fsync_noflush(filp, &MSDOS_I(inode)->i_metadata_bhs,
- start, end, datasync);
+ err = simple_fsync_noflush(filp, start, end, datasync);
if (err)
return err;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 3aa52481ad5c..c4d8ca8736fb 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -623,7 +623,37 @@ struct inode *fat_build_inode(struct super_block *sb,
EXPORT_SYMBOL_GPL(fat_build_inode);
-static int __fat_write_inode(struct inode *inode, int wait);
+static int __fat_write_inode(struct inode *inode);
+
+static int fat_sync_inode_metadata(struct inode *inode,
+ struct writeback_control *wbc)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+ struct buffer_head *bh;
+ loff_t i_pos;
+ sector_t blocknr;
+ int offset;
+
+ if (inode->i_ino == MSDOS_ROOT_INO)
+ return 0;
+ i_pos = fat_i_pos_read(sbi, inode);
+ if (!i_pos)
+ return 0;
+
+ fat_get_blknr_offset(sbi, i_pos, &blocknr, &offset);
+ bh = sb_find_get_block_nonatomic(inode->i_sb, blocknr);
+ /*
+ * Buffer already written? We leave buffer_dirty check for
+ * sync_dirty_buffer() for proper synchronization with ongoing IO.
+ */
+ if (!bh || !buffer_uptodate(bh)) {
+ brelse(bh);
+ return 0;
+ }
+ sync_dirty_buffer(bh);
+ brelse(bh);
+ return mmb_sync(&MSDOS_I(inode)->i_metadata_bhs);
+}
static void fat_free_eofblocks(struct inode *inode)
{
@@ -640,7 +670,13 @@ static void fat_free_eofblocks(struct inode *inode)
* any corruption on the next access to the cluster
* chain for the file.
*/
- err = __fat_write_inode(inode, inode_needs_sync(inode));
+ err = __fat_write_inode(inode);
+ if (!err && inode_needs_sync(inode)) {
+ struct writeback_control wbc = {
+ .sync_mode = WB_SYNC_ALL,
+ };
+ err = fat_sync_inode_metadata(inode, &wbc);
+ }
if (err) {
fat_msg(inode->i_sb, KERN_WARNING, "Failed to "
"update on disk inode for unused "
@@ -854,7 +890,7 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
-static int __fat_write_inode(struct inode *inode, int wait)
+static int __fat_write_inode(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
@@ -863,7 +899,7 @@ static int __fat_write_inode(struct inode *inode, int wait)
struct timespec64 mtime;
loff_t i_pos;
sector_t blocknr;
- int err, offset;
+ int offset;
if (inode->i_ino == MSDOS_ROOT_INO)
return 0;
@@ -907,11 +943,9 @@ static int __fat_write_inode(struct inode *inode, int wait)
}
spin_unlock(&sbi->inode_hash_lock);
mark_buffer_dirty(bh);
- err = 0;
- if (wait)
- err = sync_dirty_buffer(bh);
brelse(bh);
- return err;
+ set_inode_metadata_writeback(inode);
+ return 0;
}
static int fat_write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -925,14 +959,22 @@ static int fat_write_inode(struct inode *inode, struct writeback_control *wbc)
err = fat_clusters_flush(sb);
mutex_unlock(&MSDOS_SB(sb)->s_lock);
} else
- err = __fat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
+ err = __fat_write_inode(inode);
return err;
}
int fat_sync_inode(struct inode *inode)
{
- return __fat_write_inode(inode, 1);
+ int err;
+ struct writeback_control wbc = {
+ .sync_mode = WB_SYNC_ALL,
+ };
+
+ err = __fat_write_inode(inode);
+ if (err)
+ return err;
+ return fat_sync_inode_metadata(inode, &wbc);
}
EXPORT_SYMBOL_GPL(fat_sync_inode);
@@ -942,6 +984,7 @@ static const struct super_operations fat_sops = {
.alloc_inode = fat_alloc_inode,
.free_inode = fat_free_inode,
.write_inode = fat_write_inode,
+ .sync_inode_metadata = fat_sync_inode_metadata,
.evict_inode = fat_evict_inode,
.put_super = fat_put_super,
.statfs = fat_statfs,
--
2.51.0
next prev 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 ` [PATCH v3 08/19] ext2: Fix data integrity writeout issues Jan Kara
2026-07-02 18:21 ` [PATCH v3 09/19] udf: " 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 ` Jan Kara [this message]
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-35-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