Module Name: src Committed By: dsl Date: Sun Dec 20 09:36:06 UTC 2009
Modified Files: src/sys/arch/xen/xen: xenevt.c src/sys/compat/svr4: svr4_net.c src/sys/compat/svr4_32: svr4_32_net.c src/sys/dev/dmover: dmover_io.c src/sys/dev/putter: putter.c src/sys/kern: kern_descrip.c kern_drvctl.c kern_event.c sys_mqueue.c sys_pipe.c sys_socket.c uipc_socket.c uipc_syscalls.c vfs_vnops.c src/sys/net: bpf.c if_tap.c src/sys/opencrypto: cryptodev.c src/sys/sys: file.h pipe.h socketvar.h Log Message: If a multithreaded app closes an fd while another thread is blocked in read/write/accept, then the expectation is that the blocked thread will exit and the close complete. Since only one fd is affected, but many fd can refer to the same file, the close code can only request the fs code unblock with ERESTART. Fixed for pipes and sockets, ERESTART will only be generated after such a close - so there should be no change for other programs. Also rename fo_abort() to fo_restart() (this used to be fo_drain()). Fixes PR/26567 To generate a diff of this commit: cvs rdiff -u -r1.35 -r1.36 src/sys/arch/xen/xen/xenevt.c cvs rdiff -u -r1.57 -r1.58 src/sys/compat/svr4/svr4_net.c cvs rdiff -u -r1.20 -r1.21 src/sys/compat/svr4_32/svr4_32_net.c cvs rdiff -u -r1.36 -r1.37 src/sys/dev/dmover/dmover_io.c cvs rdiff -u -r1.25 -r1.26 src/sys/dev/putter/putter.c cvs rdiff -u -r1.201 -r1.202 src/sys/kern/kern_descrip.c cvs rdiff -u -r1.30 -r1.31 src/sys/kern/kern_drvctl.c cvs rdiff -u -r1.67 -r1.68 src/sys/kern/kern_event.c cvs rdiff -u -r1.28 -r1.29 src/sys/kern/sys_mqueue.c cvs rdiff -u -r1.126 -r1.127 src/sys/kern/sys_pipe.c cvs rdiff -u -r1.62 -r1.63 src/sys/kern/sys_socket.c cvs rdiff -u -r1.195 -r1.196 src/sys/kern/uipc_socket.c cvs rdiff -u -r1.137 -r1.138 src/sys/kern/uipc_syscalls.c cvs rdiff -u -r1.167 -r1.168 src/sys/kern/vfs_vnops.c cvs rdiff -u -r1.149 -r1.150 src/sys/net/bpf.c cvs rdiff -u -r1.61 -r1.62 src/sys/net/if_tap.c cvs rdiff -u -r1.50 -r1.51 src/sys/opencrypto/cryptodev.c cvs rdiff -u -r1.69 -r1.70 src/sys/sys/file.h cvs rdiff -u -r1.31 -r1.32 src/sys/sys/pipe.h cvs rdiff -u -r1.122 -r1.123 src/sys/sys/socketvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/xen/xen/xenevt.c diff -u src/sys/arch/xen/xen/xenevt.c:1.35 src/sys/arch/xen/xen/xenevt.c:1.36 --- src/sys/arch/xen/xen/xenevt.c:1.35 Wed Dec 9 21:32:58 2009 +++ src/sys/arch/xen/xen/xenevt.c Sun Dec 20 09:36:05 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: xenevt.c,v 1.35 2009/12/09 21:32:58 dsl Exp $ */ +/* $NetBSD: xenevt.c,v 1.36 2009/12/20 09:36:05 dsl Exp $ */ /* * Copyright (c) 2005 Manuel Bouyer. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xenevt.c,v 1.35 2009/12/09 21:32:58 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xenevt.c,v 1.36 2009/12/20 09:36:05 dsl Exp $"); #include "opt_xen.h" #include <sys/param.h> @@ -81,7 +81,7 @@ .fo_stat = fbadop_stat, .fo_close = xenevt_fclose, .fo_kqfilter = /* xenevt_fkqfilter */ fnullop_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; dev_type_open(xenevtopen); Index: src/sys/compat/svr4/svr4_net.c diff -u src/sys/compat/svr4/svr4_net.c:1.57 src/sys/compat/svr4/svr4_net.c:1.58 --- src/sys/compat/svr4/svr4_net.c:1.57 Wed Dec 9 21:32:58 2009 +++ src/sys/compat/svr4/svr4_net.c Sun Dec 20 09:36:05 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: svr4_net.c,v 1.57 2009/12/09 21:32:58 dsl Exp $ */ +/* $NetBSD: svr4_net.c,v 1.58 2009/12/20 09:36:05 dsl Exp $ */ /*- * Copyright (c) 1994, 2008, 2009 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: svr4_net.c,v 1.57 2009/12/09 21:32:58 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: svr4_net.c,v 1.58 2009/12/20 09:36:05 dsl Exp $"); #define COMPAT_SVR4 1 @@ -108,7 +108,7 @@ .fo_stat = soo_stat, .fo_close = svr4_soo_close, .fo_kqfilter = soo_kqfilter, - .fo_abort = soo_abort, + .fo_restart = soo_restart, }; Index: src/sys/compat/svr4_32/svr4_32_net.c diff -u src/sys/compat/svr4_32/svr4_32_net.c:1.20 src/sys/compat/svr4_32/svr4_32_net.c:1.21 --- src/sys/compat/svr4_32/svr4_32_net.c:1.20 Wed Dec 9 21:32:58 2009 +++ src/sys/compat/svr4_32/svr4_32_net.c Sun Dec 20 09:36:05 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: svr4_32_net.c,v 1.20 2009/12/09 21:32:58 dsl Exp $ */ +/* $NetBSD: svr4_32_net.c,v 1.21 2009/12/20 09:36:05 dsl Exp $ */ /*- * Copyright (c) 1994, 2008, 2009 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: svr4_32_net.c,v 1.20 2009/12/09 21:32:58 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: svr4_32_net.c,v 1.21 2009/12/20 09:36:05 dsl Exp $"); #define COMPAT_SVR4 1 @@ -102,7 +102,7 @@ .fo_poll = soo_poll, .fo_stat = soo_stat, .fo_close = svr4_soo_close, - .fo_abort = soo_abort, + .fo_restart = soo_restart, }; Index: src/sys/dev/dmover/dmover_io.c diff -u src/sys/dev/dmover/dmover_io.c:1.36 src/sys/dev/dmover/dmover_io.c:1.37 --- src/sys/dev/dmover/dmover_io.c:1.36 Wed Dec 9 21:32:58 2009 +++ src/sys/dev/dmover/dmover_io.c Sun Dec 20 09:36:05 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: dmover_io.c,v 1.36 2009/12/09 21:32:58 dsl Exp $ */ +/* $NetBSD: dmover_io.c,v 1.37 2009/12/20 09:36:05 dsl Exp $ */ /* * Copyright (c) 2002, 2003 Wasabi Systems, Inc. @@ -55,7 +55,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: dmover_io.c,v 1.36 2009/12/09 21:32:58 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: dmover_io.c,v 1.37 2009/12/20 09:36:05 dsl Exp $"); #include <sys/param.h> #include <sys/queue.h> @@ -761,7 +761,7 @@ .fo_stat = dmio_stat, .fo_close = dmio_close, .fo_kqfilter = fnullop_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; /* Index: src/sys/dev/putter/putter.c diff -u src/sys/dev/putter/putter.c:1.25 src/sys/dev/putter/putter.c:1.26 --- src/sys/dev/putter/putter.c:1.25 Wed Dec 9 21:32:59 2009 +++ src/sys/dev/putter/putter.c Sun Dec 20 09:36:05 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: putter.c,v 1.25 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: putter.c,v 1.26 2009/12/20 09:36:05 dsl Exp $ */ /* * Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: putter.c,v 1.25 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: putter.c,v 1.26 2009/12/20 09:36:05 dsl Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -206,7 +206,7 @@ .fo_stat = putter_fop_stat, .fo_close = putter_fop_close, .fo_kqfilter = putter_fop_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; static int Index: src/sys/kern/kern_descrip.c diff -u src/sys/kern/kern_descrip.c:1.201 src/sys/kern/kern_descrip.c:1.202 --- src/sys/kern/kern_descrip.c:1.201 Wed Dec 9 21:32:59 2009 +++ src/sys/kern/kern_descrip.c Sun Dec 20 09:36:05 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_descrip.c,v 1.201 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: kern_descrip.c,v 1.202 2009/12/20 09:36:05 dsl Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -70,7 +70,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_descrip.c,v 1.201 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_descrip.c,v 1.202 2009/12/20 09:36:05 dsl Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -610,7 +610,8 @@ * Wait for other references to drain. This is typically * an application error - the descriptor is being closed * while still in use. - * + * (Or just a threaded application trying to unblock its + * thread that sleeps in (say) accept()). */ atomic_or_uint(&ff->ff_refcnt, FR_CLOSING); @@ -623,8 +624,15 @@ knote_fdclose(fd); } - /* Try to drain out descriptor references. */ - (*fp->f_ops->fo_abort)(fp); + /* + * Since the file system code doesn't know which fd + * each request came from (think dup()), we have to + * ask it to return ERESTART for any long-term blocks. + * The re-entry through read/write/etc will detect the + * closed fd and return EBAFD. + * Blocked partial writes may return a short length. + */ + (*fp->f_ops->fo_restart)(fp); mutex_enter(&fdp->fd_lock); /* @@ -632,6 +640,8 @@ * in order to ensure that all pre-existing references * have been drained. New references past this point are * of no interest. + * XXX (dsl) this may need to call fo_restart() after a + * timeout to guarantee that all the system calls exit. */ while ((ff->ff_refcnt & FR_MASK) != 0) { cv_wait(&ff->ff_closing, &fdp->fd_lock); @@ -1787,7 +1797,7 @@ } void -fnullop_abort(file_t *fp) +fnullop_restart(file_t *fp) { } Index: src/sys/kern/kern_drvctl.c diff -u src/sys/kern/kern_drvctl.c:1.30 src/sys/kern/kern_drvctl.c:1.31 --- src/sys/kern/kern_drvctl.c:1.30 Wed Dec 9 21:32:59 2009 +++ src/sys/kern/kern_drvctl.c Sun Dec 20 09:36:05 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_drvctl.c,v 1.30 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: kern_drvctl.c,v 1.31 2009/12/20 09:36:05 dsl Exp $ */ /* * Copyright (c) 2004 @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.30 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.31 2009/12/20 09:36:05 dsl Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -90,7 +90,7 @@ .fo_stat = drvctl_stat, .fo_close = drvctl_close, .fo_kqfilter = fnullop_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; #define MAXLOCATORS 100 Index: src/sys/kern/kern_event.c diff -u src/sys/kern/kern_event.c:1.67 src/sys/kern/kern_event.c:1.68 --- src/sys/kern/kern_event.c:1.67 Wed Dec 9 21:32:59 2009 +++ src/sys/kern/kern_event.c Sun Dec 20 09:36:05 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_event.c,v 1.67 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: kern_event.c,v 1.68 2009/12/20 09:36:05 dsl Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.67 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.68 2009/12/20 09:36:05 dsl Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -115,7 +115,7 @@ .fo_stat = kqueue_stat, .fo_close = kqueue_close, .fo_kqfilter = kqueue_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; static const struct filterops kqread_filtops = Index: src/sys/kern/sys_mqueue.c diff -u src/sys/kern/sys_mqueue.c:1.28 src/sys/kern/sys_mqueue.c:1.29 --- src/sys/kern/sys_mqueue.c:1.28 Thu Dec 10 12:22:48 2009 +++ src/sys/kern/sys_mqueue.c Sun Dec 20 09:36:05 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_mqueue.c,v 1.28 2009/12/10 12:22:48 drochner Exp $ */ +/* $NetBSD: sys_mqueue.c,v 1.29 2009/12/20 09:36:05 dsl Exp $ */ /* * Copyright (c) 2007-2009 Mindaugas Rasiukevicius <rmind at NetBSD org> @@ -42,7 +42,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.28 2009/12/10 12:22:48 drochner Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.29 2009/12/20 09:36:05 dsl Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -103,7 +103,7 @@ .fo_stat = mq_stat_fop, .fo_close = mq_close_fop, .fo_kqfilter = fnullop_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; static const struct syscall_package mqueue_syscalls[] = { Index: src/sys/kern/sys_pipe.c diff -u src/sys/kern/sys_pipe.c:1.126 src/sys/kern/sys_pipe.c:1.127 --- src/sys/kern/sys_pipe.c:1.126 Tue Dec 15 18:35:18 2009 +++ src/sys/kern/sys_pipe.c Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_pipe.c,v 1.126 2009/12/15 18:35:18 dsl Exp $ */ +/* $NetBSD: sys_pipe.c,v 1.127 2009/12/20 09:36:06 dsl Exp $ */ /*- * Copyright (c) 2003, 2007, 2008, 2009 The NetBSD Foundation, Inc. @@ -68,7 +68,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.126 2009/12/15 18:35:18 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.127 2009/12/20 09:36:06 dsl Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -109,7 +109,7 @@ static int pipe_kqfilter(file_t *, struct knote *); static int pipe_stat(file_t *, struct stat *); static int pipe_ioctl(file_t *, u_long, void *); -static void pipe_abort(file_t *); +static void pipe_restart(file_t *); static const struct fileops pipeops = { .fo_read = pipe_read, @@ -120,7 +120,7 @@ .fo_stat = pipe_stat, .fo_close = pipe_close, .fo_kqfilter = pipe_kqfilter, - .fo_abort = pipe_abort, + .fo_restart = pipe_restart, }; /* @@ -449,7 +449,7 @@ size_t nread = 0; size_t size; size_t ocnt; - int slept = 0; + unsigned int wakeup_state = 0; mutex_enter(lock); ++rpipe->pipe_busy; @@ -579,7 +579,7 @@ cv_broadcast(&rpipe->pipe_wcv); #endif - if (slept) { + if (wakeup_state & PIPE_RESTART) { error = ERESTART; goto unlocked_error; } @@ -588,7 +588,7 @@ error = cv_wait_sig(&rpipe->pipe_rcv, lock); if (error != 0) goto unlocked_error; - slept = 1; + wakeup_state = rpipe->pipe_state; goto again; } @@ -599,6 +599,7 @@ unlocked_error: --rpipe->pipe_busy; if (rpipe->pipe_busy == 0) { + rpipe->pipe_state &= ~PIPE_RESTART; cv_broadcast(&rpipe->pipe_draincv); } if (bp->cnt < MINPIPESIZE) { @@ -823,7 +824,7 @@ struct pipebuf *bp; kmutex_t *lock; int error; - int slept = 0; + unsigned int wakeup_state = 0; /* We want to write to our peer */ rpipe = (struct pipe *) fp->f_data; @@ -846,6 +847,7 @@ if ((error = pipelock(wpipe, 1)) != 0) { --wpipe->pipe_busy; if (wpipe->pipe_busy == 0) { + wpipe->pipe_state &= ~PIPE_RESTART; cv_broadcast(&wpipe->pipe_draincv); } mutex_exit(lock); @@ -976,6 +978,7 @@ bp->cnt += size; KASSERT(bp->cnt <= bp->size); + wakeup_state = 0; } else { /* * If the "read-side" has been blocked, wake it up now. @@ -997,12 +1000,10 @@ if (bp->cnt) pipeselwakeup(wpipe, wpipe, POLL_IN); -#if 0 /* I think some programs don't like the partial write... */ - if (slept) { + if (wakeup_state & PIPE_RESTART) { error = ERESTART; break; } -#endif pipeunlock(wpipe); error = cv_wait_sig(&wpipe->pipe_wcv, lock); @@ -1017,12 +1018,13 @@ error = EPIPE; break; } - slept = 1; + wakeup_state = wpipe->pipe_state; } } --wpipe->pipe_busy; if (wpipe->pipe_busy == 0) { + wpipe->pipe_state &= ~PIPE_RESTART; cv_broadcast(&wpipe->pipe_draincv); } if (bp->cnt > 0) { @@ -1223,18 +1225,19 @@ } static void -pipe_abort(file_t *fp) +pipe_restart(file_t *fp) { struct pipe *pipe = fp->f_data; /* * Unblock blocked reads/writes in order to allow close() to complete. - * This isn't going to work yet! - * The underlying problem is that only the 'fd' in question needs - * its operations terminating, the pipe itself my be open via - * other fd. + * System calls return ERESTART so that the fd is revalidated. + * (Partial writes return the transfer length.) */ mutex_enter(pipe->pipe_lock); + pipe->pipe_state |= PIPE_RESTART; + /* Wakeup both cvs, maybe we only need one, but maybe there are some + * other paths where wakeup is needed, and it saves deciding which! */ cv_broadcast(&pipe->pipe_rcv); cv_broadcast(&pipe->pipe_wcv); mutex_exit(pipe->pipe_lock); Index: src/sys/kern/sys_socket.c diff -u src/sys/kern/sys_socket.c:1.62 src/sys/kern/sys_socket.c:1.63 --- src/sys/kern/sys_socket.c:1.62 Wed Dec 9 21:32:59 2009 +++ src/sys/kern/sys_socket.c Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_socket.c,v 1.62 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: sys_socket.c,v 1.63 2009/12/20 09:36:06 dsl Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_socket.c,v 1.62 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_socket.c,v 1.63 2009/12/20 09:36:06 dsl Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -89,7 +89,7 @@ .fo_stat = soo_stat, .fo_close = soo_close, .fo_kqfilter = soo_kqfilter, - .fo_abort = soo_abort, + .fo_restart = soo_restart, }; /* ARGSUSED */ @@ -260,8 +260,8 @@ } void -soo_abort(file_t *fp) +soo_restart(file_t *fp) { - soabortop(fp->f_data); + sorestart(fp->f_data); } Index: src/sys/kern/uipc_socket.c diff -u src/sys/kern/uipc_socket.c:1.195 src/sys/kern/uipc_socket.c:1.196 --- src/sys/kern/uipc_socket.c:1.195 Wed Dec 9 21:32:59 2009 +++ src/sys/kern/uipc_socket.c Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_socket.c,v 1.195 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: uipc_socket.c,v 1.196 2009/12/20 09:36:06 dsl Exp $ */ /*- * Copyright (c) 2002, 2007, 2008, 2009 The NetBSD Foundation, Inc. @@ -63,7 +63,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.195 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.196 2009/12/20 09:36:06 dsl Exp $"); #include "opt_compat_netbsd.h" #include "opt_sock_counters.h" @@ -905,6 +905,7 @@ struct proc *p; long space, len, resid, clen, mlen; int error, s, dontroute, atomic; + short wakeup_state = 0; p = l->l_proc; sodopendfree(); @@ -979,11 +980,17 @@ goto release; } sbunlock(&so->so_snd); + if (wakeup_state & SS_RESTARTSYS) { + error = ERESTART; + goto out; + } error = sbwait(&so->so_snd); if (error) goto out; + wakeup_state = so->so_state; goto restart; } + wakeup_state = 0; mp = ⊤ space -= clen; do { @@ -1159,6 +1166,7 @@ struct mbuf *nextrecord; int mbuf_removed = 0; const struct domain *dom; + short wakeup_state = 0; pr = so->so_proto; atomic = pr->pr_flags & PR_ATOMIC; @@ -1273,12 +1281,16 @@ SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 1"); SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 1"); sbunlock(&so->so_rcv); - error = sbwait(&so->so_rcv); + if (wakeup_state & SS_RESTARTSYS) + error = ERESTART; + else + error = sbwait(&so->so_rcv); if (error != 0) { sounlock(so); splx(s); return error; } + wakeup_state = so->so_state; goto restart; } dontblock: @@ -1417,6 +1429,7 @@ panic("receive 3"); #endif so->so_state &= ~SS_RCVATMARK; + wakeup_state = 0; len = uio->uio_resid; if (so->so_oobmark && len > so->so_oobmark - offset) len = so->so_oobmark - offset; @@ -1549,7 +1562,10 @@ NULL, (struct mbuf *)(long)flags, NULL, l); SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 2"); SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 2"); - error = sbwait(&so->so_rcv); + if (wakeup_state & SS_RESTARTSYS) + error = ERESTART; + else + error = sbwait(&so->so_rcv); if (error != 0) { sbunlock(&so->so_rcv); sounlock(so); @@ -1558,6 +1574,7 @@ } if ((m = so->so_rcv.sb_mb) != NULL) nextrecord = m->m_nextpkt; + wakeup_state = so->so_state; } } @@ -1625,15 +1642,22 @@ } void -soabortop(struct socket *so) +sorestart(struct socket *so) { -#if 0 /* ad@ wrote this, then disabled it as 'not working' */ + /* + * An application has called close() on an fd on which another + * of its threads has called a socket system call. + * Mark this and wake everyone up, and code that would block again + * instead returns ERESTART. + * On system call re-entry the fd is validated and EBADF returned. + * Any other fd will block again on the 2nd syscall. + */ solock(so); - so->so_state |= SS_ISABORTING; + so->so_state |= SS_RESTARTSYS; cv_broadcast(&so->so_cv); - soshutdown(so, SHUT_RDWR); + cv_broadcast(&so->so_snd.sb_cv); + cv_broadcast(&so->so_rcv.sb_cv); sounlock(so); -#endif } void Index: src/sys/kern/uipc_syscalls.c diff -u src/sys/kern/uipc_syscalls.c:1.137 src/sys/kern/uipc_syscalls.c:1.138 --- src/sys/kern/uipc_syscalls.c:1.137 Wed Dec 9 21:33:00 2009 +++ src/sys/kern/uipc_syscalls.c Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_syscalls.c,v 1.137 2009/12/09 21:33:00 dsl Exp $ */ +/* $NetBSD: uipc_syscalls.c,v 1.138 2009/12/20 09:36:06 dsl Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls.c,v 1.137 2009/12/09 21:33:00 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls.c,v 1.138 2009/12/20 09:36:06 dsl Exp $"); #include "opt_pipe.h" @@ -170,6 +170,7 @@ struct mbuf *nam; int error, fd; struct socket *so, *so2; + short wakeup_state = 0; if ((fp = fd_getfile(sock)) == NULL) return (EBADF); @@ -202,10 +203,15 @@ so->so_error = ECONNABORTED; break; } + if (wakeup_state & SS_RESTARTSYS) { + error = ERESTART; + goto bad; + } error = sowait(so, true, 0); if (error) { goto bad; } + wakeup_state = so->so_state; } if (so->so_error) { error = so->so_error; Index: src/sys/kern/vfs_vnops.c diff -u src/sys/kern/vfs_vnops.c:1.167 src/sys/kern/vfs_vnops.c:1.168 --- src/sys/kern/vfs_vnops.c:1.167 Wed Dec 9 21:32:59 2009 +++ src/sys/kern/vfs_vnops.c Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_vnops.c,v 1.167 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: vfs_vnops.c,v 1.168 2009/12/20 09:36:06 dsl Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.167 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.168 2009/12/20 09:36:06 dsl Exp $"); #include "veriexec.h" @@ -122,7 +122,7 @@ .fo_stat = vn_statfile, .fo_close = vn_closefile, .fo_kqfilter = vn_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; /* Index: src/sys/net/bpf.c diff -u src/sys/net/bpf.c:1.149 src/sys/net/bpf.c:1.150 --- src/sys/net/bpf.c:1.149 Wed Dec 9 21:32:59 2009 +++ src/sys/net/bpf.c Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: bpf.c,v 1.149 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: bpf.c,v 1.150 2009/12/20 09:36:06 dsl Exp $ */ /* * Copyright (c) 1990, 1991, 1993 @@ -39,7 +39,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.149 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.150 2009/12/20 09:36:06 dsl Exp $"); #if defined(_KERNEL_OPT) #include "opt_bpf.h" @@ -165,7 +165,7 @@ .fo_stat = bpf_stat, .fo_close = bpf_close, .fo_kqfilter = bpf_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; dev_type_open(bpfopen); Index: src/sys/net/if_tap.c diff -u src/sys/net/if_tap.c:1.61 src/sys/net/if_tap.c:1.62 --- src/sys/net/if_tap.c:1.61 Wed Dec 9 21:32:59 2009 +++ src/sys/net/if_tap.c Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: if_tap.c,v 1.61 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: if_tap.c,v 1.62 2009/12/20 09:36:06 dsl Exp $ */ /* * Copyright (c) 2003, 2004, 2008, 2009 The NetBSD Foundation. @@ -33,7 +33,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_tap.c,v 1.61 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_tap.c,v 1.62 2009/12/20 09:36:06 dsl Exp $"); #if defined(_KERNEL_OPT) #include "bpfilter.h" @@ -161,7 +161,7 @@ .fo_stat = tap_fops_stat, .fo_close = tap_fops_close, .fo_kqfilter = tap_fops_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; /* Helper for cloning open() */ Index: src/sys/opencrypto/cryptodev.c diff -u src/sys/opencrypto/cryptodev.c:1.50 src/sys/opencrypto/cryptodev.c:1.51 --- src/sys/opencrypto/cryptodev.c:1.50 Wed Dec 9 21:32:59 2009 +++ src/sys/opencrypto/cryptodev.c Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: cryptodev.c,v 1.50 2009/12/09 21:32:59 dsl Exp $ */ +/* $NetBSD: cryptodev.c,v 1.51 2009/12/20 09:36:06 dsl Exp $ */ /* $FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.4.2.4 2003/06/03 00:09:02 sam Exp $ */ /* $OpenBSD: cryptodev.c,v 1.53 2002/07/10 22:21:30 mickey Exp $ */ @@ -64,7 +64,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cryptodev.c,v 1.50 2009/12/09 21:32:59 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cryptodev.c,v 1.51 2009/12/20 09:36:06 dsl Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -157,7 +157,7 @@ .fo_stat = cryptof_stat, .fo_close = cryptof_close, .fo_kqfilter = fnullop_kqfilter, - .fo_abort = fnullop_abort, + .fo_restart = fnullop_restart, }; struct csession *cryptodev_csefind(struct fcrypt *, u_int); Index: src/sys/sys/file.h diff -u src/sys/sys/file.h:1.69 src/sys/sys/file.h:1.70 --- src/sys/sys/file.h:1.69 Wed Dec 9 21:33:00 2009 +++ src/sys/sys/file.h Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: file.h,v 1.69 2009/12/09 21:33:00 dsl Exp $ */ +/* $NetBSD: file.h,v 1.70 2009/12/20 09:36:06 dsl Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -100,7 +100,7 @@ int (*fo_stat) (struct file *, struct stat *); int (*fo_close) (struct file *); int (*fo_kqfilter) (struct file *, struct knote *); - void (*fo_abort) (struct file *); + void (*fo_restart) (struct file *); void (*fo_spare1) (void); void (*fo_spare2) (void); } *f_ops; @@ -162,7 +162,7 @@ int fbadop_ioctl(struct file *, u_long, void *); int fbadop_close(struct file *); int fbadop_stat(struct file *, struct stat *); -void fnullop_abort(struct file *); +void fnullop_restart(struct file *); #endif /* _KERNEL */ Index: src/sys/sys/pipe.h diff -u src/sys/sys/pipe.h:1.31 src/sys/sys/pipe.h:1.32 --- src/sys/sys/pipe.h:1.31 Sun Dec 13 18:27:02 2009 +++ src/sys/sys/pipe.h Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: pipe.h,v 1.31 2009/12/13 18:27:02 dsl Exp $ */ +/* $NetBSD: pipe.h,v 1.32 2009/12/20 09:36:06 dsl Exp $ */ /* * Copyright (c) 1996 John S. Dyson @@ -96,6 +96,7 @@ pointers/data. */ #define PIPE_LWANT 0x200 /* Process wants exclusive access to pointers/data. */ +#define PIPE_RESTART 0x400 /* Return ERESTART to blocked syscalls */ /* * Per-pipe data structure. Index: src/sys/sys/socketvar.h diff -u src/sys/sys/socketvar.h:1.122 src/sys/sys/socketvar.h:1.123 --- src/sys/sys/socketvar.h:1.122 Wed Dec 9 21:33:00 2009 +++ src/sys/sys/socketvar.h Sun Dec 20 09:36:06 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: socketvar.h,v 1.122 2009/12/09 21:33:00 dsl Exp $ */ +/* $NetBSD: socketvar.h,v 1.123 2009/12/20 09:36:06 dsl Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -199,6 +199,7 @@ #define SS_CANTRCVMORE 0x020 /* can't receive more data from peer */ #define SS_RCVATMARK 0x040 /* at mark on input */ #define SS_ISABORTING 0x080 /* aborting fd references - close() */ +#define SS_RESTARTSYS 0x100 /* restart blocked system calls */ #define SS_ISDISCONNECTED 0x800 /* socket disconnected from peer */ #define SS_ASYNC 0x100 /* async i/o notify */ @@ -256,7 +257,7 @@ int soo_kqfilter(file_t *, struct knote *); int soo_close(file_t *); int soo_stat(file_t *, struct stat *); -void soo_abort(file_t *); +void soo_restart(file_t *); void sbappend(struct sockbuf *, struct mbuf *); void sbappendstream(struct sockbuf *, struct mbuf *); int sbappendaddr(struct sockbuf *, const struct sockaddr *, struct mbuf *, @@ -313,7 +314,7 @@ int sosetopt(struct socket *, struct sockopt *); int so_setsockopt(struct lwp *, struct socket *, int, int, const void *, size_t); int soshutdown(struct socket *, int); -void soabortop(struct socket *); +void sorestart(struct socket *); void sowakeup(struct socket *, struct sockbuf *, int); int sockargs(struct mbuf **, const void *, size_t, int); int sopoll(struct socket *, int);