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