diff options
-rw-r--r-- | fs/xfs/xfs_trans.c | 77 |
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 | */ |
647 | STATIC void | 659 | STATIC void |
648 | xfs_trans_unreserve_and_mod_sb( | 660 | xfs_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; |