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