diff options
-rw-r--r-- | fs/xfs/xfs_bmap.c | 416 |
1 files changed, 173 insertions, 243 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index d9de5ae1fd5c..0c9be0ed606e 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -50,17 +50,22 @@ | |||
50 | #include "xfs_trace.h" | 50 | #include "xfs_trace.h" |
51 | 51 | ||
52 | 52 | ||
53 | #ifdef DEBUG | ||
54 | STATIC void | ||
55 | xfs_bmap_check_leaf_extents(xfs_btree_cur_t *cur, xfs_inode_t *ip, int whichfork); | ||
56 | #endif | ||
57 | |||
58 | kmem_zone_t *xfs_bmap_free_item_zone; | 53 | kmem_zone_t *xfs_bmap_free_item_zone; |
59 | 54 | ||
60 | /* | 55 | /* |
61 | * Prototypes for internal bmap routines. | 56 | * Prototypes for internal bmap routines. |
62 | */ | 57 | */ |
63 | 58 | ||
59 | #ifdef DEBUG | ||
60 | STATIC void | ||
61 | xfs_bmap_check_leaf_extents( | ||
62 | struct xfs_btree_cur *cur, | ||
63 | struct xfs_inode *ip, | ||
64 | int whichfork); | ||
65 | #else | ||
66 | #define xfs_bmap_check_leaf_extents(cur, ip, whichfork) do { } while (0) | ||
67 | #endif | ||
68 | |||
64 | 69 | ||
65 | /* | 70 | /* |
66 | * Called from xfs_bmap_add_attrfork to handle extents format files. | 71 | * Called from xfs_bmap_add_attrfork to handle extents format files. |
@@ -85,47 +90,6 @@ xfs_bmap_add_attrfork_local( | |||
85 | int *flags); /* inode logging flags */ | 90 | int *flags); /* inode logging flags */ |
86 | 91 | ||
87 | /* | 92 | /* |
88 | * Called by xfs_bmap_add_extent to handle cases converting a delayed | ||
89 | * allocation to a real allocation. | ||
90 | */ | ||
91 | STATIC int /* error */ | ||
92 | xfs_bmap_add_extent_delay_real( | ||
93 | struct xfs_trans *tp, /* transaction pointer */ | ||
94 | xfs_inode_t *ip, /* incore inode pointer */ | ||
95 | xfs_extnum_t *idx, /* extent number to update/insert */ | ||
96 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ | ||
97 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | ||
98 | xfs_filblks_t *dnew, /* new delayed-alloc indirect blocks */ | ||
99 | xfs_fsblock_t *first, /* pointer to firstblock variable */ | ||
100 | xfs_bmap_free_t *flist, /* list of extents to be freed */ | ||
101 | int *logflagsp); /* inode logging flags */ | ||
102 | |||
103 | /* | ||
104 | * Called by xfs_bmap_add_extent to handle cases converting a hole | ||
105 | * to a real allocation. | ||
106 | */ | ||
107 | STATIC int /* error */ | ||
108 | xfs_bmap_add_extent_hole_real( | ||
109 | xfs_inode_t *ip, /* incore inode pointer */ | ||
110 | xfs_extnum_t *idx, /* extent number to update/insert */ | ||
111 | xfs_btree_cur_t *cur, /* if null, not a btree */ | ||
112 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | ||
113 | int *logflagsp, /* inode logging flags */ | ||
114 | int whichfork); /* data or attr fork */ | ||
115 | |||
116 | /* | ||
117 | * Called by xfs_bmap_add_extent to handle cases converting an unwritten | ||
118 | * allocation to a real allocation or vice versa. | ||
119 | */ | ||
120 | STATIC int /* error */ | ||
121 | xfs_bmap_add_extent_unwritten_real( | ||
122 | xfs_inode_t *ip, /* incore inode pointer */ | ||
123 | xfs_extnum_t *idx, /* extent number to update/insert */ | ||
124 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ | ||
125 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | ||
126 | int *logflagsp); /* inode logging flags */ | ||
127 | |||
128 | /* | ||
129 | * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. | 93 | * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. |
130 | * It figures out where to ask the underlying allocator to put the new extent. | 94 | * It figures out where to ask the underlying allocator to put the new extent. |
131 | */ | 95 | */ |
@@ -407,147 +371,7 @@ xfs_bmap_add_attrfork_local( | |||
407 | } | 371 | } |
408 | 372 | ||
409 | /* | 373 | /* |
410 | * Update file extent records and the btree after allocating space. | 374 | * Convert a delayed allocation to a real allocation. |
411 | */ | ||
412 | STATIC int /* error */ | ||
413 | xfs_bmap_add_extent( | ||
414 | struct xfs_trans *tp, /* transaction pointer */ | ||
415 | xfs_inode_t *ip, /* incore inode pointer */ | ||
416 | xfs_extnum_t *idx, /* extent number to update/insert */ | ||
417 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ | ||
418 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | ||
419 | xfs_fsblock_t *first, /* pointer to firstblock variable */ | ||
420 | xfs_bmap_free_t *flist, /* list of extents to be freed */ | ||
421 | int *logflagsp, /* inode logging flags */ | ||
422 | int whichfork) /* data or attr fork */ | ||
423 | { | ||
424 | xfs_btree_cur_t *cur; /* btree cursor or null */ | ||
425 | xfs_filblks_t da_new; /* new count del alloc blocks used */ | ||
426 | xfs_filblks_t da_old; /* old count del alloc blocks used */ | ||
427 | int error; /* error return value */ | ||
428 | xfs_ifork_t *ifp; /* inode fork ptr */ | ||
429 | int logflags; /* returned value */ | ||
430 | xfs_extnum_t nextents; /* number of extents in file now */ | ||
431 | |||
432 | XFS_STATS_INC(xs_add_exlist); | ||
433 | |||
434 | cur = *curp; | ||
435 | ifp = XFS_IFORK_PTR(ip, whichfork); | ||
436 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | ||
437 | da_old = da_new = 0; | ||
438 | error = 0; | ||
439 | |||
440 | ASSERT(*idx >= 0); | ||
441 | ASSERT(*idx <= nextents); | ||
442 | ASSERT(!isnullstartblock(new->br_startblock)); | ||
443 | |||
444 | /* | ||
445 | * Real allocation off the end of the file. | ||
446 | */ | ||
447 | if (*idx == nextents) { | ||
448 | if (cur) | ||
449 | ASSERT((cur->bc_private.b.flags & | ||
450 | XFS_BTCUR_BPRV_WASDEL) == 0); | ||
451 | error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new, | ||
452 | &logflags, whichfork); | ||
453 | } else { | ||
454 | xfs_bmbt_irec_t prev; /* old extent at offset idx */ | ||
455 | |||
456 | /* | ||
457 | * Get the record referred to by idx. | ||
458 | */ | ||
459 | xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &prev); | ||
460 | /* | ||
461 | * If it's a real allocation record, and the new allocation ends | ||
462 | * after the start of the referred to record, then we're filling | ||
463 | * in a delayed or unwritten allocation with a real one, or | ||
464 | * converting real back to unwritten. | ||
465 | */ | ||
466 | if (!isnullstartblock(new->br_startblock) && | ||
467 | new->br_startoff + new->br_blockcount > prev.br_startoff) { | ||
468 | if (prev.br_state != XFS_EXT_UNWRITTEN && | ||
469 | isnullstartblock(prev.br_startblock)) { | ||
470 | da_old = startblockval(prev.br_startblock); | ||
471 | if (cur) | ||
472 | ASSERT(cur->bc_private.b.flags & | ||
473 | XFS_BTCUR_BPRV_WASDEL); | ||
474 | error = xfs_bmap_add_extent_delay_real(tp, ip, | ||
475 | idx, &cur, new, &da_new, | ||
476 | first, flist, &logflags); | ||
477 | } else { | ||
478 | ASSERT(new->br_state == XFS_EXT_NORM || | ||
479 | new->br_state == XFS_EXT_UNWRITTEN); | ||
480 | |||
481 | error = xfs_bmap_add_extent_unwritten_real(ip, | ||
482 | idx, &cur, new, &logflags); | ||
483 | if (error) | ||
484 | goto done; | ||
485 | } | ||
486 | } | ||
487 | /* | ||
488 | * Otherwise we're filling in a hole with an allocation. | ||
489 | */ | ||
490 | else { | ||
491 | if (cur) | ||
492 | ASSERT((cur->bc_private.b.flags & | ||
493 | XFS_BTCUR_BPRV_WASDEL) == 0); | ||
494 | error = xfs_bmap_add_extent_hole_real(ip, idx, cur, | ||
495 | new, &logflags, whichfork); | ||
496 | } | ||
497 | } | ||
498 | |||
499 | if (error) | ||
500 | goto done; | ||
501 | ASSERT(*curp == cur || *curp == NULL); | ||
502 | |||
503 | /* | ||
504 | * Convert to a btree if necessary. | ||
505 | */ | ||
506 | if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && | ||
507 | XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) { | ||
508 | int tmp_logflags; /* partial log flag return val */ | ||
509 | |||
510 | ASSERT(cur == NULL); | ||
511 | error = xfs_bmap_extents_to_btree(tp, ip, first, | ||
512 | flist, &cur, da_old > 0, &tmp_logflags, whichfork); | ||
513 | logflags |= tmp_logflags; | ||
514 | if (error) | ||
515 | goto done; | ||
516 | } | ||
517 | /* | ||
518 | * Adjust for changes in reserved delayed indirect blocks. | ||
519 | * Nothing to do for disk quotas here. | ||
520 | */ | ||
521 | if (da_old || da_new) { | ||
522 | xfs_filblks_t nblks; | ||
523 | |||
524 | nblks = da_new; | ||
525 | if (cur) | ||
526 | nblks += cur->bc_private.b.allocated; | ||
527 | ASSERT(nblks <= da_old); | ||
528 | if (nblks < da_old) | ||
529 | xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS, | ||
530 | (int64_t)(da_old - nblks), 0); | ||
531 | } | ||
532 | /* | ||
533 | * Clear out the allocated field, done with it now in any case. | ||
534 | */ | ||
535 | if (cur) { | ||
536 | cur->bc_private.b.allocated = 0; | ||
537 | *curp = cur; | ||
538 | } | ||
539 | done: | ||
540 | #ifdef DEBUG | ||
541 | if (!error) | ||
542 | xfs_bmap_check_leaf_extents(*curp, ip, whichfork); | ||
543 | #endif | ||
544 | *logflagsp = logflags; | ||
545 | return error; | ||
546 | } | ||
547 | |||
548 | /* | ||
549 | * Called by xfs_bmap_add_extent to handle cases converting a delayed | ||
550 | * allocation to a real allocation. | ||
551 | */ | 375 | */ |
552 | STATIC int /* error */ | 376 | STATIC int /* error */ |
553 | xfs_bmap_add_extent_delay_real( | 377 | xfs_bmap_add_extent_delay_real( |
@@ -556,7 +380,6 @@ xfs_bmap_add_extent_delay_real( | |||
556 | xfs_extnum_t *idx, /* extent number to update/insert */ | 380 | xfs_extnum_t *idx, /* extent number to update/insert */ |
557 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ | 381 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ |
558 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 382 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
559 | xfs_filblks_t *dnew, /* new delayed-alloc indirect blocks */ | ||
560 | xfs_fsblock_t *first, /* pointer to firstblock variable */ | 383 | xfs_fsblock_t *first, /* pointer to firstblock variable */ |
561 | xfs_bmap_free_t *flist, /* list of extents to be freed */ | 384 | xfs_bmap_free_t *flist, /* list of extents to be freed */ |
562 | int *logflagsp) /* inode logging flags */ | 385 | int *logflagsp) /* inode logging flags */ |
@@ -572,10 +395,24 @@ xfs_bmap_add_extent_delay_real( | |||
572 | /* left is 0, right is 1, prev is 2 */ | 395 | /* left is 0, right is 1, prev is 2 */ |
573 | int rval=0; /* return value (logging flags) */ | 396 | int rval=0; /* return value (logging flags) */ |
574 | int state = 0;/* state bits, accessed thru macros */ | 397 | int state = 0;/* state bits, accessed thru macros */ |
575 | xfs_filblks_t temp=0; /* value for dnew calculations */ | 398 | xfs_filblks_t da_new; /* new count del alloc blocks used */ |
576 | xfs_filblks_t temp2=0;/* value for dnew calculations */ | 399 | xfs_filblks_t da_old; /* old count del alloc blocks used */ |
400 | xfs_filblks_t temp=0; /* value for da_new calculations */ | ||
401 | xfs_filblks_t temp2=0;/* value for da_new calculations */ | ||
577 | int tmp_rval; /* partial logging flags */ | 402 | int tmp_rval; /* partial logging flags */ |
578 | 403 | ||
404 | ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); | ||
405 | cur = *curp; | ||
406 | |||
407 | ASSERT(*idx >= 0); | ||
408 | ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); | ||
409 | ASSERT(!isnullstartblock(new->br_startblock)); | ||
410 | ASSERT(!cur || (cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); | ||
411 | |||
412 | XFS_STATS_INC(xs_add_exlist); | ||
413 | |||
414 | *logflagsp = 0; | ||
415 | |||
579 | #define LEFT r[0] | 416 | #define LEFT r[0] |
580 | #define RIGHT r[1] | 417 | #define RIGHT r[1] |
581 | #define PREV r[2] | 418 | #define PREV r[2] |
@@ -583,14 +420,15 @@ xfs_bmap_add_extent_delay_real( | |||
583 | /* | 420 | /* |
584 | * Set up a bunch of variables to make the tests simpler. | 421 | * Set up a bunch of variables to make the tests simpler. |
585 | */ | 422 | */ |
586 | cur = *curp; | ||
587 | ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); | ||
588 | ep = xfs_iext_get_ext(ifp, *idx); | 423 | ep = xfs_iext_get_ext(ifp, *idx); |
589 | xfs_bmbt_get_all(ep, &PREV); | 424 | xfs_bmbt_get_all(ep, &PREV); |
590 | new_endoff = new->br_startoff + new->br_blockcount; | 425 | new_endoff = new->br_startoff + new->br_blockcount; |
591 | ASSERT(PREV.br_startoff <= new->br_startoff); | 426 | ASSERT(PREV.br_startoff <= new->br_startoff); |
592 | ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); | 427 | ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); |
593 | 428 | ||
429 | da_old = startblockval(PREV.br_startblock); | ||
430 | da_new = 0; | ||
431 | |||
594 | /* | 432 | /* |
595 | * Set flags determining what part of the previous delayed allocation | 433 | * Set flags determining what part of the previous delayed allocation |
596 | * extent is being replaced by a real allocation. | 434 | * extent is being replaced by a real allocation. |
@@ -688,7 +526,6 @@ xfs_bmap_add_extent_delay_real( | |||
688 | RIGHT.br_blockcount, LEFT.br_state))) | 526 | RIGHT.br_blockcount, LEFT.br_state))) |
689 | goto done; | 527 | goto done; |
690 | } | 528 | } |
691 | *dnew = 0; | ||
692 | break; | 529 | break; |
693 | 530 | ||
694 | case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: | 531 | case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: |
@@ -719,7 +556,6 @@ xfs_bmap_add_extent_delay_real( | |||
719 | PREV.br_blockcount, LEFT.br_state))) | 556 | PREV.br_blockcount, LEFT.br_state))) |
720 | goto done; | 557 | goto done; |
721 | } | 558 | } |
722 | *dnew = 0; | ||
723 | break; | 559 | break; |
724 | 560 | ||
725 | case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: | 561 | case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: |
@@ -749,8 +585,6 @@ xfs_bmap_add_extent_delay_real( | |||
749 | RIGHT.br_blockcount, PREV.br_state))) | 585 | RIGHT.br_blockcount, PREV.br_state))) |
750 | goto done; | 586 | goto done; |
751 | } | 587 | } |
752 | |||
753 | *dnew = 0; | ||
754 | break; | 588 | break; |
755 | 589 | ||
756 | case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: | 590 | case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: |
@@ -778,8 +612,6 @@ xfs_bmap_add_extent_delay_real( | |||
778 | goto done; | 612 | goto done; |
779 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 613 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
780 | } | 614 | } |
781 | |||
782 | *dnew = 0; | ||
783 | break; | 615 | break; |
784 | 616 | ||
785 | case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: | 617 | case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: |
@@ -813,13 +645,12 @@ xfs_bmap_add_extent_delay_real( | |||
813 | LEFT.br_state))) | 645 | LEFT.br_state))) |
814 | goto done; | 646 | goto done; |
815 | } | 647 | } |
816 | temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), | 648 | da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), |
817 | startblockval(PREV.br_startblock)); | 649 | startblockval(PREV.br_startblock)); |
818 | xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); | 650 | xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); |
819 | trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); | 651 | trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); |
820 | 652 | ||
821 | --*idx; | 653 | --*idx; |
822 | *dnew = temp; | ||
823 | break; | 654 | break; |
824 | 655 | ||
825 | case BMAP_LEFT_FILLING: | 656 | case BMAP_LEFT_FILLING: |
@@ -856,14 +687,12 @@ xfs_bmap_add_extent_delay_real( | |||
856 | if (error) | 687 | if (error) |
857 | goto done; | 688 | goto done; |
858 | } | 689 | } |
859 | temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), | 690 | da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), |
860 | startblockval(PREV.br_startblock) - | 691 | startblockval(PREV.br_startblock) - |
861 | (cur ? cur->bc_private.b.allocated : 0)); | 692 | (cur ? cur->bc_private.b.allocated : 0)); |
862 | ep = xfs_iext_get_ext(ifp, *idx + 1); | 693 | ep = xfs_iext_get_ext(ifp, *idx + 1); |
863 | xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); | 694 | xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); |
864 | trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_); | 695 | trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_); |
865 | |||
866 | *dnew = temp; | ||
867 | break; | 696 | break; |
868 | 697 | ||
869 | case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: | 698 | case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: |
@@ -896,14 +725,13 @@ xfs_bmap_add_extent_delay_real( | |||
896 | goto done; | 725 | goto done; |
897 | } | 726 | } |
898 | 727 | ||
899 | temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), | 728 | da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), |
900 | startblockval(PREV.br_startblock)); | 729 | startblockval(PREV.br_startblock)); |
901 | trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); | 730 | trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); |
902 | xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); | 731 | xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); |
903 | trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); | 732 | trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); |
904 | 733 | ||
905 | ++*idx; | 734 | ++*idx; |
906 | *dnew = temp; | ||
907 | break; | 735 | break; |
908 | 736 | ||
909 | case BMAP_RIGHT_FILLING: | 737 | case BMAP_RIGHT_FILLING: |
@@ -939,15 +767,14 @@ xfs_bmap_add_extent_delay_real( | |||
939 | if (error) | 767 | if (error) |
940 | goto done; | 768 | goto done; |
941 | } | 769 | } |
942 | temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), | 770 | da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), |
943 | startblockval(PREV.br_startblock) - | 771 | startblockval(PREV.br_startblock) - |
944 | (cur ? cur->bc_private.b.allocated : 0)); | 772 | (cur ? cur->bc_private.b.allocated : 0)); |
945 | ep = xfs_iext_get_ext(ifp, *idx); | 773 | ep = xfs_iext_get_ext(ifp, *idx); |
946 | xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); | 774 | xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); |
947 | trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); | 775 | trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); |
948 | 776 | ||
949 | ++*idx; | 777 | ++*idx; |
950 | *dnew = temp; | ||
951 | break; | 778 | break; |
952 | 779 | ||
953 | case 0: | 780 | case 0: |
@@ -1029,7 +856,7 @@ xfs_bmap_add_extent_delay_real( | |||
1029 | trace_xfs_bmap_post_update(ip, *idx + 2, state, _THIS_IP_); | 856 | trace_xfs_bmap_post_update(ip, *idx + 2, state, _THIS_IP_); |
1030 | 857 | ||
1031 | ++*idx; | 858 | ++*idx; |
1032 | *dnew = temp + temp2; | 859 | da_new = temp + temp2; |
1033 | break; | 860 | break; |
1034 | 861 | ||
1035 | case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: | 862 | case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: |
@@ -1044,9 +871,39 @@ xfs_bmap_add_extent_delay_real( | |||
1044 | */ | 871 | */ |
1045 | ASSERT(0); | 872 | ASSERT(0); |
1046 | } | 873 | } |
1047 | *curp = cur; | 874 | |
875 | /* convert to a btree if necessary */ | ||
876 | if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS && | ||
877 | XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > ifp->if_ext_max) { | ||
878 | int tmp_logflags; /* partial log flag return val */ | ||
879 | |||
880 | ASSERT(cur == NULL); | ||
881 | error = xfs_bmap_extents_to_btree(tp, ip, first, flist, &cur, | ||
882 | da_old > 0, &tmp_logflags, XFS_DATA_FORK); | ||
883 | *logflagsp |= tmp_logflags; | ||
884 | if (error) | ||
885 | goto done; | ||
886 | } | ||
887 | |||
888 | /* adjust for changes in reserved delayed indirect blocks */ | ||
889 | if (da_old || da_new) { | ||
890 | temp = da_new; | ||
891 | if (cur) | ||
892 | temp += cur->bc_private.b.allocated; | ||
893 | ASSERT(temp <= da_old); | ||
894 | if (temp < da_old) | ||
895 | xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS, | ||
896 | (int64_t)(da_old - temp), 0); | ||
897 | } | ||
898 | |||
899 | /* clear out the allocated field, done with it now in any case. */ | ||
900 | if (cur) { | ||
901 | cur->bc_private.b.allocated = 0; | ||
902 | *curp = cur; | ||
903 | } | ||
904 | xfs_bmap_check_leaf_extents(cur, ip, XFS_DATA_FORK); | ||
1048 | done: | 905 | done: |
1049 | *logflagsp = rval; | 906 | *logflagsp |= rval; |
1050 | return error; | 907 | return error; |
1051 | #undef LEFT | 908 | #undef LEFT |
1052 | #undef RIGHT | 909 | #undef RIGHT |
@@ -1054,15 +911,17 @@ done: | |||
1054 | } | 911 | } |
1055 | 912 | ||
1056 | /* | 913 | /* |
1057 | * Called by xfs_bmap_add_extent to handle cases converting an unwritten | 914 | * Convert an unwritten allocation to a real allocation or vice versa. |
1058 | * allocation to a real allocation or vice versa. | ||
1059 | */ | 915 | */ |
1060 | STATIC int /* error */ | 916 | STATIC int /* error */ |
1061 | xfs_bmap_add_extent_unwritten_real( | 917 | xfs_bmap_add_extent_unwritten_real( |
918 | struct xfs_trans *tp, | ||
1062 | xfs_inode_t *ip, /* incore inode pointer */ | 919 | xfs_inode_t *ip, /* incore inode pointer */ |
1063 | xfs_extnum_t *idx, /* extent number to update/insert */ | 920 | xfs_extnum_t *idx, /* extent number to update/insert */ |
1064 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ | 921 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ |
1065 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 922 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
923 | xfs_fsblock_t *first, /* pointer to firstblock variable */ | ||
924 | xfs_bmap_free_t *flist, /* list of extents to be freed */ | ||
1066 | int *logflagsp) /* inode logging flags */ | 925 | int *logflagsp) /* inode logging flags */ |
1067 | { | 926 | { |
1068 | xfs_btree_cur_t *cur; /* btree cursor */ | 927 | xfs_btree_cur_t *cur; /* btree cursor */ |
@@ -1078,15 +937,25 @@ xfs_bmap_add_extent_unwritten_real( | |||
1078 | int rval=0; /* return value (logging flags) */ | 937 | int rval=0; /* return value (logging flags) */ |
1079 | int state = 0;/* state bits, accessed thru macros */ | 938 | int state = 0;/* state bits, accessed thru macros */ |
1080 | 939 | ||
940 | *logflagsp = 0; | ||
941 | |||
942 | cur = *curp; | ||
943 | ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); | ||
944 | |||
945 | ASSERT(*idx >= 0); | ||
946 | ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); | ||
947 | ASSERT(!isnullstartblock(new->br_startblock)); | ||
948 | |||
949 | XFS_STATS_INC(xs_add_exlist); | ||
950 | |||
1081 | #define LEFT r[0] | 951 | #define LEFT r[0] |
1082 | #define RIGHT r[1] | 952 | #define RIGHT r[1] |
1083 | #define PREV r[2] | 953 | #define PREV r[2] |
954 | |||
1084 | /* | 955 | /* |
1085 | * Set up a bunch of variables to make the tests simpler. | 956 | * Set up a bunch of variables to make the tests simpler. |
1086 | */ | 957 | */ |
1087 | error = 0; | 958 | error = 0; |
1088 | cur = *curp; | ||
1089 | ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); | ||
1090 | ep = xfs_iext_get_ext(ifp, *idx); | 959 | ep = xfs_iext_get_ext(ifp, *idx); |
1091 | xfs_bmbt_get_all(ep, &PREV); | 960 | xfs_bmbt_get_all(ep, &PREV); |
1092 | newext = new->br_state; | 961 | newext = new->br_state; |
@@ -1537,9 +1406,29 @@ xfs_bmap_add_extent_unwritten_real( | |||
1537 | */ | 1406 | */ |
1538 | ASSERT(0); | 1407 | ASSERT(0); |
1539 | } | 1408 | } |
1540 | *curp = cur; | 1409 | |
1410 | /* convert to a btree if necessary */ | ||
1411 | if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS && | ||
1412 | XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > ifp->if_ext_max) { | ||
1413 | int tmp_logflags; /* partial log flag return val */ | ||
1414 | |||
1415 | ASSERT(cur == NULL); | ||
1416 | error = xfs_bmap_extents_to_btree(tp, ip, first, flist, &cur, | ||
1417 | 0, &tmp_logflags, XFS_DATA_FORK); | ||
1418 | *logflagsp |= tmp_logflags; | ||
1419 | if (error) | ||
1420 | goto done; | ||
1421 | } | ||
1422 | |||
1423 | /* clear out the allocated field, done with it now in any case. */ | ||
1424 | if (cur) { | ||
1425 | cur->bc_private.b.allocated = 0; | ||
1426 | *curp = cur; | ||
1427 | } | ||
1428 | |||
1429 | xfs_bmap_check_leaf_extents(*curp, ip, XFS_DATA_FORK); | ||
1541 | done: | 1430 | done: |
1542 | *logflagsp = rval; | 1431 | *logflagsp |= rval; |
1543 | return error; | 1432 | return error; |
1544 | #undef LEFT | 1433 | #undef LEFT |
1545 | #undef RIGHT | 1434 | #undef RIGHT |
@@ -1691,30 +1580,42 @@ xfs_bmap_add_extent_hole_delay( | |||
1691 | } | 1580 | } |
1692 | 1581 | ||
1693 | /* | 1582 | /* |
1694 | * Called by xfs_bmap_add_extent to handle cases converting a hole | 1583 | * Convert a hole to a real allocation. |
1695 | * to a real allocation. | ||
1696 | */ | 1584 | */ |
1697 | STATIC int /* error */ | 1585 | STATIC int /* error */ |
1698 | xfs_bmap_add_extent_hole_real( | 1586 | xfs_bmap_add_extent_hole_real( |
1587 | struct xfs_trans *tp, | ||
1699 | xfs_inode_t *ip, /* incore inode pointer */ | 1588 | xfs_inode_t *ip, /* incore inode pointer */ |
1700 | xfs_extnum_t *idx, /* extent number to update/insert */ | 1589 | xfs_extnum_t *idx, /* extent number to update/insert */ |
1701 | xfs_btree_cur_t *cur, /* if null, not a btree */ | 1590 | xfs_btree_cur_t **curp, /* if null, not a btree */ |
1702 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 1591 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
1592 | xfs_fsblock_t *first, /* pointer to firstblock variable */ | ||
1593 | xfs_bmap_free_t *flist, /* list of extents to be freed */ | ||
1703 | int *logflagsp, /* inode logging flags */ | 1594 | int *logflagsp, /* inode logging flags */ |
1704 | int whichfork) /* data or attr fork */ | 1595 | int whichfork) /* data or attr fork */ |
1705 | { | 1596 | { |
1706 | int error; /* error return value */ | 1597 | int error; /* error return value */ |
1707 | int i; /* temp state */ | 1598 | int i; /* temp state */ |
1599 | xfs_btree_cur_t *cur; /* if null, not a btree */ | ||
1708 | xfs_ifork_t *ifp; /* inode fork pointer */ | 1600 | xfs_ifork_t *ifp; /* inode fork pointer */ |
1709 | xfs_bmbt_irec_t left; /* left neighbor extent entry */ | 1601 | xfs_bmbt_irec_t left; /* left neighbor extent entry */ |
1710 | xfs_bmbt_irec_t right; /* right neighbor extent entry */ | 1602 | xfs_bmbt_irec_t right; /* right neighbor extent entry */ |
1711 | int rval=0; /* return value (logging flags) */ | 1603 | int rval=0; /* return value (logging flags) */ |
1712 | int state; /* state bits, accessed thru macros */ | 1604 | int state; /* state bits, accessed thru macros */ |
1713 | 1605 | ||
1606 | *logflagsp = 0; | ||
1607 | |||
1714 | ifp = XFS_IFORK_PTR(ip, whichfork); | 1608 | ifp = XFS_IFORK_PTR(ip, whichfork); |
1715 | ASSERT(*idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)); | 1609 | cur = *curp; |
1716 | state = 0; | 1610 | |
1611 | ASSERT(*idx >= 0); | ||
1612 | ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); | ||
1613 | ASSERT(!isnullstartblock(new->br_startblock)); | ||
1614 | ASSERT(!cur || !(cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); | ||
1615 | |||
1616 | XFS_STATS_INC(xs_add_exlist); | ||
1717 | 1617 | ||
1618 | state = 0; | ||
1718 | if (whichfork == XFS_ATTR_FORK) | 1619 | if (whichfork == XFS_ATTR_FORK) |
1719 | state |= BMAP_ATTRFORK; | 1620 | state |= BMAP_ATTRFORK; |
1720 | 1621 | ||
@@ -1897,8 +1798,28 @@ xfs_bmap_add_extent_hole_real( | |||
1897 | } | 1798 | } |
1898 | break; | 1799 | break; |
1899 | } | 1800 | } |
1801 | |||
1802 | /* convert to a btree if necessary */ | ||
1803 | if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && | ||
1804 | XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) { | ||
1805 | int tmp_logflags; /* partial log flag return val */ | ||
1806 | |||
1807 | ASSERT(cur == NULL); | ||
1808 | error = xfs_bmap_extents_to_btree(tp, ip, first, | ||
1809 | flist, &cur, 0, &tmp_logflags, whichfork); | ||
1810 | *logflagsp |= tmp_logflags; | ||
1811 | if (error) | ||
1812 | goto done; | ||
1813 | } | ||
1814 | |||
1815 | /* clear out the allocated field, done with it now in any case. */ | ||
1816 | if (cur) { | ||
1817 | cur->bc_private.b.allocated = 0; | ||
1818 | *curp = cur; | ||
1819 | } | ||
1820 | xfs_bmap_check_leaf_extents(cur, ip, whichfork); | ||
1900 | done: | 1821 | done: |
1901 | *logflagsp = rval; | 1822 | *logflagsp |= rval; |
1902 | return error; | 1823 | return error; |
1903 | } | 1824 | } |
1904 | 1825 | ||
@@ -4792,14 +4713,22 @@ xfs_bmapi_allocate( | |||
4792 | xfs_sb_version_hasextflgbit(&mp->m_sb)) | 4713 | xfs_sb_version_hasextflgbit(&mp->m_sb)) |
4793 | bma->gotp->br_state = XFS_EXT_UNWRITTEN; | 4714 | bma->gotp->br_state = XFS_EXT_UNWRITTEN; |
4794 | 4715 | ||
4795 | error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, bma->gotp, | 4716 | if (bma->wasdel) { |
4796 | firstblock, flist, logflags, whichfork); | 4717 | error = xfs_bmap_add_extent_delay_real(bma->tp, bma->ip, lastx, |
4718 | cur, bma->gotp, firstblock, flist, logflags); | ||
4719 | } else { | ||
4720 | error = xfs_bmap_add_extent_hole_real(bma->tp, bma->ip, lastx, | ||
4721 | cur, bma->gotp, firstblock, flist, logflags, | ||
4722 | whichfork); | ||
4723 | } | ||
4724 | |||
4797 | if (error) | 4725 | if (error) |
4798 | return error; | 4726 | return error; |
4799 | 4727 | ||
4800 | /* | 4728 | /* |
4801 | * Update our extent pointer, given that xfs_bmap_add_extent might | 4729 | * Update our extent pointer, given that xfs_bmap_add_extent_delay_real |
4802 | * have merged it into one of the neighbouring ones. | 4730 | * or xfs_bmap_add_extent_hole_real might have merged it into one of |
4731 | * the neighbouring ones. | ||
4803 | */ | 4732 | */ |
4804 | xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp); | 4733 | xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp); |
4805 | 4734 | ||
@@ -4854,14 +4783,15 @@ xfs_bmapi_convert_unwritten( | |||
4854 | mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN) | 4783 | mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN) |
4855 | ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN; | 4784 | ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN; |
4856 | 4785 | ||
4857 | error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, mval, | 4786 | error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, lastx, |
4858 | firstblock, flist, logflags, whichfork); | 4787 | cur, mval, firstblock, flist, logflags); |
4859 | if (error) | 4788 | if (error) |
4860 | return error; | 4789 | return error; |
4861 | 4790 | ||
4862 | /* | 4791 | /* |
4863 | * Update our extent pointer, given that xfs_bmap_add_extent might | 4792 | * Update our extent pointer, given that |
4864 | * have merged it into one of the neighbouring ones. | 4793 | * xfs_bmap_add_extent_unwritten_real might have merged it into one |
4794 | * of the neighbouring ones. | ||
4865 | */ | 4795 | */ |
4866 | xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp); | 4796 | xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp); |
4867 | 4797 | ||
@@ -5287,9 +5217,9 @@ xfs_bunmapi( | |||
5287 | del.br_blockcount = mod; | 5217 | del.br_blockcount = mod; |
5288 | } | 5218 | } |
5289 | del.br_state = XFS_EXT_UNWRITTEN; | 5219 | del.br_state = XFS_EXT_UNWRITTEN; |
5290 | error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, &del, | 5220 | error = xfs_bmap_add_extent_unwritten_real(tp, ip, |
5291 | firstblock, flist, &logflags, | 5221 | &lastx, &cur, &del, firstblock, flist, |
5292 | XFS_DATA_FORK); | 5222 | &logflags); |
5293 | if (error) | 5223 | if (error) |
5294 | goto error0; | 5224 | goto error0; |
5295 | goto nodelete; | 5225 | goto nodelete; |
@@ -5345,18 +5275,18 @@ xfs_bunmapi( | |||
5345 | } | 5275 | } |
5346 | prev.br_state = XFS_EXT_UNWRITTEN; | 5276 | prev.br_state = XFS_EXT_UNWRITTEN; |
5347 | lastx--; | 5277 | lastx--; |
5348 | error = xfs_bmap_add_extent(tp, ip, &lastx, | 5278 | error = xfs_bmap_add_extent_unwritten_real(tp, |
5349 | &cur, &prev, firstblock, flist, | 5279 | ip, &lastx, &cur, &prev, |
5350 | &logflags, XFS_DATA_FORK); | 5280 | firstblock, flist, &logflags); |
5351 | if (error) | 5281 | if (error) |
5352 | goto error0; | 5282 | goto error0; |
5353 | goto nodelete; | 5283 | goto nodelete; |
5354 | } else { | 5284 | } else { |
5355 | ASSERT(del.br_state == XFS_EXT_NORM); | 5285 | ASSERT(del.br_state == XFS_EXT_NORM); |
5356 | del.br_state = XFS_EXT_UNWRITTEN; | 5286 | del.br_state = XFS_EXT_UNWRITTEN; |
5357 | error = xfs_bmap_add_extent(tp, ip, &lastx, | 5287 | error = xfs_bmap_add_extent_unwritten_real(tp, |
5358 | &cur, &del, firstblock, flist, | 5288 | ip, &lastx, &cur, &del, |
5359 | &logflags, XFS_DATA_FORK); | 5289 | firstblock, flist, &logflags); |
5360 | if (error) | 5290 | if (error) |
5361 | goto error0; | 5291 | goto error0; |
5362 | goto nodelete; | 5292 | goto nodelete; |