Blame view
fs/xfs/xfs_dir2_readdir.c
13.4 KB
0b61f8a40 xfs: convert to S... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
4a8af273d xfs: move getdent... |
2 3 4 5 |
/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. |
4a8af273d xfs: move getdent... |
6 7 8 |
*/ #include "xfs.h" #include "xfs_fs.h" |
5467b34bd xfs: move xfs_ino... |
9 |
#include "xfs_shared.h" |
a4fbe6ab1 xfs: decouple ino... |
10 |
#include "xfs_format.h" |
239880ef6 xfs: decouple log... |
11 12 |
#include "xfs_log_format.h" #include "xfs_trans_resv.h" |
4a8af273d xfs: move getdent... |
13 |
#include "xfs_mount.h" |
4a8af273d xfs: move getdent... |
14 |
#include "xfs_inode.h" |
2b9ab5ab9 xfs: reshuffle di... |
15 |
#include "xfs_dir2.h" |
4a8af273d xfs: move getdent... |
16 |
#include "xfs_dir2_priv.h" |
4a8af273d xfs: move getdent... |
17 18 |
#include "xfs_trace.h" #include "xfs_bmap.h" |
239880ef6 xfs: decouple log... |
19 |
#include "xfs_trans.h" |
04df34ac6 xfs: namecheck di... |
20 |
#include "xfs_error.h" |
4a8af273d xfs: move getdent... |
21 |
|
0cb97766f xfs: Add read-onl... |
22 23 24 25 26 27 28 |
/* * Directory file type support functions */ static unsigned char xfs_dir3_filetype_table[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK, DT_WHT, }; |
a5c46e5e8 xfs: scrub direct... |
29 |
unsigned char |
0cb97766f xfs: Add read-onl... |
30 31 |
xfs_dir3_get_dtype( struct xfs_mount *mp, |
c8ce540db xfs: remove doubl... |
32 |
uint8_t filetype) |
0cb97766f xfs: Add read-onl... |
33 34 35 36 37 38 39 40 41 |
{ if (!xfs_sb_version_hasftype(&mp->m_sb)) return DT_UNKNOWN; if (filetype >= XFS_DIR3_FT_MAX) return DT_UNKNOWN; return xfs_dir3_filetype_table[filetype]; } |
0cb97766f xfs: Add read-onl... |
42 |
|
4a8af273d xfs: move getdent... |
43 44 |
STATIC int xfs_dir2_sf_getdents( |
53f82db00 xfs: reduce direc... |
45 |
struct xfs_da_args *args, |
4a8af273d xfs: move getdent... |
46 47 48 |
struct dir_context *ctx) { int i; /* shortform entry number */ |
53f82db00 xfs: reduce direc... |
49 |
struct xfs_inode *dp = args->dp; /* incore directory inode */ |
50f6bb6b7 xfs: devirtualize... |
50 |
struct xfs_mount *mp = dp->i_mount; |
4a8af273d xfs: move getdent... |
51 52 53 54 55 56 |
xfs_dir2_dataptr_t off; /* current entry's offset */ xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ xfs_dir2_dataptr_t dot_offset; xfs_dir2_dataptr_t dotdot_offset; xfs_ino_t ino; |
53f82db00 xfs: reduce direc... |
57 |
struct xfs_da_geometry *geo = args->geo; |
4a8af273d xfs: move getdent... |
58 59 |
ASSERT(dp->i_df.if_flags & XFS_IFINLINE); |
4a8af273d xfs: move getdent... |
60 61 62 63 |
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); ASSERT(dp->i_df.if_u1.if_data != NULL); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; |
4a8af273d xfs: move getdent... |
64 65 66 |
/* * If the block number in the offset is out of range, we're done. */ |
7dda6e864 xfs: convert dire... |
67 |
if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk) |
4a8af273d xfs: move getdent... |
68 69 70 |
return 0; /* |
168231047 xfs: remove the d... |
71 72 73 |
* Precalculate offsets for "." and ".." as we will always need them. * This relies on the fact that directories always start with the * entries for "." and "..". |
4a8af273d xfs: move getdent... |
74 |
*/ |
7dda6e864 xfs: convert dire... |
75 |
dot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, |
d73e1cee8 xfs: move the dir... |
76 |
geo->data_entry_offset); |
7dda6e864 xfs: convert dire... |
77 |
dotdot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, |
d73e1cee8 xfs: move the dir... |
78 |
geo->data_entry_offset + |
fdbb8c5b8 xfs: devirtualize... |
79 |
xfs_dir2_data_entsize(mp, sizeof(".") - 1)); |
4a8af273d xfs: move getdent... |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
/* * Put . entry unless we're starting past it. */ if (ctx->pos <= dot_offset) { ctx->pos = dot_offset & 0x7fffffff; if (!dir_emit(ctx, ".", 1, dp->i_ino, DT_DIR)) return 0; } /* * Put .. entry unless we're starting past it. */ if (ctx->pos <= dotdot_offset) { |
84915e1bd xfs: devirtualize... |
94 |
ino = xfs_dir2_sf_get_parent_ino(sfp); |
4a8af273d xfs: move getdent... |
95 96 97 98 99 100 101 102 103 104 |
ctx->pos = dotdot_offset & 0x7fffffff; if (!dir_emit(ctx, "..", 2, ino, DT_DIR)) return 0; } /* * Loop while there are more entries and put'ing works. */ sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0; i < sfp->count; i++) { |
c8ce540db xfs: remove doubl... |
105 |
uint8_t filetype; |
0cb97766f xfs: Add read-onl... |
106 |
|
7dda6e864 xfs: convert dire... |
107 |
off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, |
4a8af273d xfs: move getdent... |
108 109 110 |
xfs_dir2_sf_get_offset(sfep)); if (ctx->pos > off) { |
50f6bb6b7 xfs: devirtualize... |
111 |
sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep); |
4a8af273d xfs: move getdent... |
112 113 |
continue; } |
93b1e96a4 xfs: devirtualize... |
114 |
ino = xfs_dir2_sf_get_ino(mp, sfp, sfep); |
4501ed2a3 xfs: devirtualize... |
115 |
filetype = xfs_dir2_sf_get_ftype(mp, sfep); |
4a8af273d xfs: move getdent... |
116 |
ctx->pos = off & 0x7fffffff; |
a71895c5d xfs: convert open... |
117 118 119 |
if (XFS_IS_CORRUPT(dp->i_mount, !xfs_dir2_namecheck(sfep->name, sfep->namelen))) |
04df34ac6 xfs: namecheck di... |
120 |
return -EFSCORRUPTED; |
0cb97766f xfs: Add read-onl... |
121 |
if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino, |
50f6bb6b7 xfs: devirtualize... |
122 |
xfs_dir3_get_dtype(mp, filetype))) |
4a8af273d xfs: move getdent... |
123 |
return 0; |
50f6bb6b7 xfs: devirtualize... |
124 |
sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep); |
4a8af273d xfs: move getdent... |
125 |
} |
7dda6e864 xfs: convert dire... |
126 |
ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) & |
53f82db00 xfs: reduce direc... |
127 |
0x7fffffff; |
4a8af273d xfs: move getdent... |
128 129 130 131 132 133 134 135 |
return 0; } /* * Readdir for block directories. */ STATIC int xfs_dir2_block_getdents( |
53f82db00 xfs: reduce direc... |
136 |
struct xfs_da_args *args, |
4a8af273d xfs: move getdent... |
137 138 |
struct dir_context *ctx) { |
53f82db00 xfs: reduce direc... |
139 |
struct xfs_inode *dp = args->dp; /* incore directory inode */ |
4a8af273d xfs: move getdent... |
140 |
struct xfs_buf *bp; /* buffer for block */ |
4a8af273d xfs: move getdent... |
141 |
int error; /* error return value */ |
4a8af273d xfs: move getdent... |
142 143 |
int wantoff; /* starting block offset */ xfs_off_t cook; |
53f82db00 xfs: reduce direc... |
144 |
struct xfs_da_geometry *geo = args->geo; |
dbad7c993 xfs: stop holding... |
145 |
int lock_mode; |
3d28e7e27 xfs: fix regressi... |
146 |
unsigned int offset, next_offset; |
263dde869 xfs: cleanup xfs_... |
147 |
unsigned int end; |
4a8af273d xfs: move getdent... |
148 |
|
4a8af273d xfs: move getdent... |
149 150 151 |
/* * If the block number in the offset is out of range, we're done. */ |
7dda6e864 xfs: convert dire... |
152 |
if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk) |
4a8af273d xfs: move getdent... |
153 |
return 0; |
dbad7c993 xfs: stop holding... |
154 |
lock_mode = xfs_ilock_data_map_shared(dp); |
acb9553ca xfs: pass along t... |
155 |
error = xfs_dir3_block_read(args->trans, dp, &bp); |
dbad7c993 xfs: stop holding... |
156 |
xfs_iunlock(dp, lock_mode); |
4a8af273d xfs: move getdent... |
157 158 159 160 161 162 163 |
if (error) return error; /* * Extract the byte offset we start at from the seek pointer. * We'll skip entries before this. */ |
30028030b xfs: convert dire... |
164 |
wantoff = xfs_dir2_dataptr_to_off(geo, ctx->pos); |
4a8af273d xfs: move getdent... |
165 |
xfs_dir3_data_check(dp, bp); |
4a8af273d xfs: move getdent... |
166 167 168 169 170 |
/* * Loop over the data portion of the block. * Each object is a real entry (dep) or an unused one (dup). */ |
5c072127d xfs: replace xfs_... |
171 |
end = xfs_dir3_data_end_offset(geo, bp->b_addr); |
3d28e7e27 xfs: fix regressi... |
172 173 174 |
for (offset = geo->data_entry_offset; offset < end; offset = next_offset) { |
263dde869 xfs: cleanup xfs_... |
175 176 |
struct xfs_dir2_data_unused *dup = bp->b_addr + offset; struct xfs_dir2_data_entry *dep = bp->b_addr + offset; |
c8ce540db xfs: remove doubl... |
177 |
uint8_t filetype; |
0cb97766f xfs: Add read-onl... |
178 |
|
4a8af273d xfs: move getdent... |
179 180 181 182 |
/* * Unused, skip it. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { |
3d28e7e27 xfs: fix regressi... |
183 |
next_offset = offset + be16_to_cpu(dup->length); |
4a8af273d xfs: move getdent... |
184 185 |
continue; } |
4a8af273d xfs: move getdent... |
186 187 188 |
/* * Bump pointer for the next iteration. */ |
3d28e7e27 xfs: fix regressi... |
189 190 |
next_offset = offset + xfs_dir2_data_entsize(dp->i_mount, dep->namelen); |
263dde869 xfs: cleanup xfs_... |
191 |
|
4a8af273d xfs: move getdent... |
192 193 194 |
/* * The entry is before the desired starting point, skip it. */ |
263dde869 xfs: cleanup xfs_... |
195 |
if (offset < wantoff) |
4a8af273d xfs: move getdent... |
196 |
continue; |
263dde869 xfs: cleanup xfs_... |
197 |
cook = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, offset); |
4a8af273d xfs: move getdent... |
198 199 |
ctx->pos = cook & 0x7fffffff; |
59b8b4650 xfs: devirtualize... |
200 |
filetype = xfs_dir2_data_get_ftype(dp->i_mount, dep); |
4a8af273d xfs: move getdent... |
201 202 203 |
/* * If it didn't fit, set the final offset to here & return. */ |
a71895c5d xfs: convert open... |
204 205 206 |
if (XFS_IS_CORRUPT(dp->i_mount, !xfs_dir2_namecheck(dep->name, dep->namelen))) { |
04df34ac6 xfs: namecheck di... |
207 208 209 |
error = -EFSCORRUPTED; goto out_rele; } |
4a8af273d xfs: move getdent... |
210 |
if (!dir_emit(ctx, (char *)dep->name, dep->namelen, |
0cb97766f xfs: Add read-onl... |
211 |
be64_to_cpu(dep->inumber), |
04df34ac6 xfs: namecheck di... |
212 213 |
xfs_dir3_get_dtype(dp->i_mount, filetype))) goto out_rele; |
4a8af273d xfs: move getdent... |
214 215 216 217 218 219 |
} /* * Reached the end of the block. * Set the offset to a non-existent block 1 and return. */ |
7dda6e864 xfs: convert dire... |
220 |
ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) & |
53f82db00 xfs: reduce direc... |
221 |
0x7fffffff; |
04df34ac6 xfs: namecheck di... |
222 |
out_rele: |
acb9553ca xfs: pass along t... |
223 |
xfs_trans_brelse(args->trans, bp); |
04df34ac6 xfs: namecheck di... |
224 |
return error; |
4a8af273d xfs: move getdent... |
225 |
} |
d205a7d0e xfs: refactor dir... |
226 227 228 229 230 |
/* * Read a directory block and initiate readahead for blocks beyond that. * We maintain a sliding readahead window of the remaining space in the * buffer rounded up to the nearest block. */ |
4a8af273d xfs: move getdent... |
231 232 |
STATIC int xfs_dir2_leaf_readbuf( |
53f82db00 xfs: reduce direc... |
233 |
struct xfs_da_args *args, |
4a8af273d xfs: move getdent... |
234 |
size_t bufsize, |
d205a7d0e xfs: refactor dir... |
235 236 237 |
xfs_dir2_off_t *cur_off, xfs_dablk_t *ra_blk, struct xfs_buf **bpp) |
4a8af273d xfs: move getdent... |
238 |
{ |
53f82db00 xfs: reduce direc... |
239 |
struct xfs_inode *dp = args->dp; |
9f5418010 xfs: concurrent r... |
240 |
struct xfs_buf *bp = NULL; |
d205a7d0e xfs: refactor dir... |
241 242 243 |
struct xfs_da_geometry *geo = args->geo; struct xfs_ifork *ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK); struct xfs_bmbt_irec map; |
4a8af273d xfs: move getdent... |
244 |
struct blk_plug plug; |
d205a7d0e xfs: refactor dir... |
245 246 247 248 |
xfs_dir2_off_t new_off; xfs_dablk_t next_ra; xfs_dablk_t map_off; xfs_dablk_t last_da; |
b2b1712a6 xfs: introduce th... |
249 |
struct xfs_iext_cursor icur; |
d205a7d0e xfs: refactor dir... |
250 |
int ra_want; |
4a8af273d xfs: move getdent... |
251 |
int error = 0; |
4a8af273d xfs: move getdent... |
252 |
|
d205a7d0e xfs: refactor dir... |
253 254 |
if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(args->trans, dp, XFS_DATA_FORK); |
4a8af273d xfs: move getdent... |
255 |
if (error) |
d205a7d0e xfs: refactor dir... |
256 |
goto out; |
4a8af273d xfs: move getdent... |
257 258 259 |
} /* |
d205a7d0e xfs: refactor dir... |
260 261 262 |
* Look for mapped directory blocks at or above the current offset. * Truncate down to the nearest directory block to start the scanning * operation. |
4a8af273d xfs: move getdent... |
263 |
*/ |
d205a7d0e xfs: refactor dir... |
264 265 |
last_da = xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET); map_off = xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, *cur_off)); |
b2b1712a6 xfs: introduce th... |
266 |
if (!xfs_iext_lookup_extent(dp, ifp, map_off, &icur, &map)) |
4a8af273d xfs: move getdent... |
267 |
goto out; |
d205a7d0e xfs: refactor dir... |
268 269 270 |
if (map.br_startoff >= last_da) goto out; xfs_trim_extent(&map, map_off, last_da - map_off); |
4a8af273d xfs: move getdent... |
271 |
|
d205a7d0e xfs: refactor dir... |
272 273 274 275 |
/* Read the directory block of that first mapping. */ new_off = xfs_dir2_da_to_byte(geo, map.br_startoff); if (new_off > *cur_off) *cur_off = new_off; |
cd2c9f1b5 xfs: remove the m... |
276 |
error = xfs_dir3_data_read(args->trans, dp, map.br_startoff, 0, &bp); |
4a8af273d xfs: move getdent... |
277 |
if (error) |
d205a7d0e xfs: refactor dir... |
278 |
goto out; |
4a8af273d xfs: move getdent... |
279 280 |
/* |
d205a7d0e xfs: refactor dir... |
281 282 283 |
* Start readahead for the next bufsize's worth of dir data blocks. * We may have already issued readahead for some of that range; * ra_blk tracks the last block we tried to read(ahead). |
4a8af273d xfs: move getdent... |
284 |
*/ |
d205a7d0e xfs: refactor dir... |
285 286 287 288 289 290 291 292 293 |
ra_want = howmany(bufsize + geo->blksize, (1 << geo->fsblog)); if (*ra_blk >= last_da) goto out; else if (*ra_blk == 0) *ra_blk = map.br_startoff; next_ra = map.br_startoff + geo->fsbcount; if (next_ra >= last_da) goto out_no_ra; if (map.br_blockcount < geo->fsbcount && |
b2b1712a6 xfs: introduce th... |
294 |
!xfs_iext_next_extent(ifp, &icur, &map)) |
d205a7d0e xfs: refactor dir... |
295 296 297 298 299 300 |
goto out_no_ra; if (map.br_startoff >= last_da) goto out_no_ra; xfs_trim_extent(&map, next_ra, last_da - next_ra); /* Start ra for each dir (not fs) block that has a mapping. */ |
4a8af273d xfs: move getdent... |
301 |
blk_start_plug(&plug); |
d205a7d0e xfs: refactor dir... |
302 303 304 305 306 307 308 309 310 |
while (ra_want > 0) { next_ra = roundup((xfs_dablk_t)map.br_startoff, geo->fsbcount); while (ra_want > 0 && next_ra < map.br_startoff + map.br_blockcount) { if (next_ra >= last_da) { *ra_blk = last_da; break; } if (next_ra > *ra_blk) { |
06566fda4 xfs: remove the m... |
311 312 |
xfs_dir3_data_readahead(dp, next_ra, XFS_DABUF_MAP_HOLE_OK); |
d205a7d0e xfs: refactor dir... |
313 |
*ra_blk = next_ra; |
4a8af273d xfs: move getdent... |
314 |
} |
d205a7d0e xfs: refactor dir... |
315 316 317 |
ra_want -= geo->fsbcount; next_ra += geo->fsbcount; } |
b2b1712a6 xfs: introduce th... |
318 |
if (!xfs_iext_next_extent(ifp, &icur, &map)) { |
d205a7d0e xfs: refactor dir... |
319 320 |
*ra_blk = last_da; break; |
4a8af273d xfs: move getdent... |
321 322 323 324 325 326 327 |
} } blk_finish_plug(&plug); out: *bpp = bp; return error; |
d205a7d0e xfs: refactor dir... |
328 329 330 |
out_no_ra: *ra_blk = last_da; goto out; |
4a8af273d xfs: move getdent... |
331 332 333 334 335 336 337 338 |
} /* * Getdents (readdir) for leaf and node directories. * This reads the data blocks only, so is the same for both forms. */ STATIC int xfs_dir2_leaf_getdents( |
53f82db00 xfs: reduce direc... |
339 |
struct xfs_da_args *args, |
4a8af273d xfs: move getdent... |
340 341 342 |
struct dir_context *ctx, size_t bufsize) { |
53f82db00 xfs: reduce direc... |
343 |
struct xfs_inode *dp = args->dp; |
fdbb8c5b8 xfs: devirtualize... |
344 |
struct xfs_mount *mp = dp->i_mount; |
4a8af273d xfs: move getdent... |
345 |
struct xfs_buf *bp = NULL; /* data block buffer */ |
4a8af273d xfs: move getdent... |
346 347 |
xfs_dir2_data_entry_t *dep; /* data entry */ xfs_dir2_data_unused_t *dup; /* unused entry */ |
53f82db00 xfs: reduce direc... |
348 |
struct xfs_da_geometry *geo = args->geo; |
d205a7d0e xfs: refactor dir... |
349 350 351 352 353 |
xfs_dablk_t rablk = 0; /* current readahead block */ xfs_dir2_off_t curoff; /* current overall offset */ int length; /* temporary length value */ int byteoff; /* offset in current block */ int lock_mode; |
2f4369a86 xfs: cleanup xfs_... |
354 |
unsigned int offset = 0; |
d205a7d0e xfs: refactor dir... |
355 |
int error = 0; /* error return value */ |
4a8af273d xfs: move getdent... |
356 357 358 359 360 361 362 |
/* * If the offset is at or past the largest allowed value, * give up right away. */ if (ctx->pos >= XFS_DIR2_MAX_DATAPTR) return 0; |
4a8af273d xfs: move getdent... |
363 |
/* |
4a8af273d xfs: move getdent... |
364 365 366 |
* Inside the loop we keep the main offset value as a byte offset * in the directory file. */ |
259940537 xfs: remove unuse... |
367 |
curoff = xfs_dir2_dataptr_to_byte(ctx->pos); |
4a8af273d xfs: move getdent... |
368 369 |
/* |
4a8af273d xfs: move getdent... |
370 371 372 373 |
* Loop over directory entries until we reach the end offset. * Get more blocks and readahead as necessary. */ while (curoff < XFS_DIR2_LEAF_OFFSET) { |
c8ce540db xfs: remove doubl... |
374 |
uint8_t filetype; |
0cb97766f xfs: Add read-onl... |
375 |
|
4a8af273d xfs: move getdent... |
376 377 378 379 |
/* * If we have no buffer, or we're off the end of the * current buffer, need to get another one. */ |
2f4369a86 xfs: cleanup xfs_... |
380 |
if (!bp || offset >= geo->blksize) { |
9f5418010 xfs: concurrent r... |
381 |
if (bp) { |
d205a7d0e xfs: refactor dir... |
382 |
xfs_trans_brelse(args->trans, bp); |
9f5418010 xfs: concurrent r... |
383 |
bp = NULL; |
9f5418010 xfs: concurrent r... |
384 |
} |
4a8af273d xfs: move getdent... |
385 |
|
dbad7c993 xfs: stop holding... |
386 |
lock_mode = xfs_ilock_data_map_shared(dp); |
d205a7d0e xfs: refactor dir... |
387 388 |
error = xfs_dir2_leaf_readbuf(args, bufsize, &curoff, &rablk, &bp); |
dbad7c993 xfs: stop holding... |
389 |
xfs_iunlock(dp, lock_mode); |
d205a7d0e xfs: refactor dir... |
390 |
if (error || !bp) |
4a8af273d xfs: move getdent... |
391 |
break; |
4a8af273d xfs: move getdent... |
392 393 394 395 |
xfs_dir3_data_check(dp, bp); /* * Find our position in the block. */ |
d73e1cee8 xfs: move the dir... |
396 |
offset = geo->data_entry_offset; |
53f82db00 xfs: reduce direc... |
397 |
byteoff = xfs_dir2_byte_to_off(geo, curoff); |
4a8af273d xfs: move getdent... |
398 399 400 401 |
/* * Skip past the header. */ if (byteoff == 0) |
d73e1cee8 xfs: move the dir... |
402 |
curoff += geo->data_entry_offset; |
4a8af273d xfs: move getdent... |
403 404 405 406 |
/* * Skip past entries until we reach our offset. */ else { |
2f4369a86 xfs: cleanup xfs_... |
407 408 |
while (offset < byteoff) { dup = bp->b_addr + offset; |
4a8af273d xfs: move getdent... |
409 410 411 412 413 |
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { length = be16_to_cpu(dup->length); |
2f4369a86 xfs: cleanup xfs_... |
414 |
offset += length; |
4a8af273d xfs: move getdent... |
415 416 |
continue; } |
2f4369a86 xfs: cleanup xfs_... |
417 |
dep = bp->b_addr + offset; |
fdbb8c5b8 xfs: devirtualize... |
418 419 |
length = xfs_dir2_data_entsize(mp, dep->namelen); |
2f4369a86 xfs: cleanup xfs_... |
420 |
offset += length; |
4a8af273d xfs: move getdent... |
421 422 423 424 425 |
} /* * Now set our real offset. */ curoff = |
30028030b xfs: convert dire... |
426 427 |
xfs_dir2_db_off_to_byte(geo, xfs_dir2_byte_to_db(geo, curoff), |
2f4369a86 xfs: cleanup xfs_... |
428 429 |
offset); if (offset >= geo->blksize) |
4a8af273d xfs: move getdent... |
430 |
continue; |
4a8af273d xfs: move getdent... |
431 432 |
} } |
2f4369a86 xfs: cleanup xfs_... |
433 |
|
4a8af273d xfs: move getdent... |
434 |
/* |
2f4369a86 xfs: cleanup xfs_... |
435 |
* We have a pointer to an entry. Is it a live one? |
4a8af273d xfs: move getdent... |
436 |
*/ |
2f4369a86 xfs: cleanup xfs_... |
437 |
dup = bp->b_addr + offset; |
4a8af273d xfs: move getdent... |
438 439 440 441 442 |
/* * No, it's unused, skip over it. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { length = be16_to_cpu(dup->length); |
2f4369a86 xfs: cleanup xfs_... |
443 |
offset += length; |
4a8af273d xfs: move getdent... |
444 445 446 |
curoff += length; continue; } |
2f4369a86 xfs: cleanup xfs_... |
447 |
dep = bp->b_addr + offset; |
fdbb8c5b8 xfs: devirtualize... |
448 |
length = xfs_dir2_data_entsize(mp, dep->namelen); |
59b8b4650 xfs: devirtualize... |
449 |
filetype = xfs_dir2_data_get_ftype(mp, dep); |
4a8af273d xfs: move getdent... |
450 |
|
259940537 xfs: remove unuse... |
451 |
ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff; |
a71895c5d xfs: convert open... |
452 453 454 |
if (XFS_IS_CORRUPT(dp->i_mount, !xfs_dir2_namecheck(dep->name, dep->namelen))) { |
04df34ac6 xfs: namecheck di... |
455 456 457 |
error = -EFSCORRUPTED; break; } |
4a8af273d xfs: move getdent... |
458 |
if (!dir_emit(ctx, (char *)dep->name, dep->namelen, |
0cb97766f xfs: Add read-onl... |
459 |
be64_to_cpu(dep->inumber), |
53f82db00 xfs: reduce direc... |
460 |
xfs_dir3_get_dtype(dp->i_mount, filetype))) |
4a8af273d xfs: move getdent... |
461 462 463 464 465 |
break; /* * Advance to next entry in the block. */ |
2f4369a86 xfs: cleanup xfs_... |
466 |
offset += length; |
4a8af273d xfs: move getdent... |
467 468 469 470 471 472 473 474 |
curoff += length; /* bufsize may have just been a guess; don't go negative */ bufsize = bufsize > length ? bufsize - length : 0; } /* * All done. Set output offset value to current offset. */ |
259940537 xfs: remove unuse... |
475 |
if (curoff > xfs_dir2_dataptr_to_byte(XFS_DIR2_MAX_DATAPTR)) |
4a8af273d xfs: move getdent... |
476 477 |
ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff; else |
259940537 xfs: remove unuse... |
478 |
ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff; |
4a8af273d xfs: move getdent... |
479 |
if (bp) |
acb9553ca xfs: pass along t... |
480 |
xfs_trans_brelse(args->trans, bp); |
4a8af273d xfs: move getdent... |
481 482 483 484 485 |
return error; } /* * Read a directory. |
acb9553ca xfs: pass along t... |
486 487 488 489 490 |
* * If supplied, the transaction collects locked dir buffers to avoid * nested buffer deadlocks. This function does not dirty the * transaction. The caller should ensure that the inode is locked * before calling this function. |
4a8af273d xfs: move getdent... |
491 492 493 |
*/ int xfs_readdir( |
acb9553ca xfs: pass along t... |
494 |
struct xfs_trans *tp, |
53f82db00 xfs: reduce direc... |
495 496 497 |
struct xfs_inode *dp, struct dir_context *ctx, size_t bufsize) |
4a8af273d xfs: move getdent... |
498 |
{ |
35f46c5f0 xfs: fix xfs_da_a... |
499 |
struct xfs_da_args args = { NULL }; |
53f82db00 xfs: reduce direc... |
500 501 |
int rval; int v; |
4a8af273d xfs: move getdent... |
502 503 504 505 |
trace_xfs_readdir(dp); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) |
2451337dd xfs: global error... |
506 |
return -EIO; |
4a8af273d xfs: move getdent... |
507 |
|
c19b3b05a xfs: mode di_mode... |
508 |
ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); |
ff6d6af23 xfs: per-filesyst... |
509 |
XFS_STATS_INC(dp->i_mount, xs_dir_getdents); |
4a8af273d xfs: move getdent... |
510 |
|
53f82db00 xfs: reduce direc... |
511 512 |
args.dp = dp; args.geo = dp->i_mount->m_dir_geo; |
acb9553ca xfs: pass along t... |
513 |
args.trans = tp; |
53f82db00 xfs: reduce direc... |
514 |
|
f7e67b20e xfs: move the for... |
515 |
if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) |
53f82db00 xfs: reduce direc... |
516 517 |
rval = xfs_dir2_sf_getdents(&args, ctx); else if ((rval = xfs_dir2_isblock(&args, &v))) |
4a8af273d xfs: move getdent... |
518 519 |
; else if (v) |
53f82db00 xfs: reduce direc... |
520 |
rval = xfs_dir2_block_getdents(&args, ctx); |
4a8af273d xfs: move getdent... |
521 |
else |
53f82db00 xfs: reduce direc... |
522 |
rval = xfs_dir2_leaf_getdents(&args, ctx, bufsize); |
40194ecc6 xfs: reinstate th... |
523 |
|
4a8af273d xfs: move getdent... |
524 525 |
return rval; } |