clnt_rc.c revision 261058
1219820Sjeff/*- 2219820Sjeff * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3219820Sjeff * Authors: Doug Rabson <dfr@rabson.org> 4219820Sjeff * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5219820Sjeff * 6219820Sjeff * Redistribution and use in source and binary forms, with or without 7219820Sjeff * modification, are permitted provided that the following conditions 8219820Sjeff * are met: 9219820Sjeff * 1. Redistributions of source code must retain the above copyright 10219820Sjeff * notice, this list of conditions and the following disclaimer. 11219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 12219820Sjeff * notice, this list of conditions and the following disclaimer in the 13219820Sjeff * documentation and/or other materials provided with the distribution. 14219820Sjeff * 15219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18219820Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25219820Sjeff * SUCH DAMAGE. 26219820Sjeff */ 27219820Sjeff 28219820Sjeff#include <sys/cdefs.h> 29219820Sjeff__FBSDID("$FreeBSD: stable/9/sys/rpc/clnt_rc.c 261058 2014-01-23 00:35:41Z mav $"); 30219820Sjeff 31219820Sjeff#include <sys/param.h> 32219820Sjeff#include <sys/systm.h> 33219820Sjeff#include <sys/kernel.h> 34219820Sjeff#include <sys/limits.h> 35219820Sjeff#include <sys/lock.h> 36219820Sjeff#include <sys/malloc.h> 37219820Sjeff#include <sys/mbuf.h> 38219820Sjeff#include <sys/mutex.h> 39219820Sjeff#include <sys/pcpu.h> 40219820Sjeff#include <sys/proc.h> 41219820Sjeff#include <sys/socket.h> 42219820Sjeff#include <sys/socketvar.h> 43219820Sjeff#include <sys/time.h> 44219820Sjeff#include <sys/uio.h> 45219820Sjeff 46219820Sjeff#include <rpc/rpc.h> 47219820Sjeff#include <rpc/rpc_com.h> 48219820Sjeff#include <rpc/krpc.h> 49219820Sjeff 50219820Sjeffstatic enum clnt_stat clnt_reconnect_call(CLIENT *, struct rpc_callextra *, 51219820Sjeff rpcproc_t, struct mbuf *, struct mbuf **, struct timeval); 52219820Sjeffstatic void clnt_reconnect_geterr(CLIENT *, struct rpc_err *); 53219820Sjeffstatic bool_t clnt_reconnect_freeres(CLIENT *, xdrproc_t, void *); 54219820Sjeffstatic void clnt_reconnect_abort(CLIENT *); 55219820Sjeffstatic bool_t clnt_reconnect_control(CLIENT *, u_int, void *); 56219820Sjeffstatic void clnt_reconnect_close(CLIENT *); 57219820Sjeffstatic void clnt_reconnect_destroy(CLIENT *); 58219820Sjeff 59219820Sjeffstatic struct clnt_ops clnt_reconnect_ops = { 60219820Sjeff .cl_call = clnt_reconnect_call, 61219820Sjeff .cl_abort = clnt_reconnect_abort, 62219820Sjeff .cl_geterr = clnt_reconnect_geterr, 63219820Sjeff .cl_freeres = clnt_reconnect_freeres, 64219820Sjeff .cl_close = clnt_reconnect_close, 65219820Sjeff .cl_destroy = clnt_reconnect_destroy, 66219820Sjeff .cl_control = clnt_reconnect_control 67219820Sjeff}; 68219820Sjeff 69219820Sjeffstatic int fake_wchan; 70219820Sjeff 71219820SjeffCLIENT * 72219820Sjeffclnt_reconnect_create( 73219820Sjeff struct netconfig *nconf, /* network type */ 74219820Sjeff struct sockaddr *svcaddr, /* servers address */ 75219820Sjeff rpcprog_t program, /* program number */ 76219820Sjeff rpcvers_t version, /* version number */ 77219820Sjeff size_t sendsz, /* buffer recv size */ 78219820Sjeff size_t recvsz) /* buffer send size */ 79219820Sjeff{ 80219820Sjeff CLIENT *cl = NULL; /* client handle */ 81219820Sjeff struct rc_data *rc = NULL; /* private data */ 82219820Sjeff 83219820Sjeff if (svcaddr == NULL) { 84219820Sjeff rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 85219820Sjeff return (NULL); 86219820Sjeff } 87219820Sjeff 88219820Sjeff cl = mem_alloc(sizeof (CLIENT)); 89219820Sjeff rc = mem_alloc(sizeof (*rc)); 90219820Sjeff mtx_init(&rc->rc_lock, "rc->rc_lock", NULL, MTX_DEF); 91219820Sjeff (void) memcpy(&rc->rc_addr, svcaddr, (size_t)svcaddr->sa_len); 92219820Sjeff rc->rc_nconf = nconf; 93219820Sjeff rc->rc_prog = program; 94219820Sjeff rc->rc_vers = version; 95219820Sjeff rc->rc_sendsz = sendsz; 96219820Sjeff rc->rc_recvsz = recvsz; 97219820Sjeff rc->rc_timeout.tv_sec = -1; 98219820Sjeff rc->rc_timeout.tv_usec = -1; 99219820Sjeff rc->rc_retry.tv_sec = 3; 100219820Sjeff rc->rc_retry.tv_usec = 0; 101219820Sjeff rc->rc_retries = INT_MAX; 102219820Sjeff rc->rc_privport = FALSE; 103219820Sjeff rc->rc_waitchan = "rpcrecv"; 104219820Sjeff rc->rc_intr = 0; 105219820Sjeff rc->rc_connecting = FALSE; 106219820Sjeff rc->rc_closed = FALSE; 107219820Sjeff rc->rc_ucred = crdup(curthread->td_ucred); 108219820Sjeff rc->rc_client = NULL; 109219820Sjeff 110219820Sjeff cl->cl_refs = 1; 111219820Sjeff cl->cl_ops = &clnt_reconnect_ops; 112219820Sjeff cl->cl_private = (caddr_t)(void *)rc; 113219820Sjeff cl->cl_auth = authnone_create(); 114219820Sjeff cl->cl_tp = NULL; 115219820Sjeff cl->cl_netid = NULL; 116219820Sjeff return (cl); 117219820Sjeff} 118219820Sjeff 119219820Sjeffstatic enum clnt_stat 120219820Sjeffclnt_reconnect_connect(CLIENT *cl) 121219820Sjeff{ 122219820Sjeff struct thread *td = curthread; 123219820Sjeff struct rc_data *rc = (struct rc_data *)cl->cl_private; 124219820Sjeff struct socket *so; 125219820Sjeff enum clnt_stat stat; 126219820Sjeff int error; 127219820Sjeff int one = 1; 128219820Sjeff struct ucred *oldcred; 129219820Sjeff CLIENT *newclient = NULL; 130219820Sjeff 131219820Sjeff mtx_lock(&rc->rc_lock); 132219820Sjeff while (rc->rc_connecting) { 133219820Sjeff error = msleep(rc, &rc->rc_lock, 134219820Sjeff rc->rc_intr ? PCATCH : 0, "rpcrecon", 0); 135219820Sjeff if (error) { 136219820Sjeff mtx_unlock(&rc->rc_lock); 137219820Sjeff return (RPC_INTR); 138219820Sjeff } 139219820Sjeff } 140219820Sjeff if (rc->rc_closed) { 141219820Sjeff mtx_unlock(&rc->rc_lock); 142219820Sjeff return (RPC_CANTSEND); 143219820Sjeff } 144219820Sjeff if (rc->rc_client) { 145219820Sjeff mtx_unlock(&rc->rc_lock); 146219820Sjeff return (RPC_SUCCESS); 147219820Sjeff } 148219820Sjeff 149219820Sjeff /* 150219820Sjeff * My turn to attempt a connect. The rc_connecting variable 151219820Sjeff * serializes the following code sequence, so it is guaranteed 152219820Sjeff * that rc_client will still be NULL after it is re-locked below, 153219820Sjeff * since that is the only place it is set non-NULL. 154219820Sjeff */ 155219820Sjeff rc->rc_connecting = TRUE; 156219820Sjeff mtx_unlock(&rc->rc_lock); 157219820Sjeff 158219820Sjeff oldcred = td->td_ucred; 159219820Sjeff td->td_ucred = rc->rc_ucred; 160219820Sjeff so = __rpc_nconf2socket(rc->rc_nconf); 161219820Sjeff if (!so) { 162219820Sjeff stat = rpc_createerr.cf_stat = RPC_TLIERROR; 163219820Sjeff rpc_createerr.cf_error.re_errno = 0; 164219820Sjeff td->td_ucred = oldcred; 165219820Sjeff goto out; 166219820Sjeff } 167219820Sjeff 168219820Sjeff if (rc->rc_privport) 169219820Sjeff bindresvport(so, NULL); 170219820Sjeff 171219820Sjeff if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS) 172219820Sjeff newclient = clnt_dg_create(so, 173219820Sjeff (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers, 174219820Sjeff rc->rc_sendsz, rc->rc_recvsz); 175219820Sjeff else 176219820Sjeff newclient = clnt_vc_create(so, 177219820Sjeff (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers, 178219820Sjeff rc->rc_sendsz, rc->rc_recvsz, rc->rc_intr); 179219820Sjeff td->td_ucred = oldcred; 180219820Sjeff 181219820Sjeff if (!newclient) { 182219820Sjeff soclose(so); 183219820Sjeff rc->rc_err = rpc_createerr.cf_error; 184219820Sjeff stat = rpc_createerr.cf_stat; 185219820Sjeff goto out; 186219820Sjeff } 187219820Sjeff 188219820Sjeff CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0); 189219820Sjeff CLNT_CONTROL(newclient, CLSET_CONNECT, &one); 190219820Sjeff CLNT_CONTROL(newclient, CLSET_TIMEOUT, &rc->rc_timeout); 191219820Sjeff CLNT_CONTROL(newclient, CLSET_RETRY_TIMEOUT, &rc->rc_retry); 192219820Sjeff CLNT_CONTROL(newclient, CLSET_WAITCHAN, rc->rc_waitchan); 193219820Sjeff CLNT_CONTROL(newclient, CLSET_INTERRUPTIBLE, &rc->rc_intr); 194219820Sjeff if (rc->rc_backchannel != NULL) 195219820Sjeff CLNT_CONTROL(newclient, CLSET_BACKCHANNEL, rc->rc_backchannel); 196219820Sjeff stat = RPC_SUCCESS; 197219820Sjeff 198219820Sjeffout: 199219820Sjeff mtx_lock(&rc->rc_lock); 200219820Sjeff KASSERT(rc->rc_client == NULL, ("rc_client not null")); 201219820Sjeff if (!rc->rc_closed) { 202219820Sjeff rc->rc_client = newclient; 203219820Sjeff newclient = NULL; 204219820Sjeff } 205219820Sjeff rc->rc_connecting = FALSE; 206219820Sjeff wakeup(rc); 207219820Sjeff mtx_unlock(&rc->rc_lock); 208219820Sjeff 209219820Sjeff if (newclient) { 210219820Sjeff /* 211219820Sjeff * It has been closed, so discard the new client. 212219820Sjeff * nb: clnt_[dg|vc]_close()/clnt_[dg|vc]_destroy() cannot 213219820Sjeff * be called with the rc_lock mutex held, since they may 214219820Sjeff * msleep() while holding a different mutex. 215219820Sjeff */ 216219820Sjeff CLNT_CLOSE(newclient); 217219820Sjeff CLNT_RELEASE(newclient); 218219820Sjeff } 219219820Sjeff 220219820Sjeff return (stat); 221219820Sjeff} 222219820Sjeff 223219820Sjeffstatic enum clnt_stat 224219820Sjeffclnt_reconnect_call( 225219820Sjeff CLIENT *cl, /* client handle */ 226219820Sjeff struct rpc_callextra *ext, /* call metadata */ 227219820Sjeff rpcproc_t proc, /* procedure number */ 228219820Sjeff struct mbuf *args, /* pointer to args */ 229219820Sjeff struct mbuf **resultsp, /* pointer to results */ 230219820Sjeff struct timeval utimeout) 231219820Sjeff{ 232219820Sjeff struct rc_data *rc = (struct rc_data *)cl->cl_private; 233219820Sjeff CLIENT *client; 234219820Sjeff enum clnt_stat stat; 235219820Sjeff int tries, error; 236219820Sjeff 237219820Sjeff tries = 0; 238219820Sjeff do { 239219820Sjeff mtx_lock(&rc->rc_lock); 240219820Sjeff if (rc->rc_closed) { 241219820Sjeff mtx_unlock(&rc->rc_lock); 242219820Sjeff return (RPC_CANTSEND); 243219820Sjeff } 244219820Sjeff 245219820Sjeff if (!rc->rc_client) { 246219820Sjeff mtx_unlock(&rc->rc_lock); 247219820Sjeff stat = clnt_reconnect_connect(cl); 248219820Sjeff if (stat == RPC_SYSTEMERROR) { 249219820Sjeff error = tsleep(&fake_wchan, 250219820Sjeff rc->rc_intr ? PCATCH | PBDRY : 0, "rpccon", 251219820Sjeff hz); 252219820Sjeff if (error == EINTR || error == ERESTART) 253219820Sjeff return (RPC_INTR); 254219820Sjeff tries++; 255219820Sjeff if (tries >= rc->rc_retries) 256219820Sjeff return (stat); 257219820Sjeff continue; 258219820Sjeff } 259219820Sjeff if (stat != RPC_SUCCESS) 260219820Sjeff return (stat); 261219820Sjeff mtx_lock(&rc->rc_lock); 262219820Sjeff } 263219820Sjeff 264219820Sjeff if (!rc->rc_client) { 265219820Sjeff mtx_unlock(&rc->rc_lock); 266219820Sjeff stat = RPC_FAILED; 267219820Sjeff continue; 268219820Sjeff } 269219820Sjeff CLNT_ACQUIRE(rc->rc_client); 270219820Sjeff client = rc->rc_client; 271219820Sjeff mtx_unlock(&rc->rc_lock); 272219820Sjeff stat = CLNT_CALL_MBUF(client, ext, proc, args, 273219820Sjeff resultsp, utimeout); 274219820Sjeff 275219820Sjeff if (stat != RPC_SUCCESS) { 276219820Sjeff if (!ext) 277219820Sjeff CLNT_GETERR(client, &rc->rc_err); 278219820Sjeff } 279219820Sjeff 280219820Sjeff if (stat == RPC_TIMEDOUT) { 281219820Sjeff /* 282219820Sjeff * Check for async send misfeature for NLM 283219820Sjeff * protocol. 284219820Sjeff */ 285219820Sjeff if ((rc->rc_timeout.tv_sec == 0 286219820Sjeff && rc->rc_timeout.tv_usec == 0) 287219820Sjeff || (rc->rc_timeout.tv_sec == -1 288219820Sjeff && utimeout.tv_sec == 0 289219820Sjeff && utimeout.tv_usec == 0)) { 290219820Sjeff CLNT_RELEASE(client); 291219820Sjeff break; 292219820Sjeff } 293219820Sjeff } 294219820Sjeff 295219820Sjeff if (stat == RPC_TIMEDOUT || stat == RPC_CANTSEND 296219820Sjeff || stat == RPC_CANTRECV) { 297219820Sjeff tries++; 298219820Sjeff if (tries >= rc->rc_retries) { 299219820Sjeff CLNT_RELEASE(client); 300219820Sjeff break; 301219820Sjeff } 302219820Sjeff 303219820Sjeff if (ext && ext->rc_feedback) 304219820Sjeff ext->rc_feedback(FEEDBACK_RECONNECT, proc, 305219820Sjeff ext->rc_feedback_arg); 306219820Sjeff 307219820Sjeff mtx_lock(&rc->rc_lock); 308219820Sjeff /* 309219820Sjeff * Make sure that someone else hasn't already 310219820Sjeff * reconnected by checking if rc_client has changed. 311219820Sjeff * If not, we are done with the client and must 312219820Sjeff * do CLNT_RELEASE(client) twice to dispose of it, 313219820Sjeff * because there is both an initial refcnt and one 314219820Sjeff * acquired by CLNT_ACQUIRE() above. 315219820Sjeff */ 316219820Sjeff if (rc->rc_client == client) { 317219820Sjeff rc->rc_client = NULL; 318219820Sjeff mtx_unlock(&rc->rc_lock); 319219820Sjeff CLNT_RELEASE(client); 320219820Sjeff } else { 321219820Sjeff mtx_unlock(&rc->rc_lock); 322219820Sjeff } 323219820Sjeff CLNT_RELEASE(client); 324219820Sjeff } else { 325219820Sjeff CLNT_RELEASE(client); 326219820Sjeff break; 327219820Sjeff } 328219820Sjeff } while (stat != RPC_SUCCESS); 329219820Sjeff 330219820Sjeff KASSERT(stat != RPC_SUCCESS || *resultsp, 331219820Sjeff ("RPC_SUCCESS without reply")); 332219820Sjeff 333219820Sjeff return (stat); 334219820Sjeff} 335219820Sjeff 336219820Sjeffstatic void 337219820Sjeffclnt_reconnect_geterr(CLIENT *cl, struct rpc_err *errp) 338219820Sjeff{ 339219820Sjeff struct rc_data *rc = (struct rc_data *)cl->cl_private; 340219820Sjeff 341219820Sjeff *errp = rc->rc_err; 342219820Sjeff} 343219820Sjeff 344219820Sjeff/* 345219820Sjeff * Since this function requires that rc_client be valid, it can 346219820Sjeff * only be called when that is guaranteed to be the case. 347219820Sjeff */ 348219820Sjeffstatic bool_t 349219820Sjeffclnt_reconnect_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 350219820Sjeff{ 351219820Sjeff struct rc_data *rc = (struct rc_data *)cl->cl_private; 352219820Sjeff 353219820Sjeff return (CLNT_FREERES(rc->rc_client, xdr_res, res_ptr)); 354219820Sjeff} 355219820Sjeff 356219820Sjeff/*ARGSUSED*/ 357219820Sjeffstatic void 358219820Sjeffclnt_reconnect_abort(CLIENT *h) 359219820Sjeff{ 360219820Sjeff} 361219820Sjeff 362219820Sjeff/* 363219820Sjeff * CLNT_CONTROL() on the client returned by clnt_reconnect_create() must 364219820Sjeff * always be called before CLNT_CALL_MBUF() by a single thread only. 365219820Sjeff */ 366219820Sjeffstatic bool_t 367219820Sjeffclnt_reconnect_control(CLIENT *cl, u_int request, void *info) 368219820Sjeff{ 369219820Sjeff struct rc_data *rc = (struct rc_data *)cl->cl_private; 370219820Sjeff SVCXPRT *xprt; 371219820Sjeff 372219820Sjeff if (info == NULL) { 373219820Sjeff return (FALSE); 374219820Sjeff } 375219820Sjeff switch (request) { 376219820Sjeff case CLSET_TIMEOUT: 377219820Sjeff rc->rc_timeout = *(struct timeval *)info; 378219820Sjeff if (rc->rc_client) 379219820Sjeff CLNT_CONTROL(rc->rc_client, request, info); 380219820Sjeff break; 381219820Sjeff 382219820Sjeff case CLGET_TIMEOUT: 383219820Sjeff *(struct timeval *)info = rc->rc_timeout; 384219820Sjeff break; 385219820Sjeff 386219820Sjeff case CLSET_RETRY_TIMEOUT: 387219820Sjeff rc->rc_retry = *(struct timeval *)info; 388219820Sjeff if (rc->rc_client) 389219820Sjeff CLNT_CONTROL(rc->rc_client, request, info); 390219820Sjeff break; 391219820Sjeff 392219820Sjeff case CLGET_RETRY_TIMEOUT: 393219820Sjeff *(struct timeval *)info = rc->rc_retry; 394219820Sjeff break; 395219820Sjeff 396219820Sjeff case CLGET_VERS: 397219820Sjeff *(uint32_t *)info = rc->rc_vers; 398219820Sjeff break; 399219820Sjeff 400219820Sjeff case CLSET_VERS: 401219820Sjeff rc->rc_vers = *(uint32_t *) info; 402219820Sjeff if (rc->rc_client) 403219820Sjeff CLNT_CONTROL(rc->rc_client, CLSET_VERS, info); 404219820Sjeff break; 405219820Sjeff 406219820Sjeff case CLGET_PROG: 407219820Sjeff *(uint32_t *)info = rc->rc_prog; 408219820Sjeff break; 409219820Sjeff 410219820Sjeff case CLSET_PROG: 411219820Sjeff rc->rc_prog = *(uint32_t *) info; 412219820Sjeff if (rc->rc_client) 413219820Sjeff CLNT_CONTROL(rc->rc_client, request, info); 414219820Sjeff break; 415219820Sjeff 416219820Sjeff case CLSET_WAITCHAN: 417219820Sjeff rc->rc_waitchan = (char *)info; 418219820Sjeff if (rc->rc_client) 419219820Sjeff CLNT_CONTROL(rc->rc_client, request, info); 420219820Sjeff break; 421219820Sjeff 422219820Sjeff case CLGET_WAITCHAN: 423219820Sjeff *(const char **) info = rc->rc_waitchan; 424219820Sjeff break; 425219820Sjeff 426219820Sjeff case CLSET_INTERRUPTIBLE: 427219820Sjeff rc->rc_intr = *(int *) info; 428219820Sjeff if (rc->rc_client) 429219820Sjeff CLNT_CONTROL(rc->rc_client, request, info); 430219820Sjeff break; 431219820Sjeff 432219820Sjeff case CLGET_INTERRUPTIBLE: 433219820Sjeff *(int *) info = rc->rc_intr; 434219820Sjeff break; 435219820Sjeff 436219820Sjeff case CLSET_RETRIES: 437219820Sjeff rc->rc_retries = *(int *) info; 438219820Sjeff break; 439219820Sjeff 440219820Sjeff case CLGET_RETRIES: 441219820Sjeff *(int *) info = rc->rc_retries; 442219820Sjeff break; 443219820Sjeff 444219820Sjeff case CLSET_PRIVPORT: 445219820Sjeff rc->rc_privport = *(int *) info; 446219820Sjeff break; 447219820Sjeff 448219820Sjeff case CLGET_PRIVPORT: 449219820Sjeff *(int *) info = rc->rc_privport; 450219820Sjeff break; 451219820Sjeff 452219820Sjeff case CLSET_BACKCHANNEL: 453219820Sjeff xprt = (SVCXPRT *)info; 454219820Sjeff SVC_ACQUIRE(xprt); 455219820Sjeff xprt_register(xprt); 456219820Sjeff rc->rc_backchannel = info; 457219820Sjeff break; 458219820Sjeff 459219820Sjeff default: 460219820Sjeff return (FALSE); 461219820Sjeff } 462219820Sjeff 463219820Sjeff return (TRUE); 464219820Sjeff} 465219820Sjeff 466219820Sjeffstatic void 467219820Sjeffclnt_reconnect_close(CLIENT *cl) 468219820Sjeff{ 469219820Sjeff struct rc_data *rc = (struct rc_data *)cl->cl_private; 470219820Sjeff CLIENT *client; 471219820Sjeff 472219820Sjeff mtx_lock(&rc->rc_lock); 473219820Sjeff 474219820Sjeff if (rc->rc_closed) { 475219820Sjeff mtx_unlock(&rc->rc_lock); 476219820Sjeff return; 477219820Sjeff } 478219820Sjeff 479219820Sjeff rc->rc_closed = TRUE; 480219820Sjeff client = rc->rc_client; 481219820Sjeff rc->rc_client = NULL; 482219820Sjeff 483219820Sjeff mtx_unlock(&rc->rc_lock); 484219820Sjeff 485219820Sjeff if (client) { 486219820Sjeff CLNT_CLOSE(client); 487219820Sjeff CLNT_RELEASE(client); 488219820Sjeff } 489219820Sjeff} 490219820Sjeff 491219820Sjeffstatic void 492219820Sjeffclnt_reconnect_destroy(CLIENT *cl) 493219820Sjeff{ 494219820Sjeff struct rc_data *rc = (struct rc_data *)cl->cl_private; 495219820Sjeff SVCXPRT *xprt; 496219820Sjeff 497219820Sjeff if (rc->rc_client) 498219820Sjeff CLNT_DESTROY(rc->rc_client); 499219820Sjeff if (rc->rc_backchannel) { 500219820Sjeff xprt = (SVCXPRT *)rc->rc_backchannel; 501219820Sjeff xprt_unregister(xprt); 502219820Sjeff SVC_RELEASE(xprt); 503219820Sjeff } 504219820Sjeff crfree(rc->rc_ucred); 505219820Sjeff mtx_destroy(&rc->rc_lock); 506219820Sjeff mem_free(rc, sizeof(*rc)); 507219820Sjeff mem_free(cl, sizeof (CLIENT)); 508219820Sjeff} 509219820Sjeff