From: Philippe Gerum <[email protected]> Concurrent reads or writes to a buffer causing nested buffer space reservations could end up in a miscalculation of the number of bytes remaining to be read or written. Fix this by updating these counts only once the last reservation is committed.
Signed-off-by: Philippe Gerum <[email protected]> --- kernel/drivers/ipc/bufp.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/kernel/drivers/ipc/bufp.c b/kernel/drivers/ipc/bufp.c index 3d0929df7..45c917eb0 100644 --- a/kernel/drivers/ipc/bufp.c +++ b/kernel/drivers/ipc/bufp.c @@ -43,8 +43,10 @@ struct bufp_socket { off_t rdoff; off_t rdrsvd; + int rdsem; off_t wroff; off_t wrrsvd; + int wrsem; size_t fillsz; rtdm_event_t i_event; rtdm_event_t o_event; @@ -188,6 +190,7 @@ redo: rdoff = sk->rdoff; sk->rdoff = (rdoff + len) % sk->bufsz; sk->rdrsvd += len; + sk->rdsem++; rbytes = ret = len; do { @@ -213,14 +216,17 @@ redo: rdoff = (rdoff + n) % sk->bufsz; } while (rbytes > 0); + if (--sk->rdsem > 0) + goto out; + resched = 0; - if (sk->fillsz == sk->bufsz) /* -> writable */ + if (sk->fillsz == sk->bufsz) /* -> becomes writable */ resched |= xnselect_signal(&sk->priv->send_block, POLLOUT); - sk->rdrsvd -= len; - sk->fillsz -= len; + sk->fillsz -= sk->rdrsvd; + sk->rdrsvd = 0; - if (sk->fillsz == 0) /* -> non-readable */ + if (sk->fillsz == 0) /* -> becomes non-readable */ resched |= xnselect_signal(&sk->priv->recv_block, 0); /* @@ -431,6 +437,7 @@ static ssize_t __bufp_writebuf(struct bufp_socket *rsk, wroff = rsk->wroff; rsk->wroff = (wroff + len) % rsk->bufsz; rsk->wrrsvd += len; + rsk->wrsem++; wbytes = ret = len; do { @@ -459,14 +466,17 @@ static ssize_t __bufp_writebuf(struct bufp_socket *rsk, wroff = (wroff + n) % rsk->bufsz; } while (wbytes > 0); - rsk->fillsz += len; - rsk->wrrsvd -= len; + if (--rsk->wrsem > 0) + goto out; resched = 0; - if (rsk->fillsz == len) /* -> readable */ + if (rsk->fillsz == 0) /* -> becomes readable */ resched |= xnselect_signal(&rsk->priv->recv_block, POLLIN); - if (rsk->fillsz == rsk->bufsz) /* non-writable */ + rsk->fillsz += rsk->wrrsvd; + rsk->wrrsvd = 0; + + if (rsk->fillsz == rsk->bufsz) /* becomes non-writable */ resched |= xnselect_signal(&rsk->priv->send_block, 0); /* * Wake up all threads pending on the input wait -- 2.24.1
