Since these paths became netlock serialized, we don't need to handle
side effects caused by context switch.
somove() return type changed to the type of void because we can't have
concurrent somove() while we sleep. SB_SPLICE bits we set before
somove() call will be cleared within somove() if splicing will be
finished.
Index: sys/kern/uipc_socket.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.298
diff -u -p -r1.298 uipc_socket.c
--- sys/kern/uipc_socket.c 27 Jan 2023 18:46:34 -0000 1.298
+++ sys/kern/uipc_socket.c 27 Jan 2023 20:41:10 -0000
@@ -64,7 +64,7 @@ void soidle(void *);
void sotask(void *);
void soreaper(void *);
void soput(void *);
-int somove(struct socket *, int);
+void somove(struct socket *, int);
void sorflush(struct socket *);
void filt_sordetach(struct knote *kn);
@@ -123,7 +123,6 @@ struct pool socket_pool;
#ifdef SOCKET_SPLICE
struct pool sosplice_pool;
struct taskq *sosplice_taskq;
-struct rwlock sosplice_lock = RWLOCK_INITIALIZER("sosplicelk");
#endif
void
@@ -1239,25 +1238,16 @@ sosplice(struct socket *so, int fd, off_
{
struct file *fp;
struct socket *sosp;
- struct sosplice *sp;
- struct taskq *tq;
int error = 0;
soassertlocked(so);
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);
+ sosplice_taskq = taskq_create("sosplice", 1, IPL_SOFTNET,
+ TASKQ_MPSAFE);
+ if (sosplice_taskq == NULL)
+ return (ENOMEM);
}
- if (sosplice_taskq == NULL)
- return (ENOMEM);
if ((so->so_proto->pr_flags & PR_SPLICE) == 0)
return (EPROTONOSUPPORT);
@@ -1266,13 +1256,8 @@ sosplice(struct socket *so, int fd, off_
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
(so->so_proto->pr_flags & PR_CONNREQUIRED))
return (ENOTCONN);
- if (so->so_sp == NULL) {
- sp = pool_get(&sosplice_pool, PR_WAITOK | PR_ZERO);
- if (so->so_sp == NULL)
- so->so_sp = sp;
- else
- pool_put(&sosplice_pool, sp);
- }
+ if (so->so_sp == NULL)
+ so->so_sp = pool_get(&sosplice_pool, PR_WAITOK | PR_ZERO);
/* If no fd is given, unsplice by removing existing link. */
if (fd < 0) {
@@ -1301,13 +1286,8 @@ sosplice(struct socket *so, int fd, off_
error = EPROTONOSUPPORT;
goto frele;
}
- if (sosp->so_sp == NULL) {
- sp = pool_get(&sosplice_pool, PR_WAITOK | PR_ZERO);
- if (sosp->so_sp == NULL)
- sosp->so_sp = sp;
- else
- pool_put(&sosplice_pool, sp);
- }
+ if (sosp->so_sp == NULL)
+ sosp->so_sp = pool_get(&sosplice_pool, PR_WAITOK | PR_ZERO);
/* Lock both receive and send buffer. */
if ((error = sblock(so, &so->so_rcv, M_WAITOK)) != 0) {
@@ -1320,7 +1300,6 @@ sosplice(struct socket *so, int fd, off_
if (so->so_sp->ssp_socket || sosp->so_sp->ssp_soback) {
error = EBUSY;
- goto release;
}
if (sosp->so_options & SO_ACCEPTCONN) {
error = EOPNOTSUPP;
@@ -1334,6 +1313,8 @@ sosplice(struct socket *so, int fd, off_
/* Splice so and sosp together. */
so->so_sp->ssp_socket = sosp;
sosp->so_sp->ssp_soback = so;
+ so->so_rcv.sb_flags |= SB_SPLICE;
+ sosp->so_snd.sb_flags |= SB_SPLICE;
so->so_splicelen = 0;
so->so_splicemax = max;
if (tv)
@@ -1343,14 +1324,7 @@ sosplice(struct socket *so, int fd, off_
timeout_set_proc(&so->so_idleto, soidle, so);
task_set(&so->so_splicetask, sotask, so);
- /*
- * To prevent softnet interrupt from calling somove() while
- * we sleep, the socket buffers are not marked as spliced yet.
- */
- if (somove(so, M_WAIT)) {
- so->so_rcv.sb_flags |= SB_SPLICE;
- sosp->so_snd.sb_flags |= SB_SPLICE;
- }
+ somove(so, M_WAIT);
release:
sbunlock(sosp, &sosp->so_snd);
@@ -1448,9 +1422,8 @@ soput(void *arg)
* Move data from receive buffer of spliced source socket to send
* buffer of drain socket. Try to move as much as possible in one
* big chunk. It is a TCP only implementation.
- * Return value 0 means splicing has been finished, 1 continue.
*/
-int
+void
somove(struct socket *so, int wait)
{
struct socket *sosp = so->so_sp->ssp_socket;
@@ -1721,11 +1694,10 @@ somove(struct socket *so, int wait)
(sosp->so_snd.sb_state & SS_CANTSENDMORE) ||
maxreached || error) {
sounsplice(so, sosp, 0);
- return (0);
+ } else {
+ if (timerisset(&so->so_idletv))
+ timeout_add_tv(&so->so_idleto, &so->so_idletv);
}
- if (timerisset(&so->so_idletv))
- timeout_add_tv(&so->so_idleto, &so->so_idletv);
- return (1);
}
#endif /* SOCKET_SPLICE */