soo_ioctl() will need to grab the socket lock since it modifies its
states.  Sadly this function is sometimes called from socket-only
syscalls which already held the corresponding socket lock.

So the diff below simply set/remove SS_NBIO directly in places where
we are dealing with sockets and already have the lock.

ok?

Index: kern/uipc_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.151
diff -u -p -r1.151 uipc_syscalls.c
--- kern/uipc_syscalls.c        27 Mar 2017 11:45:49 -0000      1.151
+++ kern/uipc_syscalls.c        3 Jul 2017 12:37:03 -0000
@@ -110,10 +110,10 @@ sys_socket(struct proc *p, void *v, regi
                closef(fp, p);
                fdpunlock(fdp);
        } else {
-               fp->f_data = so;
                if (type & SOCK_NONBLOCK)
-                       (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&type, p);
+                       so->so_state |= SS_NBIO;
                so->so_state |= ss;
+               fp->f_data = so;
                FILE_SET_MATURE(fp, p);
                *retval = fd;
        }
@@ -332,12 +332,15 @@ doaccept(struct proc *p, int sock, struc
        fp->f_type = DTYPE_SOCKET;
        fp->f_flag = FREAD | FWRITE | nflag;
        fp->f_ops = &socketops;
-       fp->f_data = so;
        error = soaccept(so, nam);
        if (!error && name != NULL)
                error = copyaddrout(p, nam, name, namelen, anamelen);
        if (!error) {
-               (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&nflag, p);
+               if (nflag & FNONBLOCK)
+                       so->so_state |= SS_NBIO;
+               else
+                       so->so_state &= ~SS_NBIO;
+               fp->f_data = so;
                FILE_SET_MATURE(fp, p);
                *retval = tmpfd;
        }

Reply via email to