bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * CDDL HEADER START
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin *
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * The contents of this file are subject to the terms of the
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Common Development and Distribution License (the "License").
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * You may not use this file except in compliance with the License.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin *
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * or http://www.opensolaris.org/os/licensing.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * See the License for the specific language governing permissions
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * and limitations under the License.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin *
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * When distributing Covered Code, include this CDDL HEADER in each
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * If applicable, add the following below this CDDL HEADER, with the
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * fields enclosed by brackets "[]" replaced with your own identifying
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * information: Portions Copyright [yyyy] [name of copyright owner]
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin *
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * CDDL HEADER END
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Copyright (c) 2012 by Delphix. All rights reserved.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <sys/param.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <sys/systm.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <sys/socket.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <sys/syslog.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <sys/systm.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <sys/unistd.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <sys/queue.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <sys/sdt.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <netinet/in.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <rpc/rpc.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <rpc/xdr.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <rpc/pmap_prot.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <rpc/pmap_clnt.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <rpc/rpcb_prot.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <rpcsvc/nlm_prot.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include <rpcsvc/sm_inter.h>
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#include "nlm_impl.h"
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * The following errors codes from nlm_null_rpc indicate that the port we have
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * cached for the client's NLM service is stale and that we need to establish
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * a new RPC client.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin#define NLM_STALE_CLNT(_status) \
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ((_status) == RPC_PROGUNAVAIL || \
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin (_status) == RPC_PROGVERSMISMATCH || \
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin (_status) == RPC_PROCUNAVAIL || \
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin (_status) == RPC_CANTCONNECT || \
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin (_status) == RPC_XPRTFAILED)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic struct kmem_cache *nlm_rpch_cache = NULL;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic int nlm_rpch_ctor(void *, void *, int);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic void nlm_rpch_dtor(void *, void *);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic void destroy_rpch(nlm_rpc_t *);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic nlm_rpc_t *get_nlm_rpc_fromcache(struct nlm_host *, int);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic void update_host_rpcbinding(struct nlm_host *, int);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic int refresh_nlm_rpc(struct nlm_host *, nlm_rpc_t *);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic void nlm_host_rele_rpc_locked(struct nlm_host *, nlm_rpc_t *);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic nlm_rpc_t *
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininget_nlm_rpc_fromcache(struct nlm_host *hostp, int vers)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin nlm_rpc_t *rpcp;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin bool_t found = FALSE;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ASSERT(MUTEX_HELD(&hostp->nh_lock));
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (TAILQ_EMPTY(&hostp->nh_rpchc))
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin return (NULL);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin TAILQ_FOREACH(rpcp, &hostp->nh_rpchc, nr_link) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (rpcp->nr_vers == vers) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin found = TRUE;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin break;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (!found)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin return (NULL);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin TAILQ_REMOVE(&hostp->nh_rpchc, rpcp, nr_link);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin return (rpcp);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Update host's RPC binding (host->nh_addr).
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * The function is executed by only one thread at time.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic void
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininupdate_host_rpcbinding(struct nlm_host *hostp, int vers)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin enum clnt_stat stat;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ASSERT(MUTEX_HELD(&hostp->nh_lock));
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Mark RPC binding state as "update in progress" in order
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * to say other threads that they need to wait until binding
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * is fully updated.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin hostp->nh_rpcb_state = NRPCB_UPDATE_INPROGRESS;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin hostp->nh_rpcb_ustat = RPC_SUCCESS;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_exit(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin stat = rpcbind_getaddr(&hostp->nh_knc, NLM_PROG, vers, &hostp->nh_addr);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_enter(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin hostp->nh_rpcb_state = ((stat == RPC_SUCCESS) ?
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin NRPCB_UPDATED : NRPCB_NEED_UPDATE);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin hostp->nh_rpcb_ustat = stat;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin cv_broadcast(&hostp->nh_rpcb_cv);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Refresh RPC handle taken from host handles cache.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * This function is called when an RPC handle is either
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * uninitialized or was initialized using a binding that's
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * no longer current.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic int
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininrefresh_nlm_rpc(struct nlm_host *hostp, nlm_rpc_t *rpcp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin int ret;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (rpcp->nr_handle == NULL) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin bool_t clset = TRUE;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ret = clnt_tli_kcreate(&hostp->nh_knc, &hostp->nh_addr,
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin NLM_PROG, rpcp->nr_vers, 0, NLM_RPC_RETRIES,
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin CRED(), &rpcp->nr_handle);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Set the client's CLSET_NODELAYONERR option to true. The
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * RPC clnt_call interface creates an artificial delay for
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * certain call errors in order to prevent RPC consumers
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * from getting into tight retry loops. Since this function is
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * called by the NLM service routines we would like to avoid
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * this artificial delay when possible. We do not retry if the
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * NULL request fails so it is safe for us to turn this option
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * on.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (clnt_control(rpcp->nr_handle, CLSET_NODELAYONERR,
fc2b8335a96b36a076f9614647182dd090cb6ee0Dan McDonald (char *)&clset) == FALSE) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin NLM_ERR("Unable to set CLSET_NODELAYONERR\n");
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin } else {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ret = clnt_tli_kinit(rpcp->nr_handle, &hostp->nh_knc,
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin &hostp->nh_addr, 0, NLM_RPC_RETRIES, CRED());
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (ret == 0) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin enum clnt_stat stat;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Check whether host's RPC binding is still
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * fresh, i.e. if remote program is still sits
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * on the same port we assume. Call NULL proc
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * to do it.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin *
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Note: Even though we set no delay on error on the
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * client handle the call to nlm_null_rpc can still
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * delay for 10 seconds before returning an error. For
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * example the no delay on error option is not honored
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * for RPC_XPRTFAILED errors (see clnt_cots_kcallit).
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin stat = nlm_null_rpc(rpcp->nr_handle, rpcp->nr_vers);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (NLM_STALE_CLNT(stat)) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ret = ESTALE;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin return (ret);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Get RPC handle that can be used to talk to the NLM
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * of given version running on given host.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Saves obtained RPC handle to rpcpp argument.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin *
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * If error occures, return nonzero error code.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininint
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_host_get_rpc(struct nlm_host *hostp, int vers, nlm_rpc_t **rpcpp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin nlm_rpc_t *rpcp = NULL;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin int rc;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_enter(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * If this handle is either uninitialized, or was
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * initialized using binding that's now stale
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * do the init or re-init.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * See comments to enum nlm_rpcb_state for more
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * details.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininagain:
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin while (hostp->nh_rpcb_state != NRPCB_UPDATED) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (hostp->nh_rpcb_state == NRPCB_UPDATE_INPROGRESS) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin rc = cv_wait_sig(&hostp->nh_rpcb_cv, &hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (rc == 0) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_exit(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin return (EINTR);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Check if RPC binding was marked for update.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * If so, start RPC binding update operation.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * NOTE: the operation can be executed by only
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * one thread at time.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (hostp->nh_rpcb_state == NRPCB_NEED_UPDATE)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin update_host_rpcbinding(hostp, vers);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Check if RPC error occured during RPC binding
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * update operation. If so, report a correspoding
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * error.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (hostp->nh_rpcb_ustat != RPC_SUCCESS) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_exit(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin return (ENOENT);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin rpcp = get_nlm_rpc_fromcache(hostp, vers);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_exit(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (rpcp == NULL) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * There weren't any RPC handles in a host
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * cache. No luck, just create a new one.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin rpcp = kmem_cache_alloc(nlm_rpch_cache, KM_SLEEP);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin rpcp->nr_vers = vers;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Refresh RPC binding
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin rc = refresh_nlm_rpc(hostp, rpcp);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (rc != 0) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (rc == ESTALE) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Host's RPC binding is stale, we have
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * to update it. Put the RPC handle back
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * to the cache and mark the host as
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * "need update".
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_enter(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin hostp->nh_rpcb_state = NRPCB_NEED_UPDATE;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin nlm_host_rele_rpc_locked(hostp, rpcp);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin goto again;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin destroy_rpch(rpcp);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin return (rc);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin DTRACE_PROBE2(end, struct nlm_host *, hostp,
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin nlm_rpc_t *, rpcp);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin *rpcpp = rpcp;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin return (0);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininvoid
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_host_rele_rpc(struct nlm_host *hostp, nlm_rpc_t *rpcp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_enter(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin nlm_host_rele_rpc_locked(hostp, rpcp);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_exit(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic void
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_host_rele_rpc_locked(struct nlm_host *hostp, nlm_rpc_t *rpcp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ASSERT(mutex_owned(&hostp->nh_lock));
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin TAILQ_INSERT_HEAD(&hostp->nh_rpchc, rpcp, nr_link);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * The function invalidates host's RPC binding by marking it
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * as not fresh. In this case another time thread tries to
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * get RPC handle from host's handles cache, host's RPC binding
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * will be updated.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin *
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * The function should be executed when RPC call invoked via
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * handle taken from RPC cache returns RPC_PROCUNAVAIL.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininvoid
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_host_invalidate_binding(struct nlm_host *hostp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_enter(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin hostp->nh_rpcb_state = NRPCB_NEED_UPDATE;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin mutex_exit(&hostp->nh_lock);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininvoid
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_rpc_init(void)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin nlm_rpch_cache = kmem_cache_create("nlm_rpch_cache",
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin sizeof (nlm_rpc_t), 0, nlm_rpch_ctor, nlm_rpch_dtor,
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin NULL, NULL, NULL, 0);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininvoid
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_rpc_cache_destroy(struct nlm_host *hostp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin nlm_rpc_t *rpcp;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin /*
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * There's no need to lock host's mutex here,
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * nlm_rpc_cache_destroy() should be called from
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * only one place: nlm_host_destroy, when all
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * resources host owns are already cleaned up.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * So there shouldn't be any raises.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin while ((rpcp = TAILQ_FIRST(&hostp->nh_rpchc)) != NULL) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin TAILQ_REMOVE(&hostp->nh_rpchc, rpcp, nr_link);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin destroy_rpch(rpcp);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/* ARGSUSED */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic int
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_rpch_ctor(void *datap, void *cdrarg, int kmflags)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin nlm_rpc_t *rpcp = (nlm_rpc_t *)datap;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin bzero(rpcp, sizeof (*rpcp));
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin return (0);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/* ARGSUSED */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic void
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_rpch_dtor(void *datap, void *cdrarg)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin nlm_rpc_t *rpcp = (nlm_rpc_t *)datap;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ASSERT(rpcp->nr_handle == NULL);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic void
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinindestroy_rpch(nlm_rpc_t *rpcp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin{
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin if (rpcp->nr_handle != NULL) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin AUTH_DESTROY(rpcp->nr_handle->cl_auth);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin CLNT_DESTROY(rpcp->nr_handle);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin rpcp->nr_handle = NULL;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin }
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin kmem_cache_free(nlm_rpch_cache, rpcp);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin}