xref: /openbmc/linux/fs/xfs/scrub/readdir.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1*4c233b5cSDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later
2*4c233b5cSDarrick J. Wong /*
3*4c233b5cSDarrick J. Wong  * Copyright (C) 2022-2023 Oracle.  All Rights Reserved.
4*4c233b5cSDarrick J. Wong  * Author: Darrick J. Wong <djwong@kernel.org>
5*4c233b5cSDarrick J. Wong  */
6*4c233b5cSDarrick J. Wong #include "xfs.h"
7*4c233b5cSDarrick J. Wong #include "xfs_fs.h"
8*4c233b5cSDarrick J. Wong #include "xfs_shared.h"
9*4c233b5cSDarrick J. Wong #include "xfs_format.h"
10*4c233b5cSDarrick J. Wong #include "xfs_log_format.h"
11*4c233b5cSDarrick J. Wong #include "xfs_trans_resv.h"
12*4c233b5cSDarrick J. Wong #include "xfs_mount.h"
13*4c233b5cSDarrick J. Wong #include "xfs_inode.h"
14*4c233b5cSDarrick J. Wong #include "xfs_dir2.h"
15*4c233b5cSDarrick J. Wong #include "xfs_dir2_priv.h"
16*4c233b5cSDarrick J. Wong #include "xfs_trace.h"
17*4c233b5cSDarrick J. Wong #include "xfs_bmap.h"
18*4c233b5cSDarrick J. Wong #include "xfs_trans.h"
19*4c233b5cSDarrick J. Wong #include "xfs_error.h"
20*4c233b5cSDarrick J. Wong #include "scrub/scrub.h"
21*4c233b5cSDarrick J. Wong #include "scrub/readdir.h"
22*4c233b5cSDarrick J. Wong 
23*4c233b5cSDarrick J. Wong /* Call a function for every entry in a shortform directory. */
24*4c233b5cSDarrick J. Wong STATIC int
xchk_dir_walk_sf(struct xfs_scrub * sc,struct xfs_inode * dp,xchk_dirent_fn dirent_fn,void * priv)25*4c233b5cSDarrick J. Wong xchk_dir_walk_sf(
26*4c233b5cSDarrick J. Wong 	struct xfs_scrub	*sc,
27*4c233b5cSDarrick J. Wong 	struct xfs_inode	*dp,
28*4c233b5cSDarrick J. Wong 	xchk_dirent_fn		dirent_fn,
29*4c233b5cSDarrick J. Wong 	void			*priv)
30*4c233b5cSDarrick J. Wong {
31*4c233b5cSDarrick J. Wong 	struct xfs_name		name = {
32*4c233b5cSDarrick J. Wong 		.name		= ".",
33*4c233b5cSDarrick J. Wong 		.len		= 1,
34*4c233b5cSDarrick J. Wong 		.type		= XFS_DIR3_FT_DIR,
35*4c233b5cSDarrick J. Wong 	};
36*4c233b5cSDarrick J. Wong 	struct xfs_mount	*mp = dp->i_mount;
37*4c233b5cSDarrick J. Wong 	struct xfs_da_geometry	*geo = mp->m_dir_geo;
38*4c233b5cSDarrick J. Wong 	struct xfs_dir2_sf_entry *sfep;
39*4c233b5cSDarrick J. Wong 	struct xfs_dir2_sf_hdr	*sfp;
40*4c233b5cSDarrick J. Wong 	xfs_ino_t		ino;
41*4c233b5cSDarrick J. Wong 	xfs_dir2_dataptr_t	dapos;
42*4c233b5cSDarrick J. Wong 	unsigned int		i;
43*4c233b5cSDarrick J. Wong 	int			error;
44*4c233b5cSDarrick J. Wong 
45*4c233b5cSDarrick J. Wong 	ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
46*4c233b5cSDarrick J. Wong 	ASSERT(dp->i_df.if_u1.if_data != NULL);
47*4c233b5cSDarrick J. Wong 
48*4c233b5cSDarrick J. Wong 	sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data;
49*4c233b5cSDarrick J. Wong 
50*4c233b5cSDarrick J. Wong 	/* dot entry */
51*4c233b5cSDarrick J. Wong 	dapos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
52*4c233b5cSDarrick J. Wong 			geo->data_entry_offset);
53*4c233b5cSDarrick J. Wong 
54*4c233b5cSDarrick J. Wong 	error = dirent_fn(sc, dp, dapos, &name, dp->i_ino, priv);
55*4c233b5cSDarrick J. Wong 	if (error)
56*4c233b5cSDarrick J. Wong 		return error;
57*4c233b5cSDarrick J. Wong 
58*4c233b5cSDarrick J. Wong 	/* dotdot entry */
59*4c233b5cSDarrick J. Wong 	dapos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
60*4c233b5cSDarrick J. Wong 			geo->data_entry_offset +
61*4c233b5cSDarrick J. Wong 			xfs_dir2_data_entsize(mp, sizeof(".") - 1));
62*4c233b5cSDarrick J. Wong 	ino = xfs_dir2_sf_get_parent_ino(sfp);
63*4c233b5cSDarrick J. Wong 	name.name = "..";
64*4c233b5cSDarrick J. Wong 	name.len = 2;
65*4c233b5cSDarrick J. Wong 
66*4c233b5cSDarrick J. Wong 	error = dirent_fn(sc, dp, dapos, &name, ino, priv);
67*4c233b5cSDarrick J. Wong 	if (error)
68*4c233b5cSDarrick J. Wong 		return error;
69*4c233b5cSDarrick J. Wong 
70*4c233b5cSDarrick J. Wong 	/* iterate everything else */
71*4c233b5cSDarrick J. Wong 	sfep = xfs_dir2_sf_firstentry(sfp);
72*4c233b5cSDarrick J. Wong 	for (i = 0; i < sfp->count; i++) {
73*4c233b5cSDarrick J. Wong 		dapos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
74*4c233b5cSDarrick J. Wong 				xfs_dir2_sf_get_offset(sfep));
75*4c233b5cSDarrick J. Wong 		ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
76*4c233b5cSDarrick J. Wong 		name.name = sfep->name;
77*4c233b5cSDarrick J. Wong 		name.len = sfep->namelen;
78*4c233b5cSDarrick J. Wong 		name.type = xfs_dir2_sf_get_ftype(mp, sfep);
79*4c233b5cSDarrick J. Wong 
80*4c233b5cSDarrick J. Wong 		error = dirent_fn(sc, dp, dapos, &name, ino, priv);
81*4c233b5cSDarrick J. Wong 		if (error)
82*4c233b5cSDarrick J. Wong 			return error;
83*4c233b5cSDarrick J. Wong 
84*4c233b5cSDarrick J. Wong 		sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
85*4c233b5cSDarrick J. Wong 	}
86*4c233b5cSDarrick J. Wong 
87*4c233b5cSDarrick J. Wong 	return 0;
88*4c233b5cSDarrick J. Wong }
89*4c233b5cSDarrick J. Wong 
90*4c233b5cSDarrick J. Wong /* Call a function for every entry in a block directory. */
91*4c233b5cSDarrick J. Wong STATIC int
xchk_dir_walk_block(struct xfs_scrub * sc,struct xfs_inode * dp,xchk_dirent_fn dirent_fn,void * priv)92*4c233b5cSDarrick J. Wong xchk_dir_walk_block(
93*4c233b5cSDarrick J. Wong 	struct xfs_scrub	*sc,
94*4c233b5cSDarrick J. Wong 	struct xfs_inode	*dp,
95*4c233b5cSDarrick J. Wong 	xchk_dirent_fn		dirent_fn,
96*4c233b5cSDarrick J. Wong 	void			*priv)
97*4c233b5cSDarrick J. Wong {
98*4c233b5cSDarrick J. Wong 	struct xfs_mount	*mp = dp->i_mount;
99*4c233b5cSDarrick J. Wong 	struct xfs_da_geometry	*geo = mp->m_dir_geo;
100*4c233b5cSDarrick J. Wong 	struct xfs_buf		*bp;
101*4c233b5cSDarrick J. Wong 	unsigned int		off, next_off, end;
102*4c233b5cSDarrick J. Wong 	int			error;
103*4c233b5cSDarrick J. Wong 
104*4c233b5cSDarrick J. Wong 	error = xfs_dir3_block_read(sc->tp, dp, &bp);
105*4c233b5cSDarrick J. Wong 	if (error)
106*4c233b5cSDarrick J. Wong 		return error;
107*4c233b5cSDarrick J. Wong 
108*4c233b5cSDarrick J. Wong 	/* Walk each directory entry. */
109*4c233b5cSDarrick J. Wong 	end = xfs_dir3_data_end_offset(geo, bp->b_addr);
110*4c233b5cSDarrick J. Wong 	for (off = geo->data_entry_offset; off < end; off = next_off) {
111*4c233b5cSDarrick J. Wong 		struct xfs_name			name = { };
112*4c233b5cSDarrick J. Wong 		struct xfs_dir2_data_unused	*dup = bp->b_addr + off;
113*4c233b5cSDarrick J. Wong 		struct xfs_dir2_data_entry	*dep = bp->b_addr + off;
114*4c233b5cSDarrick J. Wong 		xfs_ino_t			ino;
115*4c233b5cSDarrick J. Wong 		xfs_dir2_dataptr_t		dapos;
116*4c233b5cSDarrick J. Wong 
117*4c233b5cSDarrick J. Wong 		/* Skip an empty entry. */
118*4c233b5cSDarrick J. Wong 		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
119*4c233b5cSDarrick J. Wong 			next_off = off + be16_to_cpu(dup->length);
120*4c233b5cSDarrick J. Wong 			continue;
121*4c233b5cSDarrick J. Wong 		}
122*4c233b5cSDarrick J. Wong 
123*4c233b5cSDarrick J. Wong 		/* Otherwise, find the next entry and report it. */
124*4c233b5cSDarrick J. Wong 		next_off = off + xfs_dir2_data_entsize(mp, dep->namelen);
125*4c233b5cSDarrick J. Wong 		if (next_off > end)
126*4c233b5cSDarrick J. Wong 			break;
127*4c233b5cSDarrick J. Wong 
128*4c233b5cSDarrick J. Wong 		dapos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, off);
129*4c233b5cSDarrick J. Wong 		ino = be64_to_cpu(dep->inumber);
130*4c233b5cSDarrick J. Wong 		name.name = dep->name;
131*4c233b5cSDarrick J. Wong 		name.len = dep->namelen;
132*4c233b5cSDarrick J. Wong 		name.type = xfs_dir2_data_get_ftype(mp, dep);
133*4c233b5cSDarrick J. Wong 
134*4c233b5cSDarrick J. Wong 		error = dirent_fn(sc, dp, dapos, &name, ino, priv);
135*4c233b5cSDarrick J. Wong 		if (error)
136*4c233b5cSDarrick J. Wong 			break;
137*4c233b5cSDarrick J. Wong 	}
138*4c233b5cSDarrick J. Wong 
139*4c233b5cSDarrick J. Wong 	xfs_trans_brelse(sc->tp, bp);
140*4c233b5cSDarrick J. Wong 	return error;
141*4c233b5cSDarrick J. Wong }
142*4c233b5cSDarrick J. Wong 
143*4c233b5cSDarrick J. Wong /* Read a leaf-format directory buffer. */
144*4c233b5cSDarrick J. Wong STATIC int
xchk_read_leaf_dir_buf(struct xfs_trans * tp,struct xfs_inode * dp,struct xfs_da_geometry * geo,xfs_dir2_off_t * curoff,struct xfs_buf ** bpp)145*4c233b5cSDarrick J. Wong xchk_read_leaf_dir_buf(
146*4c233b5cSDarrick J. Wong 	struct xfs_trans	*tp,
147*4c233b5cSDarrick J. Wong 	struct xfs_inode	*dp,
148*4c233b5cSDarrick J. Wong 	struct xfs_da_geometry	*geo,
149*4c233b5cSDarrick J. Wong 	xfs_dir2_off_t		*curoff,
150*4c233b5cSDarrick J. Wong 	struct xfs_buf		**bpp)
151*4c233b5cSDarrick J. Wong {
152*4c233b5cSDarrick J. Wong 	struct xfs_iext_cursor	icur;
153*4c233b5cSDarrick J. Wong 	struct xfs_bmbt_irec	map;
154*4c233b5cSDarrick J. Wong 	struct xfs_ifork	*ifp = xfs_ifork_ptr(dp, XFS_DATA_FORK);
155*4c233b5cSDarrick J. Wong 	xfs_dablk_t		last_da;
156*4c233b5cSDarrick J. Wong 	xfs_dablk_t		map_off;
157*4c233b5cSDarrick J. Wong 	xfs_dir2_off_t		new_off;
158*4c233b5cSDarrick J. Wong 
159*4c233b5cSDarrick J. Wong 	*bpp = NULL;
160*4c233b5cSDarrick J. Wong 
161*4c233b5cSDarrick J. Wong 	/*
162*4c233b5cSDarrick J. Wong 	 * Look for mapped directory blocks at or above the current offset.
163*4c233b5cSDarrick J. Wong 	 * Truncate down to the nearest directory block to start the scanning
164*4c233b5cSDarrick J. Wong 	 * operation.
165*4c233b5cSDarrick J. Wong 	 */
166*4c233b5cSDarrick J. Wong 	last_da = xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET);
167*4c233b5cSDarrick J. Wong 	map_off = xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, *curoff));
168*4c233b5cSDarrick J. Wong 
169*4c233b5cSDarrick J. Wong 	if (!xfs_iext_lookup_extent(dp, ifp, map_off, &icur, &map))
170*4c233b5cSDarrick J. Wong 		return 0;
171*4c233b5cSDarrick J. Wong 	if (map.br_startoff >= last_da)
172*4c233b5cSDarrick J. Wong 		return 0;
173*4c233b5cSDarrick J. Wong 	xfs_trim_extent(&map, map_off, last_da - map_off);
174*4c233b5cSDarrick J. Wong 
175*4c233b5cSDarrick J. Wong 	/* Read the directory block of that first mapping. */
176*4c233b5cSDarrick J. Wong 	new_off = xfs_dir2_da_to_byte(geo, map.br_startoff);
177*4c233b5cSDarrick J. Wong 	if (new_off > *curoff)
178*4c233b5cSDarrick J. Wong 		*curoff = new_off;
179*4c233b5cSDarrick J. Wong 
180*4c233b5cSDarrick J. Wong 	return xfs_dir3_data_read(tp, dp, map.br_startoff, 0, bpp);
181*4c233b5cSDarrick J. Wong }
182*4c233b5cSDarrick J. Wong 
183*4c233b5cSDarrick J. Wong /* Call a function for every entry in a leaf directory. */
184*4c233b5cSDarrick J. Wong STATIC int
xchk_dir_walk_leaf(struct xfs_scrub * sc,struct xfs_inode * dp,xchk_dirent_fn dirent_fn,void * priv)185*4c233b5cSDarrick J. Wong xchk_dir_walk_leaf(
186*4c233b5cSDarrick J. Wong 	struct xfs_scrub	*sc,
187*4c233b5cSDarrick J. Wong 	struct xfs_inode	*dp,
188*4c233b5cSDarrick J. Wong 	xchk_dirent_fn		dirent_fn,
189*4c233b5cSDarrick J. Wong 	void			*priv)
190*4c233b5cSDarrick J. Wong {
191*4c233b5cSDarrick J. Wong 	struct xfs_mount	*mp = dp->i_mount;
192*4c233b5cSDarrick J. Wong 	struct xfs_da_geometry	*geo = mp->m_dir_geo;
193*4c233b5cSDarrick J. Wong 	struct xfs_buf		*bp = NULL;
194*4c233b5cSDarrick J. Wong 	xfs_dir2_off_t		curoff = 0;
195*4c233b5cSDarrick J. Wong 	unsigned int		offset = 0;
196*4c233b5cSDarrick J. Wong 	int			error;
197*4c233b5cSDarrick J. Wong 
198*4c233b5cSDarrick J. Wong 	/* Iterate every directory offset in this directory. */
199*4c233b5cSDarrick J. Wong 	while (curoff < XFS_DIR2_LEAF_OFFSET) {
200*4c233b5cSDarrick J. Wong 		struct xfs_name			name = { };
201*4c233b5cSDarrick J. Wong 		struct xfs_dir2_data_unused	*dup;
202*4c233b5cSDarrick J. Wong 		struct xfs_dir2_data_entry	*dep;
203*4c233b5cSDarrick J. Wong 		xfs_ino_t			ino;
204*4c233b5cSDarrick J. Wong 		unsigned int			length;
205*4c233b5cSDarrick J. Wong 		xfs_dir2_dataptr_t		dapos;
206*4c233b5cSDarrick J. Wong 
207*4c233b5cSDarrick J. Wong 		/*
208*4c233b5cSDarrick J. Wong 		 * If we have no buffer, or we're off the end of the
209*4c233b5cSDarrick J. Wong 		 * current buffer, need to get another one.
210*4c233b5cSDarrick J. Wong 		 */
211*4c233b5cSDarrick J. Wong 		if (!bp || offset >= geo->blksize) {
212*4c233b5cSDarrick J. Wong 			if (bp) {
213*4c233b5cSDarrick J. Wong 				xfs_trans_brelse(sc->tp, bp);
214*4c233b5cSDarrick J. Wong 				bp = NULL;
215*4c233b5cSDarrick J. Wong 			}
216*4c233b5cSDarrick J. Wong 
217*4c233b5cSDarrick J. Wong 			error = xchk_read_leaf_dir_buf(sc->tp, dp, geo, &curoff,
218*4c233b5cSDarrick J. Wong 					&bp);
219*4c233b5cSDarrick J. Wong 			if (error || !bp)
220*4c233b5cSDarrick J. Wong 				break;
221*4c233b5cSDarrick J. Wong 
222*4c233b5cSDarrick J. Wong 			/*
223*4c233b5cSDarrick J. Wong 			 * Find our position in the block.
224*4c233b5cSDarrick J. Wong 			 */
225*4c233b5cSDarrick J. Wong 			offset = geo->data_entry_offset;
226*4c233b5cSDarrick J. Wong 			curoff += geo->data_entry_offset;
227*4c233b5cSDarrick J. Wong 		}
228*4c233b5cSDarrick J. Wong 
229*4c233b5cSDarrick J. Wong 		/* Skip an empty entry. */
230*4c233b5cSDarrick J. Wong 		dup = bp->b_addr + offset;
231*4c233b5cSDarrick J. Wong 		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
232*4c233b5cSDarrick J. Wong 			length = be16_to_cpu(dup->length);
233*4c233b5cSDarrick J. Wong 			offset += length;
234*4c233b5cSDarrick J. Wong 			curoff += length;
235*4c233b5cSDarrick J. Wong 			continue;
236*4c233b5cSDarrick J. Wong 		}
237*4c233b5cSDarrick J. Wong 
238*4c233b5cSDarrick J. Wong 		/* Otherwise, find the next entry and report it. */
239*4c233b5cSDarrick J. Wong 		dep = bp->b_addr + offset;
240*4c233b5cSDarrick J. Wong 		length = xfs_dir2_data_entsize(mp, dep->namelen);
241*4c233b5cSDarrick J. Wong 
242*4c233b5cSDarrick J. Wong 		dapos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
243*4c233b5cSDarrick J. Wong 		ino = be64_to_cpu(dep->inumber);
244*4c233b5cSDarrick J. Wong 		name.name = dep->name;
245*4c233b5cSDarrick J. Wong 		name.len = dep->namelen;
246*4c233b5cSDarrick J. Wong 		name.type = xfs_dir2_data_get_ftype(mp, dep);
247*4c233b5cSDarrick J. Wong 
248*4c233b5cSDarrick J. Wong 		error = dirent_fn(sc, dp, dapos, &name, ino, priv);
249*4c233b5cSDarrick J. Wong 		if (error)
250*4c233b5cSDarrick J. Wong 			break;
251*4c233b5cSDarrick J. Wong 
252*4c233b5cSDarrick J. Wong 		/* Advance to the next entry. */
253*4c233b5cSDarrick J. Wong 		offset += length;
254*4c233b5cSDarrick J. Wong 		curoff += length;
255*4c233b5cSDarrick J. Wong 	}
256*4c233b5cSDarrick J. Wong 
257*4c233b5cSDarrick J. Wong 	if (bp)
258*4c233b5cSDarrick J. Wong 		xfs_trans_brelse(sc->tp, bp);
259*4c233b5cSDarrick J. Wong 	return error;
260*4c233b5cSDarrick J. Wong }
261*4c233b5cSDarrick J. Wong 
262*4c233b5cSDarrick J. Wong /*
263*4c233b5cSDarrick J. Wong  * Call a function for every entry in a directory.
264*4c233b5cSDarrick J. Wong  *
265*4c233b5cSDarrick J. Wong  * Callers must hold the ILOCK.  File types are XFS_DIR3_FT_*.
266*4c233b5cSDarrick J. Wong  */
267*4c233b5cSDarrick J. Wong int
xchk_dir_walk(struct xfs_scrub * sc,struct xfs_inode * dp,xchk_dirent_fn dirent_fn,void * priv)268*4c233b5cSDarrick J. Wong xchk_dir_walk(
269*4c233b5cSDarrick J. Wong 	struct xfs_scrub	*sc,
270*4c233b5cSDarrick J. Wong 	struct xfs_inode	*dp,
271*4c233b5cSDarrick J. Wong 	xchk_dirent_fn		dirent_fn,
272*4c233b5cSDarrick J. Wong 	void			*priv)
273*4c233b5cSDarrick J. Wong {
274*4c233b5cSDarrick J. Wong 	struct xfs_da_args	args = {
275*4c233b5cSDarrick J. Wong 		.dp		= dp,
276*4c233b5cSDarrick J. Wong 		.geo		= dp->i_mount->m_dir_geo,
277*4c233b5cSDarrick J. Wong 		.trans		= sc->tp,
278*4c233b5cSDarrick J. Wong 	};
279*4c233b5cSDarrick J. Wong 	bool			isblock;
280*4c233b5cSDarrick J. Wong 	int			error;
281*4c233b5cSDarrick J. Wong 
282*4c233b5cSDarrick J. Wong 	if (xfs_is_shutdown(dp->i_mount))
283*4c233b5cSDarrick J. Wong 		return -EIO;
284*4c233b5cSDarrick J. Wong 
285*4c233b5cSDarrick J. Wong 	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
286*4c233b5cSDarrick J. Wong 	ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
287*4c233b5cSDarrick J. Wong 
288*4c233b5cSDarrick J. Wong 	if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
289*4c233b5cSDarrick J. Wong 		return xchk_dir_walk_sf(sc, dp, dirent_fn, priv);
290*4c233b5cSDarrick J. Wong 
291*4c233b5cSDarrick J. Wong 	/* dir2 functions require that the data fork is loaded */
292*4c233b5cSDarrick J. Wong 	error = xfs_iread_extents(sc->tp, dp, XFS_DATA_FORK);
293*4c233b5cSDarrick J. Wong 	if (error)
294*4c233b5cSDarrick J. Wong 		return error;
295*4c233b5cSDarrick J. Wong 
296*4c233b5cSDarrick J. Wong 	error = xfs_dir2_isblock(&args, &isblock);
297*4c233b5cSDarrick J. Wong 	if (error)
298*4c233b5cSDarrick J. Wong 		return error;
299*4c233b5cSDarrick J. Wong 
300*4c233b5cSDarrick J. Wong 	if (isblock)
301*4c233b5cSDarrick J. Wong 		return xchk_dir_walk_block(sc, dp, dirent_fn, priv);
302*4c233b5cSDarrick J. Wong 
303*4c233b5cSDarrick J. Wong 	return xchk_dir_walk_leaf(sc, dp, dirent_fn, priv);
304*4c233b5cSDarrick J. Wong }
305*4c233b5cSDarrick J. Wong 
306*4c233b5cSDarrick J. Wong /*
307*4c233b5cSDarrick J. Wong  * Look up the inode number for an exact name in a directory.
308*4c233b5cSDarrick J. Wong  *
309*4c233b5cSDarrick J. Wong  * Callers must hold the ILOCK.  File types are XFS_DIR3_FT_*.  Names are not
310*4c233b5cSDarrick J. Wong  * checked for correctness.
311*4c233b5cSDarrick J. Wong  */
312*4c233b5cSDarrick J. Wong int
xchk_dir_lookup(struct xfs_scrub * sc,struct xfs_inode * dp,const struct xfs_name * name,xfs_ino_t * ino)313*4c233b5cSDarrick J. Wong xchk_dir_lookup(
314*4c233b5cSDarrick J. Wong 	struct xfs_scrub	*sc,
315*4c233b5cSDarrick J. Wong 	struct xfs_inode	*dp,
316*4c233b5cSDarrick J. Wong 	const struct xfs_name	*name,
317*4c233b5cSDarrick J. Wong 	xfs_ino_t		*ino)
318*4c233b5cSDarrick J. Wong {
319*4c233b5cSDarrick J. Wong 	struct xfs_da_args	args = {
320*4c233b5cSDarrick J. Wong 		.dp		= dp,
321*4c233b5cSDarrick J. Wong 		.geo		= dp->i_mount->m_dir_geo,
322*4c233b5cSDarrick J. Wong 		.trans		= sc->tp,
323*4c233b5cSDarrick J. Wong 		.name		= name->name,
324*4c233b5cSDarrick J. Wong 		.namelen	= name->len,
325*4c233b5cSDarrick J. Wong 		.filetype	= name->type,
326*4c233b5cSDarrick J. Wong 		.hashval	= xfs_dir2_hashname(dp->i_mount, name),
327*4c233b5cSDarrick J. Wong 		.whichfork	= XFS_DATA_FORK,
328*4c233b5cSDarrick J. Wong 		.op_flags	= XFS_DA_OP_OKNOENT,
329*4c233b5cSDarrick J. Wong 	};
330*4c233b5cSDarrick J. Wong 	bool			isblock, isleaf;
331*4c233b5cSDarrick J. Wong 	int			error;
332*4c233b5cSDarrick J. Wong 
333*4c233b5cSDarrick J. Wong 	if (xfs_is_shutdown(dp->i_mount))
334*4c233b5cSDarrick J. Wong 		return -EIO;
335*4c233b5cSDarrick J. Wong 
336*4c233b5cSDarrick J. Wong 	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
337*4c233b5cSDarrick J. Wong 	ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
338*4c233b5cSDarrick J. Wong 
339*4c233b5cSDarrick J. Wong 	if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
340*4c233b5cSDarrick J. Wong 		error = xfs_dir2_sf_lookup(&args);
341*4c233b5cSDarrick J. Wong 		goto out_check_rval;
342*4c233b5cSDarrick J. Wong 	}
343*4c233b5cSDarrick J. Wong 
344*4c233b5cSDarrick J. Wong 	/* dir2 functions require that the data fork is loaded */
345*4c233b5cSDarrick J. Wong 	error = xfs_iread_extents(sc->tp, dp, XFS_DATA_FORK);
346*4c233b5cSDarrick J. Wong 	if (error)
347*4c233b5cSDarrick J. Wong 		return error;
348*4c233b5cSDarrick J. Wong 
349*4c233b5cSDarrick J. Wong 	error = xfs_dir2_isblock(&args, &isblock);
350*4c233b5cSDarrick J. Wong 	if (error)
351*4c233b5cSDarrick J. Wong 		return error;
352*4c233b5cSDarrick J. Wong 
353*4c233b5cSDarrick J. Wong 	if (isblock) {
354*4c233b5cSDarrick J. Wong 		error = xfs_dir2_block_lookup(&args);
355*4c233b5cSDarrick J. Wong 		goto out_check_rval;
356*4c233b5cSDarrick J. Wong 	}
357*4c233b5cSDarrick J. Wong 
358*4c233b5cSDarrick J. Wong 	error = xfs_dir2_isleaf(&args, &isleaf);
359*4c233b5cSDarrick J. Wong 	if (error)
360*4c233b5cSDarrick J. Wong 		return error;
361*4c233b5cSDarrick J. Wong 
362*4c233b5cSDarrick J. Wong 	if (isleaf) {
363*4c233b5cSDarrick J. Wong 		error = xfs_dir2_leaf_lookup(&args);
364*4c233b5cSDarrick J. Wong 		goto out_check_rval;
365*4c233b5cSDarrick J. Wong 	}
366*4c233b5cSDarrick J. Wong 
367*4c233b5cSDarrick J. Wong 	error = xfs_dir2_node_lookup(&args);
368*4c233b5cSDarrick J. Wong 
369*4c233b5cSDarrick J. Wong out_check_rval:
370*4c233b5cSDarrick J. Wong 	if (error == -EEXIST)
371*4c233b5cSDarrick J. Wong 		error = 0;
372*4c233b5cSDarrick J. Wong 	if (!error)
373*4c233b5cSDarrick J. Wong 		*ino = args.inumber;
374*4c233b5cSDarrick J. Wong 	return error;
375*4c233b5cSDarrick J. Wong }
376