1 // SPDX-License-Identifier: GPL-2.0-or-later 1 2 /* 3 * Copyright (C) 2023 Oracle. All Rights Rese 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 */ 6 #include "xfs.h" 7 #include "xfs_fs.h" 8 #include "xfs_shared.h" 9 #include "xfs_bit.h" 10 #include "xfs_format.h" 11 #include "xfs_trans_resv.h" 12 #include "xfs_mount.h" 13 #include "xfs_log_format.h" 14 #include "xfs_trans.h" 15 #include "xfs_inode.h" 16 #include "xfs_quota.h" 17 #include "xfs_qm.h" 18 #include "xfs_bmap.h" 19 #include "scrub/scrub.h" 20 #include "scrub/common.h" 21 #include "scrub/quota.h" 22 #include "scrub/trace.h" 23 24 /* Initialize a dquot iteration cursor. */ 25 void 26 xchk_dqiter_init( 27 struct xchk_dqiter *cursor, 28 struct xfs_scrub *sc, 29 xfs_dqtype_t dqtype) 30 { 31 cursor->sc = sc; 32 cursor->bmap.br_startoff = NULLFILEOFF 33 cursor->dqtype = dqtype & XFS_DQTYPE_R 34 cursor->quota_ip = xfs_quota_inode(sc- 35 cursor->id = 0; 36 } 37 38 /* 39 * Ensure that the cached data fork mapping fo 40 * covers the dquot pointed to by the scan cur 41 */ 42 STATIC int 43 xchk_dquot_iter_revalidate_bmap( 44 struct xchk_dqiter *cursor) 45 { 46 struct xfs_quotainfo *qi = cursor-> 47 struct xfs_ifork *ifp = xfs_ifo 48 49 xfs_fileoff_t fileoff; 50 xfs_dqid_t this_id = curs 51 int nmaps = 1; 52 int error; 53 54 fileoff = this_id / qi->qi_dqperchunk; 55 56 /* 57 * If we have a mapping for cursor->id 58 * no need to reread the bmbt. 59 */ 60 if (cursor->bmap.br_startoff != NULLFI 61 cursor->if_seq == ifp->if_seq && 62 cursor->bmap.br_startoff + cursor- 63 return 0; 64 65 /* Look up the data fork mapping for t 66 error = xfs_bmapi_read(cursor->quota_i 67 XFS_MAX_FILEOFF - file 68 if (error) 69 return error; 70 if (!nmaps) { 71 ASSERT(nmaps > 0); 72 return -EFSCORRUPTED; 73 } 74 if (cursor->bmap.br_startoff > fileoff 75 ASSERT(cursor->bmap.br_startof 76 return -EFSCORRUPTED; 77 } 78 79 cursor->if_seq = ifp->if_seq; 80 trace_xchk_dquot_iter_revalidate_bmap( 81 return 0; 82 } 83 84 /* Advance the dqiter cursor to the next non-s 85 STATIC int 86 xchk_dquot_iter_advance_bmap( 87 struct xchk_dqiter *cursor, 88 uint64_t *next_ondisk_i 89 { 90 struct xfs_quotainfo *qi = cursor-> 91 struct xfs_ifork *ifp = xfs_ifo 92 93 xfs_fileoff_t fileoff; 94 uint64_t next_id; 95 int nmaps = 1; 96 int error; 97 98 /* Find the dquot id for the next non- 99 do { 100 fileoff = cursor->bmap.br_star 101 if (fileoff > XFS_DQ_ID_MAX / 102 /* The hole goes beyon 103 *next_ondisk_id = -1UL 104 return 0; 105 } 106 107 error = xfs_bmapi_read(cursor- 108 XFS_MAX_FILEOF 109 &nmaps, 0); 110 if (error) 111 return error; 112 if (!nmaps) { 113 /* Must have reached t 114 *next_ondisk_id = -1UL 115 return 0; 116 } 117 if (cursor->bmap.br_startoff > 118 ASSERT(cursor->bmap.br 119 return -EFSCORRUPTED; 120 } 121 } while (!xfs_bmap_is_real_extent(&cur 122 123 next_id = cursor->bmap.br_startoff * q 124 if (next_id > XFS_DQ_ID_MAX) { 125 /* The hole goes beyond the ma 126 *next_ondisk_id = -1ULL; 127 return 0; 128 } 129 130 /* Propose jumping forward to the dquo 131 *next_ondisk_id = next_id; 132 cursor->if_seq = ifp->if_seq; 133 trace_xchk_dquot_iter_advance_bmap(cur 134 return 0; 135 } 136 137 /* 138 * Find the id of the next highest incore dquo 139 * exactly with the quota file block mappings, 140 * mapping because it was crosslinked; in that 141 * space so that we can reset q_blkno. 142 */ 143 STATIC void 144 xchk_dquot_iter_advance_incore( 145 struct xchk_dqiter *cursor, 146 uint64_t *next_incore_i 147 { 148 struct xfs_quotainfo *qi = cursor-> 149 struct radix_tree_root *tree = xfs_dq 150 struct xfs_dquot *dq; 151 unsigned int nr_found; 152 153 *next_incore_id = -1ULL; 154 155 mutex_lock(&qi->qi_tree_lock); 156 nr_found = radix_tree_gang_lookup(tree 157 if (nr_found) 158 *next_incore_id = dq->q_id; 159 mutex_unlock(&qi->qi_tree_lock); 160 161 trace_xchk_dquot_iter_advance_incore(c 162 } 163 164 /* 165 * Walk all incore dquots of this filesystem. 166 * zero before the first call, and must not ho 167 * Returns 1 and a valid *@dqpp; 0 and *@dqpp 168 * dquots to iterate; or a negative errno. 169 */ 170 int 171 xchk_dquot_iter( 172 struct xchk_dqiter *cursor, 173 struct xfs_dquot **dqpp) 174 { 175 struct xfs_mount *mp = cursor-> 176 struct xfs_dquot *dq = NULL; 177 uint64_t next_ondisk, n 178 unsigned int lock_mode; 179 int error = 0; 180 181 if (cursor->id > XFS_DQ_ID_MAX) 182 return 0; 183 next_ondisk = cursor->id; 184 185 /* Revalidate and/or advance the curso 186 lock_mode = xfs_ilock_data_map_shared( 187 error = xchk_dquot_iter_revalidate_bma 188 if (!error && !xfs_bmap_is_real_extent 189 error = xchk_dquot_iter_advanc 190 xfs_iunlock(cursor->quota_ip, lock_mod 191 if (error) 192 return error; 193 194 if (next_ondisk > cursor->id) 195 xchk_dquot_iter_advance_incore 196 197 /* Pick the next dquot in the sequence 198 cursor->id = min(next_ondisk, next_inc 199 if (cursor->id > XFS_DQ_ID_MAX) 200 return 0; 201 202 trace_xchk_dquot_iter(cursor, cursor-> 203 204 error = xfs_qm_dqget(mp, cursor->id, c 205 if (error) 206 return error; 207 208 cursor->id = dq->q_id + 1; 209 *dqpp = dq; 210 return 1; 211 } 212
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.