diff options
Diffstat (limited to 'fs/xfs/xfs_trans.c')
-rw-r--r-- | fs/xfs/xfs_trans.c | 125 |
1 files changed, 81 insertions, 44 deletions
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index cc2d60951e21..356d6627f581 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c | |||
@@ -427,6 +427,14 @@ undo_blocks: | |||
427 | * | 427 | * |
428 | * Mark the transaction structure to indicate that the superblock | 428 | * Mark the transaction structure to indicate that the superblock |
429 | * needs to be updated before committing. | 429 | * needs to be updated before committing. |
430 | * | ||
431 | * Because we may not be keeping track of allocated/free inodes and | ||
432 | * used filesystem blocks in the superblock, we do not mark the | ||
433 | * superblock dirty in this transaction if we modify these fields. | ||
434 | * We still need to update the transaction deltas so that they get | ||
435 | * applied to the incore superblock, but we don't want them to | ||
436 | * cause the superblock to get locked and logged if these are the | ||
437 | * only fields in the superblock that the transaction modifies. | ||
430 | */ | 438 | */ |
431 | void | 439 | void |
432 | xfs_trans_mod_sb( | 440 | xfs_trans_mod_sb( |
@@ -434,13 +442,19 @@ xfs_trans_mod_sb( | |||
434 | uint field, | 442 | uint field, |
435 | int64_t delta) | 443 | int64_t delta) |
436 | { | 444 | { |
445 | uint32_t flags = (XFS_TRANS_DIRTY|XFS_TRANS_SB_DIRTY); | ||
446 | xfs_mount_t *mp = tp->t_mountp; | ||
437 | 447 | ||
438 | switch (field) { | 448 | switch (field) { |
439 | case XFS_TRANS_SB_ICOUNT: | 449 | case XFS_TRANS_SB_ICOUNT: |
440 | tp->t_icount_delta += delta; | 450 | tp->t_icount_delta += delta; |
451 | if (xfs_sb_version_haslazysbcount(&mp->m_sb)) | ||
452 | flags &= ~XFS_TRANS_SB_DIRTY; | ||
441 | break; | 453 | break; |
442 | case XFS_TRANS_SB_IFREE: | 454 | case XFS_TRANS_SB_IFREE: |
443 | tp->t_ifree_delta += delta; | 455 | tp->t_ifree_delta += delta; |
456 | if (xfs_sb_version_haslazysbcount(&mp->m_sb)) | ||
457 | flags &= ~XFS_TRANS_SB_DIRTY; | ||
444 | break; | 458 | break; |
445 | case XFS_TRANS_SB_FDBLOCKS: | 459 | case XFS_TRANS_SB_FDBLOCKS: |
446 | /* | 460 | /* |
@@ -453,6 +467,8 @@ xfs_trans_mod_sb( | |||
453 | ASSERT(tp->t_blk_res_used <= tp->t_blk_res); | 467 | ASSERT(tp->t_blk_res_used <= tp->t_blk_res); |
454 | } | 468 | } |
455 | tp->t_fdblocks_delta += delta; | 469 | tp->t_fdblocks_delta += delta; |
470 | if (xfs_sb_version_haslazysbcount(&mp->m_sb)) | ||
471 | flags &= ~XFS_TRANS_SB_DIRTY; | ||
456 | break; | 472 | break; |
457 | case XFS_TRANS_SB_RES_FDBLOCKS: | 473 | case XFS_TRANS_SB_RES_FDBLOCKS: |
458 | /* | 474 | /* |
@@ -462,6 +478,8 @@ xfs_trans_mod_sb( | |||
462 | */ | 478 | */ |
463 | ASSERT(delta < 0); | 479 | ASSERT(delta < 0); |
464 | tp->t_res_fdblocks_delta += delta; | 480 | tp->t_res_fdblocks_delta += delta; |
481 | if (xfs_sb_version_haslazysbcount(&mp->m_sb)) | ||
482 | flags &= ~XFS_TRANS_SB_DIRTY; | ||
465 | break; | 483 | break; |
466 | case XFS_TRANS_SB_FREXTENTS: | 484 | case XFS_TRANS_SB_FREXTENTS: |
467 | /* | 485 | /* |
@@ -515,7 +533,7 @@ xfs_trans_mod_sb( | |||
515 | return; | 533 | return; |
516 | } | 534 | } |
517 | 535 | ||
518 | tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY); | 536 | tp->t_flags |= flags; |
519 | } | 537 | } |
520 | 538 | ||
521 | /* | 539 | /* |
@@ -544,18 +562,23 @@ xfs_trans_apply_sb_deltas( | |||
544 | (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta + | 562 | (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta + |
545 | tp->t_ag_btree_delta)); | 563 | tp->t_ag_btree_delta)); |
546 | 564 | ||
547 | if (tp->t_icount_delta != 0) { | 565 | /* |
548 | INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta); | 566 | * Only update the superblock counters if we are logging them |
549 | } | 567 | */ |
550 | if (tp->t_ifree_delta != 0) { | 568 | if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) { |
551 | INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta); | 569 | if (tp->t_icount_delta != 0) { |
552 | } | 570 | INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta); |
571 | } | ||
572 | if (tp->t_ifree_delta != 0) { | ||
573 | INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta); | ||
574 | } | ||
553 | 575 | ||
554 | if (tp->t_fdblocks_delta != 0) { | 576 | if (tp->t_fdblocks_delta != 0) { |
555 | INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta); | 577 | INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta); |
556 | } | 578 | } |
557 | if (tp->t_res_fdblocks_delta != 0) { | 579 | if (tp->t_res_fdblocks_delta != 0) { |
558 | INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta); | 580 | INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta); |
581 | } | ||
559 | } | 582 | } |
560 | 583 | ||
561 | if (tp->t_frextents_delta != 0) { | 584 | if (tp->t_frextents_delta != 0) { |
@@ -615,11 +638,23 @@ xfs_trans_apply_sb_deltas( | |||
615 | } | 638 | } |
616 | 639 | ||
617 | /* | 640 | /* |
618 | * xfs_trans_unreserve_and_mod_sb() is called to release unused | 641 | * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations |
619 | * reservations and apply superblock counter changes to the in-core | 642 | * and apply superblock counter changes to the in-core superblock. The |
620 | * superblock. | 643 | * t_res_fdblocks_delta and t_res_frextents_delta fields are explicitly NOT |
644 | * applied to the in-core superblock. The idea is that that has already been | ||
645 | * done. | ||
621 | * | 646 | * |
622 | * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). | 647 | * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). |
648 | * However, we have to ensure that we only modify each superblock field only | ||
649 | * once because the application of the delta values may not be atomic. That can | ||
650 | * lead to ENOSPC races occurring if we have two separate modifcations of the | ||
651 | * free space counter to put back the entire reservation and then take away | ||
652 | * what we used. | ||
653 | * | ||
654 | * If we are not logging superblock counters, then the inode allocated/free and | ||
655 | * used block counts are not updated in the on disk superblock. In this case, | ||
656 | * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we | ||
657 | * still need to update the incore superblock with the changes. | ||
623 | */ | 658 | */ |
624 | STATIC void | 659 | STATIC void |
625 | xfs_trans_unreserve_and_mod_sb( | 660 | xfs_trans_unreserve_and_mod_sb( |
@@ -627,40 +662,49 @@ xfs_trans_unreserve_and_mod_sb( | |||
627 | { | 662 | { |
628 | xfs_mod_sb_t msb[14]; /* If you add cases, add entries */ | 663 | xfs_mod_sb_t msb[14]; /* If you add cases, add entries */ |
629 | xfs_mod_sb_t *msbp; | 664 | xfs_mod_sb_t *msbp; |
665 | xfs_mount_t *mp = tp->t_mountp; | ||
630 | /* REFERENCED */ | 666 | /* REFERENCED */ |
631 | int error; | 667 | int error; |
632 | int rsvd; | 668 | int rsvd; |
669 | int64_t blkdelta = 0; | ||
670 | int64_t rtxdelta = 0; | ||
633 | 671 | ||
634 | msbp = msb; | 672 | msbp = msb; |
635 | rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; | 673 | rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; |
636 | 674 | ||
637 | /* | 675 | /* calculate free blocks delta */ |
638 | * Release any reserved blocks. Any that were allocated | 676 | if (tp->t_blk_res > 0) |
639 | * will be taken back again by fdblocks_delta below. | 677 | blkdelta = tp->t_blk_res; |
640 | */ | 678 | |
641 | if (tp->t_blk_res > 0) { | 679 | if ((tp->t_fdblocks_delta != 0) && |
680 | (xfs_sb_version_haslazysbcount(&mp->m_sb) || | ||
681 | (tp->t_flags & XFS_TRANS_SB_DIRTY))) | ||
682 | blkdelta += tp->t_fdblocks_delta; | ||
683 | |||
684 | if (blkdelta != 0) { | ||
642 | msbp->msb_field = XFS_SBS_FDBLOCKS; | 685 | msbp->msb_field = XFS_SBS_FDBLOCKS; |
643 | msbp->msb_delta = tp->t_blk_res; | 686 | msbp->msb_delta = blkdelta; |
644 | msbp++; | 687 | msbp++; |
645 | } | 688 | } |
646 | 689 | ||
647 | /* | 690 | /* calculate free realtime extents delta */ |
648 | * Release any reserved real time extents . Any that were | 691 | if (tp->t_rtx_res > 0) |
649 | * allocated will be taken back again by frextents_delta below. | 692 | rtxdelta = tp->t_rtx_res; |
650 | */ | 693 | |
651 | if (tp->t_rtx_res > 0) { | 694 | if ((tp->t_frextents_delta != 0) && |
695 | (tp->t_flags & XFS_TRANS_SB_DIRTY)) | ||
696 | rtxdelta += tp->t_frextents_delta; | ||
697 | |||
698 | if (rtxdelta != 0) { | ||
652 | msbp->msb_field = XFS_SBS_FREXTENTS; | 699 | msbp->msb_field = XFS_SBS_FREXTENTS; |
653 | msbp->msb_delta = tp->t_rtx_res; | 700 | msbp->msb_delta = rtxdelta; |
654 | msbp++; | 701 | msbp++; |
655 | } | 702 | } |
656 | 703 | ||
657 | /* | 704 | /* apply remaining deltas */ |
658 | * Apply any superblock modifications to the in-core version. | 705 | |
659 | * The t_res_fdblocks_delta and t_res_frextents_delta fields are | 706 | if (xfs_sb_version_haslazysbcount(&mp->m_sb) || |
660 | * explicitly NOT applied to the in-core superblock. | 707 | (tp->t_flags & XFS_TRANS_SB_DIRTY)) { |
661 | * The idea is that that has already been done. | ||
662 | */ | ||
663 | if (tp->t_flags & XFS_TRANS_SB_DIRTY) { | ||
664 | if (tp->t_icount_delta != 0) { | 708 | if (tp->t_icount_delta != 0) { |
665 | msbp->msb_field = XFS_SBS_ICOUNT; | 709 | msbp->msb_field = XFS_SBS_ICOUNT; |
666 | msbp->msb_delta = tp->t_icount_delta; | 710 | msbp->msb_delta = tp->t_icount_delta; |
@@ -671,16 +715,9 @@ xfs_trans_unreserve_and_mod_sb( | |||
671 | msbp->msb_delta = tp->t_ifree_delta; | 715 | msbp->msb_delta = tp->t_ifree_delta; |
672 | msbp++; | 716 | msbp++; |
673 | } | 717 | } |
674 | if (tp->t_fdblocks_delta != 0) { | 718 | } |
675 | msbp->msb_field = XFS_SBS_FDBLOCKS; | 719 | |
676 | msbp->msb_delta = tp->t_fdblocks_delta; | 720 | if (tp->t_flags & XFS_TRANS_SB_DIRTY) { |
677 | msbp++; | ||
678 | } | ||
679 | if (tp->t_frextents_delta != 0) { | ||
680 | msbp->msb_field = XFS_SBS_FREXTENTS; | ||
681 | msbp->msb_delta = tp->t_frextents_delta; | ||
682 | msbp++; | ||
683 | } | ||
684 | if (tp->t_dblocks_delta != 0) { | 721 | if (tp->t_dblocks_delta != 0) { |
685 | msbp->msb_field = XFS_SBS_DBLOCKS; | 722 | msbp->msb_field = XFS_SBS_DBLOCKS; |
686 | msbp->msb_delta = tp->t_dblocks_delta; | 723 | msbp->msb_delta = tp->t_dblocks_delta; |