Hi,
Socket splicing can delay operations by task or timeout. I have
fixed the use afer free in the task a while ago, but forgot the
timeout. Introduce soreaper() that is scheduled onto the timer
thread. soput() is scheduled from there onto the sosplice task
thread. After that it is save to pool_put() the socket and splicing
data structures.
ok?
bluhm
Index: kern/uipc_socket.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.220
diff -u -p -r1.220 uipc_socket.c
--- kern/uipc_socket.c 8 Apr 2018 18:57:39 -0000 1.220
+++ kern/uipc_socket.c 8 May 2018 11:04:43 -0000
@@ -60,6 +60,7 @@ int sosplice(struct socket *, int, off_t
void sounsplice(struct socket *, struct socket *, int);
void soidle(void *);
void sotask(void *);
+void soreaper(void *);
void soput(void *);
int somove(struct socket *, int);
@@ -219,9 +220,9 @@ sofree(struct socket *so)
sorflush(so);
#ifdef SOCKET_SPLICE
if (so->so_sp) {
- /* Reuse splice task, sounsplice() has been called before. */
- task_set(&so->so_sp->ssp_task, soput, so);
- task_add(sosplice_taskq, &so->so_sp->ssp_task);
+ /* Reuse splice idle, sounsplice() has been called before. */
+ timeout_set_proc(&so->so_sp->ssp_idleto, soreaper, so);
+ timeout_add(&so->so_sp->ssp_idleto, 0);
} else
#endif /* SOCKET_SPLICE */
{
@@ -1244,11 +1245,22 @@ sotask(void *arg)
}
/*
- * The socket splicing task may sleep while grabbing the net lock. As sofree()
- * can be called anytime, sotask() can access the socket memory of a freed
- * socket after wakeup. So delay the pool_put() after all pending socket
- * splicing tasks have finished. Do this by scheduling it on the same thread.
+ * The socket splicing task or idle timeout may sleep while grabbing the net
+ * lock. As sofree() can be called anytime, sotask() or soidle() could access
+ * the socket memory of a freed socket after wakeup. So delay the pool_put()
+ * after all pending socket splicing tasks or timeouts have finished. Do this
+ * by scheduling it on the same threads.
*/
+void
+soreaper(void *arg)
+{
+ struct socket *so = arg;
+
+ /* Reuse splice task, sounsplice() has been called before. */
+ task_set(&so->so_sp->ssp_task, soput, so);
+ task_add(sosplice_taskq, &so->so_sp->ssp_task);
+}
+
void
soput(void *arg)
{