Commit a734b95c authored by Nathan Scott's avatar Nathan Scott

[XFS] Fix a use-after-free during transaction commit when the log

is in error state.

SGI Modid: xfs-linux:xfs-kern:172041a
parent 233dc581
...@@ -337,13 +337,11 @@ xfs_log_force(xfs_mount_t *mp, ...@@ -337,13 +337,11 @@ xfs_log_force(xfs_mount_t *mp,
} /* xfs_log_force */ } /* xfs_log_force */
/* /*
* This function will take a log sequence number and check to see if that * Attaches a new iclog I/O completion callback routine during
* lsn has been flushed to disk. If it has, then the callback function is * transaction commit. If the log is in error state, a non-zero
* called with the callback argument. If the relevant in-core log has not * return code is handed back and the caller is responsible for
* been synced to disk, we add the callback to the callback list of the * executing the callback at an appropriate time.
* in-core log.
*/ */
int int
xfs_log_notify(xfs_mount_t *mp, /* mount of partition */ xfs_log_notify(xfs_mount_t *mp, /* mount of partition */
...@@ -369,10 +367,7 @@ xfs_log_notify(xfs_mount_t *mp, /* mount of partition */ ...@@ -369,10 +367,7 @@ xfs_log_notify(xfs_mount_t *mp, /* mount of partition */
iclog->ic_callback_tail = &(cb->cb_next); iclog->ic_callback_tail = &(cb->cb_next);
} }
LOG_UNLOCK(log, spl); LOG_UNLOCK(log, spl);
if (abortflg) { return abortflg;
cb->cb_func(cb->cb_arg, abortflg);
}
return 0;
} /* xfs_log_notify */ } /* xfs_log_notify */
int int
......
...@@ -855,15 +855,18 @@ xfs_trans_commit( ...@@ -855,15 +855,18 @@ xfs_trans_commit(
tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed; tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed;
tp->t_logcb.cb_arg = tp; tp->t_logcb.cb_arg = tp;
/* We need to pass the iclog buffer which was used for the /*
* We need to pass the iclog buffer which was used for the
* transaction commit record into this function, and attach * transaction commit record into this function, and attach
* the callback to it. The callback must be attached before * the callback to it. The callback must be attached before
* the items are unlocked to avoid racing with other threads * the items are unlocked to avoid racing with other threads
* waiting for an item to unlock. * waiting for an item to unlock.
*/ */
error = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb)); shutdown = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb));
/* mark this thread as no longer being in a transaction */ /*
* Mark this thread as no longer being in a transaction
*/
PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
/* /*
...@@ -881,6 +884,19 @@ xfs_trans_commit( ...@@ -881,6 +884,19 @@ xfs_trans_commit(
*/ */
xfs_trans_unlock_items(tp, commit_lsn); xfs_trans_unlock_items(tp, commit_lsn);
/*
* If we detected a log error earlier, finish committing
* the transaction now (unpin log items, etc).
*
* Order is critical here, to avoid using the transaction
* pointer after its been freed (by xfs_trans_committed
* either here now, or as a callback). We cannot do this
* step inside xfs_log_notify as was done earlier because
* of this issue.
*/
if (shutdown)
xfs_trans_committed(tp, XFS_LI_ABORTED);
/* /*
* Now that the xfs_trans_committed callback has been attached, * Now that the xfs_trans_committed callback has been attached,
* and the items are released we can finally allow the iclog to * and the items are released we can finally allow the iclog to
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment