The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/rpc/clnt_bck.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2009, Sun Microsystems, Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without 
    8  * modification, are permitted provided that the following conditions are met:
    9  * - Redistributions of source code must retain the above copyright notice, 
   10  *   this list of conditions and the following disclaimer.
   11  * - Redistributions in binary form must reproduce the above copyright notice, 
   12  *   this list of conditions and the following disclaimer in the documentation 
   13  *   and/or other materials provided with the distribution.
   14  * - Neither the name of Sun Microsystems, Inc. nor the names of its 
   15  *   contributors may be used to endorse or promote products derived 
   16  *   from this software without specific prior written permission.
   17  * 
   18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
   19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
   21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
   22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
   23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
   24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
   25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
   27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
   28  * POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 #if defined(LIBC_SCCS) && !defined(lint)
   32 static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
   33 static char *sccsid = "@(#)clnt_tcp.c   2.2 88/08/01 4.0 RPCSRC";
   34 static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
   35 #endif
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38  
   39 /*
   40  * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
   41  *
   42  * Copyright (C) 1984, Sun Microsystems, Inc.
   43  *
   44  * TCP based RPC supports 'batched calls'.
   45  * A sequence of calls may be batched-up in a send buffer.  The rpc call
   46  * return immediately to the client even though the call was not necessarily
   47  * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
   48  * the rpc timeout value is zero (see clnt.h, rpc).
   49  *
   50  * Clients should NOT casually batch calls that in fact return results; that is,
   51  * the server side should be aware that a call is batched and not produce any
   52  * return message.  Batched calls that produce many result messages can
   53  * deadlock (netlock) the client and the server....
   54  *
   55  * Now go hang yourself.
   56  */
   57 
   58 /*
   59  * This code handles the special case of a NFSv4.n backchannel for
   60  * callback RPCs. It is similar to clnt_vc.c, but uses the TCP
   61  * connection provided by the client to the server.
   62  */
   63 
   64 #include "opt_kern_tls.h"
   65 
   66 #include <sys/param.h>
   67 #include <sys/systm.h>
   68 #include <sys/ktls.h>
   69 #include <sys/lock.h>
   70 #include <sys/malloc.h>
   71 #include <sys/mbuf.h>
   72 #include <sys/mutex.h>
   73 #include <sys/pcpu.h>
   74 #include <sys/proc.h>
   75 #include <sys/protosw.h>
   76 #include <sys/socket.h>
   77 #include <sys/socketvar.h>
   78 #include <sys/sx.h>
   79 #include <sys/syslog.h>
   80 #include <sys/time.h>
   81 #include <sys/uio.h>
   82 
   83 #include <net/vnet.h>
   84 
   85 #include <netinet/tcp.h>
   86 
   87 #include <rpc/rpc.h>
   88 #include <rpc/rpc_com.h>
   89 #include <rpc/krpc.h>
   90 #include <rpc/rpcsec_tls.h>
   91 
   92 struct cmessage {
   93         struct cmsghdr cmsg;
   94         struct cmsgcred cmcred;
   95 };
   96 
   97 static void clnt_bck_geterr(CLIENT *, struct rpc_err *);
   98 static bool_t clnt_bck_freeres(CLIENT *, xdrproc_t, void *);
   99 static void clnt_bck_abort(CLIENT *);
  100 static bool_t clnt_bck_control(CLIENT *, u_int, void *);
  101 static void clnt_bck_close(CLIENT *);
  102 static void clnt_bck_destroy(CLIENT *);
  103 
  104 static const struct clnt_ops clnt_bck_ops = {
  105         .cl_abort =     clnt_bck_abort,
  106         .cl_geterr =    clnt_bck_geterr,
  107         .cl_freeres =   clnt_bck_freeres,
  108         .cl_close =     clnt_bck_close,
  109         .cl_destroy =   clnt_bck_destroy,
  110         .cl_control =   clnt_bck_control
  111 };
  112 
  113 /*
  114  * Create a client handle for a connection.
  115  * Default options are set, which the user can change using clnt_control()'s.
  116  * This code handles the special case of an NFSv4.1 session backchannel
  117  * call, which is sent on a TCP connection created against the server
  118  * by a client.
  119  */
  120 void *
  121 clnt_bck_create(
  122         struct socket *so,              /* Server transport socket. */
  123         const rpcprog_t prog,           /* program number */
  124         const rpcvers_t vers)           /* version number */
  125 {
  126         CLIENT *cl;                     /* client handle */
  127         struct ct_data *ct = NULL;      /* client handle */
  128         struct timeval now;
  129         struct rpc_msg call_msg;
  130         static uint32_t disrupt;
  131         XDR xdrs;
  132 
  133         if (disrupt == 0)
  134                 disrupt = (uint32_t)(long)so;
  135 
  136         cl = (CLIENT *)mem_alloc(sizeof (*cl));
  137         ct = (struct ct_data *)mem_alloc(sizeof (*ct));
  138 
  139         mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF);
  140         ct->ct_threads = 0;
  141         ct->ct_closing = FALSE;
  142         ct->ct_closed = FALSE;
  143         ct->ct_upcallrefs = 0;
  144         ct->ct_closeit = FALSE;
  145 
  146         /*
  147          * Set up private data struct
  148          */
  149         ct->ct_wait.tv_sec = -1;
  150         ct->ct_wait.tv_usec = -1;
  151 
  152         /*
  153          * Initialize call message
  154          */
  155         getmicrotime(&now);
  156         ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now);
  157         call_msg.rm_xid = ct->ct_xid;
  158         call_msg.rm_direction = CALL;
  159         call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  160         call_msg.rm_call.cb_prog = (uint32_t)prog;
  161         call_msg.rm_call.cb_vers = (uint32_t)vers;
  162 
  163         /*
  164          * pre-serialize the static part of the call msg and stash it away
  165          */
  166         xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE,
  167             XDR_ENCODE);
  168         if (!xdr_callhdr(&xdrs, &call_msg))
  169                 goto err;
  170         ct->ct_mpos = XDR_GETPOS(&xdrs);
  171         XDR_DESTROY(&xdrs);
  172         ct->ct_waitchan = "rpcbck";
  173         ct->ct_waitflag = 0;
  174         cl->cl_refs = 1;
  175         cl->cl_ops = &clnt_bck_ops;
  176         cl->cl_private = ct;
  177         cl->cl_auth = authnone_create();
  178         TAILQ_INIT(&ct->ct_pending);
  179         return (cl);
  180 
  181 err:
  182         mtx_destroy(&ct->ct_lock);
  183         mem_free(ct, sizeof (struct ct_data));
  184         mem_free(cl, sizeof (CLIENT));
  185         return (NULL);
  186 }
  187 
  188 enum clnt_stat
  189 clnt_bck_call(
  190         CLIENT          *cl,            /* client handle */
  191         struct rpc_callextra *ext,      /* call metadata */
  192         rpcproc_t       proc,           /* procedure number */
  193         struct mbuf     *args,          /* pointer to args */
  194         struct mbuf     **resultsp,     /* pointer to results */
  195         struct timeval  utimeout,
  196         SVCXPRT         *xprt)
  197 {
  198         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  199         AUTH *auth;
  200         struct rpc_err *errp;
  201         enum clnt_stat stat;
  202         XDR xdrs;
  203         struct rpc_msg reply_msg;
  204         bool_t ok;
  205         int nrefreshes = 2;             /* number of times to refresh cred */
  206         struct timeval timeout;
  207         uint32_t xid;
  208         struct mbuf *mreq = NULL, *results;
  209         struct ct_request *cr;
  210         int error, maxextsiz;
  211 #ifdef KERN_TLS
  212         u_int maxlen;
  213 #endif
  214 
  215         cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
  216 
  217         mtx_lock(&ct->ct_lock);
  218 
  219         if (ct->ct_closing || ct->ct_closed) {
  220                 mtx_unlock(&ct->ct_lock);
  221                 free(cr, M_RPC);
  222                 return (RPC_CANTSEND);
  223         }
  224         ct->ct_threads++;
  225 
  226         if (ext) {
  227                 auth = ext->rc_auth;
  228                 errp = &ext->rc_err;
  229         } else {
  230                 auth = cl->cl_auth;
  231                 errp = &ct->ct_error;
  232         }
  233 
  234         cr->cr_mrep = NULL;
  235         cr->cr_error = 0;
  236 
  237         if (ct->ct_wait.tv_usec == -1)
  238                 timeout = utimeout;     /* use supplied timeout */
  239         else
  240                 timeout = ct->ct_wait;  /* use default timeout */
  241 
  242 call_again:
  243         mtx_assert(&ct->ct_lock, MA_OWNED);
  244 
  245         ct->ct_xid++;
  246         xid = ct->ct_xid;
  247 
  248         mtx_unlock(&ct->ct_lock);
  249 
  250         /*
  251          * Leave space to pre-pend the record mark.
  252          */
  253         mreq = m_gethdr(M_WAITOK, MT_DATA);
  254         mreq->m_data += sizeof(uint32_t);
  255         KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN,
  256             ("RPC header too big"));
  257         bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos);
  258         mreq->m_len = ct->ct_mpos;
  259 
  260         /*
  261          * The XID is the first thing in the request.
  262          */
  263         *mtod(mreq, uint32_t *) = htonl(xid);
  264 
  265         xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
  266 
  267         errp->re_status = stat = RPC_SUCCESS;
  268 
  269         if ((!XDR_PUTINT32(&xdrs, &proc)) ||
  270             (!AUTH_MARSHALL(auth, xid, &xdrs,
  271              m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
  272                 errp->re_status = stat = RPC_CANTENCODEARGS;
  273                 mtx_lock(&ct->ct_lock);
  274                 goto out;
  275         }
  276         mreq->m_pkthdr.len = m_length(mreq, NULL);
  277 
  278         /*
  279          * Prepend a record marker containing the packet length.
  280          */
  281         M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK);
  282         *mtod(mreq, uint32_t *) =
  283             htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t)));
  284 
  285         cr->cr_xid = xid;
  286         mtx_lock(&ct->ct_lock);
  287         /*
  288          * Check to see if the client end has already started to close down
  289          * the connection. The svc code will have set ct_error.re_status
  290          * to RPC_CANTRECV if this is the case.
  291          * If the client starts to close down the connection after this
  292          * point, it will be detected later when cr_error is checked,
  293          * since the request is in the ct_pending queue.
  294          */
  295         if (ct->ct_error.re_status == RPC_CANTRECV) {
  296                 if (errp != &ct->ct_error) {
  297                         errp->re_errno = ct->ct_error.re_errno;
  298                         errp->re_status = RPC_CANTRECV;
  299                 }
  300                 stat = RPC_CANTRECV;
  301                 goto out;
  302         }
  303         TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link);
  304         mtx_unlock(&ct->ct_lock);
  305 
  306         /* For RPC-over-TLS, copy mrep to a chain of ext_pgs. */
  307         if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0) {
  308                 /*
  309                  * Copy the mbuf chain to a chain of
  310                  * ext_pgs mbuf(s) as required by KERN_TLS.
  311                  */
  312                 maxextsiz = TLS_MAX_MSG_SIZE_V10_2;
  313 #ifdef KERN_TLS
  314                 if (rpctls_getinfo(&maxlen, false, false))
  315                         maxextsiz = min(maxextsiz, maxlen);
  316 #endif
  317                 mreq = _rpc_copym_into_ext_pgs(mreq, maxextsiz);
  318         }
  319         /*
  320          * sosend consumes mreq.
  321          */
  322         sx_xlock(&xprt->xp_lock);
  323         error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread);
  324 if (error != 0) printf("sosend=%d\n", error);
  325         mreq = NULL;
  326         if (error == EMSGSIZE) {
  327 printf("emsgsize\n");
  328                 SOCKBUF_LOCK(&xprt->xp_socket->so_snd);
  329                 sbwait(xprt->xp_socket, SO_SND);
  330                 SOCKBUF_UNLOCK(&xprt->xp_socket->so_snd);
  331                 sx_xunlock(&xprt->xp_lock);
  332                 AUTH_VALIDATE(auth, xid, NULL, NULL);
  333                 mtx_lock(&ct->ct_lock);
  334                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  335                 goto call_again;
  336         }
  337         sx_xunlock(&xprt->xp_lock);
  338 
  339         reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
  340         reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
  341         reply_msg.acpted_rply.ar_verf.oa_length = 0;
  342         reply_msg.acpted_rply.ar_results.where = NULL;
  343         reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
  344 
  345         mtx_lock(&ct->ct_lock);
  346         if (error) {
  347                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  348                 errp->re_errno = error;
  349                 errp->re_status = stat = RPC_CANTSEND;
  350                 goto out;
  351         }
  352 
  353         /*
  354          * Check to see if we got an upcall while waiting for the
  355          * lock. In both these cases, the request has been removed
  356          * from ct->ct_pending.
  357          */
  358         if (cr->cr_error) {
  359                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  360                 errp->re_errno = cr->cr_error;
  361                 errp->re_status = stat = RPC_CANTRECV;
  362                 goto out;
  363         }
  364         if (cr->cr_mrep) {
  365                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  366                 goto got_reply;
  367         }
  368 
  369         /*
  370          * Hack to provide rpc-based message passing
  371          */
  372         if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
  373                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  374                 errp->re_status = stat = RPC_TIMEDOUT;
  375                 goto out;
  376         }
  377 
  378         error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan,
  379             tvtohz(&timeout));
  380 
  381         TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  382 
  383         if (error) {
  384                 /*
  385                  * The sleep returned an error so our request is still
  386                  * on the list. Turn the error code into an
  387                  * appropriate client status.
  388                  */
  389                 errp->re_errno = error;
  390                 switch (error) {
  391                 case EINTR:
  392                         stat = RPC_INTR;
  393                         break;
  394                 case EWOULDBLOCK:
  395                         stat = RPC_TIMEDOUT;
  396                         break;
  397                 default:
  398                         stat = RPC_CANTRECV;
  399                 }
  400                 errp->re_status = stat;
  401                 goto out;
  402         } else {
  403                 /*
  404                  * We were woken up by the svc thread.  If the
  405                  * upcall had a receive error, report that,
  406                  * otherwise we have a reply.
  407                  */
  408                 if (cr->cr_error) {
  409                         errp->re_errno = cr->cr_error;
  410                         errp->re_status = stat = RPC_CANTRECV;
  411                         goto out;
  412                 }
  413         }
  414 
  415 got_reply:
  416         /*
  417          * Now decode and validate the response. We need to drop the
  418          * lock since xdr_replymsg may end up sleeping in malloc.
  419          */
  420         mtx_unlock(&ct->ct_lock);
  421 
  422         if (ext && ext->rc_feedback)
  423                 ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
  424 
  425         xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
  426         ok = xdr_replymsg(&xdrs, &reply_msg);
  427         cr->cr_mrep = NULL;
  428 
  429         if (ok) {
  430                 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
  431                     (reply_msg.acpted_rply.ar_stat == SUCCESS))
  432                         errp->re_status = stat = RPC_SUCCESS;
  433                 else
  434                         stat = _seterr_reply(&reply_msg, errp);
  435 
  436                 if (stat == RPC_SUCCESS) {
  437                         results = xdrmbuf_getall(&xdrs);
  438                         if (!AUTH_VALIDATE(auth, xid,
  439                             &reply_msg.acpted_rply.ar_verf, &results)) {
  440                                 errp->re_status = stat = RPC_AUTHERROR;
  441                                 errp->re_why = AUTH_INVALIDRESP;
  442                         } else {
  443                                 KASSERT(results,
  444                                     ("auth validated but no result"));
  445                                 *resultsp = results;
  446                         }
  447                 }               /* end successful completion */
  448                 /*
  449                  * If unsuccessful AND error is an authentication error
  450                  * then refresh credentials and try again, else break
  451                  */
  452                 else if (stat == RPC_AUTHERROR)
  453                         /* maybe our credentials need to be refreshed ... */
  454                         if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) {
  455                                 nrefreshes--;
  456                                 XDR_DESTROY(&xdrs);
  457                                 mtx_lock(&ct->ct_lock);
  458                                 goto call_again;
  459                         }
  460                         /* end of unsuccessful completion */
  461                 /* end of valid reply message */
  462         } else
  463                 errp->re_status = stat = RPC_CANTDECODERES;
  464         XDR_DESTROY(&xdrs);
  465         mtx_lock(&ct->ct_lock);
  466 out:
  467         mtx_assert(&ct->ct_lock, MA_OWNED);
  468 
  469         KASSERT(stat != RPC_SUCCESS || *resultsp,
  470             ("RPC_SUCCESS without reply"));
  471 
  472         if (mreq != NULL)
  473                 m_freem(mreq);
  474         if (cr->cr_mrep != NULL)
  475                 m_freem(cr->cr_mrep);
  476 
  477         ct->ct_threads--;
  478         if (ct->ct_closing)
  479                 wakeup(ct);
  480                 
  481         mtx_unlock(&ct->ct_lock);
  482 
  483         if (auth && stat != RPC_SUCCESS)
  484                 AUTH_VALIDATE(auth, xid, NULL, NULL);
  485 
  486         free(cr, M_RPC);
  487 
  488         return (stat);
  489 }
  490 
  491 static void
  492 clnt_bck_geterr(CLIENT *cl, struct rpc_err *errp)
  493 {
  494         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  495 
  496         *errp = ct->ct_error;
  497 }
  498 
  499 static bool_t
  500 clnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
  501 {
  502         XDR xdrs;
  503         bool_t dummy;
  504 
  505         xdrs.x_op = XDR_FREE;
  506         dummy = (*xdr_res)(&xdrs, res_ptr);
  507 
  508         return (dummy);
  509 }
  510 
  511 /*ARGSUSED*/
  512 static void
  513 clnt_bck_abort(CLIENT *cl)
  514 {
  515 }
  516 
  517 static bool_t
  518 clnt_bck_control(CLIENT *cl, u_int request, void *info)
  519 {
  520 
  521         return (TRUE);
  522 }
  523 
  524 static void
  525 clnt_bck_close(CLIENT *cl)
  526 {
  527         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  528 
  529         mtx_lock(&ct->ct_lock);
  530 
  531         if (ct->ct_closed) {
  532                 mtx_unlock(&ct->ct_lock);
  533                 return;
  534         }
  535 
  536         if (ct->ct_closing) {
  537                 while (ct->ct_closing)
  538                         msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
  539                 KASSERT(ct->ct_closed, ("client should be closed"));
  540                 mtx_unlock(&ct->ct_lock);
  541                 return;
  542         }
  543 
  544         ct->ct_closing = FALSE;
  545         ct->ct_closed = TRUE;
  546         mtx_unlock(&ct->ct_lock);
  547         wakeup(ct);
  548 }
  549 
  550 static void
  551 clnt_bck_destroy(CLIENT *cl)
  552 {
  553         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  554 
  555         clnt_bck_close(cl);
  556 
  557         mtx_destroy(&ct->ct_lock);
  558         mem_free(ct, sizeof(struct ct_data));
  559         if (cl->cl_netid && cl->cl_netid[0])
  560                 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
  561         if (cl->cl_tp && cl->cl_tp[0])
  562                 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
  563         mem_free(cl, sizeof(CLIENT));
  564 }
  565 
  566 /*
  567  * This call is done by the svc code when a backchannel RPC reply is
  568  * received.
  569  * For the server end, where callback RPCs to the client are performed,
  570  * xp_p2 points to the "CLIENT" and not the associated "struct ct_data"
  571  * so that svc_vc_destroy() can CLNT_RELEASE() the reference count on it.
  572  */
  573 void
  574 clnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid)
  575 {
  576         CLIENT *cl = (CLIENT *)arg;
  577         struct ct_data *ct;
  578         struct ct_request *cr;
  579         int foundreq;
  580 
  581         ct = (struct ct_data *)cl->cl_private;
  582         mtx_lock(&ct->ct_lock);
  583         if (ct->ct_closing || ct->ct_closed) {
  584                 mtx_unlock(&ct->ct_lock);
  585                 m_freem(mrep);
  586                 return;
  587         }
  588 
  589         ct->ct_upcallrefs++;
  590         /*
  591          * See if we can match this reply to a request.
  592          */
  593         foundreq = 0;
  594         TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
  595                 if (cr->cr_xid == xid) {
  596                         /*
  597                          * This one matches. We leave the reply mbuf list in
  598                          * cr->cr_mrep. Set the XID to zero so that we will
  599                          * ignore any duplicated replies.
  600                          */
  601                         cr->cr_xid = 0;
  602                         cr->cr_mrep = mrep;
  603                         cr->cr_error = 0;
  604                         foundreq = 1;
  605                         wakeup(cr);
  606                         break;
  607                 }
  608         }
  609 
  610         ct->ct_upcallrefs--;
  611         if (ct->ct_upcallrefs < 0)
  612                 panic("rpcvc svccall refcnt");
  613         if (ct->ct_upcallrefs == 0)
  614                 wakeup(&ct->ct_upcallrefs);
  615         mtx_unlock(&ct->ct_lock);
  616         if (foundreq == 0)
  617                 m_freem(mrep);
  618 }
  619 

Cache object: a664ae10d82f253dcb35eb85823b8fef


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.