diff options
Diffstat (limited to 'sys/rpc/clnt_vc.c')
| -rw-r--r-- | sys/rpc/clnt_vc.c | 175 |
1 files changed, 104 insertions, 71 deletions
diff --git a/sys/rpc/clnt_vc.c b/sys/rpc/clnt_vc.c index 6655e6e7da95..e42d26d4c843 100644 --- a/sys/rpc/clnt_vc.c +++ b/sys/rpc/clnt_vc.c @@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$"); #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> +#include <sys/sx.h> #include <sys/syslog.h> #include <sys/time.h> #include <sys/uio.h> @@ -77,8 +78,7 @@ __FBSDID("$FreeBSD$"); #include <rpc/rpc.h> #include <rpc/rpc_com.h> - -#define MCALL_MSG_SIZE 24 +#include <rpc/krpc.h> struct cmessage { struct cmsghdr cmsg; @@ -106,43 +106,6 @@ static struct clnt_ops clnt_vc_ops = { .cl_control = clnt_vc_control }; -/* - * A pending RPC request which awaits a reply. Requests which have - * received their reply will have cr_xid set to zero and cr_mrep to - * the mbuf chain of the reply. - */ -struct ct_request { - TAILQ_ENTRY(ct_request) cr_link; - uint32_t cr_xid; /* XID of request */ - struct mbuf *cr_mrep; /* reply received by upcall */ - int cr_error; /* any error from upcall */ - char cr_verf[MAX_AUTH_BYTES]; /* reply verf */ -}; - -TAILQ_HEAD(ct_request_list, ct_request); - -struct ct_data { - struct mtx ct_lock; - int ct_threads; /* number of threads in clnt_vc_call */ - bool_t ct_closing; /* TRUE if we are closing */ - bool_t ct_closed; /* TRUE if we are closed */ - struct socket *ct_socket; /* connection socket */ - bool_t ct_closeit; /* close it on destroy */ - struct timeval ct_wait; /* wait interval in milliseconds */ - struct sockaddr_storage ct_addr; /* remote addr */ - struct rpc_err ct_error; - uint32_t ct_xid; - char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ - size_t ct_mpos; /* pos after marshal */ - const char *ct_waitchan; - int ct_waitflag; - struct mbuf *ct_record; /* current reply record */ - size_t ct_record_resid; /* how much left of reply to read */ - bool_t ct_record_eor; /* true if reading last fragment */ - struct ct_request_list ct_pending; - int ct_upcallrefs; /* Ref cnt of upcalls in prog. */ -}; - static void clnt_vc_upcallsdone(struct ct_data *); static const char clnt_vc_errstr[] = "%s : %s"; @@ -641,6 +604,7 @@ clnt_vc_control(CLIENT *cl, u_int request, void *info) { struct ct_data *ct = (struct ct_data *)cl->cl_private; void *infop = info; + SVCXPRT *xprt; mtx_lock(&ct->ct_lock); @@ -752,6 +716,14 @@ clnt_vc_control(CLIENT *cl, u_int request, void *info) *(int *) info = FALSE; break; + case CLSET_BACKCHANNEL: + xprt = (SVCXPRT *)info; + if (ct->ct_backchannelxprt == NULL) { + xprt->xp_p2 = ct; + ct->ct_backchannelxprt = xprt; + } + break; + default: mtx_unlock(&ct->ct_lock); return (FALSE); @@ -817,10 +789,20 @@ clnt_vc_destroy(CLIENT *cl) { struct ct_data *ct = (struct ct_data *) cl->cl_private; struct socket *so = NULL; + SVCXPRT *xprt; clnt_vc_close(cl); mtx_lock(&ct->ct_lock); + xprt = ct->ct_backchannelxprt; + ct->ct_backchannelxprt = NULL; + if (xprt != NULL) { + mtx_unlock(&ct->ct_lock); /* To avoid a LOR. */ + sx_xlock(&xprt->xp_lock); + mtx_lock(&ct->ct_lock); + xprt->xp_p2 = NULL; + xprt_unregister(xprt); + } if (ct->ct_socket) { if (ct->ct_closeit) { @@ -829,6 +811,10 @@ clnt_vc_destroy(CLIENT *cl) } mtx_unlock(&ct->ct_lock); + if (xprt != NULL) { + sx_xunlock(&xprt->xp_lock); + SVC_RELEASE(xprt); + } mtx_destroy(&ct->ct_lock); if (so) { @@ -859,12 +845,15 @@ clnt_vc_soupcall(struct socket *so, void *arg, int waitflag) { struct ct_data *ct = (struct ct_data *) arg; struct uio uio; - struct mbuf *m; + struct mbuf *m, *m2; struct ct_request *cr; int error, rcvflag, foundreq; - uint32_t xid, header; + uint32_t xid_plus_direction[2], header; bool_t do_read; + SVCXPRT *xprt; + struct cf_conn *cd; + CTASSERT(sizeof(xid_plus_direction) == 2 * sizeof(uint32_t)); ct->ct_upcallrefs++; uio.uio_td = curthread; do { @@ -978,45 +967,89 @@ clnt_vc_soupcall(struct socket *so, void *arg, int waitflag) && ct->ct_record_eor) { /* * The XID is in the first uint32_t of - * the reply. + * the reply and the message direction + * is the second one. */ - if (ct->ct_record->m_len < sizeof(xid) && + if (ct->ct_record->m_len < + sizeof(xid_plus_direction) && m_length(ct->ct_record, NULL) < - sizeof(xid)) { + sizeof(xid_plus_direction)) { m_freem(ct->ct_record); break; } - m_copydata(ct->ct_record, 0, sizeof(xid), - (char *)&xid); - xid = ntohl(xid); - - mtx_lock(&ct->ct_lock); - foundreq = 0; - TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { - if (cr->cr_xid == xid) { + m_copydata(ct->ct_record, 0, + sizeof(xid_plus_direction), + (char *)xid_plus_direction); + xid_plus_direction[0] = + ntohl(xid_plus_direction[0]); + xid_plus_direction[1] = + ntohl(xid_plus_direction[1]); + /* Check message direction. */ + if (xid_plus_direction[1] == CALL) { + /* This is a backchannel request. */ + mtx_lock(&ct->ct_lock); + xprt = ct->ct_backchannelxprt; + if (xprt == NULL) { + mtx_unlock(&ct->ct_lock); + /* Just throw it away. */ + m_freem(ct->ct_record); + ct->ct_record = NULL; + } else { + cd = (struct cf_conn *) + xprt->xp_p1; + m2 = cd->mreq; /* - * This one - * matches. We leave - * the reply mbuf in - * cr->cr_mrep. Set - * the XID to zero so - * that we will ignore - * any duplicaed - * replies. + * The requests are chained + * in the m_nextpkt list. */ - cr->cr_xid = 0; - cr->cr_mrep = ct->ct_record; - cr->cr_error = 0; - foundreq = 1; - wakeup(cr); - break; + while (m2 != NULL && + m2->m_nextpkt != NULL) + /* Find end of list. */ + m2 = m2->m_nextpkt; + if (m2 != NULL) + m2->m_nextpkt = + ct->ct_record; + else + cd->mreq = + ct->ct_record; + ct->ct_record->m_nextpkt = + NULL; + ct->ct_record = NULL; + xprt_active(xprt); + mtx_unlock(&ct->ct_lock); } - } - mtx_unlock(&ct->ct_lock); + } else { + mtx_lock(&ct->ct_lock); + foundreq = 0; + TAILQ_FOREACH(cr, &ct->ct_pending, + cr_link) { + if (cr->cr_xid == + xid_plus_direction[0]) { + /* + * This one + * matches. We leave + * the reply mbuf in + * cr->cr_mrep. Set + * the XID to zero so + * that we will ignore + * any duplicated + * replies. + */ + cr->cr_xid = 0; + cr->cr_mrep = + ct->ct_record; + cr->cr_error = 0; + foundreq = 1; + wakeup(cr); + break; + } + } + mtx_unlock(&ct->ct_lock); - if (!foundreq) - m_freem(ct->ct_record); - ct->ct_record = NULL; + if (!foundreq) + m_freem(ct->ct_record); + ct->ct_record = NULL; + } } } } while (m); |
