BUG/MEDIUM: stream-int: Don't rely on CF_WRITE_PARTIAL to unblock opposite si

In the function stream_int_notify(), when the opposite stream-interface is
blocked because there is no more room into the input buffer, if the flag
CF_WRITE_PARTIAL is set on this buffer, it is unblocked. It is a way to unblock
the reads on the other side because some data was sent.

But it is a problem during the fast-forwarding because only the stream is able
to remove the flag CF_WRITE_PARTIAL. So it is possible to have this flag because
of a previous send while the input buffer of the opposite stream-interface is
now full. In such case, the opposite stream-interface will be woken up for
nothing because its input buffer is full. If the same happens on the opposite
side, we will have a loop consumming all the CPU.

To fix the bug, the opposite side is now only notify if there is some available
room in its input buffer in the function si_cs_send(), so only if some data was
sent.

This patch must be backported to 2.0 and 1.9.
This commit is contained in:
Christopher Faulet 2019-07-05 13:44:29 +02:00
parent 86162db15c
commit 037b3ebd35
2 changed files with 5 additions and 6 deletions

View File

@ -950,6 +950,7 @@ static inline void co_skip(struct channel *chn, int len)
/* notify that some data was written to the SI from the buffer */
chn->flags |= CF_WRITE_PARTIAL | CF_WROTE_DATA;
chn_prod(chn)->flags &= ~SI_FL_RXBLK_ROOM; // si_rx_room_rdy()
}
/* HTX version of co_skip(). This function skips at most <len> bytes from the
@ -967,6 +968,7 @@ static inline void co_htx_skip(struct channel *chn, struct htx *htx, int len)
/* notify that some data was written to the SI from the buffer */
chn->flags |= CF_WRITE_PARTIAL | CF_WROTE_DATA;
chn_prod(chn)->flags &= ~SI_FL_RXBLK_ROOM; // si_rx_room_rdy()
}
}

View File

@ -482,10 +482,6 @@ static void stream_int_notify(struct stream_interface *si)
ic->rex = tick_add_ifset(now_ms, ic->rto);
}
if ((sio->flags & SI_FL_RXBLK_ROOM) &&
((oc->flags & CF_WRITE_PARTIAL) || channel_is_empty(oc)))
si_rx_room_rdy(sio);
if (oc->flags & CF_DONT_READ)
si_rx_chan_blk(sio);
else
@ -761,6 +757,8 @@ int si_cs_send(struct conn_stream *cs)
oc->flags |= CF_WRITE_PARTIAL | CF_WROTE_DATA;
if (si->state == SI_ST_CON)
si->state = SI_ST_RDY;
si_rx_room_rdy(si_opposite(si));
}
if (conn->flags & CO_FL_ERROR || cs->flags & (CS_FL_ERROR|CS_FL_ERR_PENDING)) {
@ -920,8 +918,7 @@ void si_sync_send(struct stream_interface *si)
if (cs->conn->flags & CO_FL_ERROR)
return;
if (si_cs_send(cs))
si_rx_room_rdy(si_opposite(si));
si_cs_send(cs);
}
/* Updates at once the channel flags, and timers of both stream interfaces of a