Commit 0a67a85b authored by Philippe Gerum's avatar Philippe Gerum Committed by Jan Kiszka

drivers/ipc: bufp: fix rd/rd and wr/wr races

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's avatarPhilippe Gerum <rpm@xenomai.org>
Signed-off-by: Jan Kiszka's avatarJan Kiszka <jan.kiszka@siemens.com>
parent d6af41b3
...@@ -43,8 +43,10 @@ struct bufp_socket { ...@@ -43,8 +43,10 @@ struct bufp_socket {
off_t rdoff; off_t rdoff;
off_t rdrsvd; off_t rdrsvd;
int rdsem;
off_t wroff; off_t wroff;
off_t wrrsvd; off_t wrrsvd;
int wrsem;
size_t fillsz; size_t fillsz;
rtdm_event_t i_event; rtdm_event_t i_event;
rtdm_event_t o_event; rtdm_event_t o_event;
...@@ -188,6 +190,7 @@ redo: ...@@ -188,6 +190,7 @@ redo:
rdoff = sk->rdoff; rdoff = sk->rdoff;
sk->rdoff = (rdoff + len) % sk->bufsz; sk->rdoff = (rdoff + len) % sk->bufsz;
sk->rdrsvd += len; sk->rdrsvd += len;
sk->rdsem++;
rbytes = ret = len; rbytes = ret = len;
do { do {
...@@ -213,14 +216,17 @@ redo: ...@@ -213,14 +216,17 @@ redo:
rdoff = (rdoff + n) % sk->bufsz; rdoff = (rdoff + n) % sk->bufsz;
} while (rbytes > 0); } while (rbytes > 0);
if (--sk->rdsem > 0)
goto out;
resched = 0; resched = 0;
if (sk->fillsz == sk->bufsz) /* -> writable */ if (sk->fillsz == sk->bufsz) /* -> becomes writable */
resched |= xnselect_signal(&sk->priv->send_block, POLLOUT); resched |= xnselect_signal(&sk->priv->send_block, POLLOUT);
sk->rdrsvd -= len; sk->fillsz -= sk->rdrsvd;
sk->fillsz -= len; sk->rdrsvd = 0;
if (sk->fillsz == 0) /* -> non-readable */ if (sk->fillsz == 0) /* -> becomes non-readable */
resched |= xnselect_signal(&sk->priv->recv_block, 0); resched |= xnselect_signal(&sk->priv->recv_block, 0);
/* /*
...@@ -431,6 +437,7 @@ static ssize_t __bufp_writebuf(struct bufp_socket *rsk, ...@@ -431,6 +437,7 @@ static ssize_t __bufp_writebuf(struct bufp_socket *rsk,
wroff = rsk->wroff; wroff = rsk->wroff;
rsk->wroff = (wroff + len) % rsk->bufsz; rsk->wroff = (wroff + len) % rsk->bufsz;
rsk->wrrsvd += len; rsk->wrrsvd += len;
rsk->wrsem++;
wbytes = ret = len; wbytes = ret = len;
do { do {
...@@ -459,14 +466,17 @@ static ssize_t __bufp_writebuf(struct bufp_socket *rsk, ...@@ -459,14 +466,17 @@ static ssize_t __bufp_writebuf(struct bufp_socket *rsk,
wroff = (wroff + n) % rsk->bufsz; wroff = (wroff + n) % rsk->bufsz;
} while (wbytes > 0); } while (wbytes > 0);
rsk->fillsz += len; if (--rsk->wrsem > 0)
rsk->wrrsvd -= len; goto out;
resched = 0; resched = 0;
if (rsk->fillsz == len) /* -> readable */ if (rsk->fillsz == 0) /* -> becomes readable */
resched |= xnselect_signal(&rsk->priv->recv_block, POLLIN); 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); resched |= xnselect_signal(&rsk->priv->send_block, 0);
/* /*
* Wake up all threads pending on the input wait * Wake up all threads pending on the input wait
......
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