Commit 7e537f6c authored by Stephen Lord's avatar Stephen Lord Committed by Christoph Hellwig

XFS: Fix a couple of nasty log problems

When a transaction crosses multiple iclogs, the async transaction code
needs to force the log up until the last iclog.  We need to record this
lsn in the transaction so we can do a log flush on it.

Secondly, there was a sleep/wakeup pair between flushing the log and
log write completions which was a) incorrect, and  b) no longer needed.
This could result in early wakeups of threads waiting for log flushes.

Modid: 2.5.x-xfs:slinx:129778a
parent 9318cd45
......@@ -2626,7 +2626,7 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
*/
if (cnt) {
TRACE_BUSYSEARCH("xfs_alloc_search_busy", "found", agno, bno, len, n, tp);
lsn = bsy->busy_tp->t_lsn;
lsn = bsy->busy_tp->t_commit_lsn;
mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s);
xfs_log_force(mp, lsn, XFS_LOG_FORCE|XFS_LOG_SYNC);
} else {
......
......@@ -2155,13 +2155,6 @@ xlog_state_done_syncing(
iclog->ic_state = XLOG_STATE_DONE_SYNC;
}
/*
* Someone could be sleeping on the next iclog even though it is
* in the ACTIVE state. We kick off one thread to force the
* iclog buffer out.
*/
if (iclog->ic_next->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR))
sv_signal(&iclog->ic_next->ic_forcesema);
LOG_UNLOCK(log, s);
xlog_state_do_callback(log, aborted, iclog); /* also cleans log */
} /* xlog_state_done_syncing */
......@@ -2984,11 +2977,9 @@ xlog_state_sync(xlog_t *log,
uint flags)
{
xlog_in_core_t *iclog;
int already_slept = 0;
SPLDECL(s);
try_again:
s = LOG_LOCK(log);
iclog = log->l_iclog;
......@@ -3009,32 +3000,6 @@ xlog_state_sync(xlog_t *log,
}
if (iclog->ic_state == XLOG_STATE_ACTIVE) {
/*
* We sleep here if we haven't already slept (e.g.
* this is the first time we've looked at the correct
* iclog buf) and the buffer before us is going to
* be sync'ed. We have to do that to ensure that the
* log records go out in the proper order. When it's
* done, someone waiting on this buffer will be woken up
* (maybe us) to flush this buffer out.
*
* Otherwise, we mark the buffer WANT_SYNC, and bump
* up the refcnt so we can release the log (which drops
* the ref count). The state switch keeps new transaction
* commits from using this buffer. When the current commits
* finish writing into the buffer, the refcount will drop to
* zero and the buffer will go out then.
*/
if (!already_slept &&
(iclog->ic_prev->ic_state & (XLOG_STATE_WANT_SYNC |
XLOG_STATE_SYNCING))) {
ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR));
XFS_STATS_INC(xfsstats.xs_log_force_sleep);
sv_wait(&iclog->ic_prev->ic_forcesema, PSWP,
&log->l_icloglock, s);
already_slept = 1;
goto try_again;
} else {
iclog->ic_refcnt++;
xlog_state_switch_iclogs(log, iclog, 0);
LOG_UNLOCK(log, s);
......@@ -3042,7 +3007,6 @@ xlog_state_sync(xlog_t *log,
return XFS_ERROR(EIO);
s = LOG_LOCK(log);
}
}
if ((flags & XFS_LOG_SYNC) && /* sleep */
!(iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) {
......
......@@ -788,6 +788,7 @@ xfs_trans_commit(
commit_lsn = xfs_log_done(mp, tp->t_ticket, log_flags);
#endif
tp->t_commit_lsn = commit_lsn;
if (nvec > XFS_TRANS_LOGVEC_COUNT) {
kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));
}
......
......@@ -378,7 +378,10 @@ typedef struct xfs_trans {
unsigned int t_rtx_res_used; /* # of resvd rt extents used */
xfs_log_ticket_t t_ticket; /* log mgr ticket */
sema_t t_sema; /* sema for commit completion */
xfs_lsn_t t_lsn; /* log seq num of trans commit*/
xfs_lsn_t t_lsn; /* log seq num of start of
* transaction. */
xfs_lsn_t t_commit_lsn; /* log seq num of end of
* transaction. */
struct xfs_mount *t_mountp; /* ptr to fs mount struct */
struct xfs_dquot_acct *t_dqinfo; /* accting info for dquots */
xfs_trans_callback_t t_callback; /* transaction callback */
......
......@@ -5299,8 +5299,10 @@ xfsidbg_xtp(xfs_trans_t *tp)
tp->t_log_res, tp->t_blk_res, tp->t_blk_res_used);
kdb_printf("rt res %d rt res used %d\n", tp->t_rtx_res,
tp->t_rtx_res_used);
kdb_printf("ticket 0x%lx lsn %s\n",
(unsigned long) tp->t_ticket, xfs_fmtlsn(&tp->t_lsn));
kdb_printf("ticket 0x%lx lsn %s commit_lsn %s\n",
(unsigned long) tp->t_ticket,
xfs_fmtlsn(&tp->t_lsn),
xfs_fmtlsn(&tp->t_commit_lsn));
kdb_printf("callback 0x%p callarg 0x%p\n",
tp->t_callback, tp->t_callarg);
kdb_printf("icount delta %ld ifree delta %ld\n",
......
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