Turns out that the NET_LOCK() related hang reported by many is a
deadlock.  One way to prevent it is to ensure that fdplock() is
always taken before the NET_LOCK() when both have to been hold.

This generates the diff below.

Comments, ok?

Index: kern/uipc_socket.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.171
diff -u -p -r1.171 uipc_socket.c
--- kern/uipc_socket.c  29 Dec 2016 12:12:43 -0000      1.171
+++ kern/uipc_socket.c  19 Jan 2017 09:14:22 -0000
@@ -800,9 +800,12 @@ dontblock:
                        if (controlp) {
                                if (pr->pr_domain->dom_externalize &&
                                    mtod(cm, struct cmsghdr *)->cmsg_type ==
-                                   SCM_RIGHTS)
-                                  error = (*pr->pr_domain->dom_externalize)(cm,
-                                      controllen, flags);
+                                   SCM_RIGHTS) {
+                                   NET_UNLOCK(s);
+                                   error = (*pr->pr_domain->dom_externalize)(
+                                       cm, controllen, flags);
+                                   NET_LOCK(s);
+                               }
                                *controlp = cm;
                        } else {
                                /*
Index: kern/uipc_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.144
diff -u -p -r1.144 uipc_syscalls.c
--- kern/uipc_syscalls.c        29 Dec 2016 12:12:43 -0000      1.144
+++ kern/uipc_syscalls.c        19 Jan 2017 09:03:56 -0000
@@ -278,6 +278,7 @@ doaccept(struct proc *p, int sock, struc
 
        headfp = fp;
 redo:
+       fdplock(fdp);
        NET_LOCK(s);
        head = headfp->f_data;
        if (isdnssocket(head) || (head->so_options & SO_ACCEPTCONN) == 0) {
@@ -312,11 +313,9 @@ redo:
        nflag = flags & SOCK_NONBLOCK_INHERIT ? (headfp->f_flag & FNONBLOCK)
            : (flags & SOCK_NONBLOCK ? FNONBLOCK : 0);
 
-       fdplock(fdp);
        error = falloc(p, &fp, &tmpfd);
        if (error == 0 && (flags & SOCK_CLOEXEC))
                fdp->fd_ofileflags[tmpfd] |= UF_EXCLOSE;
-       fdpunlock(fdp);
        if (error != 0) {
                /*
                 * Probably ran out of file descriptors.  Wakeup
@@ -336,7 +335,6 @@ redo:
        if (head->so_qlen == 0) {
                NET_UNLOCK(s);
                m_freem(nam);
-               fdplock(fdp);
                fdremove(fdp, tmpfd);
                closef(fp, p);
                fdpunlock(fdp);
@@ -365,7 +363,6 @@ redo:
                /* if an error occurred, free the file descriptor */
                NET_UNLOCK(s);
                m_freem(nam);
-               fdplock(fdp);
                fdremove(fdp, tmpfd);
                closef(fp, p);
                fdpunlock(fdp);
@@ -377,6 +374,7 @@ redo:
        m_freem(nam);
 bad:
        NET_UNLOCK(s);
+       fdpunlock(fdp);
 out:
        FRELE(headfp, p);
        return (error);

Reply via email to