(benno_pflow_try3_2_locked_arg.diff)

    Introduce a 'locked' argument to sobind(), socreate() and soclose() to
    indicate if its called with a lock held.
    In pflow in the ioctl path, these functions can now be used without
    giving up the netlock first.

diff --git sys/kern/sys_socket.c sys/kern/sys_socket.c
index 0a225cb95ec..4c6d9bcf516 100644
--- sys/kern/sys_socket.c
+++ sys/kern/sys_socket.c
@@ -200,7 +200,7 @@ soo_close(struct file *fp, struct proc *p)
        int error = 0;
 
        if (fp->f_data)
-               error = soclose(fp->f_data);
+               error = soclose(fp->f_data, 0);
        fp->f_data = 0;
        return (error);
 }
diff --git sys/kern/uipc_socket.c sys/kern/uipc_socket.c
index 29323e8a41f..d2973ccf053 100644
--- sys/kern/uipc_socket.c
+++ sys/kern/uipc_socket.c
@@ -108,7 +108,7 @@ soinit(void)
  * switching out to the protocol specific routines.
  */
 int
-socreate(int dom, struct socket **aso, int type, int proto)
+socreate(int dom, struct socket **aso, int type, int proto, int locked)
 {
        struct proc *p = curproc;               /* XXX */
        struct protosw *prp;
@@ -136,27 +136,32 @@ socreate(int dom, struct socket **aso, int type, int 
proto)
        so->so_cpid = p->p_p->ps_pid;
        so->so_proto = prp;
 
-       s = solock(so);
+       if (!locked)
+               s = solock(so);
        error = (*prp->pr_attach)(so, proto);
        if (error) {
                so->so_state |= SS_NOFDREF;
                sofree(so);
-               sounlock(s);
+               if (!locked)
+                       sounlock(s);
                return (error);
        }
-       sounlock(s);
+       if (!locked)
+               sounlock(s);
        *aso = so;
        return (0);
 }
 
 int
-sobind(struct socket *so, struct mbuf *nam, struct proc *p)
+sobind(struct socket *so, struct mbuf *nam, struct proc *p, int locked)
 {
        int s, error;
 
-       s = solock(so);
+       if (!locked)
+               s = solock(so);
        error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, NULL, nam, NULL, p);
-       sounlock(s);
+       if (!locked)
+               sounlock(s);
        return (error);
 }
 
@@ -227,12 +232,13 @@ sofree(struct socket *so)
  * Free socket when disconnect complete.
  */
 int
-soclose(struct socket *so)
+soclose(struct socket *so, int locked)
 {
        struct socket *so2;
        int s, error = 0;
 
-       s = solock(so);
+       if (!locked)
+               s = solock(so);
        if (so->so_options & SO_ACCEPTCONN) {
                while ((so2 = TAILQ_FIRST(&so->so_q0)) != NULL) {
                        (void) soqremque(so2, 0);
@@ -273,10 +279,12 @@ drop:
        }
 discard:
        if (so->so_state & SS_NOFDREF)
-               panic("soclose NOFDREF: so %p, so_type %d", so, so->so_type);
+               panic("soclose NOFDREF: so %p, so_type %d locked %d", so,
+                   so->so_type, locked);
        so->so_state |= SS_NOFDREF;
        sofree(so);
-       sounlock(s);
+       if (!locked)
+               sounlock(s);
        return (error);
 }
 
diff --git sys/kern/uipc_syscalls.c sys/kern/uipc_syscalls.c
index acf671a65f3..587da137dff 100644
--- sys/kern/uipc_syscalls.c
+++ sys/kern/uipc_syscalls.c
@@ -103,7 +103,8 @@ sys_socket(struct proc *p, void *v, register_t *retval)
        fp->f_type = DTYPE_SOCKET;
        fp->f_ops = &socketops;
        error = socreate(SCARG(uap, domain), &so,
-           type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_DNS), SCARG(uap, 
protocol));
+           type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_DNS),
+           SCARG(uap, protocol), 0);
        if (error) {
                fdplock(fdp);
                fdremove(fdp, fd);
@@ -201,7 +202,7 @@ sys_bind(struct proc *p, void *v, register_t *retval)
        if (KTRPOINT(p, KTR_STRUCT))
                ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
 #endif
-       error = sobind(so, nam, p);
+       error = sobind(so, nam, p, 0);
        m_freem(nam);
 out:
        FRELE(fp, p);
@@ -450,10 +451,12 @@ sys_socketpair(struct proc *p, void *v, register_t 
*retval)
        nonblock = SCARG(uap, type) &  SOCK_NONBLOCK;
        fflag = FREAD | FWRITE | (nonblock ? FNONBLOCK : 0);
 
-       error = socreate(SCARG(uap, domain), &so1, type, SCARG(uap, protocol));
+       error = socreate(SCARG(uap, domain), &so1, type,
+           SCARG(uap, protocol), 0);
        if (error)
                return (error);
-       error = socreate(SCARG(uap, domain), &so2, type, SCARG(uap, protocol));
+       error = socreate(SCARG(uap, domain), &so2, type,
+           SCARG(uap, protocol), 0);
        if (error)
                goto free1;
 
@@ -508,10 +511,10 @@ free3:
        fdpunlock(fdp);
 free2:
        if (so2 != NULL)
-               (void)soclose(so2);
+               (void)soclose(so2, 0);
 free1:
        if (so1 != NULL)
-               (void)soclose(so1);
+               (void)soclose(so1, 0);
        return (error);
 }
 
diff --git sys/miscfs/fifofs/fifo_vnops.c sys/miscfs/fifofs/fifo_vnops.c
index 6ffecdcd5fe..a7cd911318c 100644
--- sys/miscfs/fifofs/fifo_vnops.c
+++ sys/miscfs/fifofs/fifo_vnops.c
@@ -129,22 +129,22 @@ fifo_open(void *v)
        if ((fip = vp->v_fifoinfo) == NULL) {
                fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK);
                vp->v_fifoinfo = fip;
-               if ((error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) != 0) {
+               if ((error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, 0)) != 0) 
{
                        free(fip, M_VNODE, sizeof *fip);
                        vp->v_fifoinfo = NULL;
                        return (error);
                }
                fip->fi_readsock = rso;
-               if ((error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) != 0) {
-                       (void)soclose(rso);
+               if ((error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, 0)) != 0) 
{
+                       (void)soclose(rso, 0);
                        free(fip, M_VNODE, sizeof *fip);
                        vp->v_fifoinfo = NULL;
                        return (error);
                }
                fip->fi_writesock = wso;
                if ((error = soconnect2(wso, rso)) != 0) {
-                       (void)soclose(wso);
-                       (void)soclose(rso);
+                       (void)soclose(wso, 0);
+                       (void)soclose(rso, 0);
                        free(fip, M_VNODE, sizeof *fip);
                        vp->v_fifoinfo = NULL;
                        return (error);
@@ -371,8 +371,8 @@ fifo_close(void *v)
                }
        }
        if (fip->fi_readers == 0 && fip->fi_writers == 0) {
-               error1 = soclose(fip->fi_readsock);
-               error2 = soclose(fip->fi_writesock);
+               error1 = soclose(fip->fi_readsock, 0);
+               error2 = soclose(fip->fi_writesock, 0);
                free(fip, M_VNODE, sizeof *fip);
                vp->v_fifoinfo = NULL;
        }
@@ -389,8 +389,8 @@ fifo_reclaim(void *v)
        if (fip == NULL)
                return (0);
 
-       soclose(fip->fi_readsock);
-       soclose(fip->fi_writesock);
+       soclose(fip->fi_readsock, 0);
+       soclose(fip->fi_writesock, 0);
        free(fip, M_VNODE, sizeof *fip);
        vp->v_fifoinfo = NULL;
 
diff --git sys/net/bfd.c sys/net/bfd.c
index 26f487555de..9ad81167167 100644
--- sys/net/bfd.c
+++ sys/net/bfd.c
@@ -254,14 +254,14 @@ bfd_clear_task(void *arg)
        if (bfd->bc_so) {
                /* remove upcall before calling soclose or it will be called */
                bfd->bc_so->so_upcall = NULL;
-               soclose(bfd->bc_so);
+               soclose(bfd->bc_so, 0);
        }
        if (bfd->bc_soecho) {
                bfd->bc_soecho->so_upcall = NULL;
-               soclose(bfd->bc_soecho);
+               soclose(bfd->bc_soecho, 0);
        }
        if (bfd->bc_sosend)
-               soclose(bfd->bc_sosend);
+               soclose(bfd->bc_sosend, 0);
 
        rtfree(bfd->bc_rt);
        bfd->bc_rt = NULL;
@@ -442,7 +442,7 @@ bfd_listener(struct bfd_config *bfd, unsigned int port)
        if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len)
                return (NULL);
 
-       error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0);
+       error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0, 0);
        if (error) {
                printf("%s: socreate error %d\n",
                    __func__, error);
@@ -477,7 +477,7 @@ bfd_listener(struct bfd_config *bfd, unsigned int port)
                break;
        }
 
-       error = sobind(so, m, p);
+       error = sobind(so, m, p, 0);
        if (error) {
                printf("%s: sobind error %d\n",
                    __func__, error);
@@ -490,7 +490,7 @@ bfd_listener(struct bfd_config *bfd, unsigned int port)
 
  close:
        m_free(m);
-       soclose(so);
+       soclose(so, 0);
 
        return (NULL);
 }
@@ -516,7 +516,7 @@ bfd_sender(struct bfd_config *bfd, unsigned int port)
        if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len)
                return (NULL);
 
-       error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0);
+       error = socreate(dst->sa_family, &so, SOCK_DGRAM, 0, 0);
 
        if (error)
                return (NULL);
@@ -571,7 +571,7 @@ bfd_sender(struct bfd_config *bfd, unsigned int port)
                break;
        }
 
-       error = sobind(so, m, p);
+       error = sobind(so, m, p, 0);
        if (error) {
                printf("%s: sobind error %d\n",
                    __func__, error);
@@ -605,7 +605,7 @@ bfd_sender(struct bfd_config *bfd, unsigned int port)
 
  close:
        m_free(m);
-       soclose(so);
+       soclose(so, 0);
 
        return (NULL);
 }
diff --git sys/net/if_pflow.c sys/net/if_pflow.c
index 8cfffa1e4e7..68495eb885d 100644
--- sys/net/if_pflow.c
+++ sys/net/if_pflow.c
@@ -295,7 +295,7 @@ pflow_clone_destroy(struct ifnet *ifp)
        pflow_flush(sc);
        m_freem(sc->send_nam);
        if (sc->so != NULL) {
-               error = soclose(sc->so);
+               error = soclose(sc->so, 1);
                sc->so = NULL;
        }
        if (sc->sc_flowdst != NULL)
@@ -336,7 +336,7 @@ pflow_set(struct pflow_softc *sc, struct pflowreq *pflowr)
        struct proc             *p = curproc;
        struct socket           *so;
        struct sockaddr         *sa;
-       int                      s, error = 0;
+       int                      error = 0;
 
        if (pflowr->addrmask & PFLOW_MASK_VERSION) {
                switch(pflowr->version) {
@@ -356,7 +356,7 @@ pflow_set(struct pflow_softc *sc, struct pflowreq *pflowr)
                        free(sc->sc_flowdst, M_DEVBUF, sc->sc_flowdst->sa_len);
                        sc->sc_flowdst = NULL;
                        if (sc->so != NULL) {
-                               soclose(sc->so);
+                               soclose(sc->so, 1);
                                sc->so = NULL;
                        }
                }
@@ -402,7 +402,7 @@ pflow_set(struct pflow_softc *sc, struct pflowreq *pflowr)
                        free(sc->sc_flowsrc, M_DEVBUF, sc->sc_flowsrc->sa_len);
                sc->sc_flowsrc = NULL;
                if (sc->so != NULL) {
-                       soclose(sc->so);
+                       soclose(sc->so, 1);
                        sc->so = NULL;
                }
                switch(pflowr->flowsrc.ss_family) {
@@ -432,11 +432,9 @@ pflow_set(struct pflow_softc *sc, struct pflowreq *pflowr)
        }
 
        if (sc->so == NULL) {
-               rw_exit_write(&netlock);
-               s = splnet();
                if (pflowvalidsockaddr(sc->sc_flowdst, 0)) {
                        error = socreate(sc->sc_flowdst->sa_family,
-                           &so, SOCK_DGRAM, 0);
+                           &so, SOCK_DGRAM, 0, 1);
                        if (error)
                                return (error);
                        if (pflowvalidsockaddr(sc->sc_flowsrc, 1)) {
@@ -448,24 +446,18 @@ pflow_set(struct pflow_softc *sc, struct pflowreq *pflowr)
                                memcpy(sa, sc->sc_flowsrc,
                                    sc->sc_flowsrc->sa_len);
 
-                               error = sobind(so, m, p);
+                               error = sobind(so, m, p, 1);
                                m_freem(m);
                                if (error) {
-                                       soclose(so);
+                                       soclose(so, 1);
                                        return (error);
                                }
                        }
                        sc->so = so;
                }
-               splx(s);
-               rw_enter_write(&netlock);
        } else if (!pflowvalidsockaddr(sc->sc_flowdst, 0)) {
-               rw_exit_write(&netlock);
-               s = splnet();
-               soclose(sc->so);
+               soclose(sc->so, 1);
                sc->so = NULL;
-               splx(s);
-               rw_enter_write(&netlock);
        }
 
        /* error check is above */
diff --git sys/nfs/krpc_subr.c sys/nfs/krpc_subr.c
index eddad29015a..60f8b2d7619 100644
--- sys/nfs/krpc_subr.c
+++ sys/nfs/krpc_subr.c
@@ -231,7 +231,7 @@ krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, 
u_int func,
        /*
         * Create socket and set its receive timeout.
         */
-       if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)))
+       if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, 0)))
                goto out;
 
        m = m_get(M_WAIT, MT_SOOPTS);
@@ -275,7 +275,7 @@ krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, 
u_int func,
        sin->sin_family = AF_INET;
        sin->sin_addr.s_addr = INADDR_ANY;
        sin->sin_port = htons(0);
-       error = sobind(so, m, &proc0);
+       error = sobind(so, m, &proc0, 0);
        m_freem(m);
        if (error) {
                printf("bind failed\n");
@@ -453,7 +453,7 @@ krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, 
u_int func,
        m_freem(nam);
        m_freem(mhead);
        m_freem(from);
-       soclose(so);
+       soclose(so, 0);
        return error;
 }
 
diff --git sys/nfs/nfs_boot.c sys/nfs/nfs_boot.c
index f0bf6359b2f..1bbddf12fc6 100644
--- sys/nfs/nfs_boot.c
+++ sys/nfs/nfs_boot.c
@@ -157,7 +157,7 @@ nfs_boot_init(struct nfs_diskless *nd, struct proc *procp)
         * Get the old interface flags and or IFF_UP into them; if
         * IFF_UP set blindly, interface selection can be clobbered.
         */
-       if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0)
+       if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, 0)) != 0)
                panic("nfs_boot: socreate, error=%d", error);
        NET_LOCK(s);
        error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)&ireq, procp);
@@ -196,7 +196,7 @@ nfs_boot_init(struct nfs_diskless *nd, struct proc *procp)
        if (error)
                panic("nfs_boot: set if addr, error=%d", error);
 
-       soclose(so);
+       soclose(so, 0);
 
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
                if (ifa->ifa_addr->sa_family == AF_INET)
diff --git sys/nfs/nfs_socket.c sys/nfs/nfs_socket.c
index 619951ba1d5..115ba0b8532 100644
--- sys/nfs/nfs_socket.c
+++ sys/nfs/nfs_socket.c
@@ -243,7 +243,7 @@ nfs_connect(struct nfsmount *nmp, struct nfsreq *rep)
        nmp->nm_so = NULL;
        saddr = mtod(nmp->nm_nam, struct sockaddr *);
        error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype, 
-               nmp->nm_soproto);
+           nmp->nm_soproto, 0);
        if (error)
                goto bad;
        so = nmp->nm_so;
@@ -273,7 +273,7 @@ nfs_connect(struct nfsmount *nmp, struct nfsreq *rep)
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = INADDR_ANY;
                sin->sin_port = htons(0);
-               error = sobind(so, m, &proc0);
+               error = sobind(so, m, &proc0, 0);
                m_freem(m);
                if (error)
                        goto bad;
@@ -426,7 +426,7 @@ nfs_disconnect(struct nfsmount *nmp)
                so = nmp->nm_so;
                nmp->nm_so = NULL;
                soshutdown(so, SHUT_RDWR);
-               soclose(so);
+               soclose(so, 0);
        }
 }
 
diff --git sys/sys/socketvar.h sys/sys/socketvar.h
index 32967536f53..d028fc7e869 100644
--- sys/sys/socketvar.h
+++ sys/sys/socketvar.h
@@ -281,13 +281,13 @@ int       sb_lock(struct sockbuf *sb);
 void   soinit(void);
 int    soabort(struct socket *so);
 int    soaccept(struct socket *so, struct mbuf *nam);
-int    sobind(struct socket *so, struct mbuf *nam, struct proc *p);
+int    sobind(struct socket *so, struct mbuf *nam, struct proc *p, int locked);
 void   socantrcvmore(struct socket *so);
 void   socantsendmore(struct socket *so);
-int    soclose(struct socket *so);
+int    soclose(struct socket *so, int locked);
 int    soconnect(struct socket *so, struct mbuf *nam);
 int    soconnect2(struct socket *so1, struct socket *so2);
-int    socreate(int dom, struct socket **aso, int type, int proto);
+int    socreate(int dom, struct socket **aso, int type, int proto, int locked);
 int    sodisconnect(struct socket *so);
 void   sofree(struct socket *so);
 int    sogetopt(struct socket *so, int level, int optname,

Reply via email to