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.4/sys/rpc/clnt_bck.c 302451 2016-07-08 20:30:20Z ngie $");
   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         mtx_destroy(&ct->ct_lock);
  179         mem_free(ct, sizeof (struct ct_data));
  180         mem_free(cl, sizeof (CLIENT));
  181         return (NULL);
  182 }
  183 
  184 enum clnt_stat
  185 clnt_bck_call(
  186         CLIENT          *cl,            /* client handle */
  187         struct rpc_callextra *ext,      /* call metadata */
  188         rpcproc_t       proc,           /* procedure number */
  189         struct mbuf     *args,          /* pointer to args */
  190         struct mbuf     **resultsp,     /* pointer to results */
  191         struct timeval  utimeout,
  192         SVCXPRT         *xprt)
  193 {
  194         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  195         AUTH *auth;
  196         struct rpc_err *errp;
  197         enum clnt_stat stat;
  198         XDR xdrs;
  199         struct rpc_msg reply_msg;
  200         bool_t ok;
  201         int nrefreshes = 2;             /* number of times to refresh cred */
  202         struct timeval timeout;
  203         uint32_t xid;
  204         struct mbuf *mreq = NULL, *results;
  205         struct ct_request *cr;
  206         int error;
  207 
  208         cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
  209 
  210         mtx_lock(&ct->ct_lock);
  211 
  212         if (ct->ct_closing || ct->ct_closed) {
  213                 mtx_unlock(&ct->ct_lock);
  214                 free(cr, M_RPC);
  215                 return (RPC_CANTSEND);
  216         }
  217         ct->ct_threads++;
  218 
  219         if (ext) {
  220                 auth = ext->rc_auth;
  221                 errp = &ext->rc_err;
  222         } else {
  223                 auth = cl->cl_auth;
  224                 errp = &ct->ct_error;
  225         }
  226 
  227         cr->cr_mrep = NULL;
  228         cr->cr_error = 0;
  229 
  230         if (ct->ct_wait.tv_usec == -1)
  231                 timeout = utimeout;     /* use supplied timeout */
  232         else
  233                 timeout = ct->ct_wait;  /* use default timeout */
  234 
  235 call_again:
  236         mtx_assert(&ct->ct_lock, MA_OWNED);
  237 
  238         ct->ct_xid++;
  239         xid = ct->ct_xid;
  240 
  241         mtx_unlock(&ct->ct_lock);
  242 
  243         /*
  244          * Leave space to pre-pend the record mark.
  245          */
  246         mreq = m_gethdr(M_WAITOK, MT_DATA);
  247         mreq->m_data += sizeof(uint32_t);
  248         KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN,
  249             ("RPC header too big"));
  250         bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos);
  251         mreq->m_len = ct->ct_mpos;
  252 
  253         /*
  254          * The XID is the first thing in the request.
  255          */
  256         *mtod(mreq, uint32_t *) = htonl(xid);
  257 
  258         xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
  259 
  260         errp->re_status = stat = RPC_SUCCESS;
  261 
  262         if ((!XDR_PUTINT32(&xdrs, &proc)) ||
  263             (!AUTH_MARSHALL(auth, xid, &xdrs,
  264              m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
  265                 errp->re_status = stat = RPC_CANTENCODEARGS;
  266                 mtx_lock(&ct->ct_lock);
  267                 goto out;
  268         }
  269         mreq->m_pkthdr.len = m_length(mreq, NULL);
  270 
  271         /*
  272          * Prepend a record marker containing the packet length.
  273          */
  274         M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK);
  275         *mtod(mreq, uint32_t *) =
  276             htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t)));
  277 
  278         cr->cr_xid = xid;
  279         mtx_lock(&ct->ct_lock);
  280         /*
  281          * Check to see if the client end has already started to close down
  282          * the connection. The svc code will have set ct_error.re_status
  283          * to RPC_CANTRECV if this is the case.
  284          * If the client starts to close down the connection after this
  285          * point, it will be detected later when cr_error is checked,
  286          * since the request is in the ct_pending queue.
  287          */
  288         if (ct->ct_error.re_status == RPC_CANTRECV) {
  289                 if (errp != &ct->ct_error) {
  290                         errp->re_errno = ct->ct_error.re_errno;
  291                         errp->re_status = RPC_CANTRECV;
  292                 }
  293                 stat = RPC_CANTRECV;
  294                 goto out;
  295         }
  296         TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link);
  297         mtx_unlock(&ct->ct_lock);
  298 
  299         /*
  300          * sosend consumes mreq.
  301          */
  302         sx_xlock(&xprt->xp_lock);
  303         error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread);
  304 if (error != 0) printf("sosend=%d\n", error);
  305         mreq = NULL;
  306         if (error == EMSGSIZE) {
  307 printf("emsgsize\n");
  308                 SOCKBUF_LOCK(&xprt->xp_socket->so_snd);
  309                 sbwait(&xprt->xp_socket->so_snd);
  310                 SOCKBUF_UNLOCK(&xprt->xp_socket->so_snd);
  311                 sx_xunlock(&xprt->xp_lock);
  312                 AUTH_VALIDATE(auth, xid, NULL, NULL);
  313                 mtx_lock(&ct->ct_lock);
  314                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  315                 goto call_again;
  316         }
  317         sx_xunlock(&xprt->xp_lock);
  318 
  319         reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
  320         reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
  321         reply_msg.acpted_rply.ar_verf.oa_length = 0;
  322         reply_msg.acpted_rply.ar_results.where = NULL;
  323         reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
  324 
  325         mtx_lock(&ct->ct_lock);
  326         if (error) {
  327                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  328                 errp->re_errno = error;
  329                 errp->re_status = stat = RPC_CANTSEND;
  330                 goto out;
  331         }
  332 
  333         /*
  334          * Check to see if we got an upcall while waiting for the
  335          * lock. In both these cases, the request has been removed
  336          * from ct->ct_pending.
  337          */
  338         if (cr->cr_error) {
  339                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  340                 errp->re_errno = cr->cr_error;
  341                 errp->re_status = stat = RPC_CANTRECV;
  342                 goto out;
  343         }
  344         if (cr->cr_mrep) {
  345                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  346                 goto got_reply;
  347         }
  348 
  349         /*
  350          * Hack to provide rpc-based message passing
  351          */
  352         if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
  353                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  354                 errp->re_status = stat = RPC_TIMEDOUT;
  355                 goto out;
  356         }
  357 
  358         error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan,
  359             tvtohz(&timeout));
  360 
  361         TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
  362 
  363         if (error) {
  364                 /*
  365                  * The sleep returned an error so our request is still
  366                  * on the list. Turn the error code into an
  367                  * appropriate client status.
  368                  */
  369                 errp->re_errno = error;
  370                 switch (error) {
  371                 case EINTR:
  372                         stat = RPC_INTR;
  373                         break;
  374                 case EWOULDBLOCK:
  375                         stat = RPC_TIMEDOUT;
  376                         break;
  377                 default:
  378                         stat = RPC_CANTRECV;
  379                 };
  380                 errp->re_status = stat;
  381                 goto out;
  382         } else {
  383                 /*
  384                  * We were woken up by the svc thread.  If the
  385                  * upcall had a receive error, report that,
  386                  * otherwise we have a reply.
  387                  */
  388                 if (cr->cr_error) {
  389                         errp->re_errno = cr->cr_error;
  390                         errp->re_status = stat = RPC_CANTRECV;
  391                         goto out;
  392                 }
  393         }
  394 
  395 got_reply:
  396         /*
  397          * Now decode and validate the response. We need to drop the
  398          * lock since xdr_replymsg may end up sleeping in malloc.
  399          */
  400         mtx_unlock(&ct->ct_lock);
  401 
  402         if (ext && ext->rc_feedback)
  403                 ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
  404 
  405         xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
  406         ok = xdr_replymsg(&xdrs, &reply_msg);
  407         cr->cr_mrep = NULL;
  408 
  409         if (ok) {
  410                 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
  411                     (reply_msg.acpted_rply.ar_stat == SUCCESS))
  412                         errp->re_status = stat = RPC_SUCCESS;
  413                 else
  414                         stat = _seterr_reply(&reply_msg, errp);
  415 
  416                 if (stat == RPC_SUCCESS) {
  417                         results = xdrmbuf_getall(&xdrs);
  418                         if (!AUTH_VALIDATE(auth, xid,
  419                             &reply_msg.acpted_rply.ar_verf, &results)) {
  420                                 errp->re_status = stat = RPC_AUTHERROR;
  421                                 errp->re_why = AUTH_INVALIDRESP;
  422                         } else {
  423                                 KASSERT(results,
  424                                     ("auth validated but no result"));
  425                                 *resultsp = results;
  426                         }
  427                 }               /* end successful completion */
  428                 /*
  429                  * If unsuccesful AND error is an authentication error
  430                  * then refresh credentials and try again, else break
  431                  */
  432                 else if (stat == RPC_AUTHERROR)
  433                         /* maybe our credentials need to be refreshed ... */
  434                         if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) {
  435                                 nrefreshes--;
  436                                 XDR_DESTROY(&xdrs);
  437                                 mtx_lock(&ct->ct_lock);
  438                                 goto call_again;
  439                         }
  440                         /* end of unsuccessful completion */
  441                 /* end of valid reply message */
  442         } else
  443                 errp->re_status = stat = RPC_CANTDECODERES;
  444         XDR_DESTROY(&xdrs);
  445         mtx_lock(&ct->ct_lock);
  446 out:
  447         mtx_assert(&ct->ct_lock, MA_OWNED);
  448 
  449         KASSERT(stat != RPC_SUCCESS || *resultsp,
  450             ("RPC_SUCCESS without reply"));
  451 
  452         if (mreq != NULL)
  453                 m_freem(mreq);
  454         if (cr->cr_mrep != NULL)
  455                 m_freem(cr->cr_mrep);
  456 
  457         ct->ct_threads--;
  458         if (ct->ct_closing)
  459                 wakeup(ct);
  460                 
  461         mtx_unlock(&ct->ct_lock);
  462 
  463         if (auth && stat != RPC_SUCCESS)
  464                 AUTH_VALIDATE(auth, xid, NULL, NULL);
  465 
  466         free(cr, M_RPC);
  467 
  468         return (stat);
  469 }
  470 
  471 static void
  472 clnt_bck_geterr(CLIENT *cl, struct rpc_err *errp)
  473 {
  474         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  475 
  476         *errp = ct->ct_error;
  477 }
  478 
  479 static bool_t
  480 clnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
  481 {
  482         XDR xdrs;
  483         bool_t dummy;
  484 
  485         xdrs.x_op = XDR_FREE;
  486         dummy = (*xdr_res)(&xdrs, res_ptr);
  487 
  488         return (dummy);
  489 }
  490 
  491 /*ARGSUSED*/
  492 static void
  493 clnt_bck_abort(CLIENT *cl)
  494 {
  495 }
  496 
  497 static bool_t
  498 clnt_bck_control(CLIENT *cl, u_int request, void *info)
  499 {
  500 
  501         return (TRUE);
  502 }
  503 
  504 static void
  505 clnt_bck_close(CLIENT *cl)
  506 {
  507         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  508 
  509         mtx_lock(&ct->ct_lock);
  510 
  511         if (ct->ct_closed) {
  512                 mtx_unlock(&ct->ct_lock);
  513                 return;
  514         }
  515 
  516         if (ct->ct_closing) {
  517                 while (ct->ct_closing)
  518                         msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
  519                 KASSERT(ct->ct_closed, ("client should be closed"));
  520                 mtx_unlock(&ct->ct_lock);
  521                 return;
  522         }
  523 
  524         ct->ct_closing = FALSE;
  525         ct->ct_closed = TRUE;
  526         mtx_unlock(&ct->ct_lock);
  527         wakeup(ct);
  528 }
  529 
  530 static void
  531 clnt_bck_destroy(CLIENT *cl)
  532 {
  533         struct ct_data *ct = (struct ct_data *) cl->cl_private;
  534 
  535         clnt_bck_close(cl);
  536 
  537         mtx_destroy(&ct->ct_lock);
  538         mem_free(ct, sizeof(struct ct_data));
  539         if (cl->cl_netid && cl->cl_netid[0])
  540                 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
  541         if (cl->cl_tp && cl->cl_tp[0])
  542                 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
  543         mem_free(cl, sizeof(CLIENT));
  544 }
  545 
  546 /*
  547  * This call is done by the svc code when a backchannel RPC reply is
  548  * received.
  549  */
  550 void
  551 clnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid)
  552 {
  553         struct ct_data *ct = (struct ct_data *)arg;
  554         struct ct_request *cr;
  555         int foundreq;
  556 
  557         mtx_lock(&ct->ct_lock);
  558         ct->ct_upcallrefs++;
  559         /*
  560          * See if we can match this reply to a request.
  561          */
  562         foundreq = 0;
  563         TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
  564                 if (cr->cr_xid == xid) {
  565                         /*
  566                          * This one matches. We leave the reply mbuf list in
  567                          * cr->cr_mrep. Set the XID to zero so that we will
  568                          * ignore any duplicated replies.
  569                          */
  570                         cr->cr_xid = 0;
  571                         cr->cr_mrep = mrep;
  572                         cr->cr_error = 0;
  573                         foundreq = 1;
  574                         wakeup(cr);
  575                         break;
  576                 }
  577         }
  578 
  579         ct->ct_upcallrefs--;
  580         if (ct->ct_upcallrefs < 0)
  581                 panic("rpcvc svccall refcnt");
  582         if (ct->ct_upcallrefs == 0)
  583                 wakeup(&ct->ct_upcallrefs);
  584         mtx_unlock(&ct->ct_lock);
  585         if (foundreq == 0)
  586                 m_freem(mrep);
  587 }
  588 

Cache object: ce1f4a8364f3ca5b9979f71f9b1eca98


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