|
@@ -485,6 +485,54 @@ xfs_trans_apply_sb_deltas(
|
|
|
sizeof(sbp->sb_frextents) - 1);
|
|
|
}
|
|
|
|
|
|
+STATIC int
|
|
|
+xfs_sb_mod8(
|
|
|
+ uint8_t *field,
|
|
|
+ int8_t delta)
|
|
|
+{
|
|
|
+ int8_t counter = *field;
|
|
|
+
|
|
|
+ counter += delta;
|
|
|
+ if (counter < 0) {
|
|
|
+ ASSERT(0);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ *field = counter;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+STATIC int
|
|
|
+xfs_sb_mod32(
|
|
|
+ uint32_t *field,
|
|
|
+ int32_t delta)
|
|
|
+{
|
|
|
+ int32_t counter = *field;
|
|
|
+
|
|
|
+ counter += delta;
|
|
|
+ if (counter < 0) {
|
|
|
+ ASSERT(0);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ *field = counter;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+STATIC int
|
|
|
+xfs_sb_mod64(
|
|
|
+ uint64_t *field,
|
|
|
+ int64_t delta)
|
|
|
+{
|
|
|
+ int64_t counter = *field;
|
|
|
+
|
|
|
+ counter += delta;
|
|
|
+ if (counter < 0) {
|
|
|
+ ASSERT(0);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ *field = counter;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* xfs_trans_unreserve_and_mod_sb() is called to release unused reservations
|
|
|
* and apply superblock counter changes to the in-core superblock. The
|
|
@@ -492,13 +540,6 @@ xfs_trans_apply_sb_deltas(
|
|
|
* applied to the in-core superblock. The idea is that that has already been
|
|
|
* done.
|
|
|
*
|
|
|
- * This is done efficiently with a single call to xfs_mod_incore_sb_batch().
|
|
|
- * However, we have to ensure that we only modify each superblock field only
|
|
|
- * once because the application of the delta values may not be atomic. That can
|
|
|
- * lead to ENOSPC races occurring if we have two separate modifcations of the
|
|
|
- * free space counter to put back the entire reservation and then take away
|
|
|
- * what we used.
|
|
|
- *
|
|
|
* If we are not logging superblock counters, then the inode allocated/free and
|
|
|
* used block counts are not updated in the on disk superblock. In this case,
|
|
|
* XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we
|
|
@@ -506,20 +547,15 @@ xfs_trans_apply_sb_deltas(
|
|
|
*/
|
|
|
void
|
|
|
xfs_trans_unreserve_and_mod_sb(
|
|
|
- xfs_trans_t *tp)
|
|
|
+ struct xfs_trans *tp)
|
|
|
{
|
|
|
- xfs_mod_sb_t msb[9]; /* If you add cases, add entries */
|
|
|
- xfs_mod_sb_t *msbp;
|
|
|
- xfs_mount_t *mp = tp->t_mountp;
|
|
|
- /* REFERENCED */
|
|
|
- int error;
|
|
|
- bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
|
|
|
- int64_t blkdelta = 0;
|
|
|
- int64_t rtxdelta = 0;
|
|
|
- int64_t idelta = 0;
|
|
|
- int64_t ifreedelta = 0;
|
|
|
-
|
|
|
- msbp = msb;
|
|
|
+ struct xfs_mount *mp = tp->t_mountp;
|
|
|
+ bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
|
|
|
+ int64_t blkdelta = 0;
|
|
|
+ int64_t rtxdelta = 0;
|
|
|
+ int64_t idelta = 0;
|
|
|
+ int64_t ifreedelta = 0;
|
|
|
+ int error;
|
|
|
|
|
|
/* calculate deltas */
|
|
|
if (tp->t_blk_res > 0)
|
|
@@ -560,72 +596,90 @@ xfs_trans_unreserve_and_mod_sb(
|
|
|
goto out_undo_icount;
|
|
|
}
|
|
|
|
|
|
+ if (rtxdelta == 0 && !(tp->t_flags & XFS_TRANS_SB_DIRTY))
|
|
|
+ return;
|
|
|
+
|
|
|
/* apply remaining deltas */
|
|
|
+ spin_lock(&mp->m_sb_lock);
|
|
|
if (rtxdelta) {
|
|
|
- error = xfs_mod_frextents(mp, rtxdelta);
|
|
|
+ error = xfs_sb_mod64(&mp->m_sb.sb_frextents, rtxdelta);
|
|
|
if (error)
|
|
|
goto out_undo_ifree;
|
|
|
}
|
|
|
|
|
|
- if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
|
|
|
- if (tp->t_dblocks_delta != 0) {
|
|
|
- msbp->msb_field = XFS_SBS_DBLOCKS;
|
|
|
- msbp->msb_delta = tp->t_dblocks_delta;
|
|
|
- msbp++;
|
|
|
- }
|
|
|
- if (tp->t_agcount_delta != 0) {
|
|
|
- msbp->msb_field = XFS_SBS_AGCOUNT;
|
|
|
- msbp->msb_delta = tp->t_agcount_delta;
|
|
|
- msbp++;
|
|
|
- }
|
|
|
- if (tp->t_imaxpct_delta != 0) {
|
|
|
- msbp->msb_field = XFS_SBS_IMAX_PCT;
|
|
|
- msbp->msb_delta = tp->t_imaxpct_delta;
|
|
|
- msbp++;
|
|
|
- }
|
|
|
- if (tp->t_rextsize_delta != 0) {
|
|
|
- msbp->msb_field = XFS_SBS_REXTSIZE;
|
|
|
- msbp->msb_delta = tp->t_rextsize_delta;
|
|
|
- msbp++;
|
|
|
- }
|
|
|
- if (tp->t_rbmblocks_delta != 0) {
|
|
|
- msbp->msb_field = XFS_SBS_RBMBLOCKS;
|
|
|
- msbp->msb_delta = tp->t_rbmblocks_delta;
|
|
|
- msbp++;
|
|
|
- }
|
|
|
- if (tp->t_rblocks_delta != 0) {
|
|
|
- msbp->msb_field = XFS_SBS_RBLOCKS;
|
|
|
- msbp->msb_delta = tp->t_rblocks_delta;
|
|
|
- msbp++;
|
|
|
- }
|
|
|
- if (tp->t_rextents_delta != 0) {
|
|
|
- msbp->msb_field = XFS_SBS_REXTENTS;
|
|
|
- msbp->msb_delta = tp->t_rextents_delta;
|
|
|
- msbp++;
|
|
|
- }
|
|
|
- if (tp->t_rextslog_delta != 0) {
|
|
|
- msbp->msb_field = XFS_SBS_REXTSLOG;
|
|
|
- msbp->msb_delta = tp->t_rextslog_delta;
|
|
|
- msbp++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * If we need to change anything, do it.
|
|
|
- */
|
|
|
- if (msbp > msb) {
|
|
|
- error = xfs_mod_incore_sb_batch(tp->t_mountp, msb,
|
|
|
- (uint)(msbp - msb), rsvd);
|
|
|
+ if (tp->t_dblocks_delta != 0) {
|
|
|
+ error = xfs_sb_mod64(&mp->m_sb.sb_dblocks, tp->t_dblocks_delta);
|
|
|
if (error)
|
|
|
goto out_undo_frextents;
|
|
|
}
|
|
|
-
|
|
|
+ if (tp->t_agcount_delta != 0) {
|
|
|
+ error = xfs_sb_mod32(&mp->m_sb.sb_agcount, tp->t_agcount_delta);
|
|
|
+ if (error)
|
|
|
+ goto out_undo_dblocks;
|
|
|
+ }
|
|
|
+ if (tp->t_imaxpct_delta != 0) {
|
|
|
+ error = xfs_sb_mod8(&mp->m_sb.sb_imax_pct, tp->t_imaxpct_delta);
|
|
|
+ if (error)
|
|
|
+ goto out_undo_agcount;
|
|
|
+ }
|
|
|
+ if (tp->t_rextsize_delta != 0) {
|
|
|
+ error = xfs_sb_mod32(&mp->m_sb.sb_rextsize,
|
|
|
+ tp->t_rextsize_delta);
|
|
|
+ if (error)
|
|
|
+ goto out_undo_imaxpct;
|
|
|
+ }
|
|
|
+ if (tp->t_rbmblocks_delta != 0) {
|
|
|
+ error = xfs_sb_mod32(&mp->m_sb.sb_rbmblocks,
|
|
|
+ tp->t_rbmblocks_delta);
|
|
|
+ if (error)
|
|
|
+ goto out_undo_rextsize;
|
|
|
+ }
|
|
|
+ if (tp->t_rblocks_delta != 0) {
|
|
|
+ error = xfs_sb_mod64(&mp->m_sb.sb_rblocks, tp->t_rblocks_delta);
|
|
|
+ if (error)
|
|
|
+ goto out_undo_rbmblocks;
|
|
|
+ }
|
|
|
+ if (tp->t_rextents_delta != 0) {
|
|
|
+ error = xfs_sb_mod64(&mp->m_sb.sb_rextents,
|
|
|
+ tp->t_rextents_delta);
|
|
|
+ if (error)
|
|
|
+ goto out_undo_rblocks;
|
|
|
+ }
|
|
|
+ if (tp->t_rextslog_delta != 0) {
|
|
|
+ error = xfs_sb_mod8(&mp->m_sb.sb_rextslog,
|
|
|
+ tp->t_rextslog_delta);
|
|
|
+ if (error)
|
|
|
+ goto out_undo_rextents;
|
|
|
+ }
|
|
|
+ spin_unlock(&mp->m_sb_lock);
|
|
|
return;
|
|
|
|
|
|
+out_undo_rextents:
|
|
|
+ if (tp->t_rextents_delta)
|
|
|
+ xfs_sb_mod64(&mp->m_sb.sb_rextents, -tp->t_rextents_delta);
|
|
|
+out_undo_rblocks:
|
|
|
+ if (tp->t_rblocks_delta)
|
|
|
+ xfs_sb_mod64(&mp->m_sb.sb_rblocks, -tp->t_rblocks_delta);
|
|
|
+out_undo_rbmblocks:
|
|
|
+ if (tp->t_rbmblocks_delta)
|
|
|
+ xfs_sb_mod32(&mp->m_sb.sb_rbmblocks, -tp->t_rbmblocks_delta);
|
|
|
+out_undo_rextsize:
|
|
|
+ if (tp->t_rextsize_delta)
|
|
|
+ xfs_sb_mod32(&mp->m_sb.sb_rextsize, -tp->t_rextsize_delta);
|
|
|
+out_undo_imaxpct:
|
|
|
+ if (tp->t_rextsize_delta)
|
|
|
+ xfs_sb_mod8(&mp->m_sb.sb_imax_pct, -tp->t_imaxpct_delta);
|
|
|
+out_undo_agcount:
|
|
|
+ if (tp->t_agcount_delta)
|
|
|
+ xfs_sb_mod32(&mp->m_sb.sb_agcount, -tp->t_agcount_delta);
|
|
|
+out_undo_dblocks:
|
|
|
+ if (tp->t_dblocks_delta)
|
|
|
+ xfs_sb_mod64(&mp->m_sb.sb_dblocks, -tp->t_dblocks_delta);
|
|
|
out_undo_frextents:
|
|
|
if (rtxdelta)
|
|
|
- xfs_mod_frextents(mp, -rtxdelta);
|
|
|
+ xfs_sb_mod64(&mp->m_sb.sb_frextents, -rtxdelta);
|
|
|
out_undo_ifree:
|
|
|
+ spin_unlock(&mp->m_sb_lock);
|
|
|
if (ifreedelta)
|
|
|
xfs_mod_ifree(mp, -ifreedelta);
|
|
|
out_undo_icount:
|