4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 2012 by Delphix. All rights reserved.
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/socket.h>
30 #include <sys/syslog.h>
31 #include <sys/systm.h>
32 #include <sys/unistd.h>
33 #include <sys/queue.h>
35 #include <netinet/in.h>
39 #include <rpc/pmap_prot.h>
40 #include <rpc/pmap_clnt.h>
41 #include <rpc/rpcb_prot.h>
43 #include <rpcsvc/nlm_prot.h>
44 #include <rpcsvc/sm_inter.h>
49 * The following errors codes from nlm_null_rpc indicate that the port we have
50 * cached for the client's NLM service is stale and that we need to establish
53 #define NLM_STALE_CLNT(_status) \
54 ((_status) == RPC_PROGUNAVAIL || \
55 (_status) == RPC_PROGVERSMISMATCH || \
56 (_status) == RPC_PROCUNAVAIL || \
57 (_status) == RPC_CANTCONNECT || \
58 (_status) == RPC_XPRTFAILED)
60 static struct kmem_cache
*nlm_rpch_cache
= NULL
;
62 static int nlm_rpch_ctor(void *, void *, int);
63 static void nlm_rpch_dtor(void *, void *);
64 static void destroy_rpch(nlm_rpc_t
*);
65 static nlm_rpc_t
*get_nlm_rpc_fromcache(struct nlm_host
*, int);
66 static void update_host_rpcbinding(struct nlm_host
*, int);
67 static int refresh_nlm_rpc(struct nlm_host
*, nlm_rpc_t
*);
68 static void nlm_host_rele_rpc_locked(struct nlm_host
*, nlm_rpc_t
*);
71 get_nlm_rpc_fromcache(struct nlm_host
*hostp
, int vers
)
76 ASSERT(MUTEX_HELD(&hostp
->nh_lock
));
77 if (TAILQ_EMPTY(&hostp
->nh_rpchc
))
80 TAILQ_FOREACH(rpcp
, &hostp
->nh_rpchc
, nr_link
) {
81 if (rpcp
->nr_vers
== vers
) {
90 TAILQ_REMOVE(&hostp
->nh_rpchc
, rpcp
, nr_link
);
95 * Update host's RPC binding (host->nh_addr).
96 * The function is executed by only one thread at time.
99 update_host_rpcbinding(struct nlm_host
*hostp
, int vers
)
103 ASSERT(MUTEX_HELD(&hostp
->nh_lock
));
106 * Mark RPC binding state as "update in progress" in order
107 * to say other threads that they need to wait until binding
110 hostp
->nh_rpcb_state
= NRPCB_UPDATE_INPROGRESS
;
111 hostp
->nh_rpcb_ustat
= RPC_SUCCESS
;
112 mutex_exit(&hostp
->nh_lock
);
114 stat
= rpcbind_getaddr(&hostp
->nh_knc
, NLM_PROG
, vers
, &hostp
->nh_addr
);
115 mutex_enter(&hostp
->nh_lock
);
117 hostp
->nh_rpcb_state
= ((stat
== RPC_SUCCESS
) ?
118 NRPCB_UPDATED
: NRPCB_NEED_UPDATE
);
120 hostp
->nh_rpcb_ustat
= stat
;
121 cv_broadcast(&hostp
->nh_rpcb_cv
);
125 * Refresh RPC handle taken from host handles cache.
126 * This function is called when an RPC handle is either
127 * uninitialized or was initialized using a binding that's
131 refresh_nlm_rpc(struct nlm_host
*hostp
, nlm_rpc_t
*rpcp
)
135 if (rpcp
->nr_handle
== NULL
) {
138 ret
= clnt_tli_kcreate(&hostp
->nh_knc
, &hostp
->nh_addr
,
139 NLM_PROG
, rpcp
->nr_vers
, 0, NLM_RPC_RETRIES
,
140 CRED(), &rpcp
->nr_handle
);
143 * Set the client's CLSET_NODELAYONERR option to true. The
144 * RPC clnt_call interface creates an artificial delay for
145 * certain call errors in order to prevent RPC consumers
146 * from getting into tight retry loops. Since this function is
147 * called by the NLM service routines we would like to avoid
148 * this artificial delay when possible. We do not retry if the
149 * NULL request fails so it is safe for us to turn this option
152 if (clnt_control(rpcp
->nr_handle
, CLSET_NODELAYONERR
,
153 (char *)&clset
) == FALSE
) {
154 NLM_ERR("Unable to set CLSET_NODELAYONERR\n");
157 ret
= clnt_tli_kinit(rpcp
->nr_handle
, &hostp
->nh_knc
,
158 &hostp
->nh_addr
, 0, NLM_RPC_RETRIES
, CRED());
163 * Check whether host's RPC binding is still
164 * fresh, i.e. if remote program is still sits
165 * on the same port we assume. Call NULL proc
168 * Note: Even though we set no delay on error on the
169 * client handle the call to nlm_null_rpc can still
170 * delay for 10 seconds before returning an error. For
171 * example the no delay on error option is not honored
172 * for RPC_XPRTFAILED errors (see clnt_cots_kcallit).
174 stat
= nlm_null_rpc(rpcp
->nr_handle
, rpcp
->nr_vers
);
175 if (NLM_STALE_CLNT(stat
)) {
185 * Get RPC handle that can be used to talk to the NLM
186 * of given version running on given host.
187 * Saves obtained RPC handle to rpcpp argument.
189 * If error occures, return nonzero error code.
192 nlm_host_get_rpc(struct nlm_host
*hostp
, int vers
, nlm_rpc_t
**rpcpp
)
194 nlm_rpc_t
*rpcp
= NULL
;
197 mutex_enter(&hostp
->nh_lock
);
200 * If this handle is either uninitialized, or was
201 * initialized using binding that's now stale
202 * do the init or re-init.
203 * See comments to enum nlm_rpcb_state for more
207 while (hostp
->nh_rpcb_state
!= NRPCB_UPDATED
) {
208 if (hostp
->nh_rpcb_state
== NRPCB_UPDATE_INPROGRESS
) {
209 rc
= cv_wait_sig(&hostp
->nh_rpcb_cv
, &hostp
->nh_lock
);
211 mutex_exit(&hostp
->nh_lock
);
217 * Check if RPC binding was marked for update.
218 * If so, start RPC binding update operation.
219 * NOTE: the operation can be executed by only
220 * one thread at time.
222 if (hostp
->nh_rpcb_state
== NRPCB_NEED_UPDATE
)
223 update_host_rpcbinding(hostp
, vers
);
226 * Check if RPC error occured during RPC binding
227 * update operation. If so, report a correspoding
230 if (hostp
->nh_rpcb_ustat
!= RPC_SUCCESS
) {
231 mutex_exit(&hostp
->nh_lock
);
236 rpcp
= get_nlm_rpc_fromcache(hostp
, vers
);
237 mutex_exit(&hostp
->nh_lock
);
240 * There weren't any RPC handles in a host
241 * cache. No luck, just create a new one.
243 rpcp
= kmem_cache_alloc(nlm_rpch_cache
, KM_SLEEP
);
244 rpcp
->nr_vers
= vers
;
248 * Refresh RPC binding
250 rc
= refresh_nlm_rpc(hostp
, rpcp
);
254 * Host's RPC binding is stale, we have
255 * to update it. Put the RPC handle back
256 * to the cache and mark the host as
259 mutex_enter(&hostp
->nh_lock
);
260 hostp
->nh_rpcb_state
= NRPCB_NEED_UPDATE
;
261 nlm_host_rele_rpc_locked(hostp
, rpcp
);
269 DTRACE_PROBE2(end
, struct nlm_host
*, hostp
,
277 nlm_host_rele_rpc(struct nlm_host
*hostp
, nlm_rpc_t
*rpcp
)
279 mutex_enter(&hostp
->nh_lock
);
280 nlm_host_rele_rpc_locked(hostp
, rpcp
);
281 mutex_exit(&hostp
->nh_lock
);
285 nlm_host_rele_rpc_locked(struct nlm_host
*hostp
, nlm_rpc_t
*rpcp
)
287 ASSERT(mutex_owned(&hostp
->nh_lock
));
288 TAILQ_INSERT_HEAD(&hostp
->nh_rpchc
, rpcp
, nr_link
);
292 * The function invalidates host's RPC binding by marking it
293 * as not fresh. In this case another time thread tries to
294 * get RPC handle from host's handles cache, host's RPC binding
297 * The function should be executed when RPC call invoked via
298 * handle taken from RPC cache returns RPC_PROCUNAVAIL.
301 nlm_host_invalidate_binding(struct nlm_host
*hostp
)
303 mutex_enter(&hostp
->nh_lock
);
304 hostp
->nh_rpcb_state
= NRPCB_NEED_UPDATE
;
305 mutex_exit(&hostp
->nh_lock
);
311 nlm_rpch_cache
= kmem_cache_create("nlm_rpch_cache",
312 sizeof (nlm_rpc_t
), 0, nlm_rpch_ctor
, nlm_rpch_dtor
,
313 NULL
, NULL
, NULL
, 0);
317 nlm_rpc_cache_destroy(struct nlm_host
*hostp
)
322 * There's no need to lock host's mutex here,
323 * nlm_rpc_cache_destroy() should be called from
324 * only one place: nlm_host_destroy, when all
325 * resources host owns are already cleaned up.
326 * So there shouldn't be any raises.
328 while ((rpcp
= TAILQ_FIRST(&hostp
->nh_rpchc
)) != NULL
) {
329 TAILQ_REMOVE(&hostp
->nh_rpchc
, rpcp
, nr_link
);
336 nlm_rpch_ctor(void *datap
, void *cdrarg
, int kmflags
)
338 nlm_rpc_t
*rpcp
= (nlm_rpc_t
*)datap
;
340 bzero(rpcp
, sizeof (*rpcp
));
346 nlm_rpch_dtor(void *datap
, void *cdrarg
)
348 nlm_rpc_t
*rpcp
= (nlm_rpc_t
*)datap
;
349 ASSERT(rpcp
->nr_handle
== NULL
);
353 destroy_rpch(nlm_rpc_t
*rpcp
)
355 if (rpcp
->nr_handle
!= NULL
) {
356 AUTH_DESTROY(rpcp
->nr_handle
->cl_auth
);
357 CLNT_DESTROY(rpcp
->nr_handle
);
358 rpcp
->nr_handle
= NULL
;
361 kmem_cache_free(nlm_rpch_cache
, rpcp
);