xfs: add helpers to attach quotas to inodes
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 30 May 2018 05:18:11 +0000 (22:18 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 30 May 2018 15:03:15 +0000 (08:03 -0700)
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: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/scrub/repair.c
fs/xfs/scrub/repair.h
fs/xfs/xfs_quota.h

index 877488c..e3e8fba 100644 (file)
@@ -42,6 +42,7 @@
 #include "xfs_extent_busy.h"
 #include "xfs_ag_resv.h"
 #include "xfs_trans_space.h"
+#include "xfs_quota.h"
 #include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
@@ -1026,3 +1027,63 @@ xfs_repair_find_ag_btree_roots(
 
        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;
+}
index c922ef0..e9213e7 100644 (file)
@@ -96,6 +96,8 @@ int xfs_repair_find_ag_btree_roots(struct xfs_scrub_context *sc,
                struct xfs_buf *agf_bp,
                struct xfs_repair_find_ag_btree *btree_info,
                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 */
 
index 1c79ebb..3edf52b 100644 (file)
@@ -48,6 +48,22 @@ struct xfs_trans;
         (XFS_IS_PQUOTA_ON(mp) && \
                (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
  * within a transaction and apply them later.