|
@@ -45,20 +45,12 @@
|
|
|
#include "xfs_trans_space.h"
|
|
|
#include "xfs_inode_item.h"
|
|
|
|
|
|
-
|
|
|
-STATIC void xfs_trans_apply_sb_deltas(xfs_trans_t *);
|
|
|
-STATIC void xfs_trans_uncommit(xfs_trans_t *, uint);
|
|
|
-STATIC void xfs_trans_committed(xfs_trans_t *, int);
|
|
|
-STATIC void xfs_trans_free(xfs_trans_t *);
|
|
|
-
|
|
|
kmem_zone_t *xfs_trans_zone;
|
|
|
|
|
|
-
|
|
|
/*
|
|
|
* Reservation functions here avoid a huge stack in xfs_trans_init
|
|
|
* due to register overflow from temporaries in the calculations.
|
|
|
*/
|
|
|
-
|
|
|
STATIC uint
|
|
|
xfs_calc_write_reservation(xfs_mount_t *mp)
|
|
|
{
|
|
@@ -257,6 +249,19 @@ _xfs_trans_alloc(
|
|
|
return tp;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Free the transaction structure. If there is more clean up
|
|
|
+ * to do when the structure is freed, add it here.
|
|
|
+ */
|
|
|
+STATIC void
|
|
|
+xfs_trans_free(
|
|
|
+ xfs_trans_t *tp)
|
|
|
+{
|
|
|
+ atomic_dec(&tp->t_mountp->m_active_trans);
|
|
|
+ xfs_trans_free_dqinfo(tp);
|
|
|
+ kmem_zone_free(xfs_trans_zone, tp);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This is called to create a new transaction which will share the
|
|
|
* permanent log reservation of the given transaction. The remaining
|
|
@@ -769,7 +774,7 @@ xfs_trans_unreserve_and_mod_sb(
|
|
|
*/
|
|
|
static uint
|
|
|
xfs_trans_count_vecs(
|
|
|
- xfs_trans_t *tp)
|
|
|
+ struct xfs_trans *tp)
|
|
|
{
|
|
|
int nvecs;
|
|
|
xfs_log_item_desc_t *lidp;
|
|
@@ -860,6 +865,158 @@ xfs_trans_fill_vecs(
|
|
|
log_vector->i_type = XLOG_REG_TYPE_TRANSHDR;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * The committed item processing consists of calling the committed routine of
|
|
|
+ * each logged item, updating the item's position in the AIL if necessary, and
|
|
|
+ * unpinning each item. If the committed routine returns -1, then do nothing
|
|
|
+ * further with the item because it may have been freed.
|
|
|
+ *
|
|
|
+ * Since items are unlocked when they are copied to the incore log, it is
|
|
|
+ * possible for two transactions to be completing and manipulating the same
|
|
|
+ * item simultaneously. The AIL lock will protect the lsn field of each item.
|
|
|
+ * The value of this field can never go backwards.
|
|
|
+ *
|
|
|
+ * We unpin the items after repositioning them in the AIL, because otherwise
|
|
|
+ * they could be immediately flushed and we'd have to race with the flusher
|
|
|
+ * trying to pull the item from the AIL as we add it.
|
|
|
+ */
|
|
|
+static void
|
|
|
+xfs_trans_item_committed(
|
|
|
+ struct xfs_log_item *lip,
|
|
|
+ xfs_lsn_t commit_lsn,
|
|
|
+ int aborted)
|
|
|
+{
|
|
|
+ xfs_lsn_t item_lsn;
|
|
|
+ struct xfs_ail *ailp;
|
|
|
+
|
|
|
+ if (aborted)
|
|
|
+ lip->li_flags |= XFS_LI_ABORTED;
|
|
|
+ item_lsn = IOP_COMMITTED(lip, commit_lsn);
|
|
|
+
|
|
|
+ /* If the committed routine returns -1, item has been freed. */
|
|
|
+ if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the returned lsn is greater than what it contained before, update
|
|
|
+ * the location of the item in the AIL. If it is not, then do nothing.
|
|
|
+ * Items can never move backwards in the AIL.
|
|
|
+ *
|
|
|
+ * While the new lsn should usually be greater, it is possible that a
|
|
|
+ * later transaction completing simultaneously with an earlier one
|
|
|
+ * using the same item could complete first with a higher lsn. This
|
|
|
+ * would cause the earlier transaction to fail the test below.
|
|
|
+ */
|
|
|
+ ailp = lip->li_ailp;
|
|
|
+ spin_lock(&ailp->xa_lock);
|
|
|
+ if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) {
|
|
|
+ /*
|
|
|
+ * This will set the item's lsn to item_lsn and update the
|
|
|
+ * position of the item in the AIL.
|
|
|
+ *
|
|
|
+ * xfs_trans_ail_update() drops the AIL lock.
|
|
|
+ */
|
|
|
+ xfs_trans_ail_update(ailp, lip, item_lsn);
|
|
|
+ } else {
|
|
|
+ spin_unlock(&ailp->xa_lock);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Now that we've repositioned the item in the AIL, unpin it so it can
|
|
|
+ * be flushed. Pass information about buffer stale state down from the
|
|
|
+ * log item flags, if anyone else stales the buffer we do not want to
|
|
|
+ * pay any attention to it.
|
|
|
+ */
|
|
|
+ IOP_UNPIN(lip);
|
|
|
+}
|
|
|
+
|
|
|
+/* Clear all the per-AG busy list items listed in this transaction */
|
|
|
+static void
|
|
|
+xfs_trans_clear_busy_extents(
|
|
|
+ struct xfs_trans *tp)
|
|
|
+{
|
|
|
+ xfs_log_busy_chunk_t *lbcp;
|
|
|
+ xfs_log_busy_slot_t *lbsp;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (lbcp = &tp->t_busy; lbcp != NULL; lbcp = lbcp->lbc_next) {
|
|
|
+ i = 0;
|
|
|
+ for (lbsp = lbcp->lbc_busy; i < lbcp->lbc_unused; i++, lbsp++) {
|
|
|
+ if (XFS_LBC_ISFREE(lbcp, i))
|
|
|
+ continue;
|
|
|
+ xfs_alloc_clear_busy(tp, lbsp->lbc_ag, lbsp->lbc_idx);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ xfs_trans_free_busy(tp);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * This is typically called by the LM when a transaction has been fully
|
|
|
+ * committed to disk. It needs to unpin the items which have
|
|
|
+ * been logged by the transaction and update their positions
|
|
|
+ * in the AIL if necessary.
|
|
|
+ *
|
|
|
+ * This also gets called when the transactions didn't get written out
|
|
|
+ * because of an I/O error. Abortflag & XFS_LI_ABORTED is set then.
|
|
|
+ */
|
|
|
+STATIC void
|
|
|
+xfs_trans_committed(
|
|
|
+ struct xfs_trans *tp,
|
|
|
+ int abortflag)
|
|
|
+{
|
|
|
+ xfs_log_item_desc_t *lidp;
|
|
|
+ xfs_log_item_chunk_t *licp;
|
|
|
+ xfs_log_item_chunk_t *next_licp;
|
|
|
+
|
|
|
+ /* Call the transaction's completion callback if there is one. */
|
|
|
+ if (tp->t_callback != NULL)
|
|
|
+ tp->t_callback(tp, tp->t_callarg);
|
|
|
+
|
|
|
+ for (lidp = xfs_trans_first_item(tp);
|
|
|
+ lidp != NULL;
|
|
|
+ lidp = xfs_trans_next_item(tp, lidp)) {
|
|
|
+ xfs_trans_item_committed(lidp->lid_item, tp->t_lsn, abortflag);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* free the item chunks, ignoring the embedded chunk */
|
|
|
+ for (licp = tp->t_items.lic_next; licp != NULL; licp = next_licp) {
|
|
|
+ next_licp = licp->lic_next;
|
|
|
+ kmem_free(licp);
|
|
|
+ }
|
|
|
+
|
|
|
+ xfs_trans_clear_busy_extents(tp);
|
|
|
+ xfs_trans_free(tp);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Called from the trans_commit code when we notice that
|
|
|
+ * the filesystem is in the middle of a forced shutdown.
|
|
|
+ */
|
|
|
+STATIC void
|
|
|
+xfs_trans_uncommit(
|
|
|
+ struct xfs_trans *tp,
|
|
|
+ uint flags)
|
|
|
+{
|
|
|
+ xfs_log_item_desc_t *lidp;
|
|
|
+
|
|
|
+ for (lidp = xfs_trans_first_item(tp);
|
|
|
+ lidp != NULL;
|
|
|
+ lidp = xfs_trans_next_item(tp, lidp)) {
|
|
|
+ /*
|
|
|
+ * Unpin all but those that aren't dirty.
|
|
|
+ */
|
|
|
+ if (lidp->lid_flags & XFS_LID_DIRTY)
|
|
|
+ IOP_UNPIN_REMOVE(lidp->lid_item, tp);
|
|
|
+ }
|
|
|
+
|
|
|
+ xfs_trans_unreserve_and_mod_sb(tp);
|
|
|
+ xfs_trans_unreserve_and_mod_dquots(tp);
|
|
|
+
|
|
|
+ xfs_trans_free_items(tp, flags);
|
|
|
+ xfs_trans_free_busy(tp);
|
|
|
+ xfs_trans_free(tp);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Format the transaction direct to the iclog. This isolates the physical
|
|
|
* transaction commit operation from the logical operation and hence allows
|
|
@@ -1110,35 +1267,6 @@ out_unreserve:
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Called from the trans_commit code when we notice that
|
|
|
- * the filesystem is in the middle of a forced shutdown.
|
|
|
- */
|
|
|
-STATIC void
|
|
|
-xfs_trans_uncommit(
|
|
|
- xfs_trans_t *tp,
|
|
|
- uint flags)
|
|
|
-{
|
|
|
- xfs_log_item_desc_t *lidp;
|
|
|
-
|
|
|
- for (lidp = xfs_trans_first_item(tp);
|
|
|
- lidp != NULL;
|
|
|
- lidp = xfs_trans_next_item(tp, lidp)) {
|
|
|
- /*
|
|
|
- * Unpin all but those that aren't dirty.
|
|
|
- */
|
|
|
- if (lidp->lid_flags & XFS_LID_DIRTY)
|
|
|
- IOP_UNPIN_REMOVE(lidp->lid_item, tp);
|
|
|
- }
|
|
|
-
|
|
|
- xfs_trans_unreserve_and_mod_sb(tp);
|
|
|
- xfs_trans_unreserve_and_mod_dquots(tp);
|
|
|
-
|
|
|
- xfs_trans_free_items(tp, flags);
|
|
|
- xfs_trans_free_busy(tp);
|
|
|
- xfs_trans_free(tp);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Unlock all of the transaction's items and free the transaction.
|
|
|
* The transaction must not have modified any of its items, because
|
|
@@ -1215,20 +1343,6 @@ xfs_trans_cancel(
|
|
|
xfs_trans_free(tp);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-/*
|
|
|
- * Free the transaction structure. If there is more clean up
|
|
|
- * to do when the structure is freed, add it here.
|
|
|
- */
|
|
|
-STATIC void
|
|
|
-xfs_trans_free(
|
|
|
- xfs_trans_t *tp)
|
|
|
-{
|
|
|
- atomic_dec(&tp->t_mountp->m_active_trans);
|
|
|
- xfs_trans_free_dqinfo(tp);
|
|
|
- kmem_zone_free(xfs_trans_zone, tp);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Roll from one trans in the sequence of PERMANENT transactions to
|
|
|
* the next: permanent transactions are only flushed out when
|
|
@@ -1298,141 +1412,3 @@ xfs_trans_roll(
|
|
|
xfs_trans_ihold(trans, dp);
|
|
|
return 0;
|
|
|
}
|
|
|
-
|
|
|
-/*
|
|
|
- * The committed item processing consists of calling the committed routine of
|
|
|
- * each logged item, updating the item's position in the AIL if necessary, and
|
|
|
- * unpinning each item. If the committed routine returns -1, then do nothing
|
|
|
- * further with the item because it may have been freed.
|
|
|
- *
|
|
|
- * Since items are unlocked when they are copied to the incore log, it is
|
|
|
- * possible for two transactions to be completing and manipulating the same
|
|
|
- * item simultaneously. The AIL lock will protect the lsn field of each item.
|
|
|
- * The value of this field can never go backwards.
|
|
|
- *
|
|
|
- * We unpin the items after repositioning them in the AIL, because otherwise
|
|
|
- * they could be immediately flushed and we'd have to race with the flusher
|
|
|
- * trying to pull the item from the AIL as we add it.
|
|
|
- */
|
|
|
-static void
|
|
|
-xfs_trans_item_committed(
|
|
|
- xfs_log_item_t *lip,
|
|
|
- xfs_lsn_t commit_lsn,
|
|
|
- int aborted)
|
|
|
-{
|
|
|
- xfs_lsn_t item_lsn;
|
|
|
- struct xfs_ail *ailp;
|
|
|
-
|
|
|
- if (aborted)
|
|
|
- lip->li_flags |= XFS_LI_ABORTED;
|
|
|
-
|
|
|
- /*
|
|
|
- * Send in the ABORTED flag to the COMMITTED routine so that it knows
|
|
|
- * whether the transaction was aborted or not.
|
|
|
- */
|
|
|
- item_lsn = IOP_COMMITTED(lip, commit_lsn);
|
|
|
-
|
|
|
- /*
|
|
|
- * If the committed routine returns -1, item has been freed.
|
|
|
- */
|
|
|
- if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0)
|
|
|
- return;
|
|
|
-
|
|
|
- /*
|
|
|
- * If the returned lsn is greater than what it contained before, update
|
|
|
- * the location of the item in the AIL. If it is not, then do nothing.
|
|
|
- * Items can never move backwards in the AIL.
|
|
|
- *
|
|
|
- * While the new lsn should usually be greater, it is possible that a
|
|
|
- * later transaction completing simultaneously with an earlier one
|
|
|
- * using the same item could complete first with a higher lsn. This
|
|
|
- * would cause the earlier transaction to fail the test below.
|
|
|
- */
|
|
|
- ailp = lip->li_ailp;
|
|
|
- spin_lock(&ailp->xa_lock);
|
|
|
- if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) {
|
|
|
- /*
|
|
|
- * This will set the item's lsn to item_lsn and update the
|
|
|
- * position of the item in the AIL.
|
|
|
- *
|
|
|
- * xfs_trans_ail_update() drops the AIL lock.
|
|
|
- */
|
|
|
- xfs_trans_ail_update(ailp, lip, item_lsn);
|
|
|
- } else {
|
|
|
- spin_unlock(&ailp->xa_lock);
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Now that we've repositioned the item in the AIL, unpin it so it can
|
|
|
- * be flushed. Pass information about buffer stale state down from the
|
|
|
- * log item flags, if anyone else stales the buffer we do not want to
|
|
|
- * pay any attention to it.
|
|
|
- */
|
|
|
- IOP_UNPIN(lip);
|
|
|
-}
|
|
|
-
|
|
|
-/* Clear all the per-AG busy list items listed in this transaction */
|
|
|
-static void
|
|
|
-xfs_trans_clear_busy_extents(
|
|
|
- struct xfs_trans *tp)
|
|
|
-{
|
|
|
- xfs_log_busy_chunk_t *lbcp;
|
|
|
- xfs_log_busy_slot_t *lbsp;
|
|
|
- int i;
|
|
|
-
|
|
|
- lbcp = &tp->t_busy;
|
|
|
- while (lbcp != NULL) {
|
|
|
- for (i = 0, lbsp = lbcp->lbc_busy; i < lbcp->lbc_unused; i++, lbsp++) {
|
|
|
- if (!XFS_LBC_ISFREE(lbcp, i)) {
|
|
|
- xfs_alloc_clear_busy(tp, lbsp->lbc_ag,
|
|
|
- lbsp->lbc_idx);
|
|
|
- }
|
|
|
- }
|
|
|
- lbcp = lbcp->lbc_next;
|
|
|
- }
|
|
|
- xfs_trans_free_busy(tp);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * This is typically called by the LM when a transaction has been fully
|
|
|
- * committed to disk. It needs to unpin the items which have
|
|
|
- * been logged by the transaction and update their positions
|
|
|
- * in the AIL if necessary.
|
|
|
- *
|
|
|
- * This also gets called when the transactions didn't get written out
|
|
|
- * because of an I/O error. Abortflag & XFS_LI_ABORTED is set then.
|
|
|
- */
|
|
|
-STATIC void
|
|
|
-xfs_trans_committed(
|
|
|
- xfs_trans_t *tp,
|
|
|
- int abortflag)
|
|
|
-{
|
|
|
- xfs_log_item_desc_t *lidp;
|
|
|
- xfs_log_item_chunk_t *licp;
|
|
|
- xfs_log_item_chunk_t *next_licp;
|
|
|
-
|
|
|
- /*
|
|
|
- * Call the transaction's completion callback if there
|
|
|
- * is one.
|
|
|
- */
|
|
|
- if (tp->t_callback != NULL) {
|
|
|
- tp->t_callback(tp, tp->t_callarg);
|
|
|
- }
|
|
|
-
|
|
|
- for (lidp = xfs_trans_first_item(tp);
|
|
|
- lidp != NULL;
|
|
|
- lidp = xfs_trans_next_item(tp, lidp)) {
|
|
|
- xfs_trans_item_committed(lidp->lid_item, tp->t_lsn, abortflag);
|
|
|
- }
|
|
|
-
|
|
|
- /* free the item chunks, ignoring the embedded chunk */
|
|
|
- licp = tp->t_items.lic_next;
|
|
|
- while (licp != NULL) {
|
|
|
- next_licp = licp->lic_next;
|
|
|
- kmem_free(licp);
|
|
|
- licp = next_licp;
|
|
|
- }
|
|
|
-
|
|
|
- xfs_trans_clear_busy_extents(tp);
|
|
|
- xfs_trans_free(tp);
|
|
|
-}
|