Commit 7e85bc6c authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: add helpers to attach quotas to inodes

Add a helper routine to attach quota information to inodes that are
about to undergo repair.  If that fails, we need to schedule a
quotacheck for the next mount but allow the corrupted metadata repair to
continue.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarAllison Henderson <allison.henderson@oracle.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent 04a2b7b2
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "xfs_extent_busy.h" #include "xfs_extent_busy.h"
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
#include "xfs_trans_space.h" #include "xfs_trans_space.h"
#include "xfs_quota.h"
#include "scrub/xfs_scrub.h" #include "scrub/xfs_scrub.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
...@@ -1026,3 +1027,63 @@ xfs_repair_find_ag_btree_roots( ...@@ -1026,3 +1027,63 @@ xfs_repair_find_ag_btree_roots(
return error; return error;
} }
/* Force a quotacheck the next time we mount. */
void
xfs_repair_force_quotacheck(
struct xfs_scrub_context *sc,
uint dqtype)
{
uint flag;
flag = xfs_quota_chkd_flag(dqtype);
if (!(flag & sc->mp->m_qflags))
return;
sc->mp->m_qflags &= ~flag;
spin_lock(&sc->mp->m_sb_lock);
sc->mp->m_sb.sb_qflags &= ~flag;
spin_unlock(&sc->mp->m_sb_lock);
xfs_log_sb(sc->tp);
}
/*
* Attach dquots to this inode, or schedule quotacheck to fix them.
*
* This function ensures that the appropriate dquots are attached to an inode.
* We cannot allow the dquot code to allocate an on-disk dquot block here
* because we're already in transaction context with the inode locked. The
* on-disk dquot should already exist anyway. If the quota code signals
* corruption or missing quota information, schedule quotacheck, which will
* repair corruptions in the quota metadata.
*/
int
xfs_repair_ino_dqattach(
struct xfs_scrub_context *sc)
{
int error;
error = xfs_qm_dqattach_locked(sc->ip, false);
switch (error) {
case -EFSBADCRC:
case -EFSCORRUPTED:
case -ENOENT:
xfs_err_ratelimited(sc->mp,
"inode %llu repair encountered quota error %d, quotacheck forced.",
(unsigned long long)sc->ip->i_ino, error);
if (XFS_IS_UQUOTA_ON(sc->mp) && !sc->ip->i_udquot)
xfs_repair_force_quotacheck(sc, XFS_DQ_USER);
if (XFS_IS_GQUOTA_ON(sc->mp) && !sc->ip->i_gdquot)
xfs_repair_force_quotacheck(sc, XFS_DQ_GROUP);
if (XFS_IS_PQUOTA_ON(sc->mp) && !sc->ip->i_pdquot)
xfs_repair_force_quotacheck(sc, XFS_DQ_PROJ);
/* fall through */
case -ESRCH:
error = 0;
break;
default:
break;
}
return error;
}
...@@ -96,6 +96,8 @@ int xfs_repair_find_ag_btree_roots(struct xfs_scrub_context *sc, ...@@ -96,6 +96,8 @@ int xfs_repair_find_ag_btree_roots(struct xfs_scrub_context *sc,
struct xfs_buf *agf_bp, struct xfs_buf *agf_bp,
struct xfs_repair_find_ag_btree *btree_info, struct xfs_repair_find_ag_btree *btree_info,
struct xfs_buf *agfl_bp); struct xfs_buf *agfl_bp);
void xfs_repair_force_quotacheck(struct xfs_scrub_context *sc, uint dqtype);
int xfs_repair_ino_dqattach(struct xfs_scrub_context *sc);
/* Metadata repairers */ /* Metadata repairers */
......
...@@ -48,6 +48,22 @@ struct xfs_trans; ...@@ -48,6 +48,22 @@ struct xfs_trans;
(XFS_IS_PQUOTA_ON(mp) && \ (XFS_IS_PQUOTA_ON(mp) && \
(mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0)) (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0))
static inline uint
xfs_quota_chkd_flag(
uint dqtype)
{
switch (dqtype) {
case XFS_DQ_USER:
return XFS_UQUOTA_CHKD;
case XFS_DQ_GROUP:
return XFS_GQUOTA_CHKD;
case XFS_DQ_PROJ:
return XFS_PQUOTA_CHKD;
default:
return 0;
}
}
/* /*
* The structure kept inside the xfs_trans_t keep track of dquot changes * The structure kept inside the xfs_trans_t keep track of dquot changes
* within a transaction and apply them later. * within a transaction and apply them later.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment