diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2018-07-05 14:45:08 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2018-07-05 14:45:08 +0000 |
commit | 203c115311736d26f7522cedb23471514e1521df (patch) | |
tree | 353c311a7fa996a54a90618f9a058e9c9ed937e1 /sys | |
parent | 706aa2cbc0136d0c02efba27f1d92615ebb93d18 (diff) |
Serialize the sosplice taskq allocation. This prevents an unlikely
duplicate allocation that could happen in the future when each socket
has a dedicated lock. Right now, the code path is serialized also by
the NET_LOCK() (and the KERNEL_LOCK()).
OK mpi@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/uipc_socket.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 010b18aebea..793914b0a0c 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket.c,v 1.224 2018/06/14 08:46:09 bluhm Exp $ */ +/* $OpenBSD: uipc_socket.c,v 1.225 2018/07/05 14:45:07 visa Exp $ */ /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ /* @@ -49,6 +49,8 @@ #include <sys/signalvar.h> #include <net/if.h> #include <sys/pool.h> +#include <sys/atomic.h> +#include <sys/rwlock.h> #ifdef DDB #include <machine/db_machdep.h> @@ -89,6 +91,7 @@ struct pool socket_pool; #ifdef SOCKET_SPLICE struct pool sosplice_pool; struct taskq *sosplice_taskq; +struct rwlock sosplice_lock = RWLOCK_INITIALIZER("sosplicelk"); #endif void @@ -1088,13 +1091,22 @@ sosplice(struct socket *so, int fd, off_t max, struct timeval *tv) struct file *fp; struct socket *sosp; struct sosplice *sp; + struct taskq *tq; int error = 0; soassertlocked(so); - if (sosplice_taskq == NULL) - sosplice_taskq = taskq_create("sosplice", 1, IPL_SOFTNET, - TASKQ_MPSAFE); + if (sosplice_taskq == NULL) { + rw_enter_write(&sosplice_lock); + if (sosplice_taskq == NULL) { + tq = taskq_create("sosplice", 1, IPL_SOFTNET, + TASKQ_MPSAFE); + /* Ensure the taskq is fully visible to other CPUs. */ + membar_producer(); + sosplice_taskq = tq; + } + rw_exit_write(&sosplice_lock); + } if (sosplice_taskq == NULL) return (ENOMEM); |