summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2018-07-05 14:45:08 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2018-07-05 14:45:08 +0000
commit203c115311736d26f7522cedb23471514e1521df (patch)
tree353c311a7fa996a54a90618f9a058e9c9ed937e1
parent706aa2cbc0136d0c02efba27f1d92615ebb93d18 (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@
-rw-r--r--sys/kern/uipc_socket.c20
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);