From 3efe70084788876ff2d0763c7ec49044d8787002 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 7 Jun 2004 07:01:36 +0000 Subject: [PATCH] Recent accept() changes started depending on the protosw->pr_mport field being non-NULL, but unix domain sockets still used a NULL pr_mport field. This was causing e.g. XFree86 to panic the system. Unix domain socket calls must still be executed synchronously in the context of the originating process in order to access the proc structure (for ucred and other things). Implement a special synchronous port (netisr_sync_port) and hook function for the protosw called sync_soport() and hook it into the unix domain socket protosw. This port executes netmsg's synchronously and also supports aborts for predicate messages (used by connect and accept). The atm protosw also specified NULL which we change to the standard cpu0_soport(). Remove previous workaround code for NULL mports, since we no longer have any NULL mports. Remove an assertion in connect2() that was designed to detect mis-programmed use of the UNIX DOMAIN socket protosw structure. Original-problem-reported-by: David Rhodus --- sys/kern/lwkt_msgport.c | 10 ++++-- sys/kern/uipc_msg.c | 68 +----------------------------------- sys/kern/uipc_proto.c | 8 ++--- sys/net/netisr.c | 68 ++++++++++++++++++++++++++++++++++-- sys/netproto/atm/atm_proto.c | 4 +-- sys/sys/msgport.h | 40 ++++++++++++++++++++- sys/sys/protosw.h | 3 +- 7 files changed, 122 insertions(+), 79 deletions(-) diff --git a/sys/kern/lwkt_msgport.c b/sys/kern/lwkt_msgport.c index 1f08ef87c8..70161f759d 100644 --- a/sys/kern/lwkt_msgport.c +++ b/sys/kern/lwkt_msgport.c @@ -26,7 +26,7 @@ * NOTE! This file may be compiled for userland libraries as well as for * the kernel. * - * $DragonFly: src/sys/kern/lwkt_msgport.c,v 1.22 2004/06/04 20:35:36 dillon Exp $ + * $DragonFly: src/sys/kern/lwkt_msgport.c,v 1.23 2004/06/07 07:01:34 dillon Exp $ */ #ifdef _KERNEL @@ -474,8 +474,13 @@ lwkt_abortmsg(lwkt_msg_t msg) else port = msg->ms_target_port; cpu_mb1(); + + /* + * The chase call must run on the cpu owning the port. Fully + * synchronous ports (mp_td == NULL) can run the call on any cpu. + */ td = port->mp_td; - if (td->td_gd != mycpu) { + if (td && td->td_gd != mycpu) { lwkt_send_ipiq(td->td_gd, (ipifunc_t)lwkt_abortmsg_remote, msg); } else { port->mp_abortport(port, msg); @@ -612,6 +617,7 @@ lwkt_default_waitport(lwkt_port_t port, lwkt_msg_t msg) if (sentabort == 0 && CURSIG(port->mp_td->td_proc)) { sentabort = 1; lwkt_abortmsg(msg); + continue; } } #endif diff --git a/sys/kern/uipc_msg.c b/sys/kern/uipc_msg.c index e18a5c72b4..4e533314e9 100644 --- a/sys/kern/uipc_msg.c +++ b/sys/kern/uipc_msg.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $DragonFly: src/sys/kern/uipc_msg.c,v 1.11 2004/06/06 05:59:44 hsu Exp $ + * $DragonFly: src/sys/kern/uipc_msg.c,v 1.12 2004/06/07 07:01:34 dillon Exp $ */ #include @@ -51,9 +51,6 @@ so_pru_abort(struct socket *so) struct netmsg_pru_abort msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_abort)(so)); - port = so->so_proto->pr_mport(so, NULL, PRU_ABORT); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_abort), lwkt_cmd_op_none); @@ -74,9 +71,6 @@ so_pru_accept(struct socket *so, struct sockaddr **nam) struct netmsg_pru_accept msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_accept)(so, nam)); - port = so->so_proto->pr_mport(so, NULL, PRU_ACCEPT); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_accept), lwkt_cmd_op_none); @@ -95,9 +89,6 @@ so_pru_attach(struct socket *so, int proto, struct pru_attach_info *ai) struct netmsg_pru_attach msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_attach)(so, proto, ai)); - port = so->so_proto->pr_mport(NULL, NULL, PRU_ATTACH); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_attach), lwkt_cmd_op_none); @@ -116,9 +107,6 @@ so_pru_bind(struct socket *so, struct sockaddr *nam, struct thread *td) struct netmsg_pru_bind msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_bind)(so, nam, td)); - /* Send mesg to thread for new address. */ port = so->so_proto->pr_mport(NULL, nam, PRU_BIND); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, @@ -138,9 +126,6 @@ so_pru_connect(struct socket *so, struct sockaddr *nam, struct thread *td) struct netmsg_pru_connect msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td)); - port = so->so_proto->pr_mport(so, nam, PRU_CONNECT); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_connect), lwkt_cmd_op_none); @@ -159,15 +144,6 @@ so_pru_connect2(struct socket *so1, struct socket *so2) struct netmsg_pru_connect2 msg; lwkt_port_t port; - if (!so1->so_proto->pr_mport) - return ((*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2)); - - /* - * Actually, connect2() is only called for Unix domain sockets - * and we currently short-circuit that above, so the following - * code is never reached. - */ - panic("connect2 on socket type %d", so1->so_type); port = so1->so_proto->pr_mport(so1, NULL, PRU_CONNECT2); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_connect2), lwkt_cmd_op_none); @@ -189,10 +165,6 @@ so_pru_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct netmsg_pru_control msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data, - ifp, td)); - port = so->so_proto->pr_mport(so, NULL, PRU_CONTROL); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_control), lwkt_cmd_op_none); @@ -214,9 +186,6 @@ so_pru_detach(struct socket *so) struct netmsg_pru_detach msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_detach)(so)); - port = so->so_proto->pr_mport(so, NULL, PRU_DETACH); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_detach), lwkt_cmd_op_none); @@ -233,9 +202,6 @@ so_pru_disconnect(struct socket *so) struct netmsg_pru_disconnect msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_disconnect)(so)); - port = so->so_proto->pr_mport(so, NULL, PRU_DISCONNECT); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_disconnect), lwkt_cmd_op_none); @@ -252,9 +218,6 @@ so_pru_listen(struct socket *so, struct thread *td) struct netmsg_pru_listen msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_listen)(so, td)); - port = so->so_proto->pr_mport(so, NULL, PRU_LISTEN); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_listen), lwkt_cmd_op_none); @@ -272,9 +235,6 @@ so_pru_peeraddr(struct socket *so, struct sockaddr **nam) struct netmsg_pru_peeraddr msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_peeraddr)(so, nam)); - port = so->so_proto->pr_mport(so, NULL, PRU_PEERADDR); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_peeraddr), lwkt_cmd_op_none); @@ -292,9 +252,6 @@ so_pru_rcvd(struct socket *so, int flags) struct netmsg_pru_rcvd msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_rcvd)(so, flags)); - port = so->so_proto->pr_mport(so, NULL, PRU_RCVD); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_rcvd), lwkt_cmd_op_none); @@ -312,9 +269,6 @@ so_pru_rcvoob(struct socket *so, struct mbuf *m, int flags) struct netmsg_pru_rcvoob msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_rcvoob)(so, m, flags)); - port = so->so_proto->pr_mport(so, NULL, PRU_RCVOOB); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_rcvoob), lwkt_cmd_op_none); @@ -334,10 +288,6 @@ so_pru_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct netmsg_pru_send msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_send)(so, flags, m, - addr, control, td)); - port = so->so_proto->pr_mport(so, NULL, PRU_SEND); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_send), lwkt_cmd_op_none); @@ -359,9 +309,6 @@ so_pru_sense(struct socket *so, struct stat *sb) struct netmsg_pru_sense msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_sense)(so, sb)); - port = so->so_proto->pr_mport(so, NULL, PRU_SENSE); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_sense), lwkt_cmd_op_none); @@ -379,9 +326,6 @@ so_pru_shutdown(struct socket *so) struct netmsg_pru_shutdown msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_shutdown)(so)); - port = so->so_proto->pr_mport(so, NULL, PRU_SHUTDOWN); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_shutdown), lwkt_cmd_op_none); @@ -398,9 +342,6 @@ so_pru_sockaddr(struct socket *so, struct sockaddr **nam) struct netmsg_pru_sockaddr msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_sockaddr)(so, nam)); - port = so->so_proto->pr_mport(so, NULL, PRU_SOCKADDR); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_sockaddr), lwkt_cmd_op_none); @@ -419,10 +360,6 @@ so_pru_sopoll(struct socket *so, int events, struct ucred *cred, struct netmsg_pru_sopoll msg; lwkt_port_t port; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_usrreqs->pru_sopoll)(so, events, - cred, td)); - port = so->so_proto->pr_mport(so, NULL, PRU_SOPOLL); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_sopoll), lwkt_cmd_op_none); @@ -444,9 +381,6 @@ so_pr_ctloutput(struct socket *so, struct sockopt *sopt) lwkt_port_t port; int error; - if (!so->so_proto->pr_mport) - return ((*so->so_proto->pr_ctloutput)(so, sopt)); - port = so->so_proto->pr_mport(so, NULL); lwkt_initmsg(&msg.nm_lmsg, &curthread->td_msgport, 0, lwkt_cmd_func(netmsg_pru_ctloutput), lwkt_cmd_op_none); diff --git a/sys/kern/uipc_proto.c b/sys/kern/uipc_proto.c index 89089cdb4e..da87495c27 100644 --- a/sys/kern/uipc_proto.c +++ b/sys/kern/uipc_proto.c @@ -32,7 +32,7 @@ * * @(#)uipc_proto.c 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/kern/uipc_proto.c,v 1.21.2.1 2002/03/09 05:22:23 dd Exp $ - * $DragonFly: src/sys/kern/uipc_proto.c,v 1.3 2004/03/06 01:58:54 hsu Exp $ + * $DragonFly: src/sys/kern/uipc_proto.c,v 1.4 2004/06/07 07:01:34 dillon Exp $ */ #include @@ -53,19 +53,19 @@ static struct protosw localsw[] = { { SOCK_STREAM, &localdomain, 0, PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS, 0, 0, 0, &uipc_ctloutput, - NULL, + sync_soport, 0, 0, 0, 0, &uipc_usrreqs }, { SOCK_DGRAM, &localdomain, 0, PR_ATOMIC|PR_ADDR|PR_RIGHTS, 0, 0, 0, 0, - NULL, + sync_soport, 0, 0, 0, 0, &uipc_usrreqs }, { 0, 0, 0, 0, 0, 0, raw_ctlinput, 0, - NULL, + sync_soport, raw_init, 0, 0, 0, &raw_usrreqs } diff --git a/sys/net/netisr.c b/sys/net/netisr.c index 207bf2364d..c3cde6d33b 100644 --- a/sys/net/netisr.c +++ b/sys/net/netisr.c @@ -3,7 +3,7 @@ * Copyright (c) 2003 Jonathan Lemon * Copyright (c) 2003 Matthew Dillon * - * $DragonFly: src/sys/net/netisr.c,v 1.16 2004/04/24 06:55:57 hsu Exp $ + * $DragonFly: src/sys/net/netisr.c,v 1.17 2004/06/07 07:01:36 dillon Exp $ */ #include @@ -29,6 +29,7 @@ static struct netisr netisrs[NETISR_MAX]; /* Per-CPU thread to handle any protocol. */ struct thread netisr_cpu[MAXCPU]; lwkt_port netisr_afree_rport; +lwkt_port netisr_sync_port; /* * netisr_afree_rport replymsg function, only used to handle async @@ -49,6 +50,9 @@ netisr_autofree_reply(lwkt_port_t port, lwkt_msg_t msg) * messages are executed synchronously. However, we must panic if the message * is not marked DONE on completion because the self-referential case cannot * block without deadlocking. + * + * note: ms_target_port does not need to be set when returning a synchronous + * error code. */ int netmsg_put_port(lwkt_port_t port, lwkt_msg_t lmsg) @@ -65,19 +69,72 @@ netmsg_put_port(lwkt_port_t port, lwkt_msg_t lmsg) } } +/* + * UNIX DOMAIN sockets still have to run their uipc functions synchronously, + * because they depend on the user proc context for a number of things + * (like creds) which we have not yet incorporated into the message structure. + * + * However, we maintain or message/port abstraction. Having a special + * synchronous port which runs the commands synchronously gives us the + * ability to serialize operations in one place later on when we start + * removing the BGL. + * + * We clear MSGF_DONE prior to executing the message in order to close + * any potential replymsg races with the flags field. If a synchronous + * result code is returned we set MSGF_DONE again. MSGF_DONE's flag state + * must be correct or the caller will be confused. + */ +static int +netmsg_sync_putport(lwkt_port_t port, lwkt_msg_t lmsg) +{ + int error; + + lmsg->ms_flags &= ~MSGF_DONE; + lmsg->ms_target_port = port; /* required for abort */ + error = lmsg->ms_cmd.cm_func(lmsg); + if (error == EASYNC) + error = lwkt_waitmsg(lmsg); + else + lmsg->ms_flags |= MSGF_DONE; + return(error); +} + +static void +netmsg_sync_abortport(lwkt_port_t port, lwkt_msg_t lmsg) +{ + lmsg->ms_abort_port = lmsg->ms_reply_port; + lmsg->ms_flags |= MSGF_ABORTED; + lmsg->ms_abort.cm_func(lmsg); +} + static void netisr_init(void) { int i; - /* Create default per-cpu threads for generic protocol handling. */ + /* + * Create default per-cpu threads for generic protocol handling. + */ for (i = 0; i < ncpus; ++i) { lwkt_create(netmsg_service_loop, NULL, NULL, &netisr_cpu[i], 0, i, "netisr_cpu %d", i); netisr_cpu[i].td_msgport.mp_putport = netmsg_put_port; } + + /* + * The netisr_afree_rport is a special reply port which automatically + * frees the replied message. + */ lwkt_initport(&netisr_afree_rport, NULL); netisr_afree_rport.mp_replyport = netisr_autofree_reply; + + /* + * The netisr_syncport is a special port which executes the message + * synchronously and waits for it if EASYNC is returned. + */ + lwkt_initport(&netisr_sync_port, NULL); + netisr_sync_port.mp_putport = netmsg_sync_putport; + netisr_sync_port.mp_abortport = netmsg_sync_abortport; } SYSINIT(netisr, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, netisr_init, NULL); @@ -173,6 +230,13 @@ cpu0_soport(struct socket *so __unused, struct sockaddr *nam __unused, return (&netisr_cpu[0].td_msgport); } +lwkt_port_t +sync_soport(struct socket *so __unused, struct sockaddr *nam __unused, + int req __unused) +{ + return (&netisr_sync_port); +} + /* * This function is used to call the netisr handler from the appropriate * netisr thread for polling and other purposes. diff --git a/sys/netproto/atm/atm_proto.c b/sys/netproto/atm/atm_proto.c index 45e02f61b4..beac59b431 100644 --- a/sys/netproto/atm/atm_proto.c +++ b/sys/netproto/atm/atm_proto.c @@ -24,7 +24,7 @@ * notice must be reproduced on all copies. * * @(#) $FreeBSD: src/sys/netatm/atm_proto.c,v 1.3 1999/08/28 00:48:36 peter Exp $ - * @(#) $DragonFly: src/sys/netproto/atm/atm_proto.c,v 1.6 2004/03/06 01:58:56 hsu Exp $ + * @(#) $DragonFly: src/sys/netproto/atm/atm_proto.c,v 1.7 2004/06/07 07:01:36 dillon Exp $ */ /* @@ -62,7 +62,7 @@ struct protosw atmsw[] = { 0, /* pr_output */ 0, /* pr_ctlinput */ atm_aal5_ctloutput, /* pr_ctloutput */ - 0, /* pr_ousrreq */ + cpu0_soport, /* pr_ousrreq */ 0, /* pr_init */ 0, /* pr_fasttimo */ 0, /* pr_slowtimo */ diff --git a/sys/sys/msgport.h b/sys/sys/msgport.h index 6a06379d77..b00f796858 100644 --- a/sys/sys/msgport.h +++ b/sys/sys/msgport.h @@ -3,7 +3,7 @@ * * Implements LWKT messages and ports. * - * $DragonFly: src/sys/sys/msgport.h,v 1.18 2004/06/04 20:35:39 dillon Exp $ + * $DragonFly: src/sys/sys/msgport.h,v 1.19 2004/06/07 07:01:36 dillon Exp $ */ #ifndef _SYS_MSGPORT_H_ @@ -119,6 +119,44 @@ MALLOC_DECLARE(M_LWKTMSG); #endif #endif +/* + * Notes on port processing requirements: + * + * mp_putport(): + * - may return synchronous error code (error != EASYNC) directly and + * does not need to check or set MSGF_DONE if so, or set ms_target_port + * - for asynch procesing should clear MSGF_DONE and set ms_target_port + * to port prior to initiation of the command. + * + * mp_waitport(): + * - if the passed msg is NULL we wait for, remove, and return the + * next pending message on the port. + * - if the passed msg is non-NULL we wait for that particular message, + * which typically involves waiting until MSGF_DONE is set then + * pulling the message off the port if MSGF_QUEUED is set and + * returning it. If MSGF_PCATCH is set in the message we allow + * a signal to interrupt and abort the message. + * + * mp_replyport(): + * - reply a message (executed on the originating port to return a + * message to it). This can be rather involved if abort is to be + * supported, see lwkt_default_replyport(). Generally speaking + * one sets MSGF_DONE. If MSGF_ASYNC is set the message is queued + * to the port, else the port's thread is scheduled. + * + * mp_abortport(): + * - abort a message. The mp_abortport function for the message's + * ms_target_port is called. ms_target_port is basically where + * the message was sent to or last forwarded to. Aborting a message + * can be rather involved. Note that the lwkt_getmsg() code ensures + * that a message is returned non-abort before it is returned again + * with its ms_cmd set to ms_abort, even if the abort occurs before + * the initial retrieval of the message. The setting of ms_cmd to + * ms_abort is NOT handled by mp_abortport(). mp_abortport() is + * basically responsible for requeueing the message to the target + * port and setting the MSGF_ABORTED flag. + * + */ typedef struct lwkt_port { lwkt_msg_queue mp_msgq; int mp_flags; diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h index 0e78c851e6..f3ae5871a2 100644 --- a/sys/sys/protosw.h +++ b/sys/sys/protosw.h @@ -32,7 +32,7 @@ * * @(#)protosw.h 8.1 (Berkeley) 6/2/93 * $FreeBSD: src/sys/sys/protosw.h,v 1.28.2.2 2001/07/03 11:02:01 ume Exp $ - * $DragonFly: src/sys/sys/protosw.h,v 1.12 2004/06/03 18:30:04 joerg Exp $ + * $DragonFly: src/sys/sys/protosw.h,v 1.13 2004/06/07 07:01:36 dillon Exp $ */ #ifndef _SYS_PROTOSW_H_ @@ -292,6 +292,7 @@ int pru_rcvoob_notsupp (struct socket *so, struct mbuf *m, int flags); int pru_sense_null (struct socket *so, struct stat *sb); struct lwkt_port *cpu0_soport(struct socket *, struct sockaddr *, int); +struct lwkt_port *sync_soport(struct socket *, struct sockaddr *, int); #endif /* _KERNEL */ -- 2.41.0