bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * CDDL HEADER START
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 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * See the License for the specific language governing permissions
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * and limitations under the License.
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 * CDDL HEADER END
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Copyright (c) 2012 by Delphix. All rights reserved.
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 Kruchininstatic struct kmem_cache *nlm_rpch_cache = NULL;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic int nlm_rpch_ctor(void *, void *, int);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininstatic void nlm_rpch_dtor(void *, void *);
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 Kruchininget_nlm_rpc_fromcache(struct nlm_host *hostp, int vers)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin TAILQ_FOREACH(rpcp, &hostp->nh_rpchc, nr_link) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin TAILQ_REMOVE(&hostp->nh_rpchc, rpcp, nr_link);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Update host's RPC binding (host->nh_addr).
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * The function is executed by only one thread at time.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininupdate_host_rpcbinding(struct nlm_host *hostp, int vers)
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 hostp->nh_rpcb_state = NRPCB_UPDATE_INPROGRESS;
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin stat = rpcbind_getaddr(&hostp->nh_knc, NLM_PROG, vers, &hostp->nh_addr);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin hostp->nh_rpcb_state = ((stat == RPC_SUCCESS) ?
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 Kruchininrefresh_nlm_rpc(struct nlm_host *hostp, nlm_rpc_t *rpcp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ret = clnt_tli_kcreate(&hostp->nh_knc, &hostp->nh_addr,
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 if (clnt_control(rpcp->nr_handle, CLSET_NODELAYONERR,
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin NLM_ERR("Unable to set CLSET_NODELAYONERR\n");
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin ret = clnt_tli_kinit(rpcp->nr_handle, &hostp->nh_knc,
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 * 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 stat = nlm_null_rpc(rpcp->nr_handle, rpcp->nr_vers);
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 * If error occures, return nonzero error code.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_host_get_rpc(struct nlm_host *hostp, int vers, nlm_rpc_t **rpcpp)
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 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 * 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 if (hostp->nh_rpcb_state == NRPCB_NEED_UPDATE)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Check if RPC error occured during RPC binding
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * update operation. If so, report a correspoding
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * There weren't any RPC handles in a host
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * cache. No luck, just create a new one.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin rpcp = kmem_cache_alloc(nlm_rpch_cache, KM_SLEEP);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * Refresh RPC binding
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 Kruchininnlm_host_rele_rpc(struct nlm_host *hostp, nlm_rpc_t *rpcp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_host_rele_rpc_locked(struct nlm_host *hostp, nlm_rpc_t *rpcp)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin TAILQ_INSERT_HEAD(&hostp->nh_rpchc, rpcp, nr_link);
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 * The function should be executed when RPC call invoked via
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin * handle taken from RPC cache returns RPC_PROCUNAVAIL.
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_host_invalidate_binding(struct nlm_host *hostp)
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 * 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 while ((rpcp = TAILQ_FIRST(&hostp->nh_rpchc)) != NULL) {
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin TAILQ_REMOVE(&hostp->nh_rpchc, rpcp, nr_link);
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/* ARGSUSED */
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchininnlm_rpch_ctor(void *datap, void *cdrarg, int kmflags)
bbaa8b60dd95d714741fc474adad3cf710ef4efdDan Kruchinin/* ARGSUSED */