xfs: abort consistently on dquot flush failure

The dquot flush handler effectively aborts the dquot flush if the
filesystem is already shut down, but doesn't actually shut down if
the flush fails. Update xfs_qm_dqflush() to consistently abort the
dquot flush and shutdown the fs if the flush fails with an
unexpected error.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
Brian Foster 2020-05-06 13:25:22 -07:00 committed by Darrick J. Wong
parent 629dcb38dc
commit b707fffda6

View file

@ -1068,6 +1068,7 @@ xfs_qm_dqflush(
struct xfs_buf **bpp) struct xfs_buf **bpp)
{ {
struct xfs_mount *mp = dqp->q_mount; struct xfs_mount *mp = dqp->q_mount;
struct xfs_log_item *lip = &dqp->q_logitem.qli_item;
struct xfs_buf *bp; struct xfs_buf *bp;
struct xfs_dqblk *dqb; struct xfs_dqblk *dqb;
struct xfs_disk_dquot *ddqp; struct xfs_disk_dquot *ddqp;
@ -1083,32 +1084,16 @@ xfs_qm_dqflush(
xfs_qm_dqunpin_wait(dqp); xfs_qm_dqunpin_wait(dqp);
/*
* This may have been unpinned because the filesystem is shutting
* down forcibly. If that's the case we must not write this dquot
* to disk, because the log record didn't make it to disk.
*
* We also have to remove the log item from the AIL in this case,
* as we wait for an emptry AIL as part of the unmount process.
*/
if (XFS_FORCED_SHUTDOWN(mp)) {
struct xfs_log_item *lip = &dqp->q_logitem.qli_item;
dqp->dq_flags &= ~XFS_DQ_DIRTY;
xfs_trans_ail_remove(lip, SHUTDOWN_CORRUPT_INCORE);
error = -EIO;
goto out_unlock;
}
/* /*
* Get the buffer containing the on-disk dquot * Get the buffer containing the on-disk dquot
*/ */
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno, error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK, mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK,
&bp, &xfs_dquot_buf_ops); &bp, &xfs_dquot_buf_ops);
if (error) if (error == -EAGAIN)
goto out_unlock; goto out_unlock;
if (error)
goto out_abort;
/* /*
* Calculate the location of the dquot inside the buffer. * Calculate the location of the dquot inside the buffer.
@ -1123,9 +1108,8 @@ xfs_qm_dqflush(
xfs_alert(mp, "corrupt dquot ID 0x%x in memory at %pS", xfs_alert(mp, "corrupt dquot ID 0x%x in memory at %pS",
be32_to_cpu(dqp->q_core.d_id), fa); be32_to_cpu(dqp->q_core.d_id), fa);
xfs_buf_relse(bp); xfs_buf_relse(bp);
xfs_dqfunlock(dqp); error = -EFSCORRUPTED;
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); goto out_abort;
return -EFSCORRUPTED;
} }
/* This is the only portion of data that needs to persist */ /* This is the only portion of data that needs to persist */
@ -1174,6 +1158,10 @@ xfs_qm_dqflush(
*bpp = bp; *bpp = bp;
return 0; return 0;
out_abort:
dqp->dq_flags &= ~XFS_DQ_DIRTY;
xfs_trans_ail_remove(lip, SHUTDOWN_CORRUPT_INCORE);
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
out_unlock: out_unlock:
xfs_dqfunlock(dqp); xfs_dqfunlock(dqp);
return error; return error;