Avoid false assertion on transmit and delayed ack timeout with enabled invariants.

Replace callout_pending() by callout_active() to remove race window.

Reviewed by:	archie
Approved by:	glebius (mentor)
This commit is contained in:
mav 2007-04-24 10:50:25 +00:00
parent d20c01926b
commit 054a6022e4

View File

@ -1047,16 +1047,16 @@ ng_l2tp_recv_ctrl(node_p node, item_p item)
seq->xwin[i] = m;
/* Sanity check receive ack timer state */
KASSERT((i == 0) ^ callout_pending(&seq->rack_timer),
KASSERT((i == 0) ^ callout_active(&seq->rack_timer),
("%s: xwin %d full but rack timer %s running",
__func__, i, callout_pending(&seq->rack_timer) ? "" : "not "));
__func__, i, callout_active(&seq->rack_timer) ? "" : "not "));
/* If peer's receive window is already full, nothing else to do */
if (i >= seq->cwnd)
return (0);
/* Start retransmit timer if not already running */
if (!callout_pending(&seq->rack_timer))
if (!callout_active(&seq->rack_timer))
ng_callout(&seq->rack_timer, node, NULL,
hz, ng_l2tp_seq_rack_timeout, NULL, 0);
@ -1330,7 +1330,7 @@ ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr)
}
/* Stop xmit timer */
if (callout_pending(&seq->rack_timer))
if (callout_active(&seq->rack_timer))
ng_uncallout(&seq->rack_timer, priv->node);
/* If transmit queue is empty, we're done for now */
@ -1385,7 +1385,7 @@ ng_l2tp_seq_recv_ns(priv_p priv, u_int16_t ns)
seq->nr++;
/* Start receive ack timer, if not already running */
if (!callout_pending(&seq->xack_timer))
if (!callout_active(&seq->xack_timer))
ng_callout(&seq->xack_timer, priv->node, NULL,
L2TP_DELAYED_ACK, ng_l2tp_seq_xack_timeout, NULL, 0);
@ -1403,14 +1403,21 @@ ng_l2tp_seq_xack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
const priv_p priv = NG_NODE_PRIVATE(node);
struct l2tp_seq *const seq = &priv->seq;
/* Make sure callout is still active before doing anything */
if (callout_pending(&seq->xack_timer) ||
(!callout_active(&seq->xack_timer)))
return;
/* Sanity check */
L2TP_SEQ_CHECK(seq);
/* If ack is still outstanding, send a ZLB */
if (seq->xack != seq->nr)
ng_l2tp_xmit_ctrl(priv, NULL, seq->ns);
/* Send a ZLB */
ng_l2tp_xmit_ctrl(priv, NULL, seq->ns);
/* Done */
/* callout_deactivate() is not needed here
as ng_uncallout() was called by ng_l2tp_xmit_ctrl() */
/* Sanity check */
L2TP_SEQ_CHECK(seq);
}
@ -1426,13 +1433,14 @@ ng_l2tp_seq_rack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
struct mbuf *m;
u_int delay;
/* Make sure callout is still active before doing anything */
if (callout_pending(&seq->rack_timer) ||
(!callout_active(&seq->rack_timer)))
return;
/* Sanity check */
L2TP_SEQ_CHECK(seq);
/* Make sure peer's ack is still outstanding before doing anything */
if (seq->rack == seq->ns)
goto done;
priv->stats.xmitRetransmits++;
/* Have we reached the retransmit limit? If so, notify owner. */
@ -1457,8 +1465,10 @@ ng_l2tp_seq_rack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
else
ng_l2tp_xmit_ctrl(priv, m, seq->rack);
done:
/* Done */
/* callout_deactivate() is not needed here
as ng_callout() is getting called each time */
/* Sanity check */
L2TP_SEQ_CHECK(seq);
}
@ -1473,6 +1483,13 @@ ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns)
u_int16_t session_id = 0;
int error;
/* Stop ack timer: we're sending an ack with this packet.
Doing this before to keep state predictable after error. */
if (callout_active(&seq->xack_timer))
ng_uncallout(&seq->xack_timer, priv->node);
seq->xack = seq->nr;
/* If no mbuf passed, send an empty packet (ZLB) */
if (m == NULL) {
@ -1515,12 +1532,6 @@ ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns)
priv->stats.xmitPackets++;
priv->stats.xmitOctets += m->m_pkthdr.len;
/* Stop ack timer: we're sending an ack with this packet */
if (callout_pending(&seq->xack_timer))
ng_uncallout(&seq->xack_timer, priv->node);
seq->xack = seq->nr;
/* Send packet */
NG_SEND_DATA_ONLY(error, priv->lower, m);
return (error);
@ -1551,8 +1562,8 @@ ng_l2tp_seq_check(struct l2tp_seq *seq)
CHECK(self_unack >= 0);
CHECK(peer_unack >= 0);
CHECK(peer_unack <= seq->wmax);
CHECK((self_unack == 0) ^ callout_pending(&seq->xack_timer));
CHECK((peer_unack == 0) ^ callout_pending(&seq->rack_timer));
CHECK((self_unack == 0) ^ callout_active(&seq->xack_timer));
CHECK((peer_unack == 0) ^ callout_active(&seq->rack_timer));
for (i = 0; i < peer_unack; i++)
CHECK(seq->xwin[i] != NULL);
for ( ; i < seq->cwnd; i++) /* verify peer's recv window full */