aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_dir2_readdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_dir2_readdir.c')
-rw-r--r--fs/xfs/xfs_dir2_readdir.c85
1 files changed, 40 insertions, 45 deletions
diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c
index fa393d5c2a14..ca1f43cd3939 100644
--- a/fs/xfs/xfs_dir2_readdir.c
+++ b/fs/xfs/xfs_dir2_readdir.c
@@ -76,28 +76,25 @@ const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = {
76 76
77STATIC int 77STATIC int
78xfs_dir2_sf_getdents( 78xfs_dir2_sf_getdents(
79 xfs_inode_t *dp, /* incore directory inode */ 79 struct xfs_da_args *args,
80 struct dir_context *ctx) 80 struct dir_context *ctx)
81{ 81{
82 int i; /* shortform entry number */ 82 int i; /* shortform entry number */
83 xfs_mount_t *mp; /* filesystem mount point */ 83 struct xfs_inode *dp = args->dp; /* incore directory inode */
84 xfs_dir2_dataptr_t off; /* current entry's offset */ 84 xfs_dir2_dataptr_t off; /* current entry's offset */
85 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ 85 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
86 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 86 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */
87 xfs_dir2_dataptr_t dot_offset; 87 xfs_dir2_dataptr_t dot_offset;
88 xfs_dir2_dataptr_t dotdot_offset; 88 xfs_dir2_dataptr_t dotdot_offset;
89 xfs_ino_t ino; 89 xfs_ino_t ino;
90 struct xfs_da_geometry *geo; 90 struct xfs_da_geometry *geo = args->geo;
91
92 mp = dp->i_mount;
93 geo = mp->m_dir_geo;
94 91
95 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 92 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
96 /* 93 /*
97 * Give up if the directory is way too short. 94 * Give up if the directory is way too short.
98 */ 95 */
99 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { 96 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
100 ASSERT(XFS_FORCED_SHUTDOWN(mp)); 97 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
101 return XFS_ERROR(EIO); 98 return XFS_ERROR(EIO);
102 } 99 }
103 100
@@ -163,13 +160,13 @@ xfs_dir2_sf_getdents(
163 filetype = dp->d_ops->sf_get_ftype(sfep); 160 filetype = dp->d_ops->sf_get_ftype(sfep);
164 ctx->pos = off & 0x7fffffff; 161 ctx->pos = off & 0x7fffffff;
165 if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino, 162 if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino,
166 xfs_dir3_get_dtype(mp, filetype))) 163 xfs_dir3_get_dtype(dp->i_mount, filetype)))
167 return 0; 164 return 0;
168 sfep = dp->d_ops->sf_nextentry(sfp, sfep); 165 sfep = dp->d_ops->sf_nextentry(sfp, sfep);
169 } 166 }
170 167
171 ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) & 168 ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
172 0x7fffffff; 169 0x7fffffff;
173 return 0; 170 return 0;
174} 171}
175 172
@@ -178,9 +175,10 @@ xfs_dir2_sf_getdents(
178 */ 175 */
179STATIC int 176STATIC int
180xfs_dir2_block_getdents( 177xfs_dir2_block_getdents(
181 xfs_inode_t *dp, /* incore inode */ 178 struct xfs_da_args *args,
182 struct dir_context *ctx) 179 struct dir_context *ctx)
183{ 180{
181 struct xfs_inode *dp = args->dp; /* incore directory inode */
184 xfs_dir2_data_hdr_t *hdr; /* block header */ 182 xfs_dir2_data_hdr_t *hdr; /* block header */
185 struct xfs_buf *bp; /* buffer for block */ 183 struct xfs_buf *bp; /* buffer for block */
186 xfs_dir2_block_tail_t *btp; /* block tail */ 184 xfs_dir2_block_tail_t *btp; /* block tail */
@@ -188,14 +186,11 @@ xfs_dir2_block_getdents(
188 xfs_dir2_data_unused_t *dup; /* block unused entry */ 186 xfs_dir2_data_unused_t *dup; /* block unused entry */
189 char *endptr; /* end of the data entries */ 187 char *endptr; /* end of the data entries */
190 int error; /* error return value */ 188 int error; /* error return value */
191 xfs_mount_t *mp; /* filesystem mount point */
192 char *ptr; /* current data entry */ 189 char *ptr; /* current data entry */
193 int wantoff; /* starting block offset */ 190 int wantoff; /* starting block offset */
194 xfs_off_t cook; 191 xfs_off_t cook;
195 struct xfs_da_geometry *geo; 192 struct xfs_da_geometry *geo = args->geo;
196 193
197 mp = dp->i_mount;
198 geo = mp->m_dir_geo;
199 /* 194 /*
200 * If the block number in the offset is out of range, we're done. 195 * If the block number in the offset is out of range, we're done.
201 */ 196 */
@@ -258,7 +253,7 @@ xfs_dir2_block_getdents(
258 */ 253 */
259 if (!dir_emit(ctx, (char *)dep->name, dep->namelen, 254 if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
260 be64_to_cpu(dep->inumber), 255 be64_to_cpu(dep->inumber),
261 xfs_dir3_get_dtype(mp, filetype))) { 256 xfs_dir3_get_dtype(dp->i_mount, filetype))) {
262 xfs_trans_brelse(NULL, bp); 257 xfs_trans_brelse(NULL, bp);
263 return 0; 258 return 0;
264 } 259 }
@@ -269,7 +264,7 @@ xfs_dir2_block_getdents(
269 * Set the offset to a non-existent block 1 and return. 264 * Set the offset to a non-existent block 1 and return.
270 */ 265 */
271 ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) & 266 ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
272 0x7fffffff; 267 0x7fffffff;
273 xfs_trans_brelse(NULL, bp); 268 xfs_trans_brelse(NULL, bp);
274 return 0; 269 return 0;
275} 270}
@@ -290,13 +285,13 @@ struct xfs_dir2_leaf_map_info {
290 285
291STATIC int 286STATIC int
292xfs_dir2_leaf_readbuf( 287xfs_dir2_leaf_readbuf(
293 struct xfs_inode *dp, 288 struct xfs_da_args *args,
294 size_t bufsize, 289 size_t bufsize,
295 struct xfs_dir2_leaf_map_info *mip, 290 struct xfs_dir2_leaf_map_info *mip,
296 xfs_dir2_off_t *curoff, 291 xfs_dir2_off_t *curoff,
297 struct xfs_buf **bpp) 292 struct xfs_buf **bpp)
298{ 293{
299 struct xfs_mount *mp = dp->i_mount; 294 struct xfs_inode *dp = args->dp;
300 struct xfs_buf *bp = *bpp; 295 struct xfs_buf *bp = *bpp;
301 struct xfs_bmbt_irec *map = mip->map; 296 struct xfs_bmbt_irec *map = mip->map;
302 struct blk_plug plug; 297 struct blk_plug plug;
@@ -304,7 +299,7 @@ xfs_dir2_leaf_readbuf(
304 int length; 299 int length;
305 int i; 300 int i;
306 int j; 301 int j;
307 struct xfs_da_geometry *geo = mp->m_dir_geo; 302 struct xfs_da_geometry *geo = args->geo;
308 303
309 /* 304 /*
310 * If we have a buffer, we need to release it and 305 * If we have a buffer, we need to release it and
@@ -338,8 +333,7 @@ xfs_dir2_leaf_readbuf(
338 /* 333 /*
339 * Recalculate the readahead blocks wanted. 334 * Recalculate the readahead blocks wanted.
340 */ 335 */
341 mip->ra_want = howmany(bufsize + geo->blksize, 336 mip->ra_want = howmany(bufsize + geo->blksize, (1 << geo->fsblog)) - 1;
342 mp->m_sb.sb_blocksize) - 1;
343 ASSERT(mip->ra_want >= 0); 337 ASSERT(mip->ra_want >= 0);
344 338
345 /* 339 /*
@@ -411,8 +405,8 @@ xfs_dir2_leaf_readbuf(
411 mip->curdb = xfs_dir2_da_to_db(geo, map->br_startoff); 405 mip->curdb = xfs_dir2_da_to_db(geo, map->br_startoff);
412 error = xfs_dir3_data_read(NULL, dp, map->br_startoff, 406 error = xfs_dir3_data_read(NULL, dp, map->br_startoff,
413 map->br_blockcount >= geo->fsbcount ? 407 map->br_blockcount >= geo->fsbcount ?
414 XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, &bp); 408 XFS_FSB_TO_DADDR(dp->i_mount, map->br_startblock) :
415 409 -1, &bp);
416 /* 410 /*
417 * Should just skip over the data block instead of giving up. 411 * Should just skip over the data block instead of giving up.
418 */ 412 */
@@ -441,7 +435,7 @@ xfs_dir2_leaf_readbuf(
441 map[mip->ra_index].br_blockcount >= geo->fsbcount) { 435 map[mip->ra_index].br_blockcount >= geo->fsbcount) {
442 xfs_dir3_data_readahead(dp, 436 xfs_dir3_data_readahead(dp,
443 map[mip->ra_index].br_startoff + mip->ra_offset, 437 map[mip->ra_index].br_startoff + mip->ra_offset,
444 XFS_FSB_TO_DADDR(mp, 438 XFS_FSB_TO_DADDR(dp->i_mount,
445 map[mip->ra_index].br_startblock + 439 map[mip->ra_index].br_startblock +
446 mip->ra_offset)); 440 mip->ra_offset));
447 mip->ra_current = i; 441 mip->ra_current = i;
@@ -493,23 +487,23 @@ out:
493 */ 487 */
494STATIC int 488STATIC int
495xfs_dir2_leaf_getdents( 489xfs_dir2_leaf_getdents(
496 xfs_inode_t *dp, /* incore directory inode */ 490 struct xfs_da_args *args,
497 struct dir_context *ctx, 491 struct dir_context *ctx,
498 size_t bufsize) 492 size_t bufsize)
499{ 493{
494 struct xfs_inode *dp = args->dp;
500 struct xfs_buf *bp = NULL; /* data block buffer */ 495 struct xfs_buf *bp = NULL; /* data block buffer */
501 xfs_dir2_data_hdr_t *hdr; /* data block header */ 496 xfs_dir2_data_hdr_t *hdr; /* data block header */
502 xfs_dir2_data_entry_t *dep; /* data entry */ 497 xfs_dir2_data_entry_t *dep; /* data entry */
503 xfs_dir2_data_unused_t *dup; /* unused entry */ 498 xfs_dir2_data_unused_t *dup; /* unused entry */
504 int error = 0; /* error return value */ 499 int error = 0; /* error return value */
505 int length; /* temporary length value */ 500 int length; /* temporary length value */
506 xfs_mount_t *mp; /* filesystem mount point */
507 int byteoff; /* offset in current block */ 501 int byteoff; /* offset in current block */
508 xfs_dir2_off_t curoff; /* current overall offset */ 502 xfs_dir2_off_t curoff; /* current overall offset */
509 xfs_dir2_off_t newoff; /* new curoff after new blk */ 503 xfs_dir2_off_t newoff; /* new curoff after new blk */
510 char *ptr = NULL; /* pointer to current data */ 504 char *ptr = NULL; /* pointer to current data */
511 struct xfs_dir2_leaf_map_info *map_info; 505 struct xfs_dir2_leaf_map_info *map_info;
512 struct xfs_da_geometry *geo; 506 struct xfs_da_geometry *geo = args->geo;
513 507
514 /* 508 /*
515 * If the offset is at or past the largest allowed value, 509 * If the offset is at or past the largest allowed value,
@@ -518,15 +512,12 @@ xfs_dir2_leaf_getdents(
518 if (ctx->pos >= XFS_DIR2_MAX_DATAPTR) 512 if (ctx->pos >= XFS_DIR2_MAX_DATAPTR)
519 return 0; 513 return 0;
520 514
521 mp = dp->i_mount;
522 geo = mp->m_dir_geo;
523
524 /* 515 /*
525 * Set up to bmap a number of blocks based on the caller's 516 * Set up to bmap a number of blocks based on the caller's
526 * buffer size, the directory block size, and the filesystem 517 * buffer size, the directory block size, and the filesystem
527 * block size. 518 * block size.
528 */ 519 */
529 length = howmany(bufsize + geo->blksize, mp->m_sb.sb_blocksize); 520 length = howmany(bufsize + geo->blksize, (1 << geo->fsblog));
530 map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) + 521 map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) +
531 (length * sizeof(struct xfs_bmbt_irec)), 522 (length * sizeof(struct xfs_bmbt_irec)),
532 KM_SLEEP | KM_NOFS); 523 KM_SLEEP | KM_NOFS);
@@ -558,7 +549,7 @@ xfs_dir2_leaf_getdents(
558 */ 549 */
559 if (!bp || ptr >= (char *)bp->b_addr + geo->blksize) { 550 if (!bp || ptr >= (char *)bp->b_addr + geo->blksize) {
560 551
561 error = xfs_dir2_leaf_readbuf(dp, bufsize, map_info, 552 error = xfs_dir2_leaf_readbuf(args, bufsize, map_info,
562 &curoff, &bp); 553 &curoff, &bp);
563 if (error || !map_info->map_valid) 554 if (error || !map_info->map_valid)
564 break; 555 break;
@@ -566,7 +557,7 @@ xfs_dir2_leaf_getdents(
566 /* 557 /*
567 * Having done a read, we need to set a new offset. 558 * Having done a read, we need to set a new offset.
568 */ 559 */
569 newoff = xfs_dir2_db_off_to_byte(mp->m_dir_geo, 560 newoff = xfs_dir2_db_off_to_byte(geo,
570 map_info->curdb, 0); 561 map_info->curdb, 0);
571 /* 562 /*
572 * Start of the current block. 563 * Start of the current block.
@@ -585,7 +576,7 @@ xfs_dir2_leaf_getdents(
585 * Find our position in the block. 576 * Find our position in the block.
586 */ 577 */
587 ptr = (char *)dp->d_ops->data_entry_p(hdr); 578 ptr = (char *)dp->d_ops->data_entry_p(hdr);
588 byteoff = xfs_dir2_byte_to_off(mp->m_dir_geo, curoff); 579 byteoff = xfs_dir2_byte_to_off(geo, curoff);
589 /* 580 /*
590 * Skip past the header. 581 * Skip past the header.
591 */ 582 */
@@ -644,7 +635,7 @@ xfs_dir2_leaf_getdents(
644 ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff; 635 ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
645 if (!dir_emit(ctx, (char *)dep->name, dep->namelen, 636 if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
646 be64_to_cpu(dep->inumber), 637 be64_to_cpu(dep->inumber),
647 xfs_dir3_get_dtype(mp, filetype))) 638 xfs_dir3_get_dtype(dp->i_mount, filetype)))
648 break; 639 break;
649 640
650 /* 641 /*
@@ -674,13 +665,14 @@ xfs_dir2_leaf_getdents(
674 */ 665 */
675int 666int
676xfs_readdir( 667xfs_readdir(
677 xfs_inode_t *dp, 668 struct xfs_inode *dp,
678 struct dir_context *ctx, 669 struct dir_context *ctx,
679 size_t bufsize) 670 size_t bufsize)
680{ 671{
681 int rval; /* return value */ 672 struct xfs_da_args args = {0};
682 int v; /* type-checking value */ 673 int rval;
683 uint lock_mode; 674 int v;
675 uint lock_mode;
684 676
685 trace_xfs_readdir(dp); 677 trace_xfs_readdir(dp);
686 678
@@ -690,15 +682,18 @@ xfs_readdir(
690 ASSERT(S_ISDIR(dp->i_d.di_mode)); 682 ASSERT(S_ISDIR(dp->i_d.di_mode));
691 XFS_STATS_INC(xs_dir_getdents); 683 XFS_STATS_INC(xs_dir_getdents);
692 684
685 args.dp = dp;
686 args.geo = dp->i_mount->m_dir_geo;
687
693 lock_mode = xfs_ilock_data_map_shared(dp); 688 lock_mode = xfs_ilock_data_map_shared(dp);
694 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) 689 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
695 rval = xfs_dir2_sf_getdents(dp, ctx); 690 rval = xfs_dir2_sf_getdents(&args, ctx);
696 else if ((rval = xfs_dir2_isblock(dp, &v))) 691 else if ((rval = xfs_dir2_isblock(&args, &v)))
697 ; 692 ;
698 else if (v) 693 else if (v)
699 rval = xfs_dir2_block_getdents(dp, ctx); 694 rval = xfs_dir2_block_getdents(&args, ctx);
700 else 695 else
701 rval = xfs_dir2_leaf_getdents(dp, ctx, bufsize); 696 rval = xfs_dir2_leaf_getdents(&args, ctx, bufsize);
702 xfs_iunlock(dp, lock_mode); 697 xfs_iunlock(dp, lock_mode);
703 698
704 return rval; 699 return rval;