aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/scrub/ialloc.c165
-rw-r--r--fs/xfs/scrub/trace.h45
2 files changed, 152 insertions, 58 deletions
diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index 0ce793d92995..708f6607db71 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -134,41 +134,69 @@ xchk_iallocbt_freecount(
134 return hweight64(freemask); 134 return hweight64(freemask);
135} 135}
136 136
137/* Check a particular inode with ir_free. */ 137/*
138 * Check that an inode's allocation status matches ir_free in the inobt
139 * record. First we try querying the in-core inode state, and if the inode
140 * isn't loaded we examine the on-disk inode directly.
141 *
142 * Since there can be 1:M and M:1 mappings between inobt records and inode
143 * clusters, we pass in the inode location information as an inobt record;
144 * the index of an inode cluster within the inobt record (as well as the
145 * cluster buffer itself); and the index of the inode within the cluster.
146 *
147 * @irec is the inobt record.
148 * @cluster_base is the inode offset of the cluster within the @irec.
149 * @cluster_bp is the cluster buffer.
150 * @cluster_index is the inode offset within the inode cluster.
151 */
138STATIC int 152STATIC int
139xchk_iallocbt_check_cluster_freemask( 153xchk_iallocbt_check_cluster_ifree(
140 struct xchk_btree *bs, 154 struct xchk_btree *bs,
141 xfs_ino_t fsino,
142 xfs_agino_t chunkino,
143 xfs_agino_t clusterino,
144 struct xfs_inobt_rec_incore *irec, 155 struct xfs_inobt_rec_incore *irec,
145 struct xfs_buf *bp) 156 unsigned int cluster_base,
157 struct xfs_buf *cluster_bp,
158 unsigned int cluster_index)
146{ 159{
147 struct xfs_dinode *dip;
148 struct xfs_mount *mp = bs->cur->bc_mp; 160 struct xfs_mount *mp = bs->cur->bc_mp;
149 bool inode_is_free = false; 161 struct xfs_dinode *dip;
162 xfs_ino_t fsino;
163 xfs_agino_t agino;
164 unsigned int offset;
165 bool irec_free;
166 bool ino_inuse;
150 bool freemask_ok; 167 bool freemask_ok;
151 bool inuse; 168 int error;
152 int error = 0;
153 169
154 if (xchk_should_terminate(bs->sc, &error)) 170 if (xchk_should_terminate(bs->sc, &error))
155 return error; 171 return error;
156 172
157 dip = xfs_buf_offset(bp, clusterino * mp->m_sb.sb_inodesize); 173 /*
174 * Given an inobt record, an offset of a cluster within the record, and
175 * an offset of an inode within a cluster, compute which fs inode we're
176 * talking about and the offset of that inode within the buffer.
177 */
178 agino = irec->ir_startino + cluster_base + cluster_index;
179 fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
180 offset = cluster_index * mp->m_sb.sb_inodesize;
181 if (offset >= BBTOB(cluster_bp->b_length)) {
182 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
183 goto out;
184 }
185 dip = xfs_buf_offset(cluster_bp, offset);
186 irec_free = (irec->ir_free & XFS_INOBT_MASK(cluster_base +
187 cluster_index));
188
158 if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC || 189 if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC ||
159 (dip->di_version >= 3 && 190 (dip->di_version >= 3 && be64_to_cpu(dip->di_ino) != fsino)) {
160 be64_to_cpu(dip->di_ino) != fsino + clusterino)) {
161 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 191 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
162 goto out; 192 goto out;
163 } 193 }
164 194
165 if (irec->ir_free & XFS_INOBT_MASK(chunkino + clusterino)) 195 error = xfs_icache_inode_is_allocated(mp, bs->cur->bc_tp, fsino,
166 inode_is_free = true; 196 &ino_inuse);
167 error = xfs_icache_inode_is_allocated(mp, bs->cur->bc_tp,
168 fsino + clusterino, &inuse);
169 if (error == -ENODATA) { 197 if (error == -ENODATA) {
170 /* Not cached, just read the disk buffer */ 198 /* Not cached, just read the disk buffer */
171 freemask_ok = inode_is_free ^ !!(dip->di_mode); 199 freemask_ok = irec_free ^ !!(dip->di_mode);
172 if (!bs->sc->try_harder && !freemask_ok) 200 if (!bs->sc->try_harder && !freemask_ok)
173 return -EDEADLOCK; 201 return -EDEADLOCK;
174 } else if (error < 0) { 202 } else if (error < 0) {
@@ -180,7 +208,7 @@ xchk_iallocbt_check_cluster_freemask(
180 goto out; 208 goto out;
181 } else { 209 } else {
182 /* Inode is all there. */ 210 /* Inode is all there. */
183 freemask_ok = inode_is_free ^ inuse; 211 freemask_ok = irec_free ^ ino_inuse;
184 } 212 }
185 if (!freemask_ok) 213 if (!freemask_ok)
186 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 214 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
@@ -188,43 +216,57 @@ out:
188 return 0; 216 return 0;
189} 217}
190 218
191/* Check an inode cluster. */ 219/*
220 * Check that the holemask and freemask of a hypothetical inode cluster match
221 * what's actually on disk. If sparse inodes are enabled, the cluster does
222 * not actually have to map to inodes if the corresponding holemask bit is set.
223 *
224 * @cluster_base is the first inode in the cluster within the @irec.
225 */
192STATIC int 226STATIC int
193xchk_iallocbt_check_cluster( 227xchk_iallocbt_check_cluster(
194 struct xchk_btree *bs, 228 struct xchk_btree *bs,
195 struct xfs_inobt_rec_incore *irec, 229 struct xfs_inobt_rec_incore *irec,
196 xfs_agino_t agino) 230 unsigned int cluster_base)
197{ 231{
198 struct xfs_imap imap; 232 struct xfs_imap imap;
199 struct xfs_mount *mp = bs->cur->bc_mp; 233 struct xfs_mount *mp = bs->cur->bc_mp;
200 struct xfs_dinode *dip; 234 struct xfs_dinode *dip;
201 struct xfs_buf *bp; 235 struct xfs_buf *cluster_bp;
202 xfs_ino_t fsino;
203 unsigned int nr_inodes; 236 unsigned int nr_inodes;
204 xfs_agino_t chunkino; 237 xfs_agnumber_t agno = bs->cur->bc_private.a.agno;
205 xfs_agino_t clusterino;
206 xfs_agblock_t agbno; 238 xfs_agblock_t agbno;
207 uint16_t holemask; 239 unsigned int cluster_index;
240 uint16_t cluster_mask = 0;
208 uint16_t ir_holemask; 241 uint16_t ir_holemask;
209 int error = 0; 242 int error = 0;
210 243
211 /* Make sure the freemask matches the inode records. */
212 nr_inodes = min_t(unsigned int, XFS_INODES_PER_CHUNK, 244 nr_inodes = min_t(unsigned int, XFS_INODES_PER_CHUNK,
213 mp->m_inodes_per_cluster); 245 mp->m_inodes_per_cluster);
214 246
215 fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino); 247 /* Map this inode cluster */
216 chunkino = agino - irec->ir_startino; 248 agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino + cluster_base);
217 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
218 249
219 /* Compute the holemask mask for this cluster. */ 250 /* Compute a bitmask for this cluster that can be used for holemask. */
220 for (clusterino = 0, holemask = 0; clusterino < nr_inodes; 251 for (cluster_index = 0;
221 clusterino += XFS_INODES_PER_HOLEMASK_BIT) 252 cluster_index < nr_inodes;
222 holemask |= XFS_INOBT_MASK((chunkino + clusterino) / 253 cluster_index += XFS_INODES_PER_HOLEMASK_BIT)
254 cluster_mask |= XFS_INOBT_MASK((cluster_base + cluster_index) /
223 XFS_INODES_PER_HOLEMASK_BIT); 255 XFS_INODES_PER_HOLEMASK_BIT);
224 256
257 ir_holemask = (irec->ir_holemask & cluster_mask);
258 imap.im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
259 imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
260 imap.im_boffset = 0;
261
262 trace_xchk_iallocbt_check_cluster(mp, agno, irec->ir_startino,
263 imap.im_blkno, imap.im_len, cluster_base, nr_inodes,
264 cluster_mask, ir_holemask,
265 XFS_INO_TO_OFFSET(mp, irec->ir_startino +
266 cluster_base));
267
225 /* The whole cluster must be a hole or not a hole. */ 268 /* The whole cluster must be a hole or not a hole. */
226 ir_holemask = (irec->ir_holemask & holemask); 269 if (ir_holemask != cluster_mask && ir_holemask != 0) {
227 if (ir_holemask != holemask && ir_holemask != 0) {
228 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 270 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
229 return 0; 271 return 0;
230 } 272 }
@@ -241,40 +283,47 @@ xchk_iallocbt_check_cluster(
241 &XFS_RMAP_OINFO_INODES); 283 &XFS_RMAP_OINFO_INODES);
242 284
243 /* Grab the inode cluster buffer. */ 285 /* Grab the inode cluster buffer. */
244 imap.im_blkno = XFS_AGB_TO_DADDR(mp, bs->cur->bc_private.a.agno, agbno); 286 error = xfs_imap_to_bp(mp, bs->cur->bc_tp, &imap, &dip, &cluster_bp,
245 imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster); 287 0, 0);
246 imap.im_boffset = 0;
247
248 error = xfs_imap_to_bp(mp, bs->cur->bc_tp, &imap, &dip, &bp, 0, 0);
249 if (!xchk_btree_xref_process_error(bs->sc, bs->cur, 0, &error)) 288 if (!xchk_btree_xref_process_error(bs->sc, bs->cur, 0, &error))
250 return 0; 289 return error;
251 290
252 /* Which inodes are free? */ 291 /* Check free status of each inode within this cluster. */
253 for (clusterino = 0; clusterino < nr_inodes; clusterino++) { 292 for (cluster_index = 0; cluster_index < nr_inodes; cluster_index++) {
254 error = xchk_iallocbt_check_cluster_freemask(bs, fsino, 293 error = xchk_iallocbt_check_cluster_ifree(bs, irec,
255 chunkino, clusterino, irec, bp); 294 cluster_base, cluster_bp, cluster_index);
256 if (error) 295 if (error)
257 break; 296 break;
258 } 297 }
259 298
260 xfs_trans_brelse(bs->cur->bc_tp, bp); 299 xfs_trans_brelse(bs->cur->bc_tp, cluster_bp);
261 return error; 300 return error;
262} 301}
263 302
264/* Make sure the free mask is consistent with what the inodes think. */ 303/*
304 * For all the inode clusters that could map to this inobt record, make sure
305 * that the holemask makes sense and that the allocation status of each inode
306 * matches the freemask.
307 */
265STATIC int 308STATIC int
266xchk_iallocbt_check_freemask( 309xchk_iallocbt_check_clusters(
267 struct xchk_btree *bs, 310 struct xchk_btree *bs,
268 struct xfs_inobt_rec_incore *irec) 311 struct xfs_inobt_rec_incore *irec)
269{ 312{
270 struct xfs_mount *mp = bs->cur->bc_mp; 313 unsigned int cluster_base;
271 xfs_agino_t agino;
272 int error = 0; 314 int error = 0;
273 315
274 for (agino = irec->ir_startino; 316 /*
275 agino < irec->ir_startino + XFS_INODES_PER_CHUNK; 317 * For the common case where this inobt record maps to multiple inode
276 agino += mp->m_inodes_per_cluster) { 318 * clusters this will call _check_cluster for each cluster.
277 error = xchk_iallocbt_check_cluster(bs, irec, agino); 319 *
320 * For the case that multiple inobt records map to a single cluster,
321 * this will call _check_cluster once.
322 */
323 for (cluster_base = 0;
324 cluster_base < XFS_INODES_PER_CHUNK;
325 cluster_base += bs->sc->mp->m_inodes_per_cluster) {
326 error = xchk_iallocbt_check_cluster(bs, irec, cluster_base);
278 if (error) 327 if (error)
279 break; 328 break;
280 } 329 }
@@ -415,7 +464,7 @@ xchk_iallocbt_rec(
415 464
416 if (!xchk_iallocbt_chunk(bs, &irec, agino, len)) 465 if (!xchk_iallocbt_chunk(bs, &irec, agino, len))
417 goto out; 466 goto out;
418 goto check_freemask; 467 goto check_clusters;
419 } 468 }
420 469
421 /* Check each chunk of a sparse inode cluster. */ 470 /* Check each chunk of a sparse inode cluster. */
@@ -441,8 +490,8 @@ xchk_iallocbt_rec(
441 holecount + irec.ir_count != XFS_INODES_PER_CHUNK) 490 holecount + irec.ir_count != XFS_INODES_PER_CHUNK)
442 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 491 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
443 492
444check_freemask: 493check_clusters:
445 error = xchk_iallocbt_check_freemask(bs, &irec); 494 error = xchk_iallocbt_check_clusters(bs, &irec);
446 if (error) 495 if (error)
447 goto out; 496 goto out;
448 497
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index 8344b14031ef..3c83e8b3b39c 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -545,6 +545,51 @@ TRACE_EVENT(xchk_xref_error,
545 __entry->ret_ip) 545 __entry->ret_ip)
546); 546);
547 547
548TRACE_EVENT(xchk_iallocbt_check_cluster,
549 TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
550 xfs_agino_t startino, xfs_daddr_t map_daddr,
551 unsigned short map_len, unsigned int chunk_ino,
552 unsigned int nr_inodes, uint16_t cluster_mask,
553 uint16_t holemask, unsigned int cluster_ino),
554 TP_ARGS(mp, agno, startino, map_daddr, map_len, chunk_ino, nr_inodes,
555 cluster_mask, holemask, cluster_ino),
556 TP_STRUCT__entry(
557 __field(dev_t, dev)
558 __field(xfs_agnumber_t, agno)
559 __field(xfs_agino_t, startino)
560 __field(xfs_daddr_t, map_daddr)
561 __field(unsigned short, map_len)
562 __field(unsigned int, chunk_ino)
563 __field(unsigned int, nr_inodes)
564 __field(unsigned int, cluster_ino)
565 __field(uint16_t, cluster_mask)
566 __field(uint16_t, holemask)
567 ),
568 TP_fast_assign(
569 __entry->dev = mp->m_super->s_dev;
570 __entry->agno = agno;
571 __entry->startino = startino;
572 __entry->map_daddr = map_daddr;
573 __entry->map_len = map_len;
574 __entry->chunk_ino = chunk_ino;
575 __entry->nr_inodes = nr_inodes;
576 __entry->cluster_mask = cluster_mask;
577 __entry->holemask = holemask;
578 __entry->cluster_ino = cluster_ino;
579 ),
580 TP_printk("dev %d:%d agno %d startino %u daddr 0x%llx len %d chunkino %u nr_inodes %u cluster_mask 0x%x holemask 0x%x cluster_ino %u",
581 MAJOR(__entry->dev), MINOR(__entry->dev),
582 __entry->agno,
583 __entry->startino,
584 __entry->map_daddr,
585 __entry->map_len,
586 __entry->chunk_ino,
587 __entry->nr_inodes,
588 __entry->cluster_mask,
589 __entry->holemask,
590 __entry->cluster_ino)
591)
592
548/* repair tracepoints */ 593/* repair tracepoints */
549#if IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR) 594#if IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR)
550 595