xref: /openbmc/linux/fs/xfs/scrub/dir.c (revision a03297a0)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2017-2023 Oracle.  All Rights Reserved.
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_format.h"
10 #include "xfs_trans_resv.h"
11 #include "xfs_mount.h"
12 #include "xfs_log_format.h"
13 #include "xfs_trans.h"
14 #include "xfs_inode.h"
15 #include "xfs_icache.h"
16 #include "xfs_dir2.h"
17 #include "xfs_dir2_priv.h"
18 #include "scrub/scrub.h"
19 #include "scrub/common.h"
20 #include "scrub/dabtree.h"
21 #include "scrub/readdir.h"
22 
23 /* Set us up to scrub directories. */
24 int
xchk_setup_directory(struct xfs_scrub * sc)25 xchk_setup_directory(
26 	struct xfs_scrub	*sc)
27 {
28 	return xchk_setup_inode_contents(sc, 0);
29 }
30 
31 /* Directories */
32 
33 /* Scrub a directory entry. */
34 
35 /* Check that an inode's mode matches a given XFS_DIR3_FT_* type. */
36 STATIC void
xchk_dir_check_ftype(struct xfs_scrub * sc,xfs_fileoff_t offset,struct xfs_inode * ip,int ftype)37 xchk_dir_check_ftype(
38 	struct xfs_scrub	*sc,
39 	xfs_fileoff_t		offset,
40 	struct xfs_inode	*ip,
41 	int			ftype)
42 {
43 	struct xfs_mount	*mp = sc->mp;
44 
45 	if (!xfs_has_ftype(mp)) {
46 		if (ftype != XFS_DIR3_FT_UNKNOWN && ftype != XFS_DIR3_FT_DIR)
47 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
48 		return;
49 	}
50 
51 	if (xfs_mode_to_ftype(VFS_I(ip)->i_mode) != ftype)
52 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
53 }
54 
55 /*
56  * Scrub a single directory entry.
57  *
58  * Check the inode number to make sure it's sane, then we check that we can
59  * look up this filename.  Finally, we check the ftype.
60  */
61 STATIC int
xchk_dir_actor(struct xfs_scrub * sc,struct xfs_inode * dp,xfs_dir2_dataptr_t dapos,const struct xfs_name * name,xfs_ino_t ino,void * priv)62 xchk_dir_actor(
63 	struct xfs_scrub	*sc,
64 	struct xfs_inode	*dp,
65 	xfs_dir2_dataptr_t	dapos,
66 	const struct xfs_name	*name,
67 	xfs_ino_t		ino,
68 	void			*priv)
69 {
70 	struct xfs_mount	*mp = dp->i_mount;
71 	struct xfs_inode	*ip;
72 	xfs_ino_t		lookup_ino;
73 	xfs_dablk_t		offset;
74 	int			error = 0;
75 
76 	offset = xfs_dir2_db_to_da(mp->m_dir_geo,
77 			xfs_dir2_dataptr_to_db(mp->m_dir_geo, dapos));
78 
79 	if (xchk_should_terminate(sc, &error))
80 		return error;
81 
82 	/* Does this inode number make sense? */
83 	if (!xfs_verify_dir_ino(mp, ino)) {
84 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
85 		return -ECANCELED;
86 	}
87 
88 	/* Does this name make sense? */
89 	if (!xfs_dir2_namecheck(name->name, name->len)) {
90 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
91 		return -ECANCELED;
92 	}
93 
94 	if (!strncmp(".", name->name, name->len)) {
95 		/* If this is "." then check that the inum matches the dir. */
96 		if (ino != dp->i_ino)
97 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
98 	} else if (!strncmp("..", name->name, name->len)) {
99 		/*
100 		 * If this is ".." in the root inode, check that the inum
101 		 * matches this dir.
102 		 */
103 		if (dp->i_ino == mp->m_sb.sb_rootino && ino != dp->i_ino)
104 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
105 	}
106 
107 	/* Verify that we can look up this name by hash. */
108 	error = xchk_dir_lookup(sc, dp, name, &lookup_ino);
109 	/* ENOENT means the hash lookup failed and the dir is corrupt */
110 	if (error == -ENOENT)
111 		error = -EFSCORRUPTED;
112 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, offset, &error))
113 		goto out;
114 	if (lookup_ino != ino) {
115 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
116 		return -ECANCELED;
117 	}
118 
119 	/*
120 	 * Grab the inode pointed to by the dirent.  We release the inode
121 	 * before we cancel the scrub transaction.
122 	 *
123 	 * If _iget returns -EINVAL or -ENOENT then the child inode number is
124 	 * garbage and the directory is corrupt.  If the _iget returns
125 	 * -EFSCORRUPTED or -EFSBADCRC then the child is corrupt which is a
126 	 *  cross referencing error.  Any other error is an operational error.
127 	 */
128 	error = xchk_iget(sc, ino, &ip);
129 	if (error == -EINVAL || error == -ENOENT) {
130 		error = -EFSCORRUPTED;
131 		xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error);
132 		goto out;
133 	}
134 	if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, offset, &error))
135 		goto out;
136 
137 	xchk_dir_check_ftype(sc, offset, ip, name->type);
138 	xchk_irele(sc, ip);
139 out:
140 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
141 		return -ECANCELED;
142 	return error;
143 }
144 
145 /* Scrub a directory btree record. */
146 STATIC int
xchk_dir_rec(struct xchk_da_btree * ds,int level)147 xchk_dir_rec(
148 	struct xchk_da_btree		*ds,
149 	int				level)
150 {
151 	struct xfs_name			dname = { };
152 	struct xfs_da_state_blk		*blk = &ds->state->path.blk[level];
153 	struct xfs_mount		*mp = ds->state->mp;
154 	struct xfs_inode		*dp = ds->dargs.dp;
155 	struct xfs_da_geometry		*geo = mp->m_dir_geo;
156 	struct xfs_dir2_data_entry	*dent;
157 	struct xfs_buf			*bp;
158 	struct xfs_dir2_leaf_entry	*ent;
159 	unsigned int			end;
160 	unsigned int			iter_off;
161 	xfs_ino_t			ino;
162 	xfs_dablk_t			rec_bno;
163 	xfs_dir2_db_t			db;
164 	xfs_dir2_data_aoff_t		off;
165 	xfs_dir2_dataptr_t		ptr;
166 	xfs_dahash_t			calc_hash;
167 	xfs_dahash_t			hash;
168 	struct xfs_dir3_icleaf_hdr	hdr;
169 	unsigned int			tag;
170 	int				error;
171 
172 	ASSERT(blk->magic == XFS_DIR2_LEAF1_MAGIC ||
173 	       blk->magic == XFS_DIR2_LEAFN_MAGIC);
174 
175 	xfs_dir2_leaf_hdr_from_disk(mp, &hdr, blk->bp->b_addr);
176 	ent = hdr.ents + blk->index;
177 
178 	/* Check the hash of the entry. */
179 	error = xchk_da_btree_hash(ds, level, &ent->hashval);
180 	if (error)
181 		goto out;
182 
183 	/* Valid hash pointer? */
184 	ptr = be32_to_cpu(ent->address);
185 	if (ptr == 0)
186 		return 0;
187 
188 	/* Find the directory entry's location. */
189 	db = xfs_dir2_dataptr_to_db(geo, ptr);
190 	off = xfs_dir2_dataptr_to_off(geo, ptr);
191 	rec_bno = xfs_dir2_db_to_da(geo, db);
192 
193 	if (rec_bno >= geo->leafblk) {
194 		xchk_da_set_corrupt(ds, level);
195 		goto out;
196 	}
197 	error = xfs_dir3_data_read(ds->dargs.trans, dp, rec_bno,
198 			XFS_DABUF_MAP_HOLE_OK, &bp);
199 	if (!xchk_fblock_process_error(ds->sc, XFS_DATA_FORK, rec_bno,
200 			&error))
201 		goto out;
202 	if (!bp) {
203 		xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
204 		goto out;
205 	}
206 	xchk_buffer_recheck(ds->sc, bp);
207 
208 	if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
209 		goto out_relse;
210 
211 	dent = bp->b_addr + off;
212 
213 	/* Make sure we got a real directory entry. */
214 	iter_off = geo->data_entry_offset;
215 	end = xfs_dir3_data_end_offset(geo, bp->b_addr);
216 	if (!end) {
217 		xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
218 		goto out_relse;
219 	}
220 	for (;;) {
221 		struct xfs_dir2_data_entry	*dep = bp->b_addr + iter_off;
222 		struct xfs_dir2_data_unused	*dup = bp->b_addr + iter_off;
223 
224 		if (iter_off >= end) {
225 			xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
226 			goto out_relse;
227 		}
228 
229 		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
230 			iter_off += be16_to_cpu(dup->length);
231 			continue;
232 		}
233 		if (dep == dent)
234 			break;
235 		iter_off += xfs_dir2_data_entsize(mp, dep->namelen);
236 	}
237 
238 	/* Retrieve the entry, sanity check it, and compare hashes. */
239 	ino = be64_to_cpu(dent->inumber);
240 	hash = be32_to_cpu(ent->hashval);
241 	tag = be16_to_cpup(xfs_dir2_data_entry_tag_p(mp, dent));
242 	if (!xfs_verify_dir_ino(mp, ino) || tag != off)
243 		xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
244 	if (dent->namelen == 0) {
245 		xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
246 		goto out_relse;
247 	}
248 
249 	/* Does the directory hash match? */
250 	dname.name = dent->name;
251 	dname.len = dent->namelen;
252 	calc_hash = xfs_dir2_hashname(mp, &dname);
253 	if (calc_hash != hash)
254 		xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
255 
256 out_relse:
257 	xfs_trans_brelse(ds->dargs.trans, bp);
258 out:
259 	return error;
260 }
261 
262 /*
263  * Is this unused entry either in the bestfree or smaller than all of
264  * them?  We've already checked that the bestfrees are sorted longest to
265  * shortest, and that there aren't any bogus entries.
266  */
267 STATIC void
xchk_directory_check_free_entry(struct xfs_scrub * sc,xfs_dablk_t lblk,struct xfs_dir2_data_free * bf,struct xfs_dir2_data_unused * dup)268 xchk_directory_check_free_entry(
269 	struct xfs_scrub		*sc,
270 	xfs_dablk_t			lblk,
271 	struct xfs_dir2_data_free	*bf,
272 	struct xfs_dir2_data_unused	*dup)
273 {
274 	struct xfs_dir2_data_free	*dfp;
275 	unsigned int			dup_length;
276 
277 	dup_length = be16_to_cpu(dup->length);
278 
279 	/* Unused entry is shorter than any of the bestfrees */
280 	if (dup_length < be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length))
281 		return;
282 
283 	for (dfp = &bf[XFS_DIR2_DATA_FD_COUNT - 1]; dfp >= bf; dfp--)
284 		if (dup_length == be16_to_cpu(dfp->length))
285 			return;
286 
287 	/* Unused entry should be in the bestfrees but wasn't found. */
288 	xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
289 }
290 
291 /* Check free space info in a directory data block. */
292 STATIC int
xchk_directory_data_bestfree(struct xfs_scrub * sc,xfs_dablk_t lblk,bool is_block)293 xchk_directory_data_bestfree(
294 	struct xfs_scrub		*sc,
295 	xfs_dablk_t			lblk,
296 	bool				is_block)
297 {
298 	struct xfs_dir2_data_unused	*dup;
299 	struct xfs_dir2_data_free	*dfp;
300 	struct xfs_buf			*bp;
301 	struct xfs_dir2_data_free	*bf;
302 	struct xfs_mount		*mp = sc->mp;
303 	u16				tag;
304 	unsigned int			nr_bestfrees = 0;
305 	unsigned int			nr_frees = 0;
306 	unsigned int			smallest_bestfree;
307 	int				newlen;
308 	unsigned int			offset;
309 	unsigned int			end;
310 	int				error;
311 
312 	if (is_block) {
313 		/* dir block format */
314 		if (lblk != XFS_B_TO_FSBT(mp, XFS_DIR2_DATA_OFFSET))
315 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
316 		error = xfs_dir3_block_read(sc->tp, sc->ip, &bp);
317 	} else {
318 		/* dir data format */
319 		error = xfs_dir3_data_read(sc->tp, sc->ip, lblk, 0, &bp);
320 	}
321 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
322 		goto out;
323 	xchk_buffer_recheck(sc, bp);
324 
325 	/* XXX: Check xfs_dir3_data_hdr.pad is zero once we start setting it. */
326 
327 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
328 		goto out_buf;
329 
330 	/* Do the bestfrees correspond to actual free space? */
331 	bf = xfs_dir2_data_bestfree_p(mp, bp->b_addr);
332 	smallest_bestfree = UINT_MAX;
333 	for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
334 		offset = be16_to_cpu(dfp->offset);
335 		if (offset == 0)
336 			continue;
337 		if (offset >= mp->m_dir_geo->blksize) {
338 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
339 			goto out_buf;
340 		}
341 		dup = bp->b_addr + offset;
342 		tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup));
343 
344 		/* bestfree doesn't match the entry it points at? */
345 		if (dup->freetag != cpu_to_be16(XFS_DIR2_DATA_FREE_TAG) ||
346 		    be16_to_cpu(dup->length) != be16_to_cpu(dfp->length) ||
347 		    tag != offset) {
348 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
349 			goto out_buf;
350 		}
351 
352 		/* bestfree records should be ordered largest to smallest */
353 		if (smallest_bestfree < be16_to_cpu(dfp->length)) {
354 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
355 			goto out_buf;
356 		}
357 
358 		smallest_bestfree = be16_to_cpu(dfp->length);
359 		nr_bestfrees++;
360 	}
361 
362 	/* Make sure the bestfrees are actually the best free spaces. */
363 	offset = mp->m_dir_geo->data_entry_offset;
364 	end = xfs_dir3_data_end_offset(mp->m_dir_geo, bp->b_addr);
365 
366 	/* Iterate the entries, stopping when we hit or go past the end. */
367 	while (offset < end) {
368 		dup = bp->b_addr + offset;
369 
370 		/* Skip real entries */
371 		if (dup->freetag != cpu_to_be16(XFS_DIR2_DATA_FREE_TAG)) {
372 			struct xfs_dir2_data_entry *dep = bp->b_addr + offset;
373 
374 			newlen = xfs_dir2_data_entsize(mp, dep->namelen);
375 			if (newlen <= 0) {
376 				xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
377 						lblk);
378 				goto out_buf;
379 			}
380 			offset += newlen;
381 			continue;
382 		}
383 
384 		/* Spot check this free entry */
385 		tag = be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup));
386 		if (tag != offset) {
387 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
388 			goto out_buf;
389 		}
390 
391 		/*
392 		 * Either this entry is a bestfree or it's smaller than
393 		 * any of the bestfrees.
394 		 */
395 		xchk_directory_check_free_entry(sc, lblk, bf, dup);
396 		if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
397 			goto out_buf;
398 
399 		/* Move on. */
400 		newlen = be16_to_cpu(dup->length);
401 		if (newlen <= 0) {
402 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
403 			goto out_buf;
404 		}
405 		offset += newlen;
406 		if (offset <= end)
407 			nr_frees++;
408 	}
409 
410 	/* We're required to fill all the space. */
411 	if (offset != end)
412 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
413 
414 	/* Did we see at least as many free slots as there are bestfrees? */
415 	if (nr_frees < nr_bestfrees)
416 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
417 out_buf:
418 	xfs_trans_brelse(sc->tp, bp);
419 out:
420 	return error;
421 }
422 
423 /*
424  * Does the free space length in the free space index block ($len) match
425  * the longest length in the directory data block's bestfree array?
426  * Assume that we've already checked that the data block's bestfree
427  * array is in order.
428  */
429 STATIC void
xchk_directory_check_freesp(struct xfs_scrub * sc,xfs_dablk_t lblk,struct xfs_buf * dbp,unsigned int len)430 xchk_directory_check_freesp(
431 	struct xfs_scrub		*sc,
432 	xfs_dablk_t			lblk,
433 	struct xfs_buf			*dbp,
434 	unsigned int			len)
435 {
436 	struct xfs_dir2_data_free	*dfp;
437 
438 	dfp = xfs_dir2_data_bestfree_p(sc->mp, dbp->b_addr);
439 
440 	if (len != be16_to_cpu(dfp->length))
441 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
442 
443 	if (len > 0 && be16_to_cpu(dfp->offset) == 0)
444 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
445 }
446 
447 /* Check free space info in a directory leaf1 block. */
448 STATIC int
xchk_directory_leaf1_bestfree(struct xfs_scrub * sc,struct xfs_da_args * args,xfs_dir2_db_t last_data_db,xfs_dablk_t lblk)449 xchk_directory_leaf1_bestfree(
450 	struct xfs_scrub		*sc,
451 	struct xfs_da_args		*args,
452 	xfs_dir2_db_t			last_data_db,
453 	xfs_dablk_t			lblk)
454 {
455 	struct xfs_dir3_icleaf_hdr	leafhdr;
456 	struct xfs_dir2_leaf_tail	*ltp;
457 	struct xfs_dir2_leaf		*leaf;
458 	struct xfs_buf			*dbp;
459 	struct xfs_buf			*bp;
460 	struct xfs_da_geometry		*geo = sc->mp->m_dir_geo;
461 	__be16				*bestp;
462 	__u16				best;
463 	__u32				hash;
464 	__u32				lasthash = 0;
465 	__u32				bestcount;
466 	unsigned int			stale = 0;
467 	int				i;
468 	int				error;
469 
470 	/* Read the free space block. */
471 	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, &bp);
472 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
473 		return error;
474 	xchk_buffer_recheck(sc, bp);
475 
476 	leaf = bp->b_addr;
477 	xfs_dir2_leaf_hdr_from_disk(sc->ip->i_mount, &leafhdr, leaf);
478 	ltp = xfs_dir2_leaf_tail_p(geo, leaf);
479 	bestcount = be32_to_cpu(ltp->bestcount);
480 	bestp = xfs_dir2_leaf_bests_p(ltp);
481 
482 	if (xfs_has_crc(sc->mp)) {
483 		struct xfs_dir3_leaf_hdr	*hdr3 = bp->b_addr;
484 
485 		if (hdr3->pad != cpu_to_be32(0))
486 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
487 	}
488 
489 	/*
490 	 * There must be enough bestfree slots to cover all the directory data
491 	 * blocks that we scanned.  It is possible for there to be a hole
492 	 * between the last data block and i_disk_size.  This seems like an
493 	 * oversight to the scrub author, but as we have been writing out
494 	 * directories like this (and xfs_repair doesn't mind them) for years,
495 	 * that's what we have to check.
496 	 */
497 	if (bestcount != last_data_db + 1) {
498 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
499 		goto out;
500 	}
501 
502 	/* Is the leaf count even remotely sane? */
503 	if (leafhdr.count > geo->leaf_max_ents) {
504 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
505 		goto out;
506 	}
507 
508 	/* Leaves and bests don't overlap in leaf format. */
509 	if ((char *)&leafhdr.ents[leafhdr.count] > (char *)bestp) {
510 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
511 		goto out;
512 	}
513 
514 	/* Check hash value order, count stale entries.  */
515 	for (i = 0; i < leafhdr.count; i++) {
516 		hash = be32_to_cpu(leafhdr.ents[i].hashval);
517 		if (i > 0 && lasthash > hash)
518 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
519 		lasthash = hash;
520 		if (leafhdr.ents[i].address ==
521 		    cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
522 			stale++;
523 	}
524 	if (leafhdr.stale != stale)
525 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
526 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
527 		goto out;
528 
529 	/* Check all the bestfree entries. */
530 	for (i = 0; i < bestcount; i++, bestp++) {
531 		best = be16_to_cpu(*bestp);
532 		error = xfs_dir3_data_read(sc->tp, sc->ip,
533 				xfs_dir2_db_to_da(args->geo, i),
534 				XFS_DABUF_MAP_HOLE_OK,
535 				&dbp);
536 		if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
537 				&error))
538 			break;
539 
540 		if (!dbp) {
541 			if (best != NULLDATAOFF) {
542 				xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
543 						lblk);
544 				break;
545 			}
546 			continue;
547 		}
548 
549 		if (best == NULLDATAOFF)
550 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
551 		else
552 			xchk_directory_check_freesp(sc, lblk, dbp, best);
553 		xfs_trans_brelse(sc->tp, dbp);
554 		if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
555 			break;
556 	}
557 out:
558 	xfs_trans_brelse(sc->tp, bp);
559 	return error;
560 }
561 
562 /* Check free space info in a directory freespace block. */
563 STATIC int
xchk_directory_free_bestfree(struct xfs_scrub * sc,struct xfs_da_args * args,xfs_dablk_t lblk)564 xchk_directory_free_bestfree(
565 	struct xfs_scrub		*sc,
566 	struct xfs_da_args		*args,
567 	xfs_dablk_t			lblk)
568 {
569 	struct xfs_dir3_icfree_hdr	freehdr;
570 	struct xfs_buf			*dbp;
571 	struct xfs_buf			*bp;
572 	__u16				best;
573 	unsigned int			stale = 0;
574 	int				i;
575 	int				error;
576 
577 	/* Read the free space block */
578 	error = xfs_dir2_free_read(sc->tp, sc->ip, lblk, &bp);
579 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
580 		return error;
581 	xchk_buffer_recheck(sc, bp);
582 
583 	if (xfs_has_crc(sc->mp)) {
584 		struct xfs_dir3_free_hdr	*hdr3 = bp->b_addr;
585 
586 		if (hdr3->pad != cpu_to_be32(0))
587 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
588 	}
589 
590 	/* Check all the entries. */
591 	xfs_dir2_free_hdr_from_disk(sc->ip->i_mount, &freehdr, bp->b_addr);
592 	for (i = 0; i < freehdr.nvalid; i++) {
593 		best = be16_to_cpu(freehdr.bests[i]);
594 		if (best == NULLDATAOFF) {
595 			stale++;
596 			continue;
597 		}
598 		error = xfs_dir3_data_read(sc->tp, sc->ip,
599 				(freehdr.firstdb + i) * args->geo->fsbcount,
600 				0, &dbp);
601 		if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
602 				&error))
603 			goto out;
604 		xchk_directory_check_freesp(sc, lblk, dbp, best);
605 		xfs_trans_brelse(sc->tp, dbp);
606 	}
607 
608 	if (freehdr.nused + stale != freehdr.nvalid)
609 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
610 out:
611 	xfs_trans_brelse(sc->tp, bp);
612 	return error;
613 }
614 
615 /* Check free space information in directories. */
616 STATIC int
xchk_directory_blocks(struct xfs_scrub * sc)617 xchk_directory_blocks(
618 	struct xfs_scrub	*sc)
619 {
620 	struct xfs_bmbt_irec	got;
621 	struct xfs_da_args	args = {
622 		.dp		= sc ->ip,
623 		.whichfork	= XFS_DATA_FORK,
624 		.geo		= sc->mp->m_dir_geo,
625 		.trans		= sc->tp,
626 	};
627 	struct xfs_ifork	*ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK);
628 	struct xfs_mount	*mp = sc->mp;
629 	xfs_fileoff_t		leaf_lblk;
630 	xfs_fileoff_t		free_lblk;
631 	xfs_fileoff_t		lblk;
632 	struct xfs_iext_cursor	icur;
633 	xfs_dablk_t		dabno;
634 	xfs_dir2_db_t		last_data_db = 0;
635 	bool			found;
636 	bool			is_block = false;
637 	int			error;
638 
639 	/* Ignore local format directories. */
640 	if (ifp->if_format != XFS_DINODE_FMT_EXTENTS &&
641 	    ifp->if_format != XFS_DINODE_FMT_BTREE)
642 		return 0;
643 
644 	lblk = XFS_B_TO_FSB(mp, XFS_DIR2_DATA_OFFSET);
645 	leaf_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_LEAF_OFFSET);
646 	free_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_FREE_OFFSET);
647 
648 	/* Is this a block dir? */
649 	error = xfs_dir2_isblock(&args, &is_block);
650 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
651 		goto out;
652 
653 	/* Iterate all the data extents in the directory... */
654 	found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);
655 	while (found && !(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {
656 		/* No more data blocks... */
657 		if (got.br_startoff >= leaf_lblk)
658 			break;
659 
660 		/*
661 		 * Check each data block's bestfree data.
662 		 *
663 		 * Iterate all the fsbcount-aligned block offsets in
664 		 * this directory.  The directory block reading code is
665 		 * smart enough to do its own bmap lookups to handle
666 		 * discontiguous directory blocks.  When we're done
667 		 * with the extent record, re-query the bmap at the
668 		 * next fsbcount-aligned offset to avoid redundant
669 		 * block checks.
670 		 */
671 		for (lblk = roundup((xfs_dablk_t)got.br_startoff,
672 				args.geo->fsbcount);
673 		     lblk < got.br_startoff + got.br_blockcount;
674 		     lblk += args.geo->fsbcount) {
675 			last_data_db = xfs_dir2_da_to_db(args.geo, lblk);
676 			error = xchk_directory_data_bestfree(sc, lblk,
677 					is_block);
678 			if (error)
679 				goto out;
680 		}
681 		dabno = got.br_startoff + got.br_blockcount;
682 		lblk = roundup(dabno, args.geo->fsbcount);
683 		found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);
684 	}
685 
686 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
687 		goto out;
688 
689 	/* Look for a leaf1 block, which has free info. */
690 	if (xfs_iext_lookup_extent(sc->ip, ifp, leaf_lblk, &icur, &got) &&
691 	    got.br_startoff == leaf_lblk &&
692 	    got.br_blockcount == args.geo->fsbcount &&
693 	    !xfs_iext_next_extent(ifp, &icur, &got)) {
694 		if (is_block) {
695 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
696 			goto out;
697 		}
698 		error = xchk_directory_leaf1_bestfree(sc, &args, last_data_db,
699 				leaf_lblk);
700 		if (error)
701 			goto out;
702 	}
703 
704 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
705 		goto out;
706 
707 	/* Scan for free blocks */
708 	lblk = free_lblk;
709 	found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);
710 	while (found && !(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {
711 		/*
712 		 * Dirs can't have blocks mapped above 2^32.
713 		 * Single-block dirs shouldn't even be here.
714 		 */
715 		lblk = got.br_startoff;
716 		if (lblk & ~0xFFFFFFFFULL) {
717 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
718 			goto out;
719 		}
720 		if (is_block) {
721 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
722 			goto out;
723 		}
724 
725 		/*
726 		 * Check each dir free block's bestfree data.
727 		 *
728 		 * Iterate all the fsbcount-aligned block offsets in
729 		 * this directory.  The directory block reading code is
730 		 * smart enough to do its own bmap lookups to handle
731 		 * discontiguous directory blocks.  When we're done
732 		 * with the extent record, re-query the bmap at the
733 		 * next fsbcount-aligned offset to avoid redundant
734 		 * block checks.
735 		 */
736 		for (lblk = roundup((xfs_dablk_t)got.br_startoff,
737 				args.geo->fsbcount);
738 		     lblk < got.br_startoff + got.br_blockcount;
739 		     lblk += args.geo->fsbcount) {
740 			error = xchk_directory_free_bestfree(sc, &args,
741 					lblk);
742 			if (error)
743 				goto out;
744 		}
745 		dabno = got.br_startoff + got.br_blockcount;
746 		lblk = roundup(dabno, args.geo->fsbcount);
747 		found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &icur, &got);
748 	}
749 out:
750 	return error;
751 }
752 
753 /* Scrub a whole directory. */
754 int
xchk_directory(struct xfs_scrub * sc)755 xchk_directory(
756 	struct xfs_scrub	*sc)
757 {
758 	int			error;
759 
760 	if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
761 		return -ENOENT;
762 
763 	/* Plausible size? */
764 	if (sc->ip->i_disk_size < xfs_dir2_sf_hdr_size(0)) {
765 		xchk_ino_set_corrupt(sc, sc->ip->i_ino);
766 		return 0;
767 	}
768 
769 	/* Check directory tree structure */
770 	error = xchk_da_btree(sc, XFS_DATA_FORK, xchk_dir_rec, NULL);
771 	if (error)
772 		return error;
773 
774 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
775 		return 0;
776 
777 	/* Check the freespace. */
778 	error = xchk_directory_blocks(sc);
779 	if (error)
780 		return error;
781 
782 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
783 		return 0;
784 
785 	/* Look up every name in this directory by hash. */
786 	error = xchk_dir_walk(sc, sc->ip, xchk_dir_actor, NULL);
787 	if (error == -ECANCELED)
788 		error = 0;
789 	return error;
790 }
791