Merge tag 'vfs-5.17-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-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
This commit is contained in:
@ -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
|
||||
|
19
fs/super.c
19
fs/super.c
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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);
|
||||
|
18
fs/sync.c
18
fs/sync.c
@ -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
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
@ -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.
|
||||
|
Reference in New Issue
Block a user