Skip to content

Commit

Permalink
Merge tag 'vfs-5.17-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/x…
Browse files Browse the repository at this point in the history
…fs-linux

Pull vfs fixes from Darrick Wong:
 "I was auditing the sync_fs code paths recently and noticed that most
  callers of ->sync_fs ignore its return value (and many implementations
  never return nonzero even if the fs is broken!), which means that
  internal fs errors and corruption are not passed up to userspace
  callers of syncfs(2) or FIFREEZE. Hence fixing the common code and
  XFS, and I'll start working on the ext4/btrfs folks if this is merged.

  Summary:

   - Fix a bug where callers of ->sync_fs (e.g. sync_filesystem and
     syncfs(2)) ignore the return value.

   - Fix a bug where callers of sync_filesystem (e.g. fs freeze) ignore
     the return value.

   - Fix a bug in XFS where xfs_fs_sync_fs never passed back error
     returns"

* tag 'vfs-5.17-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: return errors in xfs_fs_sync_fs
  quota: make dquot_quota_sync return errors from ->sync_fs
  vfs: make sync_filesystem return errors from ->sync_fs
  vfs: make freeze_super abort when sync_filesystem returns error
  • Loading branch information
torvalds committed Feb 5, 2022
2 parents 524446e + 2d86293 commit ea7b3e6
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 17 deletions.
11 changes: 8 additions & 3 deletions fs/quota/dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -690,9 +690,14 @@ int dquot_quota_sync(struct super_block *sb, int type)
/* This is not very clever (and fast) but currently I don't know about
* any other simple way of getting quota data to disk and we must get
* them there for userspace to be visible... */
if (sb->s_op->sync_fs)
sb->s_op->sync_fs(sb, 1);
sync_blockdev(sb->s_bdev);
if (sb->s_op->sync_fs) {
ret = sb->s_op->sync_fs(sb, 1);
if (ret)
return ret;
}
ret = sync_blockdev(sb->s_bdev);
if (ret)
return ret;

/*
* Now when everything is written we can discard the pagecache so
Expand Down
19 changes: 12 additions & 7 deletions fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1616,11 +1616,9 @@ static void lockdep_sb_freeze_acquire(struct super_block *sb)
percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_);
}

static void sb_freeze_unlock(struct super_block *sb)
static void sb_freeze_unlock(struct super_block *sb, int level)
{
int level;

for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--)
for (level--; level >= 0; level--)
percpu_up_write(sb->s_writers.rw_sem + level);
}

Expand Down Expand Up @@ -1691,7 +1689,14 @@ int freeze_super(struct super_block *sb)
sb_wait_write(sb, SB_FREEZE_PAGEFAULT);

/* All writers are done so after syncing there won't be dirty data */
sync_filesystem(sb);
ret = sync_filesystem(sb);
if (ret) {
sb->s_writers.frozen = SB_UNFROZEN;
sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT);
wake_up(&sb->s_writers.wait_unfrozen);
deactivate_locked_super(sb);
return ret;
}

/* Now wait for internal filesystem counter */
sb->s_writers.frozen = SB_FREEZE_FS;
Expand All @@ -1703,7 +1708,7 @@ int freeze_super(struct super_block *sb)
printk(KERN_ERR
"VFS:Filesystem freeze failed\n");
sb->s_writers.frozen = SB_UNFROZEN;
sb_freeze_unlock(sb);
sb_freeze_unlock(sb, SB_FREEZE_FS);
wake_up(&sb->s_writers.wait_unfrozen);
deactivate_locked_super(sb);
return ret;
Expand Down Expand Up @@ -1748,7 +1753,7 @@ static int thaw_super_locked(struct super_block *sb)
}

sb->s_writers.frozen = SB_UNFROZEN;
sb_freeze_unlock(sb);
sb_freeze_unlock(sb, SB_FREEZE_FS);
out:
wake_up(&sb->s_writers.wait_unfrozen);
deactivate_locked_super(sb);
Expand Down
18 changes: 12 additions & 6 deletions fs/sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*/
int sync_filesystem(struct super_block *sb)
{
int ret;
int ret = 0;

/*
* We need to be protected against the filesystem going from
Expand All @@ -52,15 +52,21 @@ int sync_filesystem(struct super_block *sb)
* at a time.
*/
writeback_inodes_sb(sb, WB_REASON_SYNC);
if (sb->s_op->sync_fs)
sb->s_op->sync_fs(sb, 0);
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);
if (ret < 0)
if (ret)
return ret;

sync_inodes_sb(sb);
if (sb->s_op->sync_fs)
sb->s_op->sync_fs(sb, 1);
if (sb->s_op->sync_fs) {
ret = sb->s_op->sync_fs(sb, 1);
if (ret)
return ret;
}
return sync_blockdev(sb->s_bdev);
}
EXPORT_SYMBOL(sync_filesystem);
Expand Down
6 changes: 5 additions & 1 deletion fs/xfs/xfs_super.c
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ xfs_fs_sync_fs(
int wait)
{
struct xfs_mount *mp = XFS_M(sb);
int error;

trace_xfs_fs_sync_fs(mp, __return_address);

Expand All @@ -744,7 +745,10 @@ xfs_fs_sync_fs(
if (!wait)
return 0;

xfs_log_force(mp, XFS_LOG_SYNC);
error = xfs_log_force(mp, XFS_LOG_SYNC);
if (error)
return error;

if (laptop_mode) {
/*
* The disk must be active because we're syncing.
Expand Down

0 comments on commit ea7b3e6

Please sign in to comment.