1 /*
2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3 * Authors: Doug Rabson <dfr@rabson.org>
4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
30 * Copyright (c) 2012 by Delphix. All rights reserved.
31 */
32
33 /*
34 * NFS LockManager, start/stop, support functions, etc.
35 * Most of the interesting code is here.
36 *
37 * Source code derived from FreeBSD nlm_prot_impl.c
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/thread.h>
43 #include <sys/fcntl.h>
44 #include <sys/flock.h>
45 #include <sys/mount.h>
46 #include <sys/priv.h>
47 #include <sys/proc.h>
48 #include <sys/share.h>
49 #include <sys/socket.h>
50 #include <sys/syscall.h>
51 #include <sys/syslog.h>
52 #include <sys/systm.h>
53 #include <sys/class.h>
54 #include <sys/unistd.h>
55 #include <sys/vnode.h>
56 #include <sys/vfs.h>
57 #include <sys/queue.h>
58 #include <sys/bitmap.h>
59 #include <sys/sdt.h>
60 #include <netinet/in.h>
61
62 #include <rpc/rpc.h>
63 #include <rpc/xdr.h>
64 #include <rpc/pmap_prot.h>
65 #include <rpc/pmap_clnt.h>
66 #include <rpc/rpcb_prot.h>
67
68 #include <rpcsvc/nlm_prot.h>
69 #include <rpcsvc/sm_inter.h>
70 #include <rpcsvc/nsm_addr.h>
71
72 #include <nfs/nfs.h>
73 #include <nfs/nfs_clnt.h>
74 #include <nfs/export.h>
75 #include <nfs/rnode.h>
76 #include <nfs/lm.h>
77
78 #include "nlm_impl.h"
79
80 struct nlm_knc {
81 struct knetconfig n_knc;
82 const char *n_netid;
83 };
84
85 /*
86 * Number of attempts NLM tries to obtain RPC binding
87 * of local statd.
88 */
89 #define NLM_NSM_RPCBIND_RETRIES 10
90
91 /*
92 * Timeout (in seconds) NLM waits before making another
93 * attempt to obtain RPC binding of local statd.
94 */
95 #define NLM_NSM_RPCBIND_TIMEOUT 5
96
97 /*
98 * Total number of sysids in NLM sysid bitmap
99 */
100 #define NLM_BMAP_NITEMS (LM_SYSID_MAX + 1)
101
102 /*
103 * Number of ulong_t words in bitmap that is used
104 * for allocation of sysid numbers.
105 */
106 #define NLM_BMAP_WORDS (NLM_BMAP_NITEMS / BT_NBIPUL)
107
108 /*
109 * Given an integer x, the macro returns
110 * -1 if x is negative,
111 * 0 if x is zero
112 * 1 if x is positive
113 */
114 #define SIGN(x) (((x) > 0) - ((x) < 0))
115
116 #define ARRSIZE(arr) (sizeof (arr) / sizeof ((arr)[0]))
117 #define NLM_KNCS ARRSIZE(nlm_netconfigs)
118
119 krwlock_t lm_lck;
120
121 /*
122 * Zero timeout for asynchronous NLM RPC operations
123 */
124 static const struct timeval nlm_rpctv_zero = { 0, 0 };
125
126 /*
127 * List of all Zone globals nlm_globals instences
128 * linked together.
129 */
130 static struct nlm_globals_list nlm_zones_list; /* (g) */
131
132 /*
133 * NLM kmem caches
134 */
135 static struct kmem_cache *nlm_hosts_cache = NULL;
136 static struct kmem_cache *nlm_vhold_cache = NULL;
137
138 /*
139 * A bitmap for allocation of new sysids.
140 * Sysid is a unique number between LM_SYSID
141 * and LM_SYSID_MAX. Sysid represents unique remote
142 * host that does file locks on the given host.
143 */
144 static ulong_t nlm_sysid_bmap[NLM_BMAP_WORDS]; /* (g) */
145 static int nlm_sysid_nidx; /* (g) */
146
147 /*
148 * RPC service registration for all transports
149 */
150 static SVC_CALLOUT nlm_svcs[] = {
151 { NLM_PROG, 4, 4, nlm_prog_4 }, /* NLM4_VERS */
152 { NLM_PROG, 1, 3, nlm_prog_3 } /* NLM_VERS - NLM_VERSX */
153 };
154
155 static SVC_CALLOUT_TABLE nlm_sct = {
156 ARRSIZE(nlm_svcs),
157 FALSE,
158 nlm_svcs
159 };
160
161 /*
162 * Static table of all netid/knetconfig network
163 * lock manager can work with. nlm_netconfigs table
164 * is used when we need to get valid knetconfig by
165 * netid and vice versa.
166 *
167 * Knetconfigs are activated either by the call from
168 * user-space lockd daemon (server side) or by taking
169 * knetconfig from NFS mountinfo (client side)
170 */
171 static struct nlm_knc nlm_netconfigs[] = { /* (g) */
172 /* UDP */
173 {
174 { NC_TPI_CLTS, NC_INET, NC_UDP, NODEV },
175 "udp",
176 },
177 /* TCP */
178 {
179 { NC_TPI_COTS_ORD, NC_INET, NC_TCP, NODEV },
180 "tcp",
181 },
182 /* UDP over IPv6 */
183 {
184 { NC_TPI_CLTS, NC_INET6, NC_UDP, NODEV },
185 "udp6",
186 },
187 /* TCP over IPv6 */
188 {
189 { NC_TPI_COTS_ORD, NC_INET6, NC_TCP, NODEV },
190 "tcp6",
191 },
192 /* ticlts (loopback over UDP) */
193 {
194 { NC_TPI_CLTS, NC_LOOPBACK, NC_NOPROTO, NODEV },
195 "ticlts",
196 },
197 /* ticotsord (loopback over TCP) */
198 {
199 { NC_TPI_COTS_ORD, NC_LOOPBACK, NC_NOPROTO, NODEV },
200 "ticotsord",
201 },
202 };
203
204 /*
205 * NLM misc. function
206 */
207 static void nlm_copy_netbuf(struct netbuf *, struct netbuf *);
208 static int nlm_netbuf_addrs_cmp(struct netbuf *, struct netbuf *);
209 static void nlm_kmem_reclaim(void *);
210 static void nlm_pool_shutdown(void);
211 static void nlm_suspend_zone(struct nlm_globals *);
212 static void nlm_resume_zone(struct nlm_globals *);
213 static void nlm_nsm_clnt_init(CLIENT *, struct nlm_nsm *);
214 static void nlm_netbuf_to_netobj(struct netbuf *, int *, netobj *);
215
216 /*
217 * NLM thread functions
218 */
219 static void nlm_gc(struct nlm_globals *);
220 static void nlm_reclaimer(struct nlm_host *);
221
222 /*
223 * NLM NSM functions
224 */
225 static int nlm_init_local_knc(struct knetconfig *);
226 static int nlm_nsm_init_local(struct nlm_nsm *);
227 static int nlm_nsm_init(struct nlm_nsm *, struct knetconfig *, struct netbuf *);
228 static void nlm_nsm_fini(struct nlm_nsm *);
229 static enum clnt_stat nlm_nsm_simu_crash(struct nlm_nsm *);
230 static enum clnt_stat nlm_nsm_stat(struct nlm_nsm *, int32_t *);
231 static enum clnt_stat nlm_nsm_mon(struct nlm_nsm *, char *, uint16_t);
232 static enum clnt_stat nlm_nsm_unmon(struct nlm_nsm *, char *);
233
234 /*
235 * NLM host functions
236 */
237 static int nlm_host_ctor(void *, void *, int);
238 static void nlm_host_dtor(void *, void *);
239 static void nlm_host_destroy(struct nlm_host *);
240 static struct nlm_host *nlm_host_create(char *, const char *,
241 struct knetconfig *, struct netbuf *);
242 static struct nlm_host *nlm_host_find_locked(struct nlm_globals *,
243 const char *, struct netbuf *, avl_index_t *);
244 static void nlm_host_unregister(struct nlm_globals *, struct nlm_host *);
245 static void nlm_host_gc_vholds(struct nlm_host *);
246 static bool_t nlm_host_has_srv_locks(struct nlm_host *);
247 static bool_t nlm_host_has_cli_locks(struct nlm_host *);
248 static bool_t nlm_host_has_locks(struct nlm_host *);
249
250 /*
251 * NLM vhold functions
252 */
253 static int nlm_vhold_ctor(void *, void *, int);
254 static void nlm_vhold_dtor(void *, void *);
255 static void nlm_vhold_destroy(struct nlm_host *,
256 struct nlm_vhold *);
257 static bool_t nlm_vhold_busy(struct nlm_host *, struct nlm_vhold *);
258 static void nlm_vhold_clean(struct nlm_vhold *, int);
259
260 /*
261 * NLM client/server sleeping locks/share reservation functions
262 */
263 struct nlm_slreq *nlm_slreq_find_locked(struct nlm_host *,
264 struct nlm_vhold *, struct flock64 *);
265 static struct nlm_shres *nlm_shres_create_item(struct shrlock *, vnode_t *);
266 static void nlm_shres_destroy_item(struct nlm_shres *);
267 static bool_t nlm_shres_equal(struct shrlock *, struct shrlock *);
268
269 /*
270 * NLM initialization functions.
271 */
272 void
nlm_init(void)273 nlm_init(void)
274 {
275 nlm_hosts_cache = kmem_cache_create("nlm_host_cache",
276 sizeof (struct nlm_host), 0, nlm_host_ctor, nlm_host_dtor,
277 nlm_kmem_reclaim, NULL, NULL, 0);
278
279 nlm_vhold_cache = kmem_cache_create("nlm_vhold_cache",
280 sizeof (struct nlm_vhold), 0, nlm_vhold_ctor, nlm_vhold_dtor,
281 NULL, NULL, NULL, 0);
282
283 nlm_rpc_init();
284 TAILQ_INIT(&nlm_zones_list);
285
286 /* initialize sysids bitmap */
287 bzero(nlm_sysid_bmap, sizeof (nlm_sysid_bmap));
288 nlm_sysid_nidx = 1;
289
290 /*
291 * Reserv the sysid #0, because it's associated
292 * with local locks only. Don't let to allocate
293 * it for remote locks.
294 */
295 BT_SET(nlm_sysid_bmap, 0);
296 }
297
298 void
nlm_globals_register(struct nlm_globals * g)299 nlm_globals_register(struct nlm_globals *g)
300 {
301 rw_enter(&lm_lck, RW_WRITER);
302 TAILQ_INSERT_TAIL(&nlm_zones_list, g, nlm_link);
303 rw_exit(&lm_lck);
304 }
305
306 void
nlm_globals_unregister(struct nlm_globals * g)307 nlm_globals_unregister(struct nlm_globals *g)
308 {
309 rw_enter(&lm_lck, RW_WRITER);
310 TAILQ_REMOVE(&nlm_zones_list, g, nlm_link);
311 rw_exit(&lm_lck);
312 }
313
314 /* ARGSUSED */
315 static void
nlm_kmem_reclaim(void * cdrarg)316 nlm_kmem_reclaim(void *cdrarg)
317 {
318 struct nlm_globals *g;
319
320 rw_enter(&lm_lck, RW_READER);
321 TAILQ_FOREACH(g, &nlm_zones_list, nlm_link)
322 cv_broadcast(&g->nlm_gc_sched_cv);
323
324 rw_exit(&lm_lck);
325 }
326
327 /*
328 * NLM garbage collector thread (GC).
329 *
330 * NLM GC periodically checks whether there're any host objects
331 * that can be cleaned up. It also releases stale vnodes that
332 * live on the server side (under protection of vhold objects).
333 *
334 * NLM host objects are cleaned up from GC thread because
335 * operations helping us to determine whether given host has
336 * any locks can be quite expensive and it's not good to call
337 * them every time the very last reference to the host is dropped.
338 * Thus we use "lazy" approach for hosts cleanup.
339 *
340 * The work of GC is to release stale vnodes on the server side
341 * and destroy hosts that haven't any locks and any activity for
342 * some time (i.e. idle hosts).
343 */
344 static void
nlm_gc(struct nlm_globals * g)345 nlm_gc(struct nlm_globals *g)
346 {
347 struct nlm_host *hostp;
348 clock_t now, idle_period;
349
350 idle_period = SEC_TO_TICK(g->cn_idle_tmo);
351 mutex_enter(&g->lock);
352 for (;;) {
353 /*
354 * GC thread can be explicitly scheduled from
355 * memory reclamation function.
356 */
357 (void) cv_timedwait(&g->nlm_gc_sched_cv, &g->lock,
358 ddi_get_lbolt() + idle_period);
359
360 /*
361 * NLM is shutting down, time to die.
362 */
363 if (g->run_status == NLM_ST_STOPPING)
364 break;
365
366 now = ddi_get_lbolt();
367 DTRACE_PROBE2(gc__start, struct nlm_globals *, g,
368 clock_t, now);
369
370 /*
371 * Find all obviously unused vholds and destroy them.
372 */
373 for (hostp = avl_first(&g->nlm_hosts_tree); hostp != NULL;
374 hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp)) {
375 struct nlm_vhold *nvp;
376
377 mutex_enter(&hostp->nh_lock);
378
379 nvp = TAILQ_FIRST(&hostp->nh_vholds_list);
380 while (nvp != NULL) {
381 struct nlm_vhold *new_nvp;
382
383 new_nvp = TAILQ_NEXT(nvp, nv_link);
384
385 /*
386 * If these conditions are met, the vhold is
387 * obviously unused and we will destroy it. In
388 * a case either v_filocks and/or v_shrlocks is
389 * non-NULL the vhold might still be unused by
390 * the host, but it is expensive to check that.
391 * We defer such check until the host is idle.
392 * The expensive check is done below without
393 * the global lock held.
394 */
395 if (nvp->nv_refcnt == 0 &&
396 nvp->nv_vp->v_filocks == NULL &&
397 nvp->nv_vp->v_shrlocks == NULL) {
398 nlm_vhold_destroy(hostp, nvp);
399 }
400
401 nvp = new_nvp;
402 }
403
404 mutex_exit(&hostp->nh_lock);
405 }
406
407 /*
408 * Handle all hosts that are unused at the moment
409 * until we meet one with idle timeout in future.
410 */
411 while ((hostp = TAILQ_FIRST(&g->nlm_idle_hosts)) != NULL) {
412 bool_t has_locks;
413
414 if (hostp->nh_idle_timeout > now)
415 break;
416
417 /*
418 * Drop global lock while doing expensive work
419 * on this host. We'll re-check any conditions
420 * that might change after retaking the global
421 * lock.
422 */
423 mutex_exit(&g->lock);
424 mutex_enter(&hostp->nh_lock);
425
426 /*
427 * nlm_globals lock was dropped earlier because
428 * garbage collecting of vholds and checking whether
429 * host has any locks/shares are expensive operations.
430 */
431 nlm_host_gc_vholds(hostp);
432 has_locks = nlm_host_has_locks(hostp);
433
434 mutex_exit(&hostp->nh_lock);
435 mutex_enter(&g->lock);
436
437 /*
438 * While we were doing expensive operations
439 * outside of nlm_globals critical section,
440 * somebody could take the host and remove it
441 * from the idle list. Whether its been
442 * reinserted or not, our information about
443 * the host is outdated, and we should take no
444 * further action.
445 */
446 if ((hostp->nh_flags & NLM_NH_INIDLE) == 0 ||
447 hostp->nh_idle_timeout > now)
448 continue;
449
450 /*
451 * If the host has locks we have to renew the
452 * host's timeout and put it at the end of LRU
453 * list.
454 */
455 if (has_locks) {
456 TAILQ_REMOVE(&g->nlm_idle_hosts,
457 hostp, nh_link);
458 hostp->nh_idle_timeout = now + idle_period;
459 TAILQ_INSERT_TAIL(&g->nlm_idle_hosts,
460 hostp, nh_link);
461 continue;
462 }
463
464 /*
465 * We're here if all the following conditions hold:
466 * 1) Host hasn't any locks or share reservations
467 * 2) Host is unused
468 * 3) Host wasn't touched by anyone at least for
469 * g->cn_idle_tmo seconds.
470 *
471 * So, now we can destroy it.
472 */
473 nlm_host_unregister(g, hostp);
474 mutex_exit(&g->lock);
475
476 nlm_host_unmonitor(g, hostp);
477 nlm_host_destroy(hostp);
478 mutex_enter(&g->lock);
479 if (g->run_status == NLM_ST_STOPPING)
480 break;
481
482 }
483
484 DTRACE_PROBE(gc__end);
485 }
486
487 DTRACE_PROBE1(gc__exit, struct nlm_globals *, g);
488
489 /* Let others know that GC has died */
490 g->nlm_gc_thread = NULL;
491 mutex_exit(&g->lock);
492
493 cv_broadcast(&g->nlm_gc_finish_cv);
494 zthread_exit();
495 }
496
497 /*
498 * Thread reclaim locks/shares acquired by the client side
499 * on the given server represented by hostp.
500 */
501 static void
nlm_reclaimer(struct nlm_host * hostp)502 nlm_reclaimer(struct nlm_host *hostp)
503 {
504 struct nlm_globals *g;
505
506 mutex_enter(&hostp->nh_lock);
507 hostp->nh_reclaimer = curthread;
508 mutex_exit(&hostp->nh_lock);
509
510 g = zone_getspecific(nlm_zone_key, curzone);
511 nlm_reclaim_client(g, hostp);
512
513 mutex_enter(&hostp->nh_lock);
514 hostp->nh_flags &= ~NLM_NH_RECLAIM;
515 hostp->nh_reclaimer = NULL;
516 cv_broadcast(&hostp->nh_recl_cv);
517 mutex_exit(&hostp->nh_lock);
518
519 /*
520 * Host was explicitly referenced before
521 * nlm_reclaim() was called, release it
522 * here.
523 */
524 nlm_host_release(g, hostp);
525 zthread_exit();
526 }
527
528 /*
529 * Copy a struct netobj. (see xdr.h)
530 */
531 void
nlm_copy_netobj(struct netobj * dst,struct netobj * src)532 nlm_copy_netobj(struct netobj *dst, struct netobj *src)
533 {
534 dst->n_len = src->n_len;
535 dst->n_bytes = kmem_alloc(src->n_len, KM_SLEEP);
536 bcopy(src->n_bytes, dst->n_bytes, src->n_len);
537 }
538
539 /*
540 * An NLM specificw replacement for clnt_call().
541 * nlm_clnt_call() is used by all RPC functions generated
542 * from nlm_prot.x specification. The function is aware
543 * about some pitfalls of NLM RPC procedures and has a logic
544 * that handles them properly.
545 */
546 enum clnt_stat
nlm_clnt_call(CLIENT * clnt,rpcproc_t procnum,xdrproc_t xdr_args,caddr_t argsp,xdrproc_t xdr_result,caddr_t resultp,struct timeval wait)547 nlm_clnt_call(CLIENT *clnt, rpcproc_t procnum, xdrproc_t xdr_args,
548 caddr_t argsp, xdrproc_t xdr_result, caddr_t resultp, struct timeval wait)
549 {
550 k_sigset_t oldmask;
551 enum clnt_stat stat;
552 bool_t sig_blocked = FALSE;
553
554 /*
555 * If NLM RPC procnum is one of the NLM _RES procedures
556 * that are used to reply to asynchronous NLM RPC
557 * (MSG calls), explicitly set RPC timeout to zero.
558 * Client doesn't send a reply to RES procedures, so
559 * we don't need to wait anything.
560 *
561 * NOTE: we ignore NLM4_*_RES procnums because they are
562 * equal to NLM_*_RES numbers.
563 */
564 if (procnum >= NLM_TEST_RES && procnum <= NLM_GRANTED_RES)
565 wait = nlm_rpctv_zero;
566
567 /*
568 * We need to block signals in case of NLM_CANCEL RPC
569 * in order to prevent interruption of network RPC
570 * calls.
571 */
572 if (procnum == NLM_CANCEL) {
573 k_sigset_t newmask;
574
575 sigfillset(&newmask);
576 sigreplace(&newmask, &oldmask);
577 sig_blocked = TRUE;
578 }
579
580 stat = clnt_call(clnt, procnum, xdr_args,
581 argsp, xdr_result, resultp, wait);
582
583 /*
584 * Restore signal mask back if signals were blocked
585 */
586 if (sig_blocked)
587 sigreplace(&oldmask, (k_sigset_t *)NULL);
588
589 return (stat);
590 }
591
592 /*
593 * Suspend NLM client/server in the given zone.
594 *
595 * During suspend operation we mark those hosts
596 * that have any locks with NLM_NH_SUSPEND flags,
597 * so that they can be checked later, when resume
598 * operation occurs.
599 */
600 static void
nlm_suspend_zone(struct nlm_globals * g)601 nlm_suspend_zone(struct nlm_globals *g)
602 {
603 struct nlm_host *hostp;
604 struct nlm_host_list all_hosts;
605
606 /*
607 * Note that while we're doing suspend, GC thread is active
608 * and it can destroy some hosts while we're walking through
609 * the hosts tree. To prevent that and make suspend logic
610 * a bit more simple we put all hosts to local "all_hosts"
611 * list and increment reference counter of each host.
612 * This guaranties that no hosts will be released while
613 * we're doing suspend.
614 * NOTE: reference of each host must be dropped during
615 * resume operation.
616 */
617 TAILQ_INIT(&all_hosts);
618 mutex_enter(&g->lock);
619 for (hostp = avl_first(&g->nlm_hosts_tree); hostp != NULL;
620 hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp)) {
621 /*
622 * If host is idle, remove it from idle list and
623 * clear idle flag. That is done to prevent GC
624 * from touching this host.
625 */
626 if (hostp->nh_flags & NLM_NH_INIDLE) {
627 TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
628 hostp->nh_flags &= ~NLM_NH_INIDLE;
629 }
630
631 hostp->nh_refs++;
632 TAILQ_INSERT_TAIL(&all_hosts, hostp, nh_link);
633 }
634
635 /*
636 * Now we can walk through all hosts on the system
637 * with zone globals lock released. The fact the
638 * we have taken a reference to each host guaranties
639 * that no hosts can be destroyed during that process.
640 */
641 mutex_exit(&g->lock);
642 while ((hostp = TAILQ_FIRST(&all_hosts)) != NULL) {
643 mutex_enter(&hostp->nh_lock);
644 if (nlm_host_has_locks(hostp))
645 hostp->nh_flags |= NLM_NH_SUSPEND;
646
647 mutex_exit(&hostp->nh_lock);
648 TAILQ_REMOVE(&all_hosts, hostp, nh_link);
649 }
650 }
651
652 /*
653 * Resume NLM hosts for the given zone.
654 *
655 * nlm_resume_zone() is called after hosts were suspended
656 * (see nlm_suspend_zone) and its main purpose to check
657 * whether remote locks owned by hosts are still in consistent
658 * state. If they aren't, resume function tries to reclaim
659 * locks (for client side hosts) and clean locks (for
660 * server side hosts).
661 */
662 static void
nlm_resume_zone(struct nlm_globals * g)663 nlm_resume_zone(struct nlm_globals *g)
664 {
665 struct nlm_host *hostp, *h_next;
666
667 mutex_enter(&g->lock);
668 hostp = avl_first(&g->nlm_hosts_tree);
669
670 /*
671 * In nlm_suspend_zone() the reference counter of each
672 * host was incremented, so we can safely iterate through
673 * all hosts without worrying that any host we touch will
674 * be removed at the moment.
675 */
676 while (hostp != NULL) {
677 struct nlm_nsm nsm;
678 enum clnt_stat stat;
679 int32_t sm_state;
680 int error;
681 bool_t resume_failed = FALSE;
682
683 h_next = AVL_NEXT(&g->nlm_hosts_tree, hostp);
684 mutex_exit(&g->lock);
685
686 DTRACE_PROBE1(resume__host, struct nlm_host *, hostp);
687
688 /*
689 * Suspend operation marked that the host doesn't
690 * have any locks. Skip it.
691 */
692 if (!(hostp->nh_flags & NLM_NH_SUSPEND))
693 goto cycle_end;
694
695 error = nlm_nsm_init(&nsm, &hostp->nh_knc, &hostp->nh_addr);
696 if (error != 0) {
697 NLM_ERR("Resume: Failed to contact to NSM of host %s "
698 "[error=%d]\n", hostp->nh_name, error);
699 resume_failed = TRUE;
700 goto cycle_end;
701 }
702
703 stat = nlm_nsm_stat(&nsm, &sm_state);
704 if (stat != RPC_SUCCESS) {
705 NLM_ERR("Resume: Failed to call SM_STAT operation for "
706 "host %s [stat=%d]\n", hostp->nh_name, stat);
707 resume_failed = TRUE;
708 nlm_nsm_fini(&nsm);
709 goto cycle_end;
710 }
711
712 if (sm_state != hostp->nh_state) {
713 /*
714 * Current SM state of the host isn't equal
715 * to the one host had when it was suspended.
716 * Probably it was rebooted. Try to reclaim
717 * locks if the host has any on its client side.
718 * Also try to clean up its server side locks
719 * (if the host has any).
720 */
721 nlm_host_notify_client(hostp, sm_state);
722 nlm_host_notify_server(hostp, sm_state);
723 }
724
725 nlm_nsm_fini(&nsm);
726
727 cycle_end:
728 if (resume_failed) {
729 /*
730 * Resume failed for the given host.
731 * Just clean up all resources it owns.
732 */
733 nlm_host_notify_server(hostp, 0);
734 nlm_client_cancel_all(g, hostp);
735 }
736
737 hostp->nh_flags &= ~NLM_NH_SUSPEND;
738 nlm_host_release(g, hostp);
739 hostp = h_next;
740 mutex_enter(&g->lock);
741 }
742
743 mutex_exit(&g->lock);
744 }
745
746 /*
747 * NLM functions responsible for operations on NSM handle.
748 */
749
750 /*
751 * Initialize knetconfig that is used for communication
752 * with local statd via loopback interface.
753 */
754 static int
nlm_init_local_knc(struct knetconfig * knc)755 nlm_init_local_knc(struct knetconfig *knc)
756 {
757 int error;
758 vnode_t *vp;
759
760 bzero(knc, sizeof (*knc));
761 error = lookupname("/dev/tcp", UIO_SYSSPACE,
762 FOLLOW, NULLVPP, &vp);
763 if (error != 0)
764 return (error);
765
766 knc->knc_semantics = NC_TPI_COTS;
767 knc->knc_protofmly = NC_INET;
768 knc->knc_proto = NC_TCP;
769 knc->knc_rdev = vp->v_rdev;
770 VN_RELE(vp);
771
772
773 return (0);
774 }
775
776 /*
777 * Initialize NSM handle that will be used to talk
778 * to local statd via loopback interface.
779 */
780 static int
nlm_nsm_init_local(struct nlm_nsm * nsm)781 nlm_nsm_init_local(struct nlm_nsm *nsm)
782 {
783 int error;
784 struct knetconfig knc;
785 struct sockaddr_in sin;
786 struct netbuf nb;
787
788 error = nlm_init_local_knc(&knc);
789 if (error != 0)
790 return (error);
791
792 bzero(&sin, sizeof (sin));
793 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
794 sin.sin_family = AF_INET;
795
796 nb.buf = (char *)&sin;
797 nb.len = nb.maxlen = sizeof (sin);
798
799 return (nlm_nsm_init(nsm, &knc, &nb));
800 }
801
802 /*
803 * Initialize NSM handle used for talking to statd
804 */
805 static int
nlm_nsm_init(struct nlm_nsm * nsm,struct knetconfig * knc,struct netbuf * nb)806 nlm_nsm_init(struct nlm_nsm *nsm, struct knetconfig *knc, struct netbuf *nb)
807 {
808 enum clnt_stat stat;
809 int error, retries;
810
811 bzero(nsm, sizeof (*nsm));
812 nsm->ns_knc = *knc;
813 nlm_copy_netbuf(&nsm->ns_addr, nb);
814
815 /*
816 * Try several times to get the port of statd service,
817 * If rpcbind_getaddr returns RPC_PROGNOTREGISTERED,
818 * retry an attempt, but wait for NLM_NSM_RPCBIND_TIMEOUT
819 * seconds berofore.
820 */
821 for (retries = 0; retries < NLM_NSM_RPCBIND_RETRIES; retries++) {
822 stat = rpcbind_getaddr(&nsm->ns_knc, SM_PROG,
823 SM_VERS, &nsm->ns_addr);
824 if (stat != RPC_SUCCESS) {
825 if (stat == RPC_PROGNOTREGISTERED) {
826 delay(SEC_TO_TICK(NLM_NSM_RPCBIND_TIMEOUT));
827 continue;
828 }
829 }
830
831 break;
832 }
833
834 if (stat != RPC_SUCCESS) {
835 DTRACE_PROBE2(rpcbind__error, enum clnt_stat, stat,
836 int, retries);
837 error = ENOENT;
838 goto error;
839 }
840
841 /*
842 * Create an RPC handle that'll be used for communication with local
843 * statd using the status monitor protocol.
844 */
845 error = clnt_tli_kcreate(&nsm->ns_knc, &nsm->ns_addr, SM_PROG, SM_VERS,
846 0, NLM_RPC_RETRIES, zone_kcred(), &nsm->ns_handle);
847 if (error != 0)
848 goto error;
849
850 /*
851 * Create an RPC handle that'll be used for communication with the
852 * local statd using the address registration protocol.
853 */
854 error = clnt_tli_kcreate(&nsm->ns_knc, &nsm->ns_addr, NSM_ADDR_PROGRAM,
855 NSM_ADDR_V1, 0, NLM_RPC_RETRIES, zone_kcred(),
856 &nsm->ns_addr_handle);
857 if (error != 0)
858 goto error;
859
860 sema_init(&nsm->ns_sem, 1, NULL, SEMA_DEFAULT, NULL);
861 return (0);
862
863 error:
864 kmem_free(nsm->ns_addr.buf, nsm->ns_addr.maxlen);
865 if (nsm->ns_handle) {
866 ASSERT(nsm->ns_handle->cl_auth != NULL);
867 auth_destroy(nsm->ns_handle->cl_auth);
868 CLNT_DESTROY(nsm->ns_handle);
869 }
870
871 return (error);
872 }
873
874 static void
nlm_nsm_fini(struct nlm_nsm * nsm)875 nlm_nsm_fini(struct nlm_nsm *nsm)
876 {
877 kmem_free(nsm->ns_addr.buf, nsm->ns_addr.maxlen);
878 if (nsm->ns_addr_handle->cl_auth != NULL)
879 auth_destroy(nsm->ns_addr_handle->cl_auth);
880 CLNT_DESTROY(nsm->ns_addr_handle);
881 nsm->ns_addr_handle = NULL;
882 if (nsm->ns_handle->cl_auth != NULL)
883 auth_destroy(nsm->ns_handle->cl_auth);
884 CLNT_DESTROY(nsm->ns_handle);
885 nsm->ns_handle = NULL;
886 sema_destroy(&nsm->ns_sem);
887 }
888
889 static enum clnt_stat
nlm_nsm_simu_crash(struct nlm_nsm * nsm)890 nlm_nsm_simu_crash(struct nlm_nsm *nsm)
891 {
892 enum clnt_stat stat;
893
894 sema_p(&nsm->ns_sem);
895 nlm_nsm_clnt_init(nsm->ns_handle, nsm);
896 stat = sm_simu_crash_1(NULL, NULL, nsm->ns_handle);
897 sema_v(&nsm->ns_sem);
898
899 return (stat);
900 }
901
902 static enum clnt_stat
nlm_nsm_stat(struct nlm_nsm * nsm,int32_t * out_stat)903 nlm_nsm_stat(struct nlm_nsm *nsm, int32_t *out_stat)
904 {
905 struct sm_name args;
906 struct sm_stat_res res;
907 enum clnt_stat stat;
908
909 args.mon_name = uts_nodename();
910 bzero(&res, sizeof (res));
911
912 sema_p(&nsm->ns_sem);
913 nlm_nsm_clnt_init(nsm->ns_handle, nsm);
914 stat = sm_stat_1(&args, &res, nsm->ns_handle);
915 sema_v(&nsm->ns_sem);
916
917 if (stat == RPC_SUCCESS)
918 *out_stat = res.state;
919
920 return (stat);
921 }
922
923 static enum clnt_stat
nlm_nsm_mon(struct nlm_nsm * nsm,char * hostname,uint16_t priv)924 nlm_nsm_mon(struct nlm_nsm *nsm, char *hostname, uint16_t priv)
925 {
926 struct mon args;
927 struct sm_stat_res res;
928 enum clnt_stat stat;
929
930 bzero(&args, sizeof (args));
931 bzero(&res, sizeof (res));
932
933 args.mon_id.mon_name = hostname;
934 args.mon_id.my_id.my_name = uts_nodename();
935 args.mon_id.my_id.my_prog = NLM_PROG;
936 args.mon_id.my_id.my_vers = NLM_SM;
937 args.mon_id.my_id.my_proc = NLM_SM_NOTIFY1;
938 bcopy(&priv, args.priv, sizeof (priv));
939
940 sema_p(&nsm->ns_sem);
941 nlm_nsm_clnt_init(nsm->ns_handle, nsm);
942 stat = sm_mon_1(&args, &res, nsm->ns_handle);
943 sema_v(&nsm->ns_sem);
944
945 return (stat);
946 }
947
948 static enum clnt_stat
nlm_nsm_unmon(struct nlm_nsm * nsm,char * hostname)949 nlm_nsm_unmon(struct nlm_nsm *nsm, char *hostname)
950 {
951 struct mon_id args;
952 struct sm_stat res;
953 enum clnt_stat stat;
954
955 bzero(&args, sizeof (args));
956 bzero(&res, sizeof (res));
957
958 args.mon_name = hostname;
959 args.my_id.my_name = uts_nodename();
960 args.my_id.my_prog = NLM_PROG;
961 args.my_id.my_vers = NLM_SM;
962 args.my_id.my_proc = NLM_SM_NOTIFY1;
963
964 sema_p(&nsm->ns_sem);
965 nlm_nsm_clnt_init(nsm->ns_handle, nsm);
966 stat = sm_unmon_1(&args, &res, nsm->ns_handle);
967 sema_v(&nsm->ns_sem);
968
969 return (stat);
970 }
971
972 static enum clnt_stat
nlm_nsmaddr_reg(struct nlm_nsm * nsm,char * name,int family,netobj * address)973 nlm_nsmaddr_reg(struct nlm_nsm *nsm, char *name, int family, netobj *address)
974 {
975 struct reg1args args = { 0 };
976 struct reg1res res = { 0 };
977 enum clnt_stat stat;
978
979 args.family = family;
980 args.name = name;
981 args.address = *address;
982
983 sema_p(&nsm->ns_sem);
984 nlm_nsm_clnt_init(nsm->ns_addr_handle, nsm);
985 stat = nsmaddrproc1_reg_1(&args, &res, nsm->ns_addr_handle);
986 sema_v(&nsm->ns_sem);
987
988 return (stat);
989 }
990
991 /*
992 * Get NLM vhold object corresponding to vnode "vp".
993 * If no such object was found, create a new one.
994 *
995 * The purpose of this function is to associate vhold
996 * object with given vnode, so that:
997 * 1) vnode is hold (VN_HOLD) while vhold object is alive.
998 * 2) host has a track of all vnodes it touched by lock
999 * or share operations. These vnodes are accessible
1000 * via collection of vhold objects.
1001 */
1002 struct nlm_vhold *
nlm_vhold_get(struct nlm_host * hostp,vnode_t * vp)1003 nlm_vhold_get(struct nlm_host *hostp, vnode_t *vp)
1004 {
1005 struct nlm_vhold *nvp, *new_nvp = NULL;
1006
1007 mutex_enter(&hostp->nh_lock);
1008 nvp = nlm_vhold_find_locked(hostp, vp);
1009 if (nvp != NULL)
1010 goto out;
1011
1012 /* nlm_vhold wasn't found, then create a new one */
1013 mutex_exit(&hostp->nh_lock);
1014 new_nvp = kmem_cache_alloc(nlm_vhold_cache, KM_SLEEP);
1015
1016 /*
1017 * Check if another thread has already
1018 * created the same nlm_vhold.
1019 */
1020 mutex_enter(&hostp->nh_lock);
1021 nvp = nlm_vhold_find_locked(hostp, vp);
1022 if (nvp == NULL) {
1023 nvp = new_nvp;
1024 new_nvp = NULL;
1025
1026 TAILQ_INIT(&nvp->nv_slreqs);
1027 nvp->nv_vp = vp;
1028 nvp->nv_refcnt = 1;
1029 VN_HOLD(nvp->nv_vp);
1030
1031 VERIFY(mod_hash_insert(hostp->nh_vholds_by_vp,
1032 (mod_hash_key_t)vp, (mod_hash_val_t)nvp) == 0);
1033 TAILQ_INSERT_TAIL(&hostp->nh_vholds_list, nvp, nv_link);
1034 }
1035
1036 out:
1037 mutex_exit(&hostp->nh_lock);
1038 if (new_nvp != NULL)
1039 kmem_cache_free(nlm_vhold_cache, new_nvp);
1040
1041 return (nvp);
1042 }
1043
1044 /*
1045 * Drop a reference to vhold object nvp.
1046 */
1047 void
nlm_vhold_release(struct nlm_host * hostp,struct nlm_vhold * nvp)1048 nlm_vhold_release(struct nlm_host *hostp, struct nlm_vhold *nvp)
1049 {
1050 if (nvp == NULL)
1051 return;
1052
1053 mutex_enter(&hostp->nh_lock);
1054 ASSERT(nvp->nv_refcnt > 0);
1055 nvp->nv_refcnt--;
1056
1057 /*
1058 * If these conditions are met, the vhold is obviously unused and we
1059 * will destroy it. In a case either v_filocks and/or v_shrlocks is
1060 * non-NULL the vhold might still be unused by the host, but it is
1061 * expensive to check that. We defer such check until the host is
1062 * idle. The expensive check is done in the NLM garbage collector.
1063 */
1064 if (nvp->nv_refcnt == 0 &&
1065 nvp->nv_vp->v_filocks == NULL &&
1066 nvp->nv_vp->v_shrlocks == NULL) {
1067 nlm_vhold_destroy(hostp, nvp);
1068 }
1069
1070 mutex_exit(&hostp->nh_lock);
1071 }
1072
1073 /*
1074 * Clean all locks and share reservations on the
1075 * given vhold object that were acquired by the
1076 * given sysid
1077 */
1078 static void
nlm_vhold_clean(struct nlm_vhold * nvp,int sysid)1079 nlm_vhold_clean(struct nlm_vhold *nvp, int sysid)
1080 {
1081 cleanlocks(nvp->nv_vp, IGN_PID, sysid);
1082 cleanshares_by_sysid(nvp->nv_vp, sysid);
1083 }
1084
1085 static void
nlm_vhold_destroy(struct nlm_host * hostp,struct nlm_vhold * nvp)1086 nlm_vhold_destroy(struct nlm_host *hostp, struct nlm_vhold *nvp)
1087 {
1088 ASSERT(MUTEX_HELD(&hostp->nh_lock));
1089
1090 ASSERT(nvp->nv_refcnt == 0);
1091 ASSERT(TAILQ_EMPTY(&nvp->nv_slreqs));
1092
1093 VERIFY(mod_hash_remove(hostp->nh_vholds_by_vp,
1094 (mod_hash_key_t)nvp->nv_vp,
1095 (mod_hash_val_t)&nvp) == 0);
1096
1097 TAILQ_REMOVE(&hostp->nh_vholds_list, nvp, nv_link);
1098 VN_RELE(nvp->nv_vp);
1099 nvp->nv_vp = NULL;
1100
1101 kmem_cache_free(nlm_vhold_cache, nvp);
1102 }
1103
1104 /*
1105 * Return TRUE if the given vhold is busy.
1106 * Vhold object is considered to be "busy" when
1107 * all the following conditions hold:
1108 * 1) No one uses it at the moment;
1109 * 2) It hasn't any locks;
1110 * 3) It hasn't any share reservations;
1111 */
1112 static bool_t
nlm_vhold_busy(struct nlm_host * hostp,struct nlm_vhold * nvp)1113 nlm_vhold_busy(struct nlm_host *hostp, struct nlm_vhold *nvp)
1114 {
1115 vnode_t *vp;
1116 int sysid;
1117
1118 ASSERT(MUTEX_HELD(&hostp->nh_lock));
1119
1120 if (nvp->nv_refcnt > 0)
1121 return (TRUE);
1122
1123 vp = nvp->nv_vp;
1124 sysid = hostp->nh_sysid;
1125 if (flk_has_remote_locks_for_sysid(vp, sysid) ||
1126 shr_has_remote_shares(vp, sysid))
1127 return (TRUE);
1128
1129 return (FALSE);
1130 }
1131
1132 /* ARGSUSED */
1133 static int
nlm_vhold_ctor(void * datap,void * cdrarg,int kmflags)1134 nlm_vhold_ctor(void *datap, void *cdrarg, int kmflags)
1135 {
1136 struct nlm_vhold *nvp = (struct nlm_vhold *)datap;
1137
1138 bzero(nvp, sizeof (*nvp));
1139 return (0);
1140 }
1141
1142 /* ARGSUSED */
1143 static void
nlm_vhold_dtor(void * datap,void * cdrarg)1144 nlm_vhold_dtor(void *datap, void *cdrarg)
1145 {
1146 struct nlm_vhold *nvp = (struct nlm_vhold *)datap;
1147
1148 ASSERT(nvp->nv_refcnt == 0);
1149 ASSERT(TAILQ_EMPTY(&nvp->nv_slreqs));
1150 ASSERT(nvp->nv_vp == NULL);
1151 }
1152
1153 struct nlm_vhold *
nlm_vhold_find_locked(struct nlm_host * hostp,const vnode_t * vp)1154 nlm_vhold_find_locked(struct nlm_host *hostp, const vnode_t *vp)
1155 {
1156 struct nlm_vhold *nvp = NULL;
1157
1158 ASSERT(MUTEX_HELD(&hostp->nh_lock));
1159 (void) mod_hash_find(hostp->nh_vholds_by_vp,
1160 (mod_hash_key_t)vp,
1161 (mod_hash_val_t)&nvp);
1162
1163 if (nvp != NULL)
1164 nvp->nv_refcnt++;
1165
1166 return (nvp);
1167 }
1168
1169 /*
1170 * NLM host functions
1171 */
1172 static void
nlm_copy_netbuf(struct netbuf * dst,struct netbuf * src)1173 nlm_copy_netbuf(struct netbuf *dst, struct netbuf *src)
1174 {
1175 ASSERT(src->len <= src->maxlen);
1176
1177 dst->maxlen = src->maxlen;
1178 dst->len = src->len;
1179 dst->buf = kmem_zalloc(src->maxlen, KM_SLEEP);
1180 bcopy(src->buf, dst->buf, src->len);
1181 }
1182
1183 /* ARGSUSED */
1184 static int
nlm_host_ctor(void * datap,void * cdrarg,int kmflags)1185 nlm_host_ctor(void *datap, void *cdrarg, int kmflags)
1186 {
1187 struct nlm_host *hostp = (struct nlm_host *)datap;
1188
1189 bzero(hostp, sizeof (*hostp));
1190 return (0);
1191 }
1192
1193 /* ARGSUSED */
1194 static void
nlm_host_dtor(void * datap,void * cdrarg)1195 nlm_host_dtor(void *datap, void *cdrarg)
1196 {
1197 struct nlm_host *hostp = (struct nlm_host *)datap;
1198 ASSERT(hostp->nh_refs == 0);
1199 }
1200
1201 static void
nlm_host_unregister(struct nlm_globals * g,struct nlm_host * hostp)1202 nlm_host_unregister(struct nlm_globals *g, struct nlm_host *hostp)
1203 {
1204 ASSERT(hostp->nh_refs == 0);
1205 ASSERT(hostp->nh_flags & NLM_NH_INIDLE);
1206
1207 avl_remove(&g->nlm_hosts_tree, hostp);
1208 VERIFY(mod_hash_remove(g->nlm_hosts_hash,
1209 (mod_hash_key_t)(uintptr_t)hostp->nh_sysid,
1210 (mod_hash_val_t)&hostp) == 0);
1211 TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
1212 hostp->nh_flags &= ~NLM_NH_INIDLE;
1213 }
1214
1215 /*
1216 * Free resources used by a host. This is called after the reference
1217 * count has reached zero so it doesn't need to worry about locks.
1218 */
1219 static void
nlm_host_destroy(struct nlm_host * hostp)1220 nlm_host_destroy(struct nlm_host *hostp)
1221 {
1222 ASSERT(hostp->nh_name != NULL);
1223 ASSERT(hostp->nh_netid != NULL);
1224 ASSERT(TAILQ_EMPTY(&hostp->nh_vholds_list));
1225
1226 strfree(hostp->nh_name);
1227 strfree(hostp->nh_netid);
1228 kmem_free(hostp->nh_addr.buf, hostp->nh_addr.maxlen);
1229
1230 if (hostp->nh_sysid != LM_NOSYSID)
1231 nlm_sysid_free(hostp->nh_sysid);
1232
1233 nlm_rpc_cache_destroy(hostp);
1234
1235 ASSERT(TAILQ_EMPTY(&hostp->nh_vholds_list));
1236 mod_hash_destroy_ptrhash(hostp->nh_vholds_by_vp);
1237
1238 mutex_destroy(&hostp->nh_lock);
1239 cv_destroy(&hostp->nh_rpcb_cv);
1240 cv_destroy(&hostp->nh_recl_cv);
1241
1242 kmem_cache_free(nlm_hosts_cache, hostp);
1243 }
1244
1245 /*
1246 * Cleanup SERVER-side state after a client restarts,
1247 * or becomes unresponsive, or whatever.
1248 *
1249 * We unlock any active locks owned by the host.
1250 * When rpc.lockd is shutting down,
1251 * this function is called with newstate set to zero
1252 * which allows us to cancel any pending async locks
1253 * and clear the locking state.
1254 *
1255 * When "state" is 0, we don't update host's state,
1256 * but cleanup all remote locks on the host.
1257 * It's useful to call this function for resources
1258 * cleanup.
1259 */
1260 void
nlm_host_notify_server(struct nlm_host * hostp,int32_t state)1261 nlm_host_notify_server(struct nlm_host *hostp, int32_t state)
1262 {
1263 struct nlm_vhold *nvp;
1264 struct nlm_slreq *slr;
1265 struct nlm_slreq_list slreqs2free;
1266
1267 TAILQ_INIT(&slreqs2free);
1268 mutex_enter(&hostp->nh_lock);
1269 if (state != 0)
1270 hostp->nh_state = state;
1271
1272 TAILQ_FOREACH(nvp, &hostp->nh_vholds_list, nv_link) {
1273
1274 /* cleanup sleeping requests at first */
1275 while ((slr = TAILQ_FIRST(&nvp->nv_slreqs)) != NULL) {
1276 TAILQ_REMOVE(&nvp->nv_slreqs, slr, nsr_link);
1277
1278 /*
1279 * Instead of freeing cancelled sleeping request
1280 * here, we add it to the linked list created
1281 * on the stack in order to do all frees outside
1282 * the critical section.
1283 */
1284 TAILQ_INSERT_TAIL(&slreqs2free, slr, nsr_link);
1285 }
1286
1287 nvp->nv_refcnt++;
1288 mutex_exit(&hostp->nh_lock);
1289
1290 nlm_vhold_clean(nvp, hostp->nh_sysid);
1291
1292 mutex_enter(&hostp->nh_lock);
1293 nvp->nv_refcnt--;
1294 }
1295
1296 mutex_exit(&hostp->nh_lock);
1297 while ((slr = TAILQ_FIRST(&slreqs2free)) != NULL) {
1298 TAILQ_REMOVE(&slreqs2free, slr, nsr_link);
1299 kmem_free(slr, sizeof (*slr));
1300 }
1301 }
1302
1303 /*
1304 * Cleanup CLIENT-side state after a server restarts,
1305 * or becomes unresponsive, or whatever.
1306 *
1307 * This is called by the local NFS statd when we receive a
1308 * host state change notification. (also nlm_svc_stopping)
1309 *
1310 * Deal with a server restart. If we are stopping the
1311 * NLM service, we'll have newstate == 0, and will just
1312 * cancel all our client-side lock requests. Otherwise,
1313 * start the "recovery" process to reclaim any locks
1314 * we hold on this server.
1315 */
1316 void
nlm_host_notify_client(struct nlm_host * hostp,int32_t state)1317 nlm_host_notify_client(struct nlm_host *hostp, int32_t state)
1318 {
1319 mutex_enter(&hostp->nh_lock);
1320 hostp->nh_state = state;
1321 if (hostp->nh_flags & NLM_NH_RECLAIM) {
1322 /*
1323 * Either host's state is up to date or
1324 * host is already in recovery.
1325 */
1326 mutex_exit(&hostp->nh_lock);
1327 return;
1328 }
1329
1330 hostp->nh_flags |= NLM_NH_RECLAIM;
1331
1332 /*
1333 * Host will be released by the recovery thread,
1334 * thus we need to increment refcount.
1335 */
1336 hostp->nh_refs++;
1337 mutex_exit(&hostp->nh_lock);
1338
1339 (void) zthread_create(NULL, 0, nlm_reclaimer,
1340 hostp, 0, minclsyspri);
1341 }
1342
1343 /*
1344 * The function is called when NLM client detects that
1345 * server has entered in grace period and client needs
1346 * to wait until reclamation process (if any) does
1347 * its job.
1348 */
1349 int
nlm_host_wait_grace(struct nlm_host * hostp)1350 nlm_host_wait_grace(struct nlm_host *hostp)
1351 {
1352 struct nlm_globals *g;
1353 int error = 0;
1354
1355 g = zone_getspecific(nlm_zone_key, curzone);
1356 mutex_enter(&hostp->nh_lock);
1357
1358 do {
1359 int rc;
1360
1361 rc = cv_timedwait_sig(&hostp->nh_recl_cv,
1362 &hostp->nh_lock, ddi_get_lbolt() +
1363 SEC_TO_TICK(g->retrans_tmo));
1364
1365 if (rc == 0) {
1366 error = EINTR;
1367 break;
1368 }
1369 } while (hostp->nh_flags & NLM_NH_RECLAIM);
1370
1371 mutex_exit(&hostp->nh_lock);
1372 return (error);
1373 }
1374
1375 /*
1376 * Create a new NLM host.
1377 *
1378 * NOTE: The in-kernel RPC (kRPC) subsystem uses TLI/XTI,
1379 * which needs both a knetconfig and an address when creating
1380 * endpoints. Thus host object stores both knetconfig and
1381 * netid.
1382 */
1383 static struct nlm_host *
nlm_host_create(char * name,const char * netid,struct knetconfig * knc,struct netbuf * naddr)1384 nlm_host_create(char *name, const char *netid,
1385 struct knetconfig *knc, struct netbuf *naddr)
1386 {
1387 struct nlm_host *host;
1388
1389 host = kmem_cache_alloc(nlm_hosts_cache, KM_SLEEP);
1390
1391 mutex_init(&host->nh_lock, NULL, MUTEX_DEFAULT, NULL);
1392 cv_init(&host->nh_rpcb_cv, NULL, CV_DEFAULT, NULL);
1393 cv_init(&host->nh_recl_cv, NULL, CV_DEFAULT, NULL);
1394
1395 host->nh_sysid = LM_NOSYSID;
1396 host->nh_refs = 1;
1397 host->nh_name = strdup(name);
1398 host->nh_netid = strdup(netid);
1399 host->nh_knc = *knc;
1400 nlm_copy_netbuf(&host->nh_addr, naddr);
1401
1402 host->nh_state = 0;
1403 host->nh_rpcb_state = NRPCB_NEED_UPDATE;
1404 host->nh_flags = 0;
1405
1406 host->nh_vholds_by_vp = mod_hash_create_ptrhash("nlm vholds hash",
1407 32, mod_hash_null_valdtor, sizeof (vnode_t));
1408
1409 TAILQ_INIT(&host->nh_vholds_list);
1410 TAILQ_INIT(&host->nh_rpchc);
1411
1412 return (host);
1413 }
1414
1415 /*
1416 * Cancel all client side sleeping locks owned by given host.
1417 */
1418 void
nlm_host_cancel_slocks(struct nlm_globals * g,struct nlm_host * hostp)1419 nlm_host_cancel_slocks(struct nlm_globals *g, struct nlm_host *hostp)
1420 {
1421 struct nlm_slock *nslp;
1422
1423 mutex_enter(&g->lock);
1424 TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) {
1425 if (nslp->nsl_host == hostp) {
1426 nslp->nsl_state = NLM_SL_CANCELLED;
1427 cv_broadcast(&nslp->nsl_cond);
1428 }
1429 }
1430
1431 mutex_exit(&g->lock);
1432 }
1433
1434 /*
1435 * Garbage collect stale vhold objects.
1436 *
1437 * In other words check whether vnodes that are
1438 * held by vhold objects still have any locks
1439 * or shares or still in use. If they aren't,
1440 * just destroy them.
1441 */
1442 static void
nlm_host_gc_vholds(struct nlm_host * hostp)1443 nlm_host_gc_vholds(struct nlm_host *hostp)
1444 {
1445 struct nlm_vhold *nvp;
1446
1447 ASSERT(MUTEX_HELD(&hostp->nh_lock));
1448
1449 nvp = TAILQ_FIRST(&hostp->nh_vholds_list);
1450 while (nvp != NULL) {
1451 struct nlm_vhold *nvp_tmp;
1452
1453 if (nlm_vhold_busy(hostp, nvp)) {
1454 nvp = TAILQ_NEXT(nvp, nv_link);
1455 continue;
1456 }
1457
1458 nvp_tmp = TAILQ_NEXT(nvp, nv_link);
1459 nlm_vhold_destroy(hostp, nvp);
1460 nvp = nvp_tmp;
1461 }
1462 }
1463
1464 /*
1465 * Check whether the given host has any
1466 * server side locks or share reservations.
1467 */
1468 static bool_t
nlm_host_has_srv_locks(struct nlm_host * hostp)1469 nlm_host_has_srv_locks(struct nlm_host *hostp)
1470 {
1471 /*
1472 * It's cheap and simple: if server has
1473 * any locks/shares there must be vhold
1474 * object storing the affected vnode.
1475 *
1476 * NOTE: We don't need to check sleeping
1477 * locks on the server side, because if
1478 * server side sleeping lock is alive,
1479 * there must be a vhold object corresponding
1480 * to target vnode.
1481 */
1482 ASSERT(MUTEX_HELD(&hostp->nh_lock));
1483 if (!TAILQ_EMPTY(&hostp->nh_vholds_list))
1484 return (TRUE);
1485
1486 return (FALSE);
1487 }
1488
1489 /*
1490 * Check whether the given host has any client side
1491 * locks or share reservations.
1492 */
1493 static bool_t
nlm_host_has_cli_locks(struct nlm_host * hostp)1494 nlm_host_has_cli_locks(struct nlm_host *hostp)
1495 {
1496 ASSERT(MUTEX_HELD(&hostp->nh_lock));
1497
1498 /*
1499 * XXX: It's not the way I'd like to do the check,
1500 * because flk_sysid_has_locks() can be very
1501 * expensive by design. Unfortunatelly it iterates
1502 * through all locks on the system, doesn't matter
1503 * were they made on remote system via NLM or
1504 * on local system via reclock. To understand the
1505 * problem, consider that there're dozens of thousands
1506 * of locks that are made on some ZFS dataset. And there's
1507 * another dataset shared by NFS where NLM client had locks
1508 * some time ago, but doesn't have them now.
1509 * In this case flk_sysid_has_locks() will iterate
1510 * thrught dozens of thousands locks until it returns us
1511 * FALSE.
1512 * Oh, I hope that in shiny future somebody will make
1513 * local lock manager (os/flock.c) better, so that
1514 * it'd be more friedly to remote locks and
1515 * flk_sysid_has_locks() wouldn't be so expensive.
1516 */
1517 if (flk_sysid_has_locks(hostp->nh_sysid |
1518 LM_SYSID_CLIENT, FLK_QUERY_ACTIVE))
1519 return (TRUE);
1520
1521 /*
1522 * Check whether host has any share reservations
1523 * registered on the client side.
1524 */
1525 if (hostp->nh_shrlist != NULL)
1526 return (TRUE);
1527
1528 return (FALSE);
1529 }
1530
1531 /*
1532 * Determine whether the given host owns any
1533 * locks or share reservations.
1534 */
1535 static bool_t
nlm_host_has_locks(struct nlm_host * hostp)1536 nlm_host_has_locks(struct nlm_host *hostp)
1537 {
1538 if (nlm_host_has_srv_locks(hostp))
1539 return (TRUE);
1540
1541 return (nlm_host_has_cli_locks(hostp));
1542 }
1543
1544 /*
1545 * This function compares only addresses of two netbufs
1546 * that belong to NC_TCP[6] or NC_UDP[6] protofamily.
1547 * Port part of netbuf is ignored.
1548 *
1549 * Return values:
1550 * -1: nb1's address is "smaller" than nb2's
1551 * 0: addresses are equal
1552 * 1: nb1's address is "greater" than nb2's
1553 */
1554 static int
nlm_netbuf_addrs_cmp(struct netbuf * nb1,struct netbuf * nb2)1555 nlm_netbuf_addrs_cmp(struct netbuf *nb1, struct netbuf *nb2)
1556 {
1557 union nlm_addr {
1558 struct sockaddr sa;
1559 struct sockaddr_in sin;
1560 struct sockaddr_in6 sin6;
1561 } *na1, *na2;
1562 int res;
1563
1564 /* LINTED E_BAD_PTR_CAST_ALIGN */
1565 na1 = (union nlm_addr *)nb1->buf;
1566 /* LINTED E_BAD_PTR_CAST_ALIGN */
1567 na2 = (union nlm_addr *)nb2->buf;
1568
1569 if (na1->sa.sa_family < na2->sa.sa_family)
1570 return (-1);
1571 if (na1->sa.sa_family > na2->sa.sa_family)
1572 return (1);
1573
1574 switch (na1->sa.sa_family) {
1575 case AF_INET:
1576 res = memcmp(&na1->sin.sin_addr, &na2->sin.sin_addr,
1577 sizeof (na1->sin.sin_addr));
1578 break;
1579 case AF_INET6:
1580 res = memcmp(&na1->sin6.sin6_addr, &na2->sin6.sin6_addr,
1581 sizeof (na1->sin6.sin6_addr));
1582 break;
1583 default:
1584 VERIFY(0);
1585 return (0);
1586 }
1587
1588 return (SIGN(res));
1589 }
1590
1591 /*
1592 * Compare two nlm hosts.
1593 * Return values:
1594 * -1: host1 is "smaller" than host2
1595 * 0: host1 is equal to host2
1596 * 1: host1 is "greater" than host2
1597 */
1598 int
nlm_host_cmp(const void * p1,const void * p2)1599 nlm_host_cmp(const void *p1, const void *p2)
1600 {
1601 struct nlm_host *h1 = (struct nlm_host *)p1;
1602 struct nlm_host *h2 = (struct nlm_host *)p2;
1603 int res;
1604
1605 res = strcmp(h1->nh_netid, h2->nh_netid);
1606 if (res != 0)
1607 return (SIGN(res));
1608
1609 res = nlm_netbuf_addrs_cmp(&h1->nh_addr, &h2->nh_addr);
1610 return (res);
1611 }
1612
1613 /*
1614 * Find the host specified by... (see below)
1615 * If found, increment the ref count.
1616 */
1617 static struct nlm_host *
nlm_host_find_locked(struct nlm_globals * g,const char * netid,struct netbuf * naddr,avl_index_t * wherep)1618 nlm_host_find_locked(struct nlm_globals *g, const char *netid,
1619 struct netbuf *naddr, avl_index_t *wherep)
1620 {
1621 struct nlm_host *hostp, key;
1622 avl_index_t pos;
1623
1624 ASSERT(MUTEX_HELD(&g->lock));
1625
1626 key.nh_netid = (char *)netid;
1627 key.nh_addr.buf = naddr->buf;
1628 key.nh_addr.len = naddr->len;
1629 key.nh_addr.maxlen = naddr->maxlen;
1630
1631 hostp = avl_find(&g->nlm_hosts_tree, &key, &pos);
1632
1633 if (hostp != NULL) {
1634 /*
1635 * Host is inuse now. Remove it from idle
1636 * hosts list if needed.
1637 */
1638 if (hostp->nh_flags & NLM_NH_INIDLE) {
1639 TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
1640 hostp->nh_flags &= ~NLM_NH_INIDLE;
1641 }
1642
1643 hostp->nh_refs++;
1644 }
1645 if (wherep != NULL)
1646 *wherep = pos;
1647
1648 return (hostp);
1649 }
1650
1651 /*
1652 * Find NLM host for the given name and address.
1653 */
1654 struct nlm_host *
nlm_host_find(struct nlm_globals * g,const char * netid,struct netbuf * addr)1655 nlm_host_find(struct nlm_globals *g, const char *netid,
1656 struct netbuf *addr)
1657 {
1658 struct nlm_host *hostp = NULL;
1659
1660 mutex_enter(&g->lock);
1661 if (g->run_status != NLM_ST_UP)
1662 goto out;
1663
1664 hostp = nlm_host_find_locked(g, netid, addr, NULL);
1665
1666 out:
1667 mutex_exit(&g->lock);
1668 return (hostp);
1669 }
1670
1671
1672 /*
1673 * Find or create an NLM host for the given name and address.
1674 *
1675 * The remote host is determined by all of: name, netid, address.
1676 * Note that the netid is whatever nlm_svc_add_ep() gave to
1677 * svc_tli_kcreate() for the service binding. If any of these
1678 * are different, allocate a new host (new sysid).
1679 */
1680 struct nlm_host *
nlm_host_findcreate(struct nlm_globals * g,char * name,const char * netid,struct netbuf * addr)1681 nlm_host_findcreate(struct nlm_globals *g, char *name,
1682 const char *netid, struct netbuf *addr)
1683 {
1684 int err;
1685 struct nlm_host *host, *newhost = NULL;
1686 struct knetconfig knc;
1687 avl_index_t where;
1688
1689 mutex_enter(&g->lock);
1690 if (g->run_status != NLM_ST_UP) {
1691 mutex_exit(&g->lock);
1692 return (NULL);
1693 }
1694
1695 host = nlm_host_find_locked(g, netid, addr, NULL);
1696 mutex_exit(&g->lock);
1697 if (host != NULL)
1698 return (host);
1699
1700 err = nlm_knc_from_netid(netid, &knc);
1701 if (err != 0)
1702 return (NULL);
1703 /*
1704 * Do allocations (etc.) outside of mutex,
1705 * and then check again before inserting.
1706 */
1707 newhost = nlm_host_create(name, netid, &knc, addr);
1708 newhost->nh_sysid = nlm_sysid_alloc();
1709 if (newhost->nh_sysid == LM_NOSYSID)
1710 goto out;
1711
1712 mutex_enter(&g->lock);
1713 host = nlm_host_find_locked(g, netid, addr, &where);
1714 if (host == NULL) {
1715 host = newhost;
1716 newhost = NULL;
1717
1718 /*
1719 * Insert host to the hosts AVL tree that is
1720 * used to lookup by <netid, address> pair.
1721 */
1722 avl_insert(&g->nlm_hosts_tree, host, where);
1723
1724 /*
1725 * Insert host to the hosts hash table that is
1726 * used to lookup host by sysid.
1727 */
1728 VERIFY(mod_hash_insert(g->nlm_hosts_hash,
1729 (mod_hash_key_t)(uintptr_t)host->nh_sysid,
1730 (mod_hash_val_t)host) == 0);
1731 }
1732
1733 mutex_exit(&g->lock);
1734
1735 out:
1736 if (newhost != NULL) {
1737 /*
1738 * We do not need the preallocated nlm_host
1739 * so decrement the reference counter
1740 * and destroy it.
1741 */
1742 newhost->nh_refs--;
1743 nlm_host_destroy(newhost);
1744 }
1745
1746 return (host);
1747 }
1748
1749 /*
1750 * Find the NLM host that matches the value of 'sysid'.
1751 * If found, return it with a new ref,
1752 * else return NULL.
1753 */
1754 struct nlm_host *
nlm_host_find_by_sysid(struct nlm_globals * g,sysid_t sysid)1755 nlm_host_find_by_sysid(struct nlm_globals *g, sysid_t sysid)
1756 {
1757 struct nlm_host *hostp = NULL;
1758
1759 mutex_enter(&g->lock);
1760 if (g->run_status != NLM_ST_UP)
1761 goto out;
1762
1763 (void) mod_hash_find(g->nlm_hosts_hash,
1764 (mod_hash_key_t)(uintptr_t)sysid,
1765 (mod_hash_val_t)&hostp);
1766
1767 if (hostp == NULL)
1768 goto out;
1769
1770 /*
1771 * Host is inuse now. Remove it
1772 * from idle hosts list if needed.
1773 */
1774 if (hostp->nh_flags & NLM_NH_INIDLE) {
1775 TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
1776 hostp->nh_flags &= ~NLM_NH_INIDLE;
1777 }
1778
1779 hostp->nh_refs++;
1780
1781 out:
1782 mutex_exit(&g->lock);
1783 return (hostp);
1784 }
1785
1786 /*
1787 * Release the given host.
1788 * I.e. drop a reference that was taken earlier by one of
1789 * the following functions: nlm_host_findcreate(), nlm_host_find(),
1790 * nlm_host_find_by_sysid().
1791 *
1792 * When the very last reference is dropped, host is moved to
1793 * so-called "idle state". All hosts that are in idle state
1794 * have an idle timeout. If timeout is expired, GC thread
1795 * checks whether hosts have any locks and if they heven't
1796 * any, it removes them.
1797 * NOTE: only unused hosts can be in idle state.
1798 */
1799 static void
nlm_host_release_locked(struct nlm_globals * g,struct nlm_host * hostp)1800 nlm_host_release_locked(struct nlm_globals *g, struct nlm_host *hostp)
1801 {
1802 if (hostp == NULL)
1803 return;
1804
1805 ASSERT(MUTEX_HELD(&g->lock));
1806 ASSERT(hostp->nh_refs > 0);
1807
1808 hostp->nh_refs--;
1809 if (hostp->nh_refs != 0)
1810 return;
1811
1812 /*
1813 * The very last reference to the host was dropped,
1814 * thus host is unused now. Set its idle timeout
1815 * and move it to the idle hosts LRU list.
1816 */
1817 hostp->nh_idle_timeout = ddi_get_lbolt() +
1818 SEC_TO_TICK(g->cn_idle_tmo);
1819
1820 ASSERT((hostp->nh_flags & NLM_NH_INIDLE) == 0);
1821 TAILQ_INSERT_TAIL(&g->nlm_idle_hosts, hostp, nh_link);
1822 hostp->nh_flags |= NLM_NH_INIDLE;
1823 }
1824
1825 void
nlm_host_release(struct nlm_globals * g,struct nlm_host * hostp)1826 nlm_host_release(struct nlm_globals *g, struct nlm_host *hostp)
1827 {
1828 if (hostp == NULL)
1829 return;
1830
1831 mutex_enter(&g->lock);
1832 nlm_host_release_locked(g, hostp);
1833 mutex_exit(&g->lock);
1834 }
1835
1836 /*
1837 * Unregister this NLM host (NFS client) with the local statd
1838 * due to idleness (no locks held for a while).
1839 */
1840 void
nlm_host_unmonitor(struct nlm_globals * g,struct nlm_host * host)1841 nlm_host_unmonitor(struct nlm_globals *g, struct nlm_host *host)
1842 {
1843 enum clnt_stat stat;
1844
1845 VERIFY(host->nh_refs == 0);
1846 if (!(host->nh_flags & NLM_NH_MONITORED))
1847 return;
1848
1849 host->nh_flags &= ~NLM_NH_MONITORED;
1850 stat = nlm_nsm_unmon(&g->nlm_nsm, host->nh_name);
1851 if (stat != RPC_SUCCESS) {
1852 NLM_WARN("NLM: Failed to contact statd, stat=%d\n", stat);
1853 return;
1854 }
1855 }
1856
1857 /*
1858 * Ask the local NFS statd to begin monitoring this host.
1859 * It will call us back when that host restarts, using the
1860 * prog,vers,proc specified below, i.e. NLM_SM_NOTIFY1,
1861 * which is handled in nlm_do_notify1().
1862 */
1863 void
nlm_host_monitor(struct nlm_globals * g,struct nlm_host * host,int state)1864 nlm_host_monitor(struct nlm_globals *g, struct nlm_host *host, int state)
1865 {
1866 int family;
1867 netobj obj;
1868 enum clnt_stat stat;
1869
1870 if (state != 0 && host->nh_state == 0) {
1871 /*
1872 * This is the first time we have seen an NSM state
1873 * Value for this host. We record it here to help
1874 * detect host reboots.
1875 */
1876 host->nh_state = state;
1877 }
1878
1879 mutex_enter(&host->nh_lock);
1880 if (host->nh_flags & NLM_NH_MONITORED) {
1881 mutex_exit(&host->nh_lock);
1882 return;
1883 }
1884
1885 host->nh_flags |= NLM_NH_MONITORED;
1886 mutex_exit(&host->nh_lock);
1887
1888 /*
1889 * Before we begin monitoring the host register the network address
1890 * associated with this hostname.
1891 */
1892 nlm_netbuf_to_netobj(&host->nh_addr, &family, &obj);
1893 stat = nlm_nsmaddr_reg(&g->nlm_nsm, host->nh_name, family, &obj);
1894 if (stat != RPC_SUCCESS) {
1895 NLM_WARN("Failed to register address, stat=%d\n", stat);
1896 mutex_enter(&g->lock);
1897 host->nh_flags &= ~NLM_NH_MONITORED;
1898 mutex_exit(&g->lock);
1899
1900 return;
1901 }
1902
1903 /*
1904 * Tell statd how to call us with status updates for
1905 * this host. Updates arrive via nlm_do_notify1().
1906 *
1907 * We put our assigned system ID value in the priv field to
1908 * make it simpler to find the host if we are notified of a
1909 * host restart.
1910 */
1911 stat = nlm_nsm_mon(&g->nlm_nsm, host->nh_name, host->nh_sysid);
1912 if (stat != RPC_SUCCESS) {
1913 NLM_WARN("Failed to contact local NSM, stat=%d\n", stat);
1914 mutex_enter(&g->lock);
1915 host->nh_flags &= ~NLM_NH_MONITORED;
1916 mutex_exit(&g->lock);
1917
1918 return;
1919 }
1920 }
1921
1922 int
nlm_host_get_state(struct nlm_host * hostp)1923 nlm_host_get_state(struct nlm_host *hostp)
1924 {
1925
1926 return (hostp->nh_state);
1927 }
1928
1929 /*
1930 * NLM client/server sleeping locks
1931 */
1932
1933 /*
1934 * Register client side sleeping lock.
1935 *
1936 * Our client code calls this to keep information
1937 * about sleeping lock somewhere. When it receives
1938 * grant callback from server or when it just
1939 * needs to remove all sleeping locks from vnode,
1940 * it uses this information for remove/apply lock
1941 * properly.
1942 */
1943 struct nlm_slock *
nlm_slock_register(struct nlm_globals * g,struct nlm_host * host,struct nlm4_lock * lock,struct vnode * vp)1944 nlm_slock_register(
1945 struct nlm_globals *g,
1946 struct nlm_host *host,
1947 struct nlm4_lock *lock,
1948 struct vnode *vp)
1949 {
1950 struct nlm_slock *nslp;
1951
1952 nslp = kmem_zalloc(sizeof (*nslp), KM_SLEEP);
1953 cv_init(&nslp->nsl_cond, NULL, CV_DEFAULT, NULL);
1954 nslp->nsl_lock = *lock;
1955 nlm_copy_netobj(&nslp->nsl_fh, &nslp->nsl_lock.fh);
1956 nslp->nsl_state = NLM_SL_BLOCKED;
1957 nslp->nsl_host = host;
1958 nslp->nsl_vp = vp;
1959
1960 mutex_enter(&g->lock);
1961 TAILQ_INSERT_TAIL(&g->nlm_slocks, nslp, nsl_link);
1962 mutex_exit(&g->lock);
1963
1964 return (nslp);
1965 }
1966
1967 /*
1968 * Remove this lock from the wait list and destroy it.
1969 */
1970 void
nlm_slock_unregister(struct nlm_globals * g,struct nlm_slock * nslp)1971 nlm_slock_unregister(struct nlm_globals *g, struct nlm_slock *nslp)
1972 {
1973 mutex_enter(&g->lock);
1974 TAILQ_REMOVE(&g->nlm_slocks, nslp, nsl_link);
1975 mutex_exit(&g->lock);
1976
1977 kmem_free(nslp->nsl_fh.n_bytes, nslp->nsl_fh.n_len);
1978 cv_destroy(&nslp->nsl_cond);
1979 kmem_free(nslp, sizeof (*nslp));
1980 }
1981
1982 /*
1983 * Wait for a granted callback or cancellation event
1984 * for a sleeping lock.
1985 *
1986 * If a signal interrupted the wait or if the lock
1987 * was cancelled, return EINTR - the caller must arrange to send
1988 * a cancellation to the server.
1989 *
1990 * If timeout occurred, return ETIMEDOUT - the caller must
1991 * resend the lock request to the server.
1992 *
1993 * On success return 0.
1994 */
1995 int
nlm_slock_wait(struct nlm_globals * g,struct nlm_slock * nslp,uint_t timeo_secs)1996 nlm_slock_wait(struct nlm_globals *g,
1997 struct nlm_slock *nslp, uint_t timeo_secs)
1998 {
1999 clock_t timeo_ticks;
2000 int cv_res, error;
2001
2002 /*
2003 * If the granted message arrived before we got here,
2004 * nslp->nsl_state will be NLM_SL_GRANTED - in that case don't sleep.
2005 */
2006 cv_res = 1;
2007 timeo_ticks = ddi_get_lbolt() + SEC_TO_TICK(timeo_secs);
2008
2009 mutex_enter(&g->lock);
2010 while (nslp->nsl_state == NLM_SL_BLOCKED && cv_res > 0) {
2011 cv_res = cv_timedwait_sig(&nslp->nsl_cond,
2012 &g->lock, timeo_ticks);
2013 }
2014
2015 /*
2016 * No matter why we wake up, if the lock was
2017 * cancelled, let the function caller to know
2018 * about it by returning EINTR.
2019 */
2020 if (nslp->nsl_state == NLM_SL_CANCELLED) {
2021 error = EINTR;
2022 goto out;
2023 }
2024
2025 if (cv_res <= 0) {
2026 /* We were woken up either by timeout or by interrupt */
2027 error = (cv_res < 0) ? ETIMEDOUT : EINTR;
2028
2029 /*
2030 * The granted message may arrive after the
2031 * interrupt/timeout but before we manage to lock the
2032 * mutex. Detect this by examining nslp.
2033 */
2034 if (nslp->nsl_state == NLM_SL_GRANTED)
2035 error = 0;
2036 } else { /* Awaken via cv_signal()/cv_broadcast() or didn't block */
2037 error = 0;
2038 VERIFY(nslp->nsl_state == NLM_SL_GRANTED);
2039 }
2040
2041 out:
2042 mutex_exit(&g->lock);
2043 return (error);
2044 }
2045
2046 /*
2047 * Mark client side sleeping lock as granted
2048 * and wake up a process blocked on the lock.
2049 * Called from server side NLM_GRANT handler.
2050 *
2051 * If sleeping lock is found return 0, otherwise
2052 * return ENOENT.
2053 */
2054 int
nlm_slock_grant(struct nlm_globals * g,struct nlm_host * hostp,struct nlm4_lock * alock)2055 nlm_slock_grant(struct nlm_globals *g,
2056 struct nlm_host *hostp, struct nlm4_lock *alock)
2057 {
2058 struct nlm_slock *nslp;
2059 int error = ENOENT;
2060
2061 mutex_enter(&g->lock);
2062 TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) {
2063 if ((nslp->nsl_state != NLM_SL_BLOCKED) ||
2064 (nslp->nsl_host != hostp))
2065 continue;
2066
2067 if (alock->svid == nslp->nsl_lock.svid &&
2068 alock->l_offset == nslp->nsl_lock.l_offset &&
2069 alock->l_len == nslp->nsl_lock.l_len &&
2070 alock->fh.n_len == nslp->nsl_lock.fh.n_len &&
2071 bcmp(alock->fh.n_bytes, nslp->nsl_lock.fh.n_bytes,
2072 nslp->nsl_lock.fh.n_len) == 0) {
2073 nslp->nsl_state = NLM_SL_GRANTED;
2074 cv_broadcast(&nslp->nsl_cond);
2075 error = 0;
2076 break;
2077 }
2078 }
2079
2080 mutex_exit(&g->lock);
2081 return (error);
2082 }
2083
2084 /*
2085 * Register sleeping lock request corresponding to
2086 * flp on the given vhold object.
2087 * On success function returns 0, otherwise (if
2088 * lock request with the same flp is already
2089 * registered) function returns EEXIST.
2090 */
2091 int
nlm_slreq_register(struct nlm_host * hostp,struct nlm_vhold * nvp,struct flock64 * flp)2092 nlm_slreq_register(struct nlm_host *hostp, struct nlm_vhold *nvp,
2093 struct flock64 *flp)
2094 {
2095 struct nlm_slreq *slr, *new_slr = NULL;
2096 int ret = EEXIST;
2097
2098 mutex_enter(&hostp->nh_lock);
2099 slr = nlm_slreq_find_locked(hostp, nvp, flp);
2100 if (slr != NULL)
2101 goto out;
2102
2103 mutex_exit(&hostp->nh_lock);
2104 new_slr = kmem_zalloc(sizeof (*slr), KM_SLEEP);
2105 bcopy(flp, &new_slr->nsr_fl, sizeof (*flp));
2106
2107 mutex_enter(&hostp->nh_lock);
2108 slr = nlm_slreq_find_locked(hostp, nvp, flp);
2109 if (slr == NULL) {
2110 slr = new_slr;
2111 new_slr = NULL;
2112 ret = 0;
2113
2114 TAILQ_INSERT_TAIL(&nvp->nv_slreqs, slr, nsr_link);
2115 }
2116
2117 out:
2118 mutex_exit(&hostp->nh_lock);
2119 if (new_slr != NULL)
2120 kmem_free(new_slr, sizeof (*new_slr));
2121
2122 return (ret);
2123 }
2124
2125 /*
2126 * Unregister sleeping lock request corresponding
2127 * to flp from the given vhold object.
2128 * On success function returns 0, otherwise (if
2129 * lock request corresponding to flp isn't found
2130 * on the given vhold) function returns ENOENT.
2131 */
2132 int
nlm_slreq_unregister(struct nlm_host * hostp,struct nlm_vhold * nvp,struct flock64 * flp)2133 nlm_slreq_unregister(struct nlm_host *hostp, struct nlm_vhold *nvp,
2134 struct flock64 *flp)
2135 {
2136 struct nlm_slreq *slr;
2137
2138 mutex_enter(&hostp->nh_lock);
2139 slr = nlm_slreq_find_locked(hostp, nvp, flp);
2140 if (slr == NULL) {
2141 mutex_exit(&hostp->nh_lock);
2142 return (ENOENT);
2143 }
2144
2145 TAILQ_REMOVE(&nvp->nv_slreqs, slr, nsr_link);
2146 mutex_exit(&hostp->nh_lock);
2147
2148 kmem_free(slr, sizeof (*slr));
2149 return (0);
2150 }
2151
2152 /*
2153 * Find sleeping lock request on the given vhold object by flp.
2154 */
2155 struct nlm_slreq *
nlm_slreq_find_locked(struct nlm_host * hostp,struct nlm_vhold * nvp,struct flock64 * flp)2156 nlm_slreq_find_locked(struct nlm_host *hostp, struct nlm_vhold *nvp,
2157 struct flock64 *flp)
2158 {
2159 struct nlm_slreq *slr = NULL;
2160
2161 ASSERT(MUTEX_HELD(&hostp->nh_lock));
2162 TAILQ_FOREACH(slr, &nvp->nv_slreqs, nsr_link) {
2163 if (slr->nsr_fl.l_start == flp->l_start &&
2164 slr->nsr_fl.l_len == flp->l_len &&
2165 slr->nsr_fl.l_pid == flp->l_pid &&
2166 slr->nsr_fl.l_type == flp->l_type)
2167 break;
2168 }
2169
2170 return (slr);
2171 }
2172
2173 /*
2174 * NLM tracks active share reservations made on the client side.
2175 * It needs to have a track of share reservations for two purposes
2176 * 1) to determine if nlm_host is busy (if it has active locks and/or
2177 * share reservations, it is)
2178 * 2) to recover active share reservations when NLM server reports
2179 * that it has rebooted.
2180 *
2181 * Unfortunately Illumos local share reservations manager (see os/share.c)
2182 * doesn't have an ability to lookup all reservations on the system
2183 * by sysid (like local lock manager) or get all reservations by sysid.
2184 * It tracks reservations per vnode and is able to get/looup them
2185 * on particular vnode. It's not what NLM needs. Thus it has that ugly
2186 * share reservations tracking scheme.
2187 */
2188
2189 void
nlm_shres_track(struct nlm_host * hostp,vnode_t * vp,struct shrlock * shrp)2190 nlm_shres_track(struct nlm_host *hostp, vnode_t *vp, struct shrlock *shrp)
2191 {
2192 struct nlm_shres *nsp, *nsp_new;
2193
2194 /*
2195 * NFS code must fill the s_owner, so that
2196 * s_own_len is never 0.
2197 */
2198 ASSERT(shrp->s_own_len > 0);
2199 nsp_new = nlm_shres_create_item(shrp, vp);
2200
2201 mutex_enter(&hostp->nh_lock);
2202 for (nsp = hostp->nh_shrlist; nsp != NULL; nsp = nsp->ns_next)
2203 if (nsp->ns_vp == vp && nlm_shres_equal(shrp, nsp->ns_shr))
2204 break;
2205
2206 if (nsp != NULL) {
2207 /*
2208 * Found a duplicate. Do nothing.
2209 */
2210
2211 goto out;
2212 }
2213
2214 nsp = nsp_new;
2215 nsp_new = NULL;
2216 nsp->ns_next = hostp->nh_shrlist;
2217 hostp->nh_shrlist = nsp;
2218
2219 out:
2220 mutex_exit(&hostp->nh_lock);
2221 if (nsp_new != NULL)
2222 nlm_shres_destroy_item(nsp_new);
2223 }
2224
2225 void
nlm_shres_untrack(struct nlm_host * hostp,vnode_t * vp,struct shrlock * shrp)2226 nlm_shres_untrack(struct nlm_host *hostp, vnode_t *vp, struct shrlock *shrp)
2227 {
2228 struct nlm_shres *nsp, *nsp_prev = NULL;
2229
2230 mutex_enter(&hostp->nh_lock);
2231 nsp = hostp->nh_shrlist;
2232 while (nsp != NULL) {
2233 if (nsp->ns_vp == vp && nlm_shres_equal(shrp, nsp->ns_shr)) {
2234 struct nlm_shres *nsp_del;
2235
2236 nsp_del = nsp;
2237 nsp = nsp->ns_next;
2238 if (nsp_prev != NULL)
2239 nsp_prev->ns_next = nsp;
2240 else
2241 hostp->nh_shrlist = nsp;
2242
2243 nlm_shres_destroy_item(nsp_del);
2244 continue;
2245 }
2246
2247 nsp_prev = nsp;
2248 nsp = nsp->ns_next;
2249 }
2250
2251 mutex_exit(&hostp->nh_lock);
2252 }
2253
2254 /*
2255 * Get a _copy_ of the list of all active share reservations
2256 * made by the given host.
2257 * NOTE: the list function returns _must_ be released using
2258 * nlm_free_shrlist().
2259 */
2260 struct nlm_shres *
nlm_get_active_shres(struct nlm_host * hostp)2261 nlm_get_active_shres(struct nlm_host *hostp)
2262 {
2263 struct nlm_shres *nsp, *nslist = NULL;
2264
2265 mutex_enter(&hostp->nh_lock);
2266 for (nsp = hostp->nh_shrlist; nsp != NULL; nsp = nsp->ns_next) {
2267 struct nlm_shres *nsp_new;
2268
2269 nsp_new = nlm_shres_create_item(nsp->ns_shr, nsp->ns_vp);
2270 nsp_new->ns_next = nslist;
2271 nslist = nsp_new;
2272 }
2273
2274 mutex_exit(&hostp->nh_lock);
2275 return (nslist);
2276 }
2277
2278 /*
2279 * Free memory allocated for the active share reservations
2280 * list created by nlm_get_active_shres() function.
2281 */
2282 void
nlm_free_shrlist(struct nlm_shres * nslist)2283 nlm_free_shrlist(struct nlm_shres *nslist)
2284 {
2285 struct nlm_shres *nsp;
2286
2287 while (nslist != NULL) {
2288 nsp = nslist;
2289 nslist = nslist->ns_next;
2290
2291 nlm_shres_destroy_item(nsp);
2292 }
2293 }
2294
2295 static bool_t
nlm_shres_equal(struct shrlock * shrp1,struct shrlock * shrp2)2296 nlm_shres_equal(struct shrlock *shrp1, struct shrlock *shrp2)
2297 {
2298 if (shrp1->s_sysid == shrp2->s_sysid &&
2299 shrp1->s_pid == shrp2->s_pid &&
2300 shrp1->s_own_len == shrp2->s_own_len &&
2301 bcmp(shrp1->s_owner, shrp2->s_owner,
2302 shrp1->s_own_len) == 0)
2303 return (TRUE);
2304
2305 return (FALSE);
2306 }
2307
2308 static struct nlm_shres *
nlm_shres_create_item(struct shrlock * shrp,vnode_t * vp)2309 nlm_shres_create_item(struct shrlock *shrp, vnode_t *vp)
2310 {
2311 struct nlm_shres *nsp;
2312
2313 nsp = kmem_alloc(sizeof (*nsp), KM_SLEEP);
2314 nsp->ns_shr = kmem_alloc(sizeof (*shrp), KM_SLEEP);
2315 bcopy(shrp, nsp->ns_shr, sizeof (*shrp));
2316 nsp->ns_shr->s_owner = kmem_alloc(shrp->s_own_len, KM_SLEEP);
2317 bcopy(shrp->s_owner, nsp->ns_shr->s_owner, shrp->s_own_len);
2318 nsp->ns_vp = vp;
2319
2320 return (nsp);
2321 }
2322
2323 static void
nlm_shres_destroy_item(struct nlm_shres * nsp)2324 nlm_shres_destroy_item(struct nlm_shres *nsp)
2325 {
2326 kmem_free(nsp->ns_shr->s_owner,
2327 nsp->ns_shr->s_own_len);
2328 kmem_free(nsp->ns_shr, sizeof (struct shrlock));
2329 kmem_free(nsp, sizeof (*nsp));
2330 }
2331
2332 /*
2333 * Called by klmmod.c when lockd adds a network endpoint
2334 * on which we should begin RPC services.
2335 */
2336 int
nlm_svc_add_ep(struct file * fp,const char * netid,struct knetconfig * knc)2337 nlm_svc_add_ep(struct file *fp, const char *netid, struct knetconfig *knc)
2338 {
2339 SVCMASTERXPRT *xprt = NULL;
2340 int error;
2341
2342 error = svc_tli_kcreate(fp, 0, (char *)netid, NULL, &xprt,
2343 &nlm_sct, NULL, NLM_SVCPOOL_ID, FALSE);
2344 if (error != 0)
2345 return (error);
2346
2347 (void) nlm_knc_to_netid(knc);
2348 return (0);
2349 }
2350
2351 /*
2352 * Start NLM service.
2353 */
2354 int
nlm_svc_starting(struct nlm_globals * g,struct file * fp,const char * netid,struct knetconfig * knc)2355 nlm_svc_starting(struct nlm_globals *g, struct file *fp,
2356 const char *netid, struct knetconfig *knc)
2357 {
2358 int error;
2359 enum clnt_stat stat;
2360
2361 VERIFY(g->run_status == NLM_ST_STARTING);
2362 VERIFY(g->nlm_gc_thread == NULL);
2363
2364 error = nlm_nsm_init_local(&g->nlm_nsm);
2365 if (error != 0) {
2366 NLM_ERR("Failed to initialize NSM handler "
2367 "(error=%d)\n", error);
2368 g->run_status = NLM_ST_DOWN;
2369 return (error);
2370 }
2371
2372 error = EIO;
2373
2374 /*
2375 * Create an NLM garbage collector thread that will
2376 * clean up stale vholds and hosts objects.
2377 */
2378 g->nlm_gc_thread = zthread_create(NULL, 0, nlm_gc,
2379 g, 0, minclsyspri);
2380
2381 /*
2382 * Send SIMU_CRASH to local statd to report that
2383 * NLM started, so that statd can report other hosts
2384 * about NLM state change.
2385 */
2386
2387 stat = nlm_nsm_simu_crash(&g->nlm_nsm);
2388 if (stat != RPC_SUCCESS) {
2389 NLM_ERR("Failed to connect to local statd "
2390 "(rpcerr=%d)\n", stat);
2391 goto shutdown_lm;
2392 }
2393
2394 stat = nlm_nsm_stat(&g->nlm_nsm, &g->nsm_state);
2395 if (stat != RPC_SUCCESS) {
2396 NLM_ERR("Failed to get the status of local statd "
2397 "(rpcerr=%d)\n", stat);
2398 goto shutdown_lm;
2399 }
2400
2401 g->grace_threshold = ddi_get_lbolt() +
2402 SEC_TO_TICK(g->grace_period);
2403
2404 /* Register endpoint used for communications with local NLM */
2405 error = nlm_svc_add_ep(fp, netid, knc);
2406 if (error != 0)
2407 goto shutdown_lm;
2408
2409 (void) svc_pool_control(NLM_SVCPOOL_ID,
2410 SVCPSET_SHUTDOWN_PROC, (void *)nlm_pool_shutdown);
2411 g->run_status = NLM_ST_UP;
2412 return (0);
2413
2414 shutdown_lm:
2415 mutex_enter(&g->lock);
2416 g->run_status = NLM_ST_STOPPING;
2417 mutex_exit(&g->lock);
2418
2419 nlm_svc_stopping(g);
2420 return (error);
2421 }
2422
2423 /*
2424 * Called when the server pool is destroyed, so that
2425 * all transports are closed and no any server threads
2426 * exist.
2427 *
2428 * Just call lm_shutdown() to shut NLM down properly.
2429 */
2430 static void
nlm_pool_shutdown(void)2431 nlm_pool_shutdown(void)
2432 {
2433 (void) lm_shutdown();
2434 }
2435
2436 /*
2437 * Stop NLM service, cleanup all resources
2438 * NLM owns at the moment.
2439 *
2440 * NOTE: NFS code can call NLM while it's
2441 * stopping or even if it's shut down. Any attempt
2442 * to lock file either on client or on the server
2443 * will fail if NLM isn't in NLM_ST_UP state.
2444 */
2445 void
nlm_svc_stopping(struct nlm_globals * g)2446 nlm_svc_stopping(struct nlm_globals *g)
2447 {
2448 mutex_enter(&g->lock);
2449 ASSERT(g->run_status == NLM_ST_STOPPING);
2450
2451 /*
2452 * Ask NLM GC thread to exit and wait until it dies.
2453 */
2454 cv_signal(&g->nlm_gc_sched_cv);
2455 while (g->nlm_gc_thread != NULL)
2456 cv_wait(&g->nlm_gc_finish_cv, &g->lock);
2457
2458 mutex_exit(&g->lock);
2459
2460 /*
2461 * Cleanup locks owned by NLM hosts.
2462 * NOTE: New hosts won't be created while
2463 * NLM is stopping.
2464 */
2465 while (!avl_is_empty(&g->nlm_hosts_tree)) {
2466 struct nlm_host *hostp;
2467 int busy_hosts = 0;
2468
2469 /*
2470 * Iterate through all NLM hosts in the system
2471 * and drop the locks they own by force.
2472 */
2473 hostp = avl_first(&g->nlm_hosts_tree);
2474 while (hostp != NULL) {
2475 /* Cleanup all client and server side locks */
2476 nlm_client_cancel_all(g, hostp);
2477 nlm_host_notify_server(hostp, 0);
2478
2479 mutex_enter(&hostp->nh_lock);
2480 nlm_host_gc_vholds(hostp);
2481 if (hostp->nh_refs > 0 || nlm_host_has_locks(hostp)) {
2482 /*
2483 * Oh, it seems the host is still busy, let
2484 * it some time to release and go to the
2485 * next one.
2486 */
2487
2488 mutex_exit(&hostp->nh_lock);
2489 hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2490 busy_hosts++;
2491 continue;
2492 }
2493
2494 mutex_exit(&hostp->nh_lock);
2495 hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2496 }
2497
2498 /*
2499 * All hosts go to nlm_idle_hosts list after
2500 * all locks they own are cleaned up and last refereces
2501 * were dropped. Just destroy all hosts in nlm_idle_hosts
2502 * list, they can not be removed from there while we're
2503 * in stopping state.
2504 */
2505 while ((hostp = TAILQ_FIRST(&g->nlm_idle_hosts)) != NULL) {
2506 nlm_host_unregister(g, hostp);
2507 nlm_host_destroy(hostp);
2508 }
2509
2510 if (busy_hosts > 0) {
2511 /*
2512 * There're some hosts that weren't cleaned
2513 * up. Probably they're in resource cleanup
2514 * process. Give them some time to do drop
2515 * references.
2516 */
2517 delay(MSEC_TO_TICK(500));
2518 }
2519 }
2520
2521 ASSERT(TAILQ_EMPTY(&g->nlm_slocks));
2522
2523 nlm_nsm_fini(&g->nlm_nsm);
2524 g->lockd_pid = 0;
2525 g->run_status = NLM_ST_DOWN;
2526 }
2527
2528 /*
2529 * Returns TRUE if the given vnode has
2530 * any active or sleeping locks.
2531 */
2532 int
nlm_vp_active(const vnode_t * vp)2533 nlm_vp_active(const vnode_t *vp)
2534 {
2535 struct nlm_globals *g;
2536 struct nlm_host *hostp;
2537 struct nlm_vhold *nvp;
2538 int active = 0;
2539
2540 g = zone_getspecific(nlm_zone_key, curzone);
2541
2542 /*
2543 * Server side NLM has locks on the given vnode
2544 * if there exist a vhold object that holds
2545 * the given vnode "vp" in one of NLM hosts.
2546 */
2547 mutex_enter(&g->lock);
2548 hostp = avl_first(&g->nlm_hosts_tree);
2549 while (hostp != NULL) {
2550 mutex_enter(&hostp->nh_lock);
2551 nvp = nlm_vhold_find_locked(hostp, vp);
2552 mutex_exit(&hostp->nh_lock);
2553 if (nvp != NULL) {
2554 active = 1;
2555 break;
2556 }
2557
2558 hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2559 }
2560
2561 mutex_exit(&g->lock);
2562 return (active);
2563 }
2564
2565 /*
2566 * Called right before NFS export is going to
2567 * dissapear. The function finds all vnodes
2568 * belonging to the given export and cleans
2569 * all remote locks and share reservations
2570 * on them.
2571 */
2572 void
nlm_zone_unexport(struct nlm_globals * g,struct exportinfo * exi)2573 nlm_zone_unexport(struct nlm_globals *g, struct exportinfo *exi)
2574 {
2575 struct nlm_host *hostp;
2576
2577 mutex_enter(&g->lock);
2578 if (g->run_status != NLM_ST_UP) {
2579 /* nothing to do */
2580 mutex_exit(&g->lock);
2581 return;
2582 }
2583
2584 hostp = avl_first(&g->nlm_hosts_tree);
2585 while (hostp != NULL) {
2586 struct nlm_vhold *nvp;
2587
2588 if (hostp->nh_flags & NLM_NH_INIDLE) {
2589 TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
2590 hostp->nh_flags &= ~NLM_NH_INIDLE;
2591 }
2592 hostp->nh_refs++;
2593
2594 mutex_exit(&g->lock);
2595
2596 mutex_enter(&hostp->nh_lock);
2597 TAILQ_FOREACH(nvp, &hostp->nh_vholds_list, nv_link) {
2598 vnode_t *vp;
2599
2600 nvp->nv_refcnt++;
2601 mutex_exit(&hostp->nh_lock);
2602
2603 vp = nvp->nv_vp;
2604
2605 if (!EQFSID(&exi->exi_fsid, &vp->v_vfsp->vfs_fsid))
2606 goto next_iter;
2607
2608 /*
2609 * Ok, it we found out that vnode vp is under
2610 * control by the exportinfo exi, now we need
2611 * to drop all locks from this vnode, let's
2612 * do it.
2613 */
2614 nlm_vhold_clean(nvp, hostp->nh_sysid);
2615
2616 next_iter:
2617 mutex_enter(&hostp->nh_lock);
2618 nvp->nv_refcnt--;
2619 }
2620 mutex_exit(&hostp->nh_lock);
2621
2622 mutex_enter(&g->lock);
2623 nlm_host_release_locked(g, hostp);
2624
2625 hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2626 }
2627
2628 mutex_exit(&g->lock);
2629 }
2630
2631 void
nlm_unexport(struct exportinfo * exi)2632 nlm_unexport(struct exportinfo *exi)
2633 {
2634 struct nlm_globals *g;
2635
2636 rw_enter(&lm_lck, RW_READER);
2637 TAILQ_FOREACH(g, &nlm_zones_list, nlm_link) {
2638 if (g->nlm_zoneid == exi->exi_zoneid) {
2639 /*
2640 * NOTE: If we want to drop lm_lock before
2641 * calling nlm_zone_unexport(), we should break,
2642 * and have a post-rw_exit() snippit like:
2643 * if (g != NULL)
2644 * nlm_zone_unexport(g, exi);
2645 */
2646 nlm_zone_unexport(g, exi);
2647 break; /* Only going to match once! */
2648 }
2649 }
2650 rw_exit(&lm_lck);
2651 }
2652
2653 /*
2654 * Allocate new unique sysid.
2655 * In case of failure (no available sysids)
2656 * return LM_NOSYSID.
2657 */
2658 sysid_t
nlm_sysid_alloc(void)2659 nlm_sysid_alloc(void)
2660 {
2661 sysid_t ret_sysid = LM_NOSYSID;
2662
2663 rw_enter(&lm_lck, RW_WRITER);
2664 if (nlm_sysid_nidx > LM_SYSID_MAX)
2665 nlm_sysid_nidx = LM_SYSID;
2666
2667 if (!BT_TEST(nlm_sysid_bmap, nlm_sysid_nidx)) {
2668 BT_SET(nlm_sysid_bmap, nlm_sysid_nidx);
2669 ret_sysid = nlm_sysid_nidx++;
2670 } else {
2671 index_t id;
2672
2673 id = bt_availbit(nlm_sysid_bmap, NLM_BMAP_NITEMS);
2674 if (id > 0) {
2675 nlm_sysid_nidx = id + 1;
2676 ret_sysid = id;
2677 BT_SET(nlm_sysid_bmap, id);
2678 }
2679 }
2680
2681 rw_exit(&lm_lck);
2682 return (ret_sysid);
2683 }
2684
2685 void
nlm_sysid_free(sysid_t sysid)2686 nlm_sysid_free(sysid_t sysid)
2687 {
2688 ASSERT(sysid >= LM_SYSID && sysid <= LM_SYSID_MAX);
2689
2690 rw_enter(&lm_lck, RW_WRITER);
2691 ASSERT(BT_TEST(nlm_sysid_bmap, sysid));
2692 BT_CLEAR(nlm_sysid_bmap, sysid);
2693 rw_exit(&lm_lck);
2694 }
2695
2696 /*
2697 * Return true if the request came from a local caller.
2698 * By necessity, this "knows" the netid names invented
2699 * in lm_svc() and nlm_netid_from_knetconfig().
2700 */
2701 bool_t
nlm_caller_is_local(SVCXPRT * transp)2702 nlm_caller_is_local(SVCXPRT *transp)
2703 {
2704 char *netid;
2705 struct netbuf *rtaddr;
2706
2707 netid = svc_getnetid(transp);
2708 rtaddr = svc_getrpccaller(transp);
2709
2710 if (netid == NULL)
2711 return (FALSE);
2712
2713 if (strcmp(netid, "ticlts") == 0 ||
2714 strcmp(netid, "ticotsord") == 0)
2715 return (TRUE);
2716
2717 if (strcmp(netid, "tcp") == 0 || strcmp(netid, "udp") == 0) {
2718 struct sockaddr_in *sin = (void *)rtaddr->buf;
2719 if (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
2720 return (TRUE);
2721 }
2722 if (strcmp(netid, "tcp6") == 0 || strcmp(netid, "udp6") == 0) {
2723 struct sockaddr_in6 *sin6 = (void *)rtaddr->buf;
2724 if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
2725 return (TRUE);
2726 }
2727
2728 return (FALSE); /* unknown transport */
2729 }
2730
2731 /*
2732 * Get netid string correspondig to the given knetconfig.
2733 * If not done already, save knc->knc_rdev in our table.
2734 */
2735 const char *
nlm_knc_to_netid(struct knetconfig * knc)2736 nlm_knc_to_netid(struct knetconfig *knc)
2737 {
2738 int i;
2739 dev_t rdev;
2740 struct nlm_knc *nc;
2741 const char *netid = NULL;
2742
2743 rw_enter(&lm_lck, RW_READER);
2744 for (i = 0; i < NLM_KNCS; i++) {
2745 nc = &nlm_netconfigs[i];
2746
2747 if (nc->n_knc.knc_semantics == knc->knc_semantics &&
2748 strcmp(nc->n_knc.knc_protofmly,
2749 knc->knc_protofmly) == 0) {
2750 netid = nc->n_netid;
2751 rdev = nc->n_knc.knc_rdev;
2752 break;
2753 }
2754 }
2755 rw_exit(&lm_lck);
2756
2757 if (netid != NULL && rdev == NODEV) {
2758 rw_enter(&lm_lck, RW_WRITER);
2759 if (nc->n_knc.knc_rdev == NODEV)
2760 nc->n_knc.knc_rdev = knc->knc_rdev;
2761 rw_exit(&lm_lck);
2762 }
2763
2764 return (netid);
2765 }
2766
2767 /*
2768 * Get a knetconfig corresponding to the given netid.
2769 * If there's no knetconfig for this netid, ENOENT
2770 * is returned.
2771 */
2772 int
nlm_knc_from_netid(const char * netid,struct knetconfig * knc)2773 nlm_knc_from_netid(const char *netid, struct knetconfig *knc)
2774 {
2775 int i, ret;
2776
2777 ret = ENOENT;
2778 for (i = 0; i < NLM_KNCS; i++) {
2779 struct nlm_knc *nknc;
2780
2781 nknc = &nlm_netconfigs[i];
2782 if (strcmp(netid, nknc->n_netid) == 0 &&
2783 nknc->n_knc.knc_rdev != NODEV) {
2784 *knc = nknc->n_knc;
2785 ret = 0;
2786 break;
2787 }
2788 }
2789
2790 return (ret);
2791 }
2792
2793 void
nlm_cprsuspend(void)2794 nlm_cprsuspend(void)
2795 {
2796 struct nlm_globals *g;
2797
2798 rw_enter(&lm_lck, RW_READER);
2799 TAILQ_FOREACH(g, &nlm_zones_list, nlm_link)
2800 nlm_suspend_zone(g);
2801
2802 rw_exit(&lm_lck);
2803 }
2804
2805 void
nlm_cprresume(void)2806 nlm_cprresume(void)
2807 {
2808 struct nlm_globals *g;
2809
2810 rw_enter(&lm_lck, RW_READER);
2811 TAILQ_FOREACH(g, &nlm_zones_list, nlm_link)
2812 nlm_resume_zone(g);
2813
2814 rw_exit(&lm_lck);
2815 }
2816
2817 static void
nlm_nsm_clnt_init(CLIENT * clnt,struct nlm_nsm * nsm)2818 nlm_nsm_clnt_init(CLIENT *clnt, struct nlm_nsm *nsm)
2819 {
2820 (void) clnt_tli_kinit(clnt, &nsm->ns_knc, &nsm->ns_addr, 0,
2821 NLM_RPC_RETRIES, zone_kcred());
2822 }
2823
2824 static void
nlm_netbuf_to_netobj(struct netbuf * addr,int * family,netobj * obj)2825 nlm_netbuf_to_netobj(struct netbuf *addr, int *family, netobj *obj)
2826 {
2827 /* LINTED pointer alignment */
2828 struct sockaddr *sa = (struct sockaddr *)addr->buf;
2829
2830 *family = sa->sa_family;
2831
2832 switch (sa->sa_family) {
2833 case AF_INET: {
2834 /* LINTED pointer alignment */
2835 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
2836
2837 obj->n_len = sizeof (sin->sin_addr);
2838 obj->n_bytes = (char *)&sin->sin_addr;
2839 break;
2840 }
2841
2842 case AF_INET6: {
2843 /* LINTED pointer alignment */
2844 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
2845
2846 obj->n_len = sizeof (sin6->sin6_addr);
2847 obj->n_bytes = (char *)&sin6->sin6_addr;
2848 break;
2849 }
2850
2851 default:
2852 VERIFY(0);
2853 break;
2854 }
2855 }
2856