On Mon, Jul 03, 2017 at 11:42:19AM +0200, Martin Pieuchot wrote:
> Updated diff that fixes some issues reported by visa@:
> 
>   - prevents relocking the netlock in the 'restart' case.
>   - always call solock() after sbunlock() in sosplice().
> 
> Alexander is there an easy way to trigger the 'restart' case in the
> regression tests?  I ran the relayd regress but I'm not sure which
> kernel code it exercises.

See /usr/src/regress/sys/kern/sosplice, it runs all tests with and
without socket splicing.  Goal was to see that behavior is identical.
It tries a bunch of timings and dataflow variants with user land
sleep, send and receive syscalls.  I triggered many goto restart
in soreceive() and a few in sosend().

> Anyway, ok?

OK bluhm@

> 
> Index: sys/socketvar.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/socketvar.h,v
> retrieving revision 1.70
> diff -u -p -r1.70 socketvar.h
> --- sys/socketvar.h   26 Jun 2017 09:32:32 -0000      1.70
> +++ sys/socketvar.h   3 Jul 2017 08:38:14 -0000
> @@ -239,7 +239,7 @@ struct rwlock;
>   * Unless SB_NOINTR is set on sockbuf, sleep is interruptible.
>   * Returns error without lock if sleep is interrupted.
>   */
> -int sblock(struct sockbuf *, int, struct rwlock *);
> +int sblock(struct socket *, struct sockbuf *, int);
>  
>  /* release lock on sockbuf sb */
>  void sbunlock(struct sockbuf *);
> Index: kern/uipc_socket.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/uipc_socket.c,v
> retrieving revision 1.191
> diff -u -p -r1.191 uipc_socket.c
> --- kern/uipc_socket.c        3 Jul 2017 08:29:24 -0000       1.191
> +++ kern/uipc_socket.c        3 Jul 2017 08:41:24 -0000
> @@ -418,14 +418,14 @@ sosend(struct socket *so, struct mbuf *a
>                           (sizeof(struct fdpass) / sizeof(int)));
>       }
>  
> -#define      snderr(errno)   { error = errno; sounlock(s); goto release; }
> +#define      snderr(errno)   { error = errno; goto release; }
>  
> +     s = solock(so);
>  restart:
> -     if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags), NULL)) != 0)
> +     if ((error = sblock(so, &so->so_snd, SBLOCKWAIT(flags))) != 0)
>               goto out;
>       so->so_state |= SS_ISSENDING;
>       do {
> -             s = solock(so);
>               if (so->so_state & SS_CANTSENDMORE)
>                       snderr(EPIPE);
>               if (so->so_error) {
> @@ -455,12 +455,10 @@ restart:
>                       sbunlock(&so->so_snd);
>                       error = sbwait(so, &so->so_snd);
>                       so->so_state &= ~SS_ISSENDING;
> -                     sounlock(s);
>                       if (error)
>                               goto out;
>                       goto restart;
>               }
> -             sounlock(s);
>               space -= clen;
>               do {
>                       if (uio == NULL) {
> @@ -471,8 +469,9 @@ restart:
>                               if (flags & MSG_EOR)
>                                       top->m_flags |= M_EOR;
>                       } else {
> -                             error = m_getuio(&top, atomic,
> -                                 space, uio);
> +                             sounlock(s);
> +                             error = m_getuio(&top, atomic, space, uio);
> +                             s = solock(so);
>                               if (error)
>                                       goto release;
>                               space -= top->m_pkthdr.len;
> @@ -480,7 +479,6 @@ restart:
>                               if (flags & MSG_EOR)
>                                       top->m_flags |= M_EOR;
>                       }
> -                     s = solock(so);
>                       if (resid == 0)
>                               so->so_state &= ~SS_ISSENDING;
>                       if (top && so->so_options & SO_ZEROIZE)
> @@ -488,7 +486,6 @@ restart:
>                       error = (*so->so_proto->pr_usrreq)(so,
>                           (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
>                           top, addr, control, curproc);
> -                     sounlock(s);
>                       clen = 0;
>                       control = NULL;
>                       top = NULL;
> @@ -501,6 +498,7 @@ release:
>       so->so_state &= ~SS_ISSENDING;
>       sbunlock(&so->so_snd);
>  out:
> +     sounlock(s);
>       m_freem(top);
>       m_freem(control);
>       return (error);
> @@ -670,9 +668,11 @@ bad:
>               *mp = NULL;
>  
>  restart:
> -     if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags), NULL)) != 0)
> -             return (error);
>       s = solock(so);
> +     if ((error = sblock(so, &so->so_rcv, SBLOCKWAIT(flags))) != 0) {
> +             sounlock(s);
> +             return (error);
> +     }
>  
>       m = so->so_rcv.sb_mb;
>  #ifdef SOCKET_SPLICE
> @@ -1040,13 +1040,10 @@ sorflush(struct socket *so)
>  {
>       struct sockbuf *sb = &so->so_rcv;
>       struct protosw *pr = so->so_proto;
> -     sa_family_t af = pr->pr_domain->dom_family;
>       struct socket aso;
>  
>       sb->sb_flags |= SB_NOINTR;
> -     sblock(sb, M_WAITOK,
> -         (af != PF_LOCAL && af != PF_ROUTE && af != PF_KEY) ?
> -         &netlock : NULL);
> +     sblock(so, sb, M_WAITOK);
>       socantrcvmore(so);
>       sbunlock(sb);
>       aso.so_proto = pr;
> @@ -1094,15 +1091,17 @@ sosplice(struct socket *so, int fd, off_
>  
>       /* If no fd is given, unsplice by removing existing link. */
>       if (fd < 0) {
> +             s = solock(so);
>               /* Lock receive buffer. */
> -             if ((error = sblock(&so->so_rcv,
> -                 (so->so_state & SS_NBIO) ? M_NOWAIT : M_WAITOK, NULL)) != 0)
> +             if ((error = sblock(so, &so->so_rcv,
> +                 (so->so_state & SS_NBIO) ? M_NOWAIT : M_WAITOK)) != 0) {
> +                     sounlock(s);
>                       return (error);
> -             s = solock(so);
> +             }
>               if (so->so_sp->ssp_socket)
>                       sounsplice(so, so->so_sp->ssp_socket, 1);
> -             sounlock(s);
>               sbunlock(&so->so_rcv);
> +             sounlock(s);
>               return (0);
>       }
>  
> @@ -1119,18 +1118,20 @@ sosplice(struct socket *so, int fd, off_
>       if (sosp->so_sp == NULL)
>               sosp->so_sp = pool_get(&sosplice_pool, PR_WAITOK | PR_ZERO);
>  
> +     s = solock(so);
>       /* Lock both receive and send buffer. */
> -     if ((error = sblock(&so->so_rcv,
> -         (so->so_state & SS_NBIO) ? M_NOWAIT : M_WAITOK, NULL)) != 0) {
> +     if ((error = sblock(so, &so->so_rcv,
> +         (so->so_state & SS_NBIO) ? M_NOWAIT : M_WAITOK)) != 0) {
> +             sounlock(s);
>               FRELE(fp, curproc);
>               return (error);
>       }
> -     if ((error = sblock(&sosp->so_snd, M_WAITOK, NULL)) != 0) {
> +     if ((error = sblock(so, &sosp->so_snd, M_WAITOK)) != 0) {
>               sbunlock(&so->so_rcv);
> +             sounlock(s);
>               FRELE(fp, curproc);
>               return (error);
>       }
> -     s = solock(so);
>  
>       if (so->so_sp->ssp_socket || sosp->so_sp->ssp_soback) {
>               error = EBUSY;
> @@ -1171,9 +1172,9 @@ sosplice(struct socket *so, int fd, off_
>       }
>  
>   release:
> -     sounlock(s);
>       sbunlock(&sosp->so_snd);
>       sbunlock(&so->so_rcv);
> +     sounlock(s);
>       FRELE(fp, curproc);
>       return (error);
>  }
> Index: kern/uipc_socket2.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/uipc_socket2.c,v
> retrieving revision 1.80
> diff -u -p -r1.80 uipc_socket2.c
> --- kern/uipc_socket2.c       27 Jun 2017 12:02:43 -0000      1.80
> +++ kern/uipc_socket2.c       3 Jul 2017 08:38:14 -0000
> @@ -54,8 +54,6 @@ u_long      sb_max = SB_MAX;                /* patchable */
>  extern struct pool mclpools[];
>  extern struct pool mbpool;
>  
> -int sbsleep(struct sockbuf *, struct rwlock *);
> -
>  /*
>   * Procedures to manipulate state flags of socket
>   * and do appropriate wakeups.  Normal sequence from the
> @@ -337,24 +335,12 @@ sbwait(struct socket *so, struct sockbuf
>  }
>  
>  int
> -sbsleep(struct sockbuf *sb, struct rwlock *lock)
> +sblock(struct socket *so, struct sockbuf *sb, int wait)
>  {
>       int error, prio = (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH;
>  
> -     if (lock != NULL)
> -             error = rwsleep(&sb->sb_flags, lock, prio, "netlck", 0);
> -     else
> -             error = tsleep(&sb->sb_flags, prio, "netlck", 0);
> -
> -     return (error);
> -}
> -
> -int
> -sblock(struct sockbuf *sb, int wait, struct rwlock *lock)
> -{
> -     int error;
> -
>       KERNEL_ASSERT_LOCKED();
> +     soassertlocked(so);
>  
>       if ((sb->sb_flags & SB_LOCK) == 0) {
>               sb->sb_flags |= SB_LOCK;
> @@ -365,7 +351,7 @@ sblock(struct sockbuf *sb, int wait, str
>  
>       while (sb->sb_flags & SB_LOCK) {
>               sb->sb_flags |= SB_WANT;
> -             error = sbsleep(sb, lock);
> +             error = sosleep(so, &sb->sb_flags, prio, "netlck", 0);
>               if (error)
>                       return (error);
>       }

Reply via email to