aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_trans.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_trans.c')
-rw-r--r--fs/xfs/xfs_trans.c77
1 files changed, 40 insertions, 37 deletions
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 2caa0783049b..356d6627f581 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -638,11 +638,23 @@ xfs_trans_apply_sb_deltas(
638} 638}
639 639
640/* 640/*
641 * xfs_trans_unreserve_and_mod_sb() is called to release unused 641 * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations
642 * reservations and apply superblock counter changes to the in-core 642 * and apply superblock counter changes to the in-core superblock. The
643 * 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.
644 * 646 *
645 * 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.
646 */ 658 */
647STATIC void 659STATIC void
648xfs_trans_unreserve_and_mod_sb( 660xfs_trans_unreserve_and_mod_sb(
@@ -654,42 +666,43 @@ xfs_trans_unreserve_and_mod_sb(
654 /* REFERENCED */ 666 /* REFERENCED */
655 int error; 667 int error;
656 int rsvd; 668 int rsvd;
669 int64_t blkdelta = 0;
670 int64_t rtxdelta = 0;
657 671
658 msbp = msb; 672 msbp = msb;
659 rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; 673 rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
660 674
661 /* 675 /* calculate free blocks delta */
662 * Release any reserved blocks. Any that were allocated 676 if (tp->t_blk_res > 0)
663 * will be taken back again by fdblocks_delta below. 677 blkdelta = tp->t_blk_res;
664 */ 678
665 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) {
666 msbp->msb_field = XFS_SBS_FDBLOCKS; 685 msbp->msb_field = XFS_SBS_FDBLOCKS;
667 msbp->msb_delta = tp->t_blk_res; 686 msbp->msb_delta = blkdelta;
668 msbp++; 687 msbp++;
669 } 688 }
670 689
671 /* 690 /* calculate free realtime extents delta */
672 * Release any reserved real time extents . Any that were 691 if (tp->t_rtx_res > 0)
673 * allocated will be taken back again by frextents_delta below. 692 rtxdelta = tp->t_rtx_res;
674 */ 693
675 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) {
676 msbp->msb_field = XFS_SBS_FREXTENTS; 699 msbp->msb_field = XFS_SBS_FREXTENTS;
677 msbp->msb_delta = tp->t_rtx_res; 700 msbp->msb_delta = rtxdelta;
678 msbp++; 701 msbp++;
679 } 702 }
680 703
681 /* 704 /* apply remaining deltas */
682 * Apply any superblock modifications to the in-core version. 705
683 * The t_res_fdblocks_delta and t_res_frextents_delta fields are
684 * explicitly NOT applied to the in-core superblock.
685 * The idea is that that has already been done.
686 *
687 * If we are not logging superblock counters, then the inode
688 * allocated/free and used block counts are not updated in the
689 * on disk superblock. In this case, XFS_TRANS_SB_DIRTY will
690 * not be set when the transaction is updated but we still need
691 * to update the incore superblock with the changes.
692 */
693 if (xfs_sb_version_haslazysbcount(&mp->m_sb) || 706 if (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
694 (tp->t_flags & XFS_TRANS_SB_DIRTY)) { 707 (tp->t_flags & XFS_TRANS_SB_DIRTY)) {
695 if (tp->t_icount_delta != 0) { 708 if (tp->t_icount_delta != 0) {
@@ -702,19 +715,9 @@ xfs_trans_unreserve_and_mod_sb(
702 msbp->msb_delta = tp->t_ifree_delta; 715 msbp->msb_delta = tp->t_ifree_delta;
703 msbp++; 716 msbp++;
704 } 717 }
705 if (tp->t_fdblocks_delta != 0) {
706 msbp->msb_field = XFS_SBS_FDBLOCKS;
707 msbp->msb_delta = tp->t_fdblocks_delta;
708 msbp++;
709 }
710 } 718 }
711 719
712 if (tp->t_flags & XFS_TRANS_SB_DIRTY) { 720 if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
713 if (tp->t_frextents_delta != 0) {
714 msbp->msb_field = XFS_SBS_FREXTENTS;
715 msbp->msb_delta = tp->t_frextents_delta;
716 msbp++;
717 }
718 if (tp->t_dblocks_delta != 0) { 721 if (tp->t_dblocks_delta != 0) {
719 msbp->msb_field = XFS_SBS_DBLOCKS; 722 msbp->msb_field = XFS_SBS_DBLOCKS;
720 msbp->msb_delta = tp->t_dblocks_delta; 723 msbp->msb_delta = tp->t_dblocks_delta;