diff options
Diffstat (limited to 'fs/xfs/xfs_dir2_readdir.c')
-rw-r--r-- | fs/xfs/xfs_dir2_readdir.c | 85 |
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 | ||
77 | STATIC int | 77 | STATIC int |
78 | xfs_dir2_sf_getdents( | 78 | xfs_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 | */ |
179 | STATIC int | 176 | STATIC int |
180 | xfs_dir2_block_getdents( | 177 | xfs_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 | ||
291 | STATIC int | 286 | STATIC int |
292 | xfs_dir2_leaf_readbuf( | 287 | xfs_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 | */ |
494 | STATIC int | 488 | STATIC int |
495 | xfs_dir2_leaf_getdents( | 489 | xfs_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 | */ |
675 | int | 666 | int |
676 | xfs_readdir( | 667 | xfs_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; |