OSDN Git Service

Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[linux-kernel-docs/linux-2.6.git] / fs / xfs / xfs_trans.c
index 7133fd9..1403864 100644 (file)
@@ -234,7 +234,7 @@ xfs_trans_alloc(
        xfs_mount_t     *mp,
        uint            type)
 {
-       vfs_wait_for_freeze(XFS_MTOVFS(mp), SB_FREEZE_TRANS);
+       xfs_wait_for_freeze(mp, SB_FREEZE_TRANS);
        return _xfs_trans_alloc(mp, type);
 }
 
@@ -533,7 +533,7 @@ xfs_trans_mod_sb(
                return;
        }
 
-       tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY);
+       tp->t_flags |= flags;
 }
 
 /*
@@ -548,7 +548,7 @@ STATIC void
 xfs_trans_apply_sb_deltas(
        xfs_trans_t     *tp)
 {
-       xfs_sb_t        *sbp;
+       xfs_dsb_t       *sbp;
        xfs_buf_t       *bp;
        int             whole = 0;
 
@@ -566,57 +566,51 @@ xfs_trans_apply_sb_deltas(
         * Only update the superblock counters if we are logging them
         */
        if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) {
-               if (tp->t_icount_delta != 0) {
-                       INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta);
-               }
-               if (tp->t_ifree_delta != 0) {
-                       INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta);
-               }
-
-               if (tp->t_fdblocks_delta != 0) {
-                       INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta);
-               }
-               if (tp->t_res_fdblocks_delta != 0) {
-                       INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta);
-               }
+               if (tp->t_icount_delta)
+                       be64_add_cpu(&sbp->sb_icount, tp->t_icount_delta);
+               if (tp->t_ifree_delta)
+                       be64_add_cpu(&sbp->sb_ifree, tp->t_ifree_delta);
+               if (tp->t_fdblocks_delta)
+                       be64_add_cpu(&sbp->sb_fdblocks, tp->t_fdblocks_delta);
+               if (tp->t_res_fdblocks_delta)
+                       be64_add_cpu(&sbp->sb_fdblocks, tp->t_res_fdblocks_delta);
        }
 
-       if (tp->t_frextents_delta != 0) {
-               INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_frextents_delta);
-       }
-       if (tp->t_res_frextents_delta != 0) {
-               INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_res_frextents_delta);
-       }
-       if (tp->t_dblocks_delta != 0) {
-               INT_MOD(sbp->sb_dblocks, ARCH_CONVERT, tp->t_dblocks_delta);
+       if (tp->t_frextents_delta)
+               be64_add_cpu(&sbp->sb_frextents, tp->t_frextents_delta);
+       if (tp->t_res_frextents_delta)
+               be64_add_cpu(&sbp->sb_frextents, tp->t_res_frextents_delta);
+
+       if (tp->t_dblocks_delta) {
+               be64_add_cpu(&sbp->sb_dblocks, tp->t_dblocks_delta);
                whole = 1;
        }
-       if (tp->t_agcount_delta != 0) {
-               INT_MOD(sbp->sb_agcount, ARCH_CONVERT, tp->t_agcount_delta);
+       if (tp->t_agcount_delta) {
+               be32_add_cpu(&sbp->sb_agcount, tp->t_agcount_delta);
                whole = 1;
        }
-       if (tp->t_imaxpct_delta != 0) {
-               INT_MOD(sbp->sb_imax_pct, ARCH_CONVERT, tp->t_imaxpct_delta);
+       if (tp->t_imaxpct_delta) {
+               sbp->sb_imax_pct += tp->t_imaxpct_delta;
                whole = 1;
        }
-       if (tp->t_rextsize_delta != 0) {
-               INT_MOD(sbp->sb_rextsize, ARCH_CONVERT, tp->t_rextsize_delta);
+       if (tp->t_rextsize_delta) {
+               be32_add_cpu(&sbp->sb_rextsize, tp->t_rextsize_delta);
                whole = 1;
        }
-       if (tp->t_rbmblocks_delta != 0) {
-               INT_MOD(sbp->sb_rbmblocks, ARCH_CONVERT, tp->t_rbmblocks_delta);
+       if (tp->t_rbmblocks_delta) {
+               be32_add_cpu(&sbp->sb_rbmblocks, tp->t_rbmblocks_delta);
                whole = 1;
        }
-       if (tp->t_rblocks_delta != 0) {
-               INT_MOD(sbp->sb_rblocks, ARCH_CONVERT, tp->t_rblocks_delta);
+       if (tp->t_rblocks_delta) {
+               be64_add_cpu(&sbp->sb_rblocks, tp->t_rblocks_delta);
                whole = 1;
        }
-       if (tp->t_rextents_delta != 0) {
-               INT_MOD(sbp->sb_rextents, ARCH_CONVERT, tp->t_rextents_delta);
+       if (tp->t_rextents_delta) {
+               be64_add_cpu(&sbp->sb_rextents, tp->t_rextents_delta);
                whole = 1;
        }
-       if (tp->t_rextslog_delta != 0) {
-               INT_MOD(sbp->sb_rextslog, ARCH_CONVERT, tp->t_rextslog_delta);
+       if (tp->t_rextslog_delta) {
+               sbp->sb_rextslog += tp->t_rextslog_delta;
                whole = 1;
        }
 
@@ -624,25 +618,37 @@ xfs_trans_apply_sb_deltas(
                /*
                 * Log the whole thing, the fields are noncontiguous.
                 */
-               xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_sb_t) - 1);
+               xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_dsb_t) - 1);
        else
                /*
                 * Since all the modifiable fields are contiguous, we
                 * can get away with this.
                 */
-               xfs_trans_log_buf(tp, bp, offsetof(xfs_sb_t, sb_icount),
-                                 offsetof(xfs_sb_t, sb_frextents) +
+               xfs_trans_log_buf(tp, bp, offsetof(xfs_dsb_t, sb_icount),
+                                 offsetof(xfs_dsb_t, sb_frextents) +
                                  sizeof(sbp->sb_frextents) - 1);
 
-       XFS_MTOVFS(tp->t_mountp)->vfs_super->s_dirt = 1;
+       tp->t_mountp->m_super->s_dirt = 1;
 }
 
 /*
- * xfs_trans_unreserve_and_mod_sb() is called to release unused
- * reservations and apply superblock counter changes to the in-core
- * superblock.
+ * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations
+ * and apply superblock counter changes to the in-core superblock.  The
+ * t_res_fdblocks_delta and t_res_frextents_delta fields are explicitly NOT
+ * 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
+ * still need to update the incore superblock with the changes.
  */
 STATIC void
 xfs_trans_unreserve_and_mod_sb(
@@ -654,42 +660,43 @@ xfs_trans_unreserve_and_mod_sb(
        /* REFERENCED */
        int             error;
        int             rsvd;
+       int64_t         blkdelta = 0;
+       int64_t         rtxdelta = 0;
 
        msbp = msb;
        rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
 
-       /*
-        * Release any reserved blocks.  Any that were allocated
-        * will be taken back again by fdblocks_delta below.
-        */
-       if (tp->t_blk_res > 0) {
+       /* calculate free blocks delta */
+       if (tp->t_blk_res > 0)
+               blkdelta = tp->t_blk_res;
+
+       if ((tp->t_fdblocks_delta != 0) &&
+           (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
+            (tp->t_flags & XFS_TRANS_SB_DIRTY)))
+               blkdelta += tp->t_fdblocks_delta;
+
+       if (blkdelta != 0) {
                msbp->msb_field = XFS_SBS_FDBLOCKS;
-               msbp->msb_delta = tp->t_blk_res;
+               msbp->msb_delta = blkdelta;
                msbp++;
        }
 
-       /*
-        * Release any reserved real time extents .  Any that were
-        * allocated will be taken back again by frextents_delta below.
-        */
-       if (tp->t_rtx_res > 0) {
+       /* calculate free realtime extents delta */
+       if (tp->t_rtx_res > 0)
+               rtxdelta = tp->t_rtx_res;
+
+       if ((tp->t_frextents_delta != 0) &&
+           (tp->t_flags & XFS_TRANS_SB_DIRTY))
+               rtxdelta += tp->t_frextents_delta;
+
+       if (rtxdelta != 0) {
                msbp->msb_field = XFS_SBS_FREXTENTS;
-               msbp->msb_delta = tp->t_rtx_res;
+               msbp->msb_delta = rtxdelta;
                msbp++;
        }
 
-       /*
-        * Apply any superblock modifications to the in-core version.
-        * The t_res_fdblocks_delta and t_res_frextents_delta fields are
-        * explicitly NOT applied to the in-core superblock.
-        * The idea is that that has already been done.
-        *
-        * 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 still need
-        * to update the incore superblock with the changes.
-        */
+       /* apply remaining deltas */
+
        if (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
             (tp->t_flags & XFS_TRANS_SB_DIRTY)) {
                if (tp->t_icount_delta != 0) {
@@ -702,19 +709,9 @@ xfs_trans_unreserve_and_mod_sb(
                        msbp->msb_delta = tp->t_ifree_delta;
                        msbp++;
                }
-               if (tp->t_fdblocks_delta != 0) {
-                       msbp->msb_field = XFS_SBS_FDBLOCKS;
-                       msbp->msb_delta = tp->t_fdblocks_delta;
-                       msbp++;
-               }
        }
 
        if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
-               if (tp->t_frextents_delta != 0) {
-                       msbp->msb_field = XFS_SBS_FREXTENTS;
-                       msbp->msb_delta = tp->t_frextents_delta;
-                       msbp++;
-               }
                if (tp->t_dblocks_delta != 0) {
                        msbp->msb_field = XFS_SBS_DBLOCKS;
                        msbp->msb_delta = tp->t_dblocks_delta;
@@ -1325,7 +1322,6 @@ xfs_trans_chunk_committed(
        xfs_lsn_t               item_lsn;
        struct xfs_mount        *mp;
        int                     i;
-       SPLDECL(s);
 
        lidp = licp->lic_descs;
        for (i = 0; i < licp->lic_unused; i++, lidp++) {
@@ -1366,7 +1362,7 @@ xfs_trans_chunk_committed(
                 * the test below.
                 */
                mp = lip->li_mountp;
-               AIL_LOCK(mp,s);
+               spin_lock(&mp->m_ail_lock);
                if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) {
                        /*
                         * This will set the item's lsn to item_lsn
@@ -1375,9 +1371,9 @@ xfs_trans_chunk_committed(
                         *
                         * xfs_trans_update_ail() drops the AIL lock.
                         */
-                       xfs_trans_update_ail(mp, lip, item_lsn, s);
+                       xfs_trans_update_ail(mp, lip, item_lsn);
                } else {
-                       AIL_UNLOCK(mp, s);
+                       spin_unlock(&mp->m_ail_lock);
                }
 
                /*