0001
0002
0003
0004
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
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
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
0065
0066 struct xchk_quota_info {
0067 struct xfs_scrub *sc;
0068 xfs_dqid_t last_id;
0069 };
0070
0071
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
0091
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
0101
0102
0103
0104
0105
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
0123 fs_icount = percpu_counter_sum(&mp->m_icount);
0124
0125
0126
0127
0128
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
0144
0145
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
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
0182 error = xchk_metadata_inode_forks(sc);
0183 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
0184 return error;
0185
0186
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
0194
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
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
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
0230
0231
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 }