Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2017 Oracle.  All Rights Reserved.
0004  * Author: Darrick J. Wong <darrick.wong@oracle.com>
0005  */
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_trans_resv.h"
0011 #include "xfs_mount.h"
0012 #include "xfs_log_format.h"
0013 #include "xfs_trans.h"
0014 #include "xfs_inode.h"
0015 #include "xfs_quota.h"
0016 #include "xfs_qm.h"
0017 #include "scrub/scrub.h"
0018 #include "scrub/common.h"
0019 
0020 /* Convert a scrub type code to a DQ flag, or return 0 if error. */
0021 static inline xfs_dqtype_t
0022 xchk_quota_to_dqtype(
0023     struct xfs_scrub    *sc)
0024 {
0025     switch (sc->sm->sm_type) {
0026     case XFS_SCRUB_TYPE_UQUOTA:
0027         return XFS_DQTYPE_USER;
0028     case XFS_SCRUB_TYPE_GQUOTA:
0029         return XFS_DQTYPE_GROUP;
0030     case XFS_SCRUB_TYPE_PQUOTA:
0031         return XFS_DQTYPE_PROJ;
0032     default:
0033         return 0;
0034     }
0035 }
0036 
0037 /* Set us up to scrub a quota. */
0038 int
0039 xchk_setup_quota(
0040     struct xfs_scrub    *sc)
0041 {
0042     xfs_dqtype_t        dqtype;
0043     int         error;
0044 
0045     if (!XFS_IS_QUOTA_ON(sc->mp))
0046         return -ENOENT;
0047 
0048     dqtype = xchk_quota_to_dqtype(sc);
0049     if (dqtype == 0)
0050         return -EINVAL;
0051 
0052     if (!xfs_this_quota_on(sc->mp, dqtype))
0053         return -ENOENT;
0054 
0055     error = xchk_setup_fs(sc);
0056     if (error)
0057         return error;
0058     sc->ip = xfs_quota_inode(sc->mp, dqtype);
0059     xfs_ilock(sc->ip, XFS_ILOCK_EXCL);
0060     sc->ilock_flags = XFS_ILOCK_EXCL;
0061     return 0;
0062 }
0063 
0064 /* Quotas. */
0065 
0066 struct xchk_quota_info {
0067     struct xfs_scrub    *sc;
0068     xfs_dqid_t      last_id;
0069 };
0070 
0071 /* Scrub the fields in an individual quota item. */
0072 STATIC int
0073 xchk_quota_item(
0074     struct xfs_dquot    *dq,
0075     xfs_dqtype_t        dqtype,
0076     void            *priv)
0077 {
0078     struct xchk_quota_info  *sqi = priv;
0079     struct xfs_scrub    *sc = sqi->sc;
0080     struct xfs_mount    *mp = sc->mp;
0081     struct xfs_quotainfo    *qi = mp->m_quotainfo;
0082     xfs_fileoff_t       offset;
0083     xfs_ino_t       fs_icount;
0084     int         error = 0;
0085 
0086     if (xchk_should_terminate(sc, &error))
0087         return -ECANCELED;
0088 
0089     /*
0090      * Except for the root dquot, the actual dquot we got must either have
0091      * the same or higher id as we saw before.
0092      */
0093     offset = dq->q_id / qi->qi_dqperchunk;
0094     if (dq->q_id && dq->q_id <= sqi->last_id)
0095         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
0096 
0097     sqi->last_id = dq->q_id;
0098 
0099     /*
0100      * Warn if the hard limits are larger than the fs.
0101      * Administrators can do this, though in production this seems
0102      * suspect, which is why we flag it for review.
0103      *
0104      * Complain about corruption if the soft limit is greater than
0105      * the hard limit.
0106      */
0107     if (dq->q_blk.hardlimit > mp->m_sb.sb_dblocks)
0108         xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
0109     if (dq->q_blk.softlimit > dq->q_blk.hardlimit)
0110         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
0111 
0112     if (dq->q_ino.hardlimit > M_IGEO(mp)->maxicount)
0113         xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
0114     if (dq->q_ino.softlimit > dq->q_ino.hardlimit)
0115         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
0116 
0117     if (dq->q_rtb.hardlimit > mp->m_sb.sb_rblocks)
0118         xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
0119     if (dq->q_rtb.softlimit > dq->q_rtb.hardlimit)
0120         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
0121 
0122     /* Check the resource counts. */
0123     fs_icount = percpu_counter_sum(&mp->m_icount);
0124 
0125     /*
0126      * Check that usage doesn't exceed physical limits.  However, on
0127      * a reflink filesystem we're allowed to exceed physical space
0128      * if there are no quota limits.
0129      */
0130     if (xfs_has_reflink(mp)) {
0131         if (mp->m_sb.sb_dblocks < dq->q_blk.count)
0132             xchk_fblock_set_warning(sc, XFS_DATA_FORK,
0133                     offset);
0134     } else {
0135         if (mp->m_sb.sb_dblocks < dq->q_blk.count)
0136             xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
0137                     offset);
0138     }
0139     if (dq->q_ino.count > fs_icount || dq->q_rtb.count > mp->m_sb.sb_rblocks)
0140         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
0141 
0142     /*
0143      * We can violate the hard limits if the admin suddenly sets a
0144      * lower limit than the actual usage.  However, we flag it for
0145      * admin review.
0146      */
0147     if (dq->q_id == 0)
0148         goto out;
0149 
0150     if (dq->q_blk.hardlimit != 0 &&
0151         dq->q_blk.count > dq->q_blk.hardlimit)
0152         xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
0153 
0154     if (dq->q_ino.hardlimit != 0 &&
0155         dq->q_ino.count > dq->q_ino.hardlimit)
0156         xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
0157 
0158     if (dq->q_rtb.hardlimit != 0 &&
0159         dq->q_rtb.count > dq->q_rtb.hardlimit)
0160         xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
0161 
0162 out:
0163     if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0164         return -ECANCELED;
0165 
0166     return 0;
0167 }
0168 
0169 /* Check the quota's data fork. */
0170 STATIC int
0171 xchk_quota_data_fork(
0172     struct xfs_scrub    *sc)
0173 {
0174     struct xfs_bmbt_irec    irec = { 0 };
0175     struct xfs_iext_cursor  icur;
0176     struct xfs_quotainfo    *qi = sc->mp->m_quotainfo;
0177     struct xfs_ifork    *ifp;
0178     xfs_fileoff_t       max_dqid_off;
0179     int         error = 0;
0180 
0181     /* Invoke the fork scrubber. */
0182     error = xchk_metadata_inode_forks(sc);
0183     if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
0184         return error;
0185 
0186     /* Check for data fork problems that apply only to quota files. */
0187     max_dqid_off = ((xfs_dqid_t)-1) / qi->qi_dqperchunk;
0188     ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK);
0189     for_each_xfs_iext(ifp, &icur, &irec) {
0190         if (xchk_should_terminate(sc, &error))
0191             break;
0192         /*
0193          * delalloc extents or blocks mapped above the highest
0194          * quota id shouldn't happen.
0195          */
0196         if (isnullstartblock(irec.br_startblock) ||
0197             irec.br_startoff > max_dqid_off ||
0198             irec.br_startoff + irec.br_blockcount - 1 > max_dqid_off) {
0199             xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
0200                     irec.br_startoff);
0201             break;
0202         }
0203     }
0204 
0205     return error;
0206 }
0207 
0208 /* Scrub all of a quota type's items. */
0209 int
0210 xchk_quota(
0211     struct xfs_scrub    *sc)
0212 {
0213     struct xchk_quota_info  sqi;
0214     struct xfs_mount    *mp = sc->mp;
0215     struct xfs_quotainfo    *qi = mp->m_quotainfo;
0216     xfs_dqtype_t        dqtype;
0217     int         error = 0;
0218 
0219     dqtype = xchk_quota_to_dqtype(sc);
0220 
0221     /* Look for problem extents. */
0222     error = xchk_quota_data_fork(sc);
0223     if (error)
0224         goto out;
0225     if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0226         goto out;
0227 
0228     /*
0229      * Check all the quota items.  Now that we've checked the quota inode
0230      * data fork we have to drop ILOCK_EXCL to use the regular dquot
0231      * functions.
0232      */
0233     xfs_iunlock(sc->ip, sc->ilock_flags);
0234     sc->ilock_flags = 0;
0235     sqi.sc = sc;
0236     sqi.last_id = 0;
0237     error = xfs_qm_dqiterate(mp, dqtype, xchk_quota_item, &sqi);
0238     sc->ilock_flags = XFS_ILOCK_EXCL;
0239     xfs_ilock(sc->ip, sc->ilock_flags);
0240     if (error == -ECANCELED)
0241         error = 0;
0242     if (!xchk_fblock_process_error(sc, XFS_DATA_FORK,
0243             sqi.last_id * qi->qi_dqperchunk, &error))
0244         goto out;
0245 
0246 out:
0247     return error;
0248 }