exfat: do not clear volume dirty flag during sync
authorYuezhang Mo <Yuezhang.Mo@sony.com>
Thu, 10 Apr 2025 23:26:14 +0000 (17:26 -0600)
committerNamjae Jeon <linkinjeon@kernel.org>
Mon, 26 May 2025 11:25:23 +0000 (20:25 +0900)
xfstests generic/482 tests the file system consistency after each
FUA operation. It fails when run on exfat.

exFAT clears the volume dirty flag with a FUA operation during sync.
Since s_lock is not held when data is being written to a file, sync
can be executed at the same time. When data is being written to a
file, the FAT chain is updated first, and then the file size is
updated. If sync is executed between updating them, the length of the
FAT chain may be inconsistent with the file size.

To avoid the situation where the file system is inconsistent but the
volume dirty flag is cleared, this commit moves the clearing of the
volume dirty flag from exfat_fs_sync() to exfat_put_super(), so that
the volume dirty flag is not cleared until unmounting. After the
move, there is no additional action during sync, so exfat_fs_sync()
can be deleted.

Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
Signed-off-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/exfat/super.c

index 8465033a6cf0c0f1026ae41f88841d391798dcfc..7ed858937d45d2d4db8f842d5a4b08b0a3cdb70e 100644 (file)
@@ -36,31 +36,12 @@ static void exfat_put_super(struct super_block *sb)
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
 
        mutex_lock(&sbi->s_lock);
+       exfat_clear_volume_dirty(sb);
        exfat_free_bitmap(sbi);
        brelse(sbi->boot_bh);
        mutex_unlock(&sbi->s_lock);
 }
 
-static int exfat_sync_fs(struct super_block *sb, int wait)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       int err = 0;
-
-       if (unlikely(exfat_forced_shutdown(sb)))
-               return 0;
-
-       if (!wait)
-               return 0;
-
-       /* If there are some dirty buffers in the bdev inode */
-       mutex_lock(&sbi->s_lock);
-       sync_blockdev(sb->s_bdev);
-       if (exfat_clear_volume_dirty(sb))
-               err = -EIO;
-       mutex_unlock(&sbi->s_lock);
-       return err;
-}
-
 static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
@@ -219,7 +200,6 @@ static const struct super_operations exfat_sops = {
        .write_inode    = exfat_write_inode,
        .evict_inode    = exfat_evict_inode,
        .put_super      = exfat_put_super,
-       .sync_fs        = exfat_sync_fs,
        .statfs         = exfat_statfs,
        .show_options   = exfat_show_options,
        .shutdown       = exfat_shutdown,
@@ -751,10 +731,14 @@ static void exfat_free(struct fs_context *fc)
 
 static int exfat_reconfigure(struct fs_context *fc)
 {
+       struct super_block *sb = fc->root->d_sb;
        fc->sb_flags |= SB_NODIRATIME;
 
-       /* volume flag will be updated in exfat_sync_fs */
-       sync_filesystem(fc->root->d_sb);
+       sync_filesystem(sb);
+       mutex_lock(&EXFAT_SB(sb)->s_lock);
+       exfat_clear_volume_dirty(sb);
+       mutex_unlock(&EXFAT_SB(sb)->s_lock);
+
        return 0;
 }