diff options
Diffstat (limited to 'fs/xfs/xfs_dir2.c')
-rw-r--r-- | fs/xfs/xfs_dir2.c | 156 |
1 files changed, 29 insertions, 127 deletions
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index dba7a71cedf..a2e27010c7f 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c | |||
@@ -24,20 +24,17 @@ | |||
24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
27 | #include "xfs_dir2.h" | ||
28 | #include "xfs_mount.h" | 27 | #include "xfs_mount.h" |
29 | #include "xfs_da_btree.h" | 28 | #include "xfs_da_btree.h" |
30 | #include "xfs_bmap_btree.h" | 29 | #include "xfs_bmap_btree.h" |
31 | #include "xfs_alloc_btree.h" | 30 | #include "xfs_alloc_btree.h" |
32 | #include "xfs_dir2_sf.h" | ||
33 | #include "xfs_dinode.h" | 31 | #include "xfs_dinode.h" |
34 | #include "xfs_inode.h" | 32 | #include "xfs_inode.h" |
35 | #include "xfs_inode_item.h" | 33 | #include "xfs_inode_item.h" |
36 | #include "xfs_bmap.h" | 34 | #include "xfs_bmap.h" |
37 | #include "xfs_dir2_data.h" | 35 | #include "xfs_dir2.h" |
38 | #include "xfs_dir2_leaf.h" | 36 | #include "xfs_dir2_format.h" |
39 | #include "xfs_dir2_block.h" | 37 | #include "xfs_dir2_priv.h" |
40 | #include "xfs_dir2_node.h" | ||
41 | #include "xfs_error.h" | 38 | #include "xfs_error.h" |
42 | #include "xfs_vnodeops.h" | 39 | #include "xfs_vnodeops.h" |
43 | #include "xfs_trace.h" | 40 | #include "xfs_trace.h" |
@@ -122,15 +119,15 @@ int | |||
122 | xfs_dir_isempty( | 119 | xfs_dir_isempty( |
123 | xfs_inode_t *dp) | 120 | xfs_inode_t *dp) |
124 | { | 121 | { |
125 | xfs_dir2_sf_t *sfp; | 122 | xfs_dir2_sf_hdr_t *sfp; |
126 | 123 | ||
127 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 124 | ASSERT(S_ISDIR(dp->i_d.di_mode)); |
128 | if (dp->i_d.di_size == 0) /* might happen during shutdown. */ | 125 | if (dp->i_d.di_size == 0) /* might happen during shutdown. */ |
129 | return 1; | 126 | return 1; |
130 | if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) | 127 | if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) |
131 | return 0; | 128 | return 0; |
132 | sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; | 129 | sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; |
133 | return !sfp->hdr.count; | 130 | return !sfp->count; |
134 | } | 131 | } |
135 | 132 | ||
136 | /* | 133 | /* |
@@ -182,7 +179,7 @@ xfs_dir_init( | |||
182 | memset((char *)&args, 0, sizeof(args)); | 179 | memset((char *)&args, 0, sizeof(args)); |
183 | args.dp = dp; | 180 | args.dp = dp; |
184 | args.trans = tp; | 181 | args.trans = tp; |
185 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 182 | ASSERT(S_ISDIR(dp->i_d.di_mode)); |
186 | if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) | 183 | if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) |
187 | return error; | 184 | return error; |
188 | return xfs_dir2_sf_create(&args, pdp->i_ino); | 185 | return xfs_dir2_sf_create(&args, pdp->i_ino); |
@@ -205,7 +202,7 @@ xfs_dir_createname( | |||
205 | int rval; | 202 | int rval; |
206 | int v; /* type-checking value */ | 203 | int v; /* type-checking value */ |
207 | 204 | ||
208 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 205 | ASSERT(S_ISDIR(dp->i_d.di_mode)); |
209 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) | 206 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) |
210 | return rval; | 207 | return rval; |
211 | XFS_STATS_INC(xs_dir_create); | 208 | XFS_STATS_INC(xs_dir_create); |
@@ -281,7 +278,7 @@ xfs_dir_lookup( | |||
281 | int rval; | 278 | int rval; |
282 | int v; /* type-checking value */ | 279 | int v; /* type-checking value */ |
283 | 280 | ||
284 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 281 | ASSERT(S_ISDIR(dp->i_d.di_mode)); |
285 | XFS_STATS_INC(xs_dir_lookup); | 282 | XFS_STATS_INC(xs_dir_lookup); |
286 | 283 | ||
287 | memset(&args, 0, sizeof(xfs_da_args_t)); | 284 | memset(&args, 0, sizeof(xfs_da_args_t)); |
@@ -336,7 +333,7 @@ xfs_dir_removename( | |||
336 | int rval; | 333 | int rval; |
337 | int v; /* type-checking value */ | 334 | int v; /* type-checking value */ |
338 | 335 | ||
339 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 336 | ASSERT(S_ISDIR(dp->i_d.di_mode)); |
340 | XFS_STATS_INC(xs_dir_remove); | 337 | XFS_STATS_INC(xs_dir_remove); |
341 | 338 | ||
342 | memset(&args, 0, sizeof(xfs_da_args_t)); | 339 | memset(&args, 0, sizeof(xfs_da_args_t)); |
@@ -385,7 +382,7 @@ xfs_readdir( | |||
385 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | 382 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) |
386 | return XFS_ERROR(EIO); | 383 | return XFS_ERROR(EIO); |
387 | 384 | ||
388 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 385 | ASSERT(S_ISDIR(dp->i_d.di_mode)); |
389 | XFS_STATS_INC(xs_dir_getdents); | 386 | XFS_STATS_INC(xs_dir_getdents); |
390 | 387 | ||
391 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 388 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
@@ -417,7 +414,7 @@ xfs_dir_replace( | |||
417 | int rval; | 414 | int rval; |
418 | int v; /* type-checking value */ | 415 | int v; /* type-checking value */ |
419 | 416 | ||
420 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 417 | ASSERT(S_ISDIR(dp->i_d.di_mode)); |
421 | 418 | ||
422 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) | 419 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) |
423 | return rval; | 420 | return rval; |
@@ -467,7 +464,7 @@ xfs_dir_canenter( | |||
467 | if (resblks) | 464 | if (resblks) |
468 | return 0; | 465 | return 0; |
469 | 466 | ||
470 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 467 | ASSERT(S_ISDIR(dp->i_d.di_mode)); |
471 | 468 | ||
472 | memset(&args, 0, sizeof(xfs_da_args_t)); | 469 | memset(&args, 0, sizeof(xfs_da_args_t)); |
473 | args.name = name->name; | 470 | args.name = name->name; |
@@ -500,129 +497,34 @@ xfs_dir_canenter( | |||
500 | 497 | ||
501 | /* | 498 | /* |
502 | * Add a block to the directory. | 499 | * Add a block to the directory. |
503 | * This routine is for data and free blocks, not leaf/node blocks | 500 | * |
504 | * which are handled by xfs_da_grow_inode. | 501 | * This routine is for data and free blocks, not leaf/node blocks which are |
502 | * handled by xfs_da_grow_inode. | ||
505 | */ | 503 | */ |
506 | int | 504 | int |
507 | xfs_dir2_grow_inode( | 505 | xfs_dir2_grow_inode( |
508 | xfs_da_args_t *args, | 506 | struct xfs_da_args *args, |
509 | int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ | 507 | int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ |
510 | xfs_dir2_db_t *dbp) /* out: block number added */ | 508 | xfs_dir2_db_t *dbp) /* out: block number added */ |
511 | { | 509 | { |
512 | xfs_fileoff_t bno; /* directory offset of new block */ | 510 | struct xfs_inode *dp = args->dp; |
513 | int count; /* count of filesystem blocks */ | 511 | struct xfs_mount *mp = dp->i_mount; |
514 | xfs_inode_t *dp; /* incore directory inode */ | 512 | xfs_fileoff_t bno; /* directory offset of new block */ |
515 | int error; | 513 | int count; /* count of filesystem blocks */ |
516 | int got; /* blocks actually mapped */ | 514 | int error; |
517 | int i; | ||
518 | xfs_bmbt_irec_t map; /* single structure for bmap */ | ||
519 | int mapi; /* mapping index */ | ||
520 | xfs_bmbt_irec_t *mapp; /* bmap mapping structure(s) */ | ||
521 | xfs_mount_t *mp; | ||
522 | int nmap; /* number of bmap entries */ | ||
523 | xfs_trans_t *tp; | ||
524 | xfs_drfsbno_t nblks; | ||
525 | 515 | ||
526 | trace_xfs_dir2_grow_inode(args, space); | 516 | trace_xfs_dir2_grow_inode(args, space); |
527 | 517 | ||
528 | dp = args->dp; | ||
529 | tp = args->trans; | ||
530 | mp = dp->i_mount; | ||
531 | nblks = dp->i_d.di_nblocks; | ||
532 | /* | 518 | /* |
533 | * Set lowest possible block in the space requested. | 519 | * Set lowest possible block in the space requested. |
534 | */ | 520 | */ |
535 | bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE); | 521 | bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE); |
536 | count = mp->m_dirblkfsbs; | 522 | count = mp->m_dirblkfsbs; |
537 | /* | ||
538 | * Find the first hole for our block. | ||
539 | */ | ||
540 | if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) | ||
541 | return error; | ||
542 | nmap = 1; | ||
543 | ASSERT(args->firstblock != NULL); | ||
544 | /* | ||
545 | * Try mapping the new block contiguously (one extent). | ||
546 | */ | ||
547 | if ((error = xfs_bmapi(tp, dp, bno, count, | ||
548 | XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, | ||
549 | args->firstblock, args->total, &map, &nmap, | ||
550 | args->flist))) | ||
551 | return error; | ||
552 | ASSERT(nmap <= 1); | ||
553 | if (nmap == 1) { | ||
554 | mapp = ↦ | ||
555 | mapi = 1; | ||
556 | } | ||
557 | /* | ||
558 | * Didn't work and this is a multiple-fsb directory block. | ||
559 | * Try again with contiguous flag turned on. | ||
560 | */ | ||
561 | else if (nmap == 0 && count > 1) { | ||
562 | xfs_fileoff_t b; /* current file offset */ | ||
563 | 523 | ||
564 | /* | 524 | error = xfs_da_grow_inode_int(args, &bno, count); |
565 | * Space for maximum number of mappings. | 525 | if (error) |
566 | */ | 526 | return error; |
567 | mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); | ||
568 | /* | ||
569 | * Iterate until we get to the end of our block. | ||
570 | */ | ||
571 | for (b = bno, mapi = 0; b < bno + count; ) { | ||
572 | int c; /* current fsb count */ | ||
573 | |||
574 | /* | ||
575 | * Can't map more than MAX_NMAP at once. | ||
576 | */ | ||
577 | nmap = MIN(XFS_BMAP_MAX_NMAP, count); | ||
578 | c = (int)(bno + count - b); | ||
579 | if ((error = xfs_bmapi(tp, dp, b, c, | ||
580 | XFS_BMAPI_WRITE|XFS_BMAPI_METADATA, | ||
581 | args->firstblock, args->total, | ||
582 | &mapp[mapi], &nmap, args->flist))) { | ||
583 | kmem_free(mapp); | ||
584 | return error; | ||
585 | } | ||
586 | if (nmap < 1) | ||
587 | break; | ||
588 | /* | ||
589 | * Add this bunch into our table, go to the next offset. | ||
590 | */ | ||
591 | mapi += nmap; | ||
592 | b = mapp[mapi - 1].br_startoff + | ||
593 | mapp[mapi - 1].br_blockcount; | ||
594 | } | ||
595 | } | ||
596 | /* | ||
597 | * Didn't work. | ||
598 | */ | ||
599 | else { | ||
600 | mapi = 0; | ||
601 | mapp = NULL; | ||
602 | } | ||
603 | /* | ||
604 | * See how many fsb's we got. | ||
605 | */ | ||
606 | for (i = 0, got = 0; i < mapi; i++) | ||
607 | got += mapp[i].br_blockcount; | ||
608 | /* | ||
609 | * Didn't get enough fsb's, or the first/last block's are wrong. | ||
610 | */ | ||
611 | if (got != count || mapp[0].br_startoff != bno || | ||
612 | mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != | ||
613 | bno + count) { | ||
614 | if (mapp != &map) | ||
615 | kmem_free(mapp); | ||
616 | return XFS_ERROR(ENOSPC); | ||
617 | } | ||
618 | /* | ||
619 | * Done with the temporary mapping table. | ||
620 | */ | ||
621 | if (mapp != &map) | ||
622 | kmem_free(mapp); | ||
623 | 527 | ||
624 | /* account for newly allocated blocks in reserved blocks total */ | ||
625 | args->total -= dp->i_d.di_nblocks - nblks; | ||
626 | *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); | 528 | *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); |
627 | 529 | ||
628 | /* | 530 | /* |
@@ -634,7 +536,7 @@ xfs_dir2_grow_inode( | |||
634 | size = XFS_FSB_TO_B(mp, bno + count); | 536 | size = XFS_FSB_TO_B(mp, bno + count); |
635 | if (size > dp->i_d.di_size) { | 537 | if (size > dp->i_d.di_size) { |
636 | dp->i_d.di_size = size; | 538 | dp->i_d.di_size = size; |
637 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 539 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); |
638 | } | 540 | } |
639 | } | 541 | } |
640 | return 0; | 542 | return 0; |