close(2) while accept(2) is blocked
Jilles Tjoelker
jilles at stack.nl
Fri Apr 5 20:32:25 UTC 2013
On Thu, Apr 04, 2013 at 08:43:17PM +0300, Andriy Gapon wrote:
> on 01/04/2013 18:22 John Baldwin said the following:
> > I think you need to split the 'struct file' reference count into two
> > different counts similar to the how we have vref/vrele vs
> > vhold/vdrop for vnodes. The fget for accept and probably most other
> > system calls should probably be equivalent to vhold, whereas things
> > like open/dup (and storing an fd in a cmsg) should be more like
> > vref. close() should then be a vrele().
> This model makes perfect sense.
> Unfortunately, ENOTIME to work on this.
This looks like it can work but I don't know whether it's worth the
trouble.
> Meanwhile I am using the following patch specific to local domain
> sockets, accept(2) and shutdown(2). Turns out that the problematic
> application does both shutdown(RDWR) and close(2), but that doesn't
> help on FreeBSD.
> BTW, this is the application:
> http://thread.gmane.org/gmane.os.freebsd.devel.office/1754
> The patch does help.
> Author: Andriy Gapon <avg at icyb.net.ua>
> Date: Thu Mar 28 20:08:13 2013 +0200
>
> [test!] uipc_shutdown: use soisdisconnected instead of socantsendmore
>
> So that in addition to disabling sends we also wake up threads blocked
> in accept (on so_timeo in general).
>
> diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
> index 9b60eab..e93d46c 100644
> --- a/sys/kern/uipc_usrreq.c
> +++ b/sys/kern/uipc_usrreq.c
> @@ -1074,7 +1074,7 @@ uipc_shutdown(struct socket *so)
>
> UNP_LINK_WLOCK();
> UNP_PCB_LOCK(unp);
> - socantsendmore(so);
> + soisdisconnected(so);
> unp_shutdown(unp);
> UNP_PCB_UNLOCK(unp);
> UNP_LINK_WUNLOCK();
I think this patch makes shutdown(SHUT_WR) on unix domain sockets act
like shutdown(SHUT_RDWR), i.e. receives are incorrectly denied.
The below patch also makes shutdown(SHUT_RDWR) abort a blocking accept
on a unix domain socket, but it should work for all domains:
Index: sys/kern/uipc_socket.c
===================================================================
--- sys/kern/uipc_socket.c (revision 248873)
+++ sys/kern/uipc_socket.c (working copy)
@@ -2428,9 +2428,11 @@ soshutdown(struct socket *so, int how)
sorflush(so);
if (how != SHUT_RD) {
error = (*pr->pr_usrreqs->pru_shutdown)(so);
+ wakeup(&so->so_timeo);
CURVNET_RESTORE();
return (error);
}
+ wakeup(&so->so_timeo);
CURVNET_RESTORE();
return (0);
}
A blocking accept (and some other operations) is waiting on
&so->so_timeo. Once it wakes up, it will detect the SBS_CANTRCVMORE bit.
A spurious wakeup on so->so_timeo appears harmless (sleep retried)
except when lingering on close (SO_LINGER) so this should be fairly
safe.
--
Jilles Tjoelker
More information about the freebsd-net
mailing list