1 /* 2 * Copyright (C) 2017 Oracle. All Rights Reserved. 3 * 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it would be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 #include "xfs.h" 21 #include "xfs_fs.h" 22 #include "xfs_shared.h" 23 #include "xfs_format.h" 24 #include "xfs_trans_resv.h" 25 #include "xfs_mount.h" 26 #include "xfs_defer.h" 27 #include "xfs_btree.h" 28 #include "xfs_bit.h" 29 #include "xfs_log_format.h" 30 #include "xfs_trans.h" 31 #include "xfs_sb.h" 32 #include "xfs_inode.h" 33 #include "xfs_inode_fork.h" 34 #include "xfs_alloc.h" 35 #include "xfs_bmap.h" 36 #include "xfs_quota.h" 37 #include "xfs_qm.h" 38 #include "xfs_dquot.h" 39 #include "xfs_dquot_item.h" 40 #include "scrub/xfs_scrub.h" 41 #include "scrub/scrub.h" 42 #include "scrub/common.h" 43 #include "scrub/trace.h" 44 45 /* Convert a scrub type code to a DQ flag, or return 0 if error. */ 46 static inline uint 47 xfs_scrub_quota_to_dqtype( 48 struct xfs_scrub_context *sc) 49 { 50 switch (sc->sm->sm_type) { 51 case XFS_SCRUB_TYPE_UQUOTA: 52 return XFS_DQ_USER; 53 case XFS_SCRUB_TYPE_GQUOTA: 54 return XFS_DQ_GROUP; 55 case XFS_SCRUB_TYPE_PQUOTA: 56 return XFS_DQ_PROJ; 57 default: 58 return 0; 59 } 60 } 61 62 /* Set us up to scrub a quota. */ 63 int 64 xfs_scrub_setup_quota( 65 struct xfs_scrub_context *sc, 66 struct xfs_inode *ip) 67 { 68 uint dqtype; 69 70 dqtype = xfs_scrub_quota_to_dqtype(sc); 71 if (dqtype == 0) 72 return -EINVAL; 73 if (!xfs_this_quota_on(sc->mp, dqtype)) 74 return -ENOENT; 75 return 0; 76 } 77 78 /* Quotas. */ 79 80 /* Scrub the fields in an individual quota item. */ 81 STATIC void 82 xfs_scrub_quota_item( 83 struct xfs_scrub_context *sc, 84 uint dqtype, 85 struct xfs_dquot *dq, 86 xfs_dqid_t id) 87 { 88 struct xfs_mount *mp = sc->mp; 89 struct xfs_disk_dquot *d = &dq->q_core; 90 struct xfs_quotainfo *qi = mp->m_quotainfo; 91 xfs_fileoff_t offset; 92 unsigned long long bsoft; 93 unsigned long long isoft; 94 unsigned long long rsoft; 95 unsigned long long bhard; 96 unsigned long long ihard; 97 unsigned long long rhard; 98 unsigned long long bcount; 99 unsigned long long icount; 100 unsigned long long rcount; 101 xfs_ino_t fs_icount; 102 103 offset = id / qi->qi_dqperchunk; 104 105 /* 106 * We fed $id and DQNEXT into the xfs_qm_dqget call, which means 107 * that the actual dquot we got must either have the same id or 108 * the next higher id. 109 */ 110 if (id > be32_to_cpu(d->d_id)) 111 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset); 112 113 /* Did we get the dquot type we wanted? */ 114 if (dqtype != (d->d_flags & XFS_DQ_ALLTYPES)) 115 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset); 116 117 if (d->d_pad0 != cpu_to_be32(0) || d->d_pad != cpu_to_be16(0)) 118 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset); 119 120 /* Check the limits. */ 121 bhard = be64_to_cpu(d->d_blk_hardlimit); 122 ihard = be64_to_cpu(d->d_ino_hardlimit); 123 rhard = be64_to_cpu(d->d_rtb_hardlimit); 124 125 bsoft = be64_to_cpu(d->d_blk_softlimit); 126 isoft = be64_to_cpu(d->d_ino_softlimit); 127 rsoft = be64_to_cpu(d->d_rtb_softlimit); 128 129 /* 130 * Warn if the hard limits are larger than the fs. 131 * Administrators can do this, though in production this seems 132 * suspect, which is why we flag it for review. 133 * 134 * Complain about corruption if the soft limit is greater than 135 * the hard limit. 136 */ 137 if (bhard > mp->m_sb.sb_dblocks) 138 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset); 139 if (bsoft > bhard) 140 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset); 141 142 if (ihard > mp->m_maxicount) 143 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset); 144 if (isoft > ihard) 145 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset); 146 147 if (rhard > mp->m_sb.sb_rblocks) 148 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset); 149 if (rsoft > rhard) 150 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset); 151 152 /* Check the resource counts. */ 153 bcount = be64_to_cpu(d->d_bcount); 154 icount = be64_to_cpu(d->d_icount); 155 rcount = be64_to_cpu(d->d_rtbcount); 156 fs_icount = percpu_counter_sum(&mp->m_icount); 157 158 /* 159 * Check that usage doesn't exceed physical limits. However, on 160 * a reflink filesystem we're allowed to exceed physical space 161 * if there are no quota limits. 162 */ 163 if (xfs_sb_version_hasreflink(&mp->m_sb)) { 164 if (mp->m_sb.sb_dblocks < bcount) 165 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, 166 offset); 167 } else { 168 if (mp->m_sb.sb_dblocks < bcount) 169 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, 170 offset); 171 } 172 if (icount > fs_icount || rcount > mp->m_sb.sb_rblocks) 173 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset); 174 175 /* 176 * We can violate the hard limits if the admin suddenly sets a 177 * lower limit than the actual usage. However, we flag it for 178 * admin review. 179 */ 180 if (id != 0 && bhard != 0 && bcount > bhard) 181 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset); 182 if (id != 0 && ihard != 0 && icount > ihard) 183 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset); 184 if (id != 0 && rhard != 0 && rcount > rhard) 185 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset); 186 } 187 188 /* Scrub all of a quota type's items. */ 189 int 190 xfs_scrub_quota( 191 struct xfs_scrub_context *sc) 192 { 193 struct xfs_bmbt_irec irec = { 0 }; 194 struct xfs_mount *mp = sc->mp; 195 struct xfs_inode *ip; 196 struct xfs_quotainfo *qi = mp->m_quotainfo; 197 struct xfs_dquot *dq; 198 xfs_fileoff_t max_dqid_off; 199 xfs_fileoff_t off = 0; 200 xfs_dqid_t id = 0; 201 uint dqtype; 202 int nimaps; 203 int error = 0; 204 205 if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp)) 206 return -ENOENT; 207 208 mutex_lock(&qi->qi_quotaofflock); 209 dqtype = xfs_scrub_quota_to_dqtype(sc); 210 if (!xfs_this_quota_on(sc->mp, dqtype)) { 211 error = -ENOENT; 212 goto out_unlock_quota; 213 } 214 215 /* Attach to the quota inode and set sc->ip so that reporting works. */ 216 ip = xfs_quota_inode(sc->mp, dqtype); 217 sc->ip = ip; 218 219 /* Look for problem extents. */ 220 xfs_ilock(ip, XFS_ILOCK_EXCL); 221 if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { 222 xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino, NULL); 223 goto out_unlock_inode; 224 } 225 max_dqid_off = ((xfs_dqid_t)-1) / qi->qi_dqperchunk; 226 while (1) { 227 if (xfs_scrub_should_terminate(sc, &error)) 228 break; 229 230 off = irec.br_startoff + irec.br_blockcount; 231 nimaps = 1; 232 error = xfs_bmapi_read(ip, off, -1, &irec, &nimaps, 233 XFS_BMAPI_ENTIRE); 234 if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, off, 235 &error)) 236 goto out_unlock_inode; 237 if (!nimaps) 238 break; 239 if (irec.br_startblock == HOLESTARTBLOCK) 240 continue; 241 242 /* Check the extent record doesn't point to crap. */ 243 if (irec.br_startblock + irec.br_blockcount <= 244 irec.br_startblock) 245 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, 246 irec.br_startoff); 247 if (!xfs_verify_fsbno(mp, irec.br_startblock) || 248 !xfs_verify_fsbno(mp, irec.br_startblock + 249 irec.br_blockcount - 1)) 250 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, 251 irec.br_startoff); 252 253 /* 254 * Unwritten extents or blocks mapped above the highest 255 * quota id shouldn't happen. 256 */ 257 if (isnullstartblock(irec.br_startblock) || 258 irec.br_startoff > max_dqid_off || 259 irec.br_startoff + irec.br_blockcount > max_dqid_off + 1) 260 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, off); 261 } 262 xfs_iunlock(ip, XFS_ILOCK_EXCL); 263 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 264 goto out; 265 266 /* Check all the quota items. */ 267 while (id < ((xfs_dqid_t)-1ULL)) { 268 if (xfs_scrub_should_terminate(sc, &error)) 269 break; 270 271 error = xfs_qm_dqget(mp, NULL, id, dqtype, XFS_QMOPT_DQNEXT, 272 &dq); 273 if (error == -ENOENT) 274 break; 275 if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, 276 id * qi->qi_dqperchunk, &error)) 277 break; 278 279 xfs_scrub_quota_item(sc, dqtype, dq, id); 280 281 id = be32_to_cpu(dq->q_core.d_id) + 1; 282 xfs_qm_dqput(dq); 283 if (!id) 284 break; 285 } 286 287 out: 288 /* We set sc->ip earlier, so make sure we clear it now. */ 289 sc->ip = NULL; 290 out_unlock_quota: 291 mutex_unlock(&qi->qi_quotaofflock); 292 return error; 293 294 out_unlock_inode: 295 xfs_iunlock(ip, XFS_ILOCK_EXCL); 296 goto out; 297 } 298