On Wed, Jan 25, 2017 at 04:32:25PM +1000, Martin Pieuchot wrote:
> I just enabled the NET_LOCK() again and I'm looking for test reports.
> Please go build a kernel from sources or wait for the next snapshot,
> run it and report back.
> 
> If you're looking for some small coding tasks related to the NET_LOCK()
> just do:
> 
>       # sysctl kern.splassert=2
>       # sysctl kern.pool_debug=2
>       
> Then watch for the traces on your console.
> 
> You'll see something like:
> 
>       Starting stack trace...
>       yield(0,1,d09dac52,f5549dbc,d94e9378) at yield+0xa4
>       yield(d0bc8f40,1,f5549e18,80,14) at yield+0xa4
>       pool_get(d0bc8f40,1,f5549ec8,d03ecbfb,d97815f4) at pool_get+0x1ba
>       m_get(1,3,f5549ec0,d03a9362,d0bc22e0) at m_get+0x30
>       doaccept(d977e6c4,3,cf7ee4f8,cf7ee4ec,2000) at doaccept+0x193
>       sys_accept(d977e6c4,f5549f5c,f5549f7c,0,f5549fa8) at sys_accept+0x37
>       syscall() at syscall+0x250
>       
> This means accept(2) is doing a memory allocation that can sleep, here
> with m_get(9), while holding the NET_LOCK().  Even if these should be
> ok, it is easy to avoid them.  In the case of doaccept() a mbuf could
> be allocated beforehand or simply use the stack for that.
> 
> Cheers,
> Martin
>

Allocate the mbuf beforehand.  Also, move the setting of nflag closer
to where its value is used.

Index: uipc_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.147
diff -u -p -r1.147 uipc_syscalls.c
--- uipc_syscalls.c     25 Jan 2017 07:35:31 -0000      1.147
+++ uipc_syscalls.c     26 Jan 2017 01:03:13 -0000
@@ -265,7 +265,7 @@ doaccept(struct proc *p, int sock, struc
 {
        struct filedesc *fdp = p->p_fd;
        struct file *fp, *headfp;
-       struct mbuf *nam = NULL;
+       struct mbuf *nam;
        socklen_t namelen;
        int error, s, tmpfd;
        struct socket *head, *so;
@@ -288,7 +288,8 @@ doaccept(struct proc *p, int sock, struc
                return (error);
        }
 
-redo:
+       nam = m_get(M_WAIT, MT_SONAME);
+       
        NET_LOCK(s);
        head = headfp->f_data;
        if (isdnssocket(head) || (head->so_options & SO_ACCEPTCONN) == 0) {
@@ -318,30 +319,16 @@ redo:
                goto out;
        }
 
-       /* Figure out whether the new socket should be non-blocking. */
-       nflag = flags & SOCK_NONBLOCK_INHERIT ? (headfp->f_flag & FNONBLOCK)
-           : (flags & SOCK_NONBLOCK ? FNONBLOCK : 0);
-
-       nam = m_get(M_WAIT, MT_SONAME);
-
-       /*
-        * Check whether the queue emptied while we slept: m_get() may have
-        * blocked, allowing the connection to be reset or another thread or
-        * process to accept it.  If so, start over.
-        */
-       if (head->so_qlen == 0) {
-               NET_UNLOCK(s);
-               m_freem(nam);
-               nam = NULL;
-               goto redo;
-       }
-
        /*
         * Do not sleep after we have taken the socket out of the queue.
         */
        so = TAILQ_FIRST(&head->so_q);
        if (soqremque(so, 1) == 0)
                panic("accept");
+
+       /* Figure out whether the new socket should be non-blocking. */
+       nflag = flags & SOCK_NONBLOCK_INHERIT ? (headfp->f_flag & FNONBLOCK)
+           : (flags & SOCK_NONBLOCK ? FNONBLOCK : 0);
 
        /* connection has been removed from the listen queue */
        KNOTE(&head->so_rcv.sb_sel.si_note, 0);

Reply via email to