summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man9/sosplice.915
-rw-r--r--sys/kern/uipc_socket.c38
2 files changed, 36 insertions, 17 deletions
diff --git a/share/man/man9/sosplice.9 b/share/man/man9/sosplice.9
index 7444281b6ba..319ca52be3c 100644
--- a/share/man/man9/sosplice.9
+++ b/share/man/man9/sosplice.9
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sosplice.9,v 1.9 2018/08/15 12:10:49 kn Exp $
+.\" $OpenBSD: sosplice.9,v 1.10 2019/07/04 17:42:17 bluhm Exp $
.\"
.\" Copyright (c) 2011-2013 Alexander Bluhm <bluhm@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 15 2018 $
+.Dd $Mdocdate: July 4 2019 $
.Dt SOSPLICE 9
.Os
.Sh NAME
@@ -206,10 +206,13 @@ will call
to trigger the transfer when new data or buffer space is available.
While socket splicing is active, any
.Xr read 2
-from the source socket will block and the wakeup will not be delivered
-to the file descriptor.
-A read event or a socket error is signaled to userland after
-dissolving.
+from the source socket will block.
+Neither read nor write wakeups will be delivered to the file
+descriptors.
+After dissolving, a read event or a socket error is signaled to
+userland on the source socket.
+If space is available, a write event will be signaled on the drain
+socket.
.Sh RETURN VALUES
.Fn sosplice
returns 0 on success and otherwise the error number.
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 802bf361a45..6989510287a 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_socket.c,v 1.231 2018/12/17 16:46:59 bluhm Exp $ */
+/* $OpenBSD: uipc_socket.c,v 1.232 2019/07/04 17:42:17 bluhm Exp $ */
/* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */
/*
@@ -195,6 +195,8 @@ solisten(struct socket *so, int backlog)
return (0);
}
+#define SOSP_FREEING_READ 1
+#define SOSP_FREEING_WRITE 2
void
sofree(struct socket *so, int s)
{
@@ -218,11 +220,20 @@ sofree(struct socket *so, int s)
sigio_free(&so->so_sigio);
#ifdef SOCKET_SPLICE
if (so->so_sp) {
- if (issplicedback(so))
- sounsplice(so->so_sp->ssp_soback, so,
- so->so_sp->ssp_soback != so);
- if (isspliced(so))
- sounsplice(so, so->so_sp->ssp_socket, 0);
+ if (issplicedback(so)) {
+ int freeing = SOSP_FREEING_WRITE;
+
+ if (so->so_sp->ssp_soback == so)
+ freeing |= SOSP_FREEING_READ;
+ sounsplice(so->so_sp->ssp_soback, so, freeing);
+ }
+ if (isspliced(so)) {
+ int freeing = SOSP_FREEING_READ;
+
+ if (so == so->so_sp->ssp_socket)
+ freeing |= SOSP_FREEING_WRITE;
+ sounsplice(so, so->so_sp->ssp_socket, freeing);
+ }
}
#endif /* SOCKET_SPLICE */
sbrelease(so, &so->so_snd);
@@ -1148,7 +1159,7 @@ sosplice(struct socket *so, int fd, off_t max, struct timeval *tv)
return (error);
}
if (so->so_sp->ssp_socket)
- sounsplice(so, so->so_sp->ssp_socket, 1);
+ sounsplice(so, so->so_sp->ssp_socket, 0);
sbunlock(so, &so->so_rcv);
return (0);
}
@@ -1227,7 +1238,7 @@ sosplice(struct socket *so, int fd, off_t max, struct timeval *tv)
}
void
-sounsplice(struct socket *so, struct socket *sosp, int wakeup)
+sounsplice(struct socket *so, struct socket *sosp, int freeing)
{
soassertlocked(so);
@@ -1236,8 +1247,11 @@ sounsplice(struct socket *so, struct socket *sosp, int wakeup)
sosp->so_snd.sb_flags &= ~SB_SPLICE;
so->so_rcv.sb_flags &= ~SB_SPLICE;
so->so_sp->ssp_socket = sosp->so_sp->ssp_soback = NULL;
- if (wakeup && soreadable(so))
+ /* Do not wakeup a socket that is about to be freed. */
+ if ((freeing & SOSP_FREEING_READ) == 0 && soreadable(so))
sorwakeup(so);
+ if ((freeing & SOSP_FREEING_WRITE) == 0 && sowriteable(sosp))
+ sowwakeup(sosp);
}
void
@@ -1249,7 +1263,7 @@ soidle(void *arg)
s = solock(so);
if (so->so_rcv.sb_flags & SB_SPLICE) {
so->so_error = ETIMEDOUT;
- sounsplice(so, so->so_sp->ssp_socket, 1);
+ sounsplice(so, so->so_sp->ssp_socket, 0);
}
sounlock(so, s);
}
@@ -1574,7 +1588,7 @@ somove(struct socket *so, int wait)
so->so_error = error;
if (((so->so_state & SS_CANTRCVMORE) && so->so_rcv.sb_cc == 0) ||
(sosp->so_state & SS_CANTSENDMORE) || maxreached || error) {
- sounsplice(so, sosp, 1);
+ sounsplice(so, sosp, 0);
return (0);
}
if (timerisset(&so->so_idletv))
@@ -1620,6 +1634,8 @@ sowwakeup(struct socket *so)
#ifdef SOCKET_SPLICE
if (so->so_snd.sb_flags & SB_SPLICE)
task_add(sosplice_taskq, &so->so_sp->ssp_soback->so_splicetask);
+ if (issplicedback(so))
+ return;
#endif
sowakeup(so, &so->so_snd);
}