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: releng/10.2/sys/rpc/clnt_bck.c 269398 2014-08-01 21:10:41Z rmacklem $");
   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 <sys/param.h>
   65 #include <sys/systm.h>
   66 #include <sys/lock.h>
   67 #include <sys/malloc.h>
   68 #include <sys/mbuf.h>
   69 #include <sys/mutex.h>
   70 #include <sys/pcpu.h>
   71 #include <sys/proc.h>
   72 #include <sys/protosw.h>
   73 #include <sys/socket.h>
   74 #include <sys/socketvar.h>
   75 #include <sys/sx.h>
   76 #include <sys/syslog.h>
   77 #include <sys/time.h>
   78 #include <sys/uio.h>
   79 
   80 #include <net/vnet.h>
   81 
   82 #include <netinet/tcp.h>
   83 
   84 #include <rpc/rpc.h>
   85 #include <rpc/rpc_com.h>
   86 #include <rpc/krpc.h>
   87 
   88 struct cmessage {
   89         struct cmsghdr cmsg;
   90         struct cmsgcred cmcred;
   91 };
   92 
   93 static void clnt_bck_geterr(CLIENT *, struct rpc_err *);
   94 static bool_t clnt_bck_freeres(CLIENT *, xdrproc_t, void *);
   95 static void clnt_bck_abort(CLIENT *);
   96 static bool_t clnt_bck_control(CLIENT *, u_int, void *);
   97 static void clnt_bck_close(CLIENT *);
   98 static void clnt_bck_destroy(CLIENT *);
   99 
  100 static struct clnt_ops clnt_bck_ops = {
  101         .cl_abort =     clnt_bck_abort,
  102         .cl_geterr =    clnt_bck_geterr,
  103         .cl_freeres =   clnt_bck_freeres,
  104         .cl_close =     clnt_bck_close,
  105         .cl_destroy =   clnt_bck_destroy,
  106         .cl_control =   clnt_bck_control
  107 };
  108 
  109 /*
  110  * Create a client handle for a connection.
  111  * Default options are set, which the user can change using clnt_control()'s.
  112  * This code handles the special case of an NFSv4.1 session backchannel
  113  * call, which is sent on a TCP connection created against the server
  114  * by a client.
  115  */
  116 void *
  117 clnt_bck_create(
  118         struct socket *so,              /* Server transport socket. */
  119         const rpcprog_t prog,           /* program number */
  120         const rpcvers_t vers)           /* version number */
  121 {
  122         CLIENT *cl;                     /* client handle */
  123         struct ct_data *ct = NULL;      /* client handle */
  124         struct timeval now;
  125         struct rpc_msg call_msg;
  126         static uint32_t disrupt;
  127         XDR xdrs;
  128 
  129         if (disrupt == 0)
  130                 disrupt = (uint32_t)(long)so;
  131 
  132         cl = (CLIENT *)mem_alloc(sizeof (*cl));
  133         ct = (struct ct_data *)mem_alloc(sizeof (*ct));
  134 
  135         mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF);
  136         ct->ct_threads = 0;
  137         ct->ct_closing = FALSE;
  138         ct->ct_closed = FALSE;
  139         ct->ct_upcallrefs = 0;
  140         ct->ct_closeit = FALSE;
  141 
  142         /*
  143          * Set up private data struct
  144          */
  145         ct->ct_wait.tv_sec = -1;
  146         ct->ct_wait.tv_usec = -1;
  147 
  148         /*
  149          * Initialize call message
  150          */
  151         getmicrotime(&now);
  152         ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now);
  153         call_msg.rm_xid = ct->ct_xid;
  154         call_msg.rm_direction = CALL;
  155         call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  156         call_msg.rm_call.cb_prog = (uint32_t)prog;
  157         call_msg.rm_call.cb_vers = (uint32_t)vers;
  158 
  159         /*
  160          * pre-serialize the static part of the call msg and stash it away
  161          */
  162         xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE,
  163             XDR_ENCODE);
  164         if (!xdr_callhdr(&xdrs, &call_msg))
  165                 goto err;
  166         ct->ct_mpos = XDR_GETPOS(&xdrs);
  167         XDR_DESTROY(&xdrs);
  168         ct->ct_waitchan = "rpcbck";
  169         ct->ct_waitflag = 0;
  170         cl->cl_refs = 1;
  171         cl->cl_ops = &clnt_bck_ops;
  172         cl->cl_private = ct;
  173         cl->cl_auth = authnone_create();
  174         TAILQ_INIT(&ct->ct_pending);
  175         return (cl);
  176 
  177 err:
  178         if (cl) {
  179                 if (ct) {
  180                         mtx_destroy(&ct->ct_lock);
  181                         mem_free(ct, sizeof (struct ct_data));
  182                 }
  183                 if (cl)
  184                         mem_free(cl, sizeof (CLIENT));
  185         }
  186         return (NULL);
  187 }
  188 
  189 enum clnt_stat
  190 clnt_bck_call(
  191         CLIENT          *cl,            /* client handle */
  192         struct rpc_callextra *ext,      /* call metadata */
  193         rpcproc_t       proc,           /* procedure number */
  194         struct mbuf     *args,          /* pointer to args */
  195         struct mbuf     **resultsp,     /* pointer to results */
  196         struct timeval  utimeout,
  197         SVCXPRT         *xprt)
  198 {
  199         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  200         AUTH *auth;
  201         struct rpc_err *errp;
  202         enum clnt_stat stat;
  203         XDR xdrs;
  204         struct rpc_msg reply_msg;
  205         bool_t ok;
  206         int nrefreshes = 2;             /* number of times to refresh cred */
  207         struct timeval timeout;
  208         uint32_t xid;
  209         struct mbuf *mreq = NULL, *results;
  210         struct ct_request *cr;
  211         int error;
  212 
  213         cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
  214 
  215         mtx_lock(&ct->ct_lock);
  216 
  217         if (ct->ct_closing || ct->ct_closed) {
  218                 mtx_unlock(&ct->ct_lock);
  219                 free(cr, M_RPC);
  220                 return (RPC_CANTSEND);
  221         }
  222         ct->ct_threads++;
  223 
  224         if (ext) {
  225                 auth = ext->rc_auth;
  226                 errp = &ext->rc_err;
  227         } else {
  228                 auth = cl->cl_auth;
  229                 errp = &ct->ct_error;
  230         }
  231 
  232         cr->cr_mrep = NULL;
  233         cr->cr_error = 0;
  234 
  235         if (ct->ct_wait.tv_usec == -1)
  236                 timeout = utimeout;     /* use supplied timeout */
  237         else
  238                 timeout = ct->ct_wait;  /* use default timeout */
  239 
  240 call_again:
  241         mtx_assert(&ct->ct_lock, MA_OWNED);
  242 
  243         ct->ct_xid++;
  244         xid = ct->ct_xid;
  245 
  246         mtx_unlock(&ct->ct_lock);
  247 
  248         /*
  249          * Leave space to pre-pend the record mark.
  250          */
  251         mreq = m_gethdr(M_WAITOK, MT_DATA);
  252         mreq->m_data += sizeof(uint32_t);
  253         KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN,
  254             ("RPC header too big"));
  255         bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos);
  256         mreq->m_len = ct->ct_mpos;
  257 
  258         /*
  259          * The XID is the first thing in the request.
  260          */
  261         *mtod(mreq, uint32_t *) = htonl(xid);
  262 
  263         xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
  264 
  265         errp->re_status = stat = RPC_SUCCESS;
  266 
  267         if ((!XDR_PUTINT32(&xdrs, &proc)) ||
  268             (!AUTH_MARSHALL(auth, xid, &xdrs,
  269              m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
  270                 errp->re_status = stat = RPC_CANTENCODEARGS;
  271                 mtx_lock(&ct->ct_lock);
  272                 goto out;
  273         }
  274         mreq->m_pkthdr.len = m_length(mreq, NULL);
  275 
  276         /*
  277          * Prepend a record marker containing the packet length.
  278          */
  279         M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK);
  280         *mtod(mreq, uint32_t *) =
  281             htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t)));
  282 
  283         cr->cr_xid = xid;
  284         mtx_lock(&ct->ct_lock);
  285         /*
  286          * Check to see if the client end has already started to close down
  287          * the connection. The svc code will have set ct_error.re_status
  288          * to RPC_CANTRECV if this is the case.
  289          * If the client starts to close down the connection after this
  290          * point, it will be detected later when cr_error is checked,
  291          * since the request is in the ct_pending queue.
  292          */
  293         if (ct->ct_error.re_status == RPC_CANTRECV) {
  294                 if (errp != &ct->ct_error) {
  295                         errp->re_errno = ct->ct_error.re_errno;
  296                         errp->re_status = RPC_CANTRECV;
  297                 }
  298                 stat = RPC_CANTRECV;
  299                 goto out;
  300         }
  301         TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link);
  302         mtx_unlock(&ct->ct_lock);
  303 
  304         /*
  305          * sosend consumes mreq.
  306          */
  307         sx_xlock(&xprt->xp_lock);
  308         error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread);
  309 if (error != 0) printf("sosend=%d\n", error);
  310         mreq = NULL;
  311         if (error == EMSGSIZE) {
  312 printf("emsgsize\n");
  313                 SOCKBUF_LOCK(&xprt->xp_socket->so_snd);
  314                 sbwait(&xprt->xp_socket->so_snd);
  315                 SOCKBUF_UNLOCK(&xprt->xp_socket->so_snd);
  316                 sx_xunlock(&xprt->xp_lock);
  317                 AUTH_VALIDATE(auth, xid, NULL, NULL);
  318                 mtx_lock(&ct->ct_lock);
  319                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  320                 goto call_again;
  321         }
  322         sx_xunlock(&xprt->xp_lock);
  323 
  324         reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
  325         reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
  326         reply_msg.acpted_rply.ar_verf.oa_length = 0;
  327         reply_msg.acpted_rply.ar_results.where = NULL;
  328         reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
  329 
  330         mtx_lock(&ct->ct_lock);
  331         if (error) {
  332                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  333                 errp->re_errno = error;
  334                 errp->re_status = stat = RPC_CANTSEND;
  335                 goto out;
  336         }
  337 
  338         /*
  339          * Check to see if we got an upcall while waiting for the
  340          * lock. In both these cases, the request has been removed
  341          * from ct->ct_pending.
  342          */
  343         if (cr->cr_error) {
  344                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  345                 errp->re_errno = cr->cr_error;
  346                 errp->re_status = stat = RPC_CANTRECV;
  347                 goto out;
  348         }
  349         if (cr->cr_mrep) {
  350                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  351                 goto got_reply;
  352         }
  353 
  354         /*
  355          * Hack to provide rpc-based message passing
  356          */
  357         if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
  358                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  359                 errp->re_status = stat = RPC_TIMEDOUT;
  360                 goto out;
  361         }
  362 
  363         error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan,
  364             tvtohz(&timeout));
  365 
  366         TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  367 
  368         if (error) {
  369                 /*
  370                  * The sleep returned an error so our request is still
  371                  * on the list. Turn the error code into an
  372                  * appropriate client status.
  373                  */
  374                 errp->re_errno = error;
  375                 switch (error) {
  376                 case EINTR:
  377                         stat = RPC_INTR;
  378                         break;
  379                 case EWOULDBLOCK:
  380                         stat = RPC_TIMEDOUT;
  381                         break;
  382                 default:
  383                         stat = RPC_CANTRECV;
  384                 };
  385                 errp->re_status = stat;
  386                 goto out;
  387         } else {
  388                 /*
  389                  * We were woken up by the svc thread.  If the
  390                  * upcall had a receive error, report that,
  391                  * otherwise we have a reply.
  392                  */
  393                 if (cr->cr_error) {
  394                         errp->re_errno = cr->cr_error;
  395                         errp->re_status = stat = RPC_CANTRECV;
  396                         goto out;
  397                 }
  398         }
  399 
  400 got_reply:
  401         /*
  402          * Now decode and validate the response. We need to drop the
  403          * lock since xdr_replymsg may end up sleeping in malloc.
  404          */
  405         mtx_unlock(&ct->ct_lock);
  406 
  407         if (ext && ext->rc_feedback)
  408                 ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
  409 
  410         xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
  411         ok = xdr_replymsg(&xdrs, &reply_msg);
  412         cr->cr_mrep = NULL;
  413 
  414         if (ok) {
  415                 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
  416                     (reply_msg.acpted_rply.ar_stat == SUCCESS))
  417                         errp->re_status = stat = RPC_SUCCESS;
  418                 else
  419                         stat = _seterr_reply(&reply_msg, errp);
  420 
  421                 if (stat == RPC_SUCCESS) {
  422                         results = xdrmbuf_getall(&xdrs);
  423                         if (!AUTH_VALIDATE(auth, xid,
  424                             &reply_msg.acpted_rply.ar_verf, &results)) {
  425                                 errp->re_status = stat = RPC_AUTHERROR;
  426                                 errp->re_why = AUTH_INVALIDRESP;
  427                         } else {
  428                                 KASSERT(results,
  429                                     ("auth validated but no result"));
  430                                 *resultsp = results;
  431                         }
  432                 }               /* end successful completion */
  433                 /*
  434                  * If unsuccesful AND error is an authentication error
  435                  * then refresh credentials and try again, else break
  436                  */
  437                 else if (stat == RPC_AUTHERROR)
  438                         /* maybe our credentials need to be refreshed ... */
  439                         if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) {
  440                                 nrefreshes--;
  441                                 XDR_DESTROY(&xdrs);
  442                                 mtx_lock(&ct->ct_lock);
  443                                 goto call_again;
  444                         }
  445                         /* end of unsuccessful completion */
  446                 /* end of valid reply message */
  447         } else
  448                 errp->re_status = stat = RPC_CANTDECODERES;
  449         XDR_DESTROY(&xdrs);
  450         mtx_lock(&ct->ct_lock);
  451 out:
  452         mtx_assert(&ct->ct_lock, MA_OWNED);
  453 
  454         KASSERT(stat != RPC_SUCCESS || *resultsp,
  455             ("RPC_SUCCESS without reply"));
  456 
  457         if (mreq != NULL)
  458                 m_freem(mreq);
  459         if (cr->cr_mrep != NULL)
  460                 m_freem(cr->cr_mrep);
  461 
  462         ct->ct_threads--;
  463         if (ct->ct_closing)
  464                 wakeup(ct);
  465                 
  466         mtx_unlock(&ct->ct_lock);
  467 
  468         if (auth && stat != RPC_SUCCESS)
  469                 AUTH_VALIDATE(auth, xid, NULL, NULL);
  470 
  471         free(cr, M_RPC);
  472 
  473         return (stat);
  474 }
  475 
  476 static void
  477 clnt_bck_geterr(CLIENT *cl, struct rpc_err *errp)
  478 {
  479         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  480 
  481         *errp = ct->ct_error;
  482 }
  483 
  484 static bool_t
  485 clnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
  486 {
  487         XDR xdrs;
  488         bool_t dummy;
  489 
  490         xdrs.x_op = XDR_FREE;
  491         dummy = (*xdr_res)(&xdrs, res_ptr);
  492 
  493         return (dummy);
  494 }
  495 
  496 /*ARGSUSED*/
  497 static void
  498 clnt_bck_abort(CLIENT *cl)
  499 {
  500 }
  501 
  502 static bool_t
  503 clnt_bck_control(CLIENT *cl, u_int request, void *info)
  504 {
  505 
  506         return (TRUE);
  507 }
  508 
  509 static void
  510 clnt_bck_close(CLIENT *cl)
  511 {
  512         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  513 
  514         mtx_lock(&ct->ct_lock);
  515 
  516         if (ct->ct_closed) {
  517                 mtx_unlock(&ct->ct_lock);
  518                 return;
  519         }
  520 
  521         if (ct->ct_closing) {
  522                 while (ct->ct_closing)
  523                         msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
  524                 KASSERT(ct->ct_closed, ("client should be closed"));
  525                 mtx_unlock(&ct->ct_lock);
  526                 return;
  527         }
  528 
  529         ct->ct_closing = FALSE;
  530         ct->ct_closed = TRUE;
  531         mtx_unlock(&ct->ct_lock);
  532         wakeup(ct);
  533 }
  534 
  535 static void
  536 clnt_bck_destroy(CLIENT *cl)
  537 {
  538         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  539 
  540         clnt_bck_close(cl);
  541 
  542         mtx_destroy(&ct->ct_lock);
  543         mem_free(ct, sizeof(struct ct_data));
  544         if (cl->cl_netid && cl->cl_netid[0])
  545                 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
  546         if (cl->cl_tp && cl->cl_tp[0])
  547                 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
  548         mem_free(cl, sizeof(CLIENT));
  549 }
  550 
  551 /*
  552  * This call is done by the svc code when a backchannel RPC reply is
  553  * received.
  554  */
  555 void
  556 clnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid)
  557 {
  558         struct ct_data *ct = (struct ct_data *)arg;
  559         struct ct_request *cr;
  560         int foundreq;
  561 
  562         mtx_lock(&ct->ct_lock);
  563         ct->ct_upcallrefs++;
  564         /*
  565          * See if we can match this reply to a request.
  566          */
  567         foundreq = 0;
  568         TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
  569                 if (cr->cr_xid == xid) {
  570                         /*
  571                          * This one matches. We leave the reply mbuf list in
  572                          * cr->cr_mrep. Set the XID to zero so that we will
  573                          * ignore any duplicated replies.
  574                          */
  575                         cr->cr_xid = 0;
  576                         cr->cr_mrep = mrep;
  577                         cr->cr_error = 0;
  578                         foundreq = 1;
  579                         wakeup(cr);
  580                         break;
  581                 }
  582         }
  583 
  584         ct->ct_upcallrefs--;
  585         if (ct->ct_upcallrefs < 0)
  586                 panic("rpcvc svccall refcnt");
  587         if (ct->ct_upcallrefs == 0)
  588                 wakeup(&ct->ct_upcallrefs);
  589         mtx_unlock(&ct->ct_lock);
  590         if (foundreq == 0)
  591                 m_freem(mrep);
  592 }
  593 

Cache object: c6608340643569ab1c18f38308d84448


[ 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.