Push kernel lock down to dopselect() and doppoll() and unlock select(2),
authormvs <mvs@openbsd.org>
Mon, 13 Feb 2023 09:42:45 +0000 (09:42 +0000)
committermvs <mvs@openbsd.org>
Mon, 13 Feb 2023 09:42:45 +0000 (09:42 +0000)
pselect(2), poll(2) and ppoll(2).

select(2) and poll(2) are just wrappers for kqueue(2)/kevent(2) which
are already unlocked. They do temporary event queue initialization and
scan for this call only. The difference is in local data conversion
between select(2)/poll(2) and kevent(2) formats.

To separate possible signal related fallout, dosigsuspend() left under
the kernel lock. It will be taken only if optional signal mask arg
passed to pselect(2) or ppoll(2). dosigsuspend() will be unlocked later
with sigsuspend(2).

Discussed with claudio@ and kettenis@.

ok claudio@

sys/kern/sys_generic.c
sys/kern/syscalls.master

index 29f7363..57f34dd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sys_generic.c,v 1.152 2023/02/10 14:34:17 visa Exp $  */
+/*     $OpenBSD: sys_generic.c,v 1.153 2023/02/13 09:42:45 mvs Exp $   */
 /*     $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $     */
 
 /*
@@ -596,15 +596,16 @@ dopselect(struct proc *p, int nd, fd_set *in, fd_set *ou, fd_set *ex,
        struct timespec zerots = {};
        fd_mask bits[6];
        fd_set *pibits[3], *pobits[3];
-       int error, ncollected = 0, nevents = 0;
+       int error, nfiles, ncollected = 0, nevents = 0;
        u_int ni;
 
        if (nd < 0)
                return (EINVAL);
-       if (nd > p->p_fd->fd_nfiles) {
-               /* forgiving; slightly wrong */
-               nd = p->p_fd->fd_nfiles;
-       }
+
+       nfiles = READ_ONCE(p->p_fd->fd_nfiles);
+       if (nd > nfiles)
+               nd = nfiles;
+
        ni = howmany(nd, NFDBITS) * sizeof(fd_mask);
        if (ni > sizeof(bits[0])) {
                caddr_t mbits;
@@ -643,8 +644,11 @@ dopselect(struct proc *p, int nd, fd_set *in, fd_set *ou, fd_set *ex,
        }
 #endif
 
-       if (sigmask)
+       if (sigmask) {
+               KERNEL_LOCK();
                dosigsuspend(p, *sigmask &~ sigcantmask);
+               KERNEL_UNLOCK();
+       }
 
        /* Register kqueue events */
        error = pselregister(p, pibits, pobits, nd, &nevents, &ncollected);
@@ -948,8 +952,11 @@ doppoll(struct proc *p, struct pollfd *fds, u_int nfds,
        if ((error = copyin(fds, pl, sz)) != 0)
                goto bad;
 
-       if (sigmask)
+       if (sigmask) {
+               KERNEL_LOCK();
                dosigsuspend(p, *sigmask &~ sigcantmask);
+               KERNEL_UNLOCK();
+       }
 
        /* Register kqueue events */
        ppollregister(p, pl, nfds, &nevents, &ncollected);
index 6da9a11..9a5793a 100644 (file)
@@ -1,4 +1,4 @@
-;      $OpenBSD: syscalls.master,v 1.241 2023/02/11 23:21:22 deraadt Exp $
+;      $OpenBSD: syscalls.master,v 1.242 2023/02/13 09:42:45 mvs Exp $
 ;      $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $
 
 ;      @(#)syscalls.master     8.2 (Berkeley) 1/13/94
                            struct itimerval *oitv); }
 70     STD NOLOCK      { int sys_getitimer(int which, \
                            struct itimerval *itv); }
-71     STD             { int sys_select(int nd, fd_set *in, fd_set *ou, \
+71     STD NOLOCK      { int sys_select(int nd, fd_set *in, fd_set *ou, \
                            fd_set *ex, struct timeval *tv); }
 72     STD NOLOCK      { int sys_kevent(int fd, \
                            const struct kevent *changelist, int nchanges, \
                            u_int flags, int atflags); }
 108    STD NOLOCK      { int sys_pledge(const char *promises, \
                            const char *execpromises); }
-109    STD             { int sys_ppoll(struct pollfd *fds, \
+109    STD NOLOCK      { int sys_ppoll(struct pollfd *fds, \
                            u_int nfds, const struct timespec *ts, \
                            const sigset_t *mask); }
-110    STD             { int sys_pselect(int nd, fd_set *in, fd_set *ou, \
+110    STD NOLOCK      { int sys_pselect(int nd, fd_set *in, fd_set *ou, \
                            fd_set *ex, const struct timespec *ts, \
                            const sigset_t *mask); }
 111    STD             { int sys_sigsuspend(int mask); }
 250    STD NOLOCK      { int sys_minherit(void *addr, size_t len, \
                            int inherit); }
 251    OBSOL           rfork
-252    STD             { int sys_poll(struct pollfd *fds, \
+252    STD NOLOCK      { int sys_poll(struct pollfd *fds, \
                            u_int nfds, int timeout); }
 253    STD NOLOCK      { int sys_issetugid(void); }
 254    STD             { int sys_lchown(const char *path, uid_t uid, gid_t gid); }