diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1176,7 +1176,15 @@ space = uipc_stream_sbspace(sb); if (space < sb->sb_lowat || space < cmc.mc_len) { if (nonblock) { + if (aio) + sb->sb_flags |= SB_AIO_PEER; SOCK_RECVBUF_UNLOCK(so2); + if (aio) { + SOCK_SENDBUF_LOCK(so); + so->so_snd.sb_ccc = + so->so_snd.sb_hiwat - space; + SOCK_SENDBUF_UNLOCK(so); + } error = EWOULDBLOCK; goto out4; } @@ -1402,6 +1410,8 @@ UIPC_STREAM_SBCHECK(sb); if (!peek) { + bool aio_peer; + if (last == NULL) STAILQ_INIT(&sb->uxst_mbq); else { @@ -1418,8 +1428,29 @@ MPASS(sb->sb_mbcnt >= mbcnt); sb->sb_mbcnt -= mbcnt; UIPC_STREAM_SBCHECK(sb); - /* Mind the name. We are waking writer here, not reader. */ + /* + * With a normal use, uipc_sosend_stream_or_seqpacket() is + * sleeping on our receive buffer, thus we are using + * sor[ead]wakeup, actually waking up a writer. + * With aio(9) use, the aio machinery uses peer's send buffer + * to sleep, so we need to workaround this. + */ + if (__predict_false((aio_peer = sb->sb_flags & SB_AIO_PEER))) + sb->sb_flags &= ~SB_AIO_PEER; sorwakeup_locked(so); + if (aio_peer) { + struct unpcb *unp2; + + if (uipc_lock_peer(so, &unp2) == 0) { + struct socket *so2 = unp2->unp_socket; + + SOCK_SENDBUF_LOCK(so2); + so2->so_snd.sb_ccc -= datalen; + sowakeup_aio(so2, SO_SND); + SOCK_SENDBUF_UNLOCK(so2); + UNP_PCB_UNLOCK(unp2); + } + } } else SOCK_RECVBUF_UNLOCK(so); diff --git a/sys/sys/sockbuf.h b/sys/sys/sockbuf.h --- a/sys/sys/sockbuf.h +++ b/sys/sys/sockbuf.h @@ -40,7 +40,7 @@ #define SB_SEL 0x08 /* someone is selecting */ #define SB_ASYNC 0x10 /* ASYNC I/O, need signals */ #define SB_UPCALL 0x20 /* someone wants an upcall */ -/* was SB_NOINTR 0x40 */ +#define SB_AIO_PEER 0x40 /* other side is in AIO mode */ #define SB_AIO 0x80 /* AIO operations queued */ #define SB_KNOTE 0x100 /* kernel note attached */ #define SB_NOCOALESCE 0x200 /* don't coalesce new data into existing mbufs */