nlm_prot_impl.c revision 225617
1177633Sdfr/*- 2177633Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3177633Sdfr * Authors: Doug Rabson <dfr@rabson.org> 4177633Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5177633Sdfr * 6177633Sdfr * Redistribution and use in source and binary forms, with or without 7177633Sdfr * modification, are permitted provided that the following conditions 8177633Sdfr * are met: 9177633Sdfr * 1. Redistributions of source code must retain the above copyright 10177633Sdfr * notice, this list of conditions and the following disclaimer. 11177633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12177633Sdfr * notice, this list of conditions and the following disclaimer in the 13177633Sdfr * documentation and/or other materials provided with the distribution. 14177633Sdfr * 15177633Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16177633Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17177633Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18177633Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19177633Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20177633Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21177633Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22177633Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23177633Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25177633Sdfr * SUCH DAMAGE. 26177633Sdfr */ 27177633Sdfr 28177633Sdfr#include "opt_inet6.h" 29177633Sdfr 30177633Sdfr#include <sys/cdefs.h> 31177633Sdfr__FBSDID("$FreeBSD: head/sys/nlm/nlm_prot_impl.c 225617 2011-09-16 13:58:51Z kmacy $"); 32177633Sdfr 33177633Sdfr#include <sys/param.h> 34197840Szml#include <sys/fail.h> 35177633Sdfr#include <sys/fcntl.h> 36177633Sdfr#include <sys/kernel.h> 37180025Sdfr#include <sys/kthread.h> 38177633Sdfr#include <sys/lockf.h> 39177633Sdfr#include <sys/malloc.h> 40177633Sdfr#include <sys/mount.h> 41177685Sdfr#if __FreeBSD_version >= 700000 42177633Sdfr#include <sys/priv.h> 43177685Sdfr#endif 44177633Sdfr#include <sys/proc.h> 45177633Sdfr#include <sys/socket.h> 46177633Sdfr#include <sys/socketvar.h> 47177633Sdfr#include <sys/syscall.h> 48177633Sdfr#include <sys/sysctl.h> 49177633Sdfr#include <sys/sysent.h> 50191918Sdfr#include <sys/syslog.h> 51177633Sdfr#include <sys/sysproto.h> 52177633Sdfr#include <sys/systm.h> 53177633Sdfr#include <sys/taskqueue.h> 54177633Sdfr#include <sys/unistd.h> 55177633Sdfr#include <sys/vnode.h> 56177633Sdfr 57180025Sdfr#include <nfs/nfsproto.h> 58214048Srmacklem#include <nfs/nfs_lock.h> 59180025Sdfr 60177685Sdfr#include <nlm/nlm_prot.h> 61177685Sdfr#include <nlm/sm_inter.h> 62177685Sdfr#include <nlm/nlm.h> 63177633Sdfr#include <rpc/rpc_com.h> 64177633Sdfr#include <rpc/rpcb_prot.h> 65177633Sdfr 66177633SdfrMALLOC_DEFINE(M_NLM, "NLM", "Network Lock Manager"); 67177633Sdfr 68177633Sdfr/* 69177633Sdfr * If a host is inactive (and holds no locks) for this amount of 70177633Sdfr * seconds, we consider it idle and stop tracking it. 71177633Sdfr */ 72177633Sdfr#define NLM_IDLE_TIMEOUT 30 73177633Sdfr 74177633Sdfr/* 75177633Sdfr * We check the host list for idle every few seconds. 76177633Sdfr */ 77177633Sdfr#define NLM_IDLE_PERIOD 5 78177633Sdfr 79177633Sdfr/* 80197840Szml * We only look for GRANTED_RES messages for a little while. 81197840Szml */ 82197840Szml#define NLM_EXPIRE_TIMEOUT 10 83197840Szml 84197840Szml/* 85177633Sdfr * Support for sysctl vfs.nlm.sysid 86177633Sdfr */ 87177633SdfrSYSCTL_NODE(_vfs, OID_AUTO, nlm, CTLFLAG_RW, NULL, "Network Lock Manager"); 88177633SdfrSYSCTL_NODE(_vfs_nlm, OID_AUTO, sysid, CTLFLAG_RW, NULL, ""); 89177633Sdfr 90177633Sdfr/* 91177633Sdfr * Syscall hooks 92177633Sdfr */ 93177633Sdfrstatic int nlm_syscall_offset = SYS_nlm_syscall; 94177633Sdfrstatic struct sysent nlm_syscall_prev_sysent; 95177685Sdfr#if __FreeBSD_version < 700000 96177685Sdfrstatic struct sysent nlm_syscall_sysent = { 97177685Sdfr (sizeof(struct nlm_syscall_args) / sizeof(register_t)) | SYF_MPSAFE, 98177685Sdfr (sy_call_t *) nlm_syscall 99177685Sdfr}; 100177685Sdfr#else 101177633SdfrMAKE_SYSENT(nlm_syscall); 102177685Sdfr#endif 103177633Sdfrstatic bool_t nlm_syscall_registered = FALSE; 104177633Sdfr 105177633Sdfr/* 106177633Sdfr * Debug level passed in from userland. We also support a sysctl hook 107177633Sdfr * so that it can be changed on a live system. 108177633Sdfr */ 109177633Sdfrstatic int nlm_debug_level; 110177633SdfrSYSCTL_INT(_debug, OID_AUTO, nlm_debug, CTLFLAG_RW, &nlm_debug_level, 0, ""); 111177633Sdfr 112191918Sdfr#define NLM_DEBUG(_level, args...) \ 113191918Sdfr do { \ 114191918Sdfr if (nlm_debug_level >= (_level)) \ 115191918Sdfr log(LOG_DEBUG, args); \ 116191918Sdfr } while(0) 117191918Sdfr#define NLM_ERR(args...) \ 118191918Sdfr do { \ 119191918Sdfr log(LOG_ERR, args); \ 120191918Sdfr } while(0) 121191918Sdfr 122177633Sdfr/* 123177633Sdfr * Grace period handling. The value of nlm_grace_threshold is the 124177633Sdfr * value of time_uptime after which we are serving requests normally. 125177633Sdfr */ 126177633Sdfrstatic time_t nlm_grace_threshold; 127177633Sdfr 128177633Sdfr/* 129177633Sdfr * We check for idle hosts if time_uptime is greater than 130177633Sdfr * nlm_next_idle_check, 131177633Sdfr */ 132177633Sdfrstatic time_t nlm_next_idle_check; 133177633Sdfr 134177633Sdfr/* 135177633Sdfr * A socket to use for RPC - shared by all IPv4 RPC clients. 136177633Sdfr */ 137177633Sdfrstatic struct socket *nlm_socket; 138177633Sdfr 139177633Sdfr#ifdef INET6 140177633Sdfr 141177633Sdfr/* 142177633Sdfr * A socket to use for RPC - shared by all IPv6 RPC clients. 143177633Sdfr */ 144177633Sdfrstatic struct socket *nlm_socket6; 145177633Sdfr 146177633Sdfr#endif 147177633Sdfr 148177633Sdfr/* 149177633Sdfr * An RPC client handle that can be used to communicate with the local 150177633Sdfr * NSM. 151177633Sdfr */ 152177633Sdfrstatic CLIENT *nlm_nsm; 153177633Sdfr 154177633Sdfr/* 155180025Sdfr * An AUTH handle for the server's creds. 156177633Sdfr */ 157180025Sdfrstatic AUTH *nlm_auth; 158177633Sdfr 159177633Sdfr/* 160180025Sdfr * A zero timeval for sending async RPC messages. 161180025Sdfr */ 162180025Sdfrstruct timeval nlm_zero_tv = { 0, 0 }; 163180025Sdfr 164180025Sdfr/* 165180025Sdfr * The local NSM state number 166180025Sdfr */ 167180025Sdfrint nlm_nsm_state; 168180025Sdfr 169180025Sdfr 170180025Sdfr/* 171180025Sdfr * A lock to protect the host list and waiting lock list. 172180025Sdfr */ 173180025Sdfrstatic struct mtx nlm_global_lock; 174180025Sdfr 175180025Sdfr/* 176177633Sdfr * Locks: 177177633Sdfr * (l) locked by nh_lock 178177633Sdfr * (s) only accessed via server RPC which is single threaded 179180025Sdfr * (g) locked by nlm_global_lock 180177633Sdfr * (c) const until freeing 181180025Sdfr * (a) modified using atomic ops 182177633Sdfr */ 183177633Sdfr 184177633Sdfr/* 185180025Sdfr * A pending client-side lock request, stored on the nlm_waiting_locks 186180025Sdfr * list. 187177633Sdfr */ 188180025Sdfrstruct nlm_waiting_lock { 189180025Sdfr TAILQ_ENTRY(nlm_waiting_lock) nw_link; /* (g) */ 190180025Sdfr bool_t nw_waiting; /* (g) */ 191180025Sdfr nlm4_lock nw_lock; /* (c) */ 192180025Sdfr union nfsfh nw_fh; /* (c) */ 193180025Sdfr struct vnode *nw_vp; /* (c) */ 194180025Sdfr}; 195180025SdfrTAILQ_HEAD(nlm_waiting_lock_list, nlm_waiting_lock); 196180025Sdfr 197180025Sdfrstruct nlm_waiting_lock_list nlm_waiting_locks; /* (g) */ 198180025Sdfr 199180025Sdfr/* 200180025Sdfr * A pending server-side asynchronous lock request, stored on the 201180025Sdfr * nh_pending list of the NLM host. 202180025Sdfr */ 203177633Sdfrstruct nlm_async_lock { 204177633Sdfr TAILQ_ENTRY(nlm_async_lock) af_link; /* (l) host's list of locks */ 205177633Sdfr struct task af_task; /* (c) async callback details */ 206177633Sdfr void *af_cookie; /* (l) lock manager cancel token */ 207177633Sdfr struct vnode *af_vp; /* (l) vnode to lock */ 208177633Sdfr struct flock af_fl; /* (c) lock details */ 209177633Sdfr struct nlm_host *af_host; /* (c) host which is locking */ 210180025Sdfr CLIENT *af_rpc; /* (c) rpc client to send message */ 211177633Sdfr nlm4_testargs af_granted; /* (c) notification details */ 212197840Szml time_t af_expiretime; /* (c) notification time */ 213177633Sdfr}; 214177633SdfrTAILQ_HEAD(nlm_async_lock_list, nlm_async_lock); 215177633Sdfr 216177633Sdfr/* 217177633Sdfr * NLM host. 218177633Sdfr */ 219178112Sdfrenum nlm_host_state { 220178112Sdfr NLM_UNMONITORED, 221178112Sdfr NLM_MONITORED, 222180025Sdfr NLM_MONITOR_FAILED, 223180025Sdfr NLM_RECOVERING 224178112Sdfr}; 225184588Sdfr 226184588Sdfrstruct nlm_rpc { 227184588Sdfr CLIENT *nr_client; /* (l) RPC client handle */ 228184588Sdfr time_t nr_create_time; /* (l) when client was created */ 229184588Sdfr}; 230184588Sdfr 231177633Sdfrstruct nlm_host { 232177633Sdfr struct mtx nh_lock; 233180025Sdfr volatile u_int nh_refs; /* (a) reference count */ 234180025Sdfr TAILQ_ENTRY(nlm_host) nh_link; /* (g) global list of hosts */ 235180025Sdfr char nh_caller_name[MAXNAMELEN]; /* (c) printable name of host */ 236177633Sdfr uint32_t nh_sysid; /* (c) our allocaed system ID */ 237177633Sdfr char nh_sysid_string[10]; /* (c) string rep. of sysid */ 238177633Sdfr struct sockaddr_storage nh_addr; /* (s) remote address of host */ 239184588Sdfr struct nlm_rpc nh_srvrpc; /* (l) RPC for server replies */ 240184588Sdfr struct nlm_rpc nh_clntrpc; /* (l) RPC for client requests */ 241177633Sdfr rpcvers_t nh_vers; /* (s) NLM version of host */ 242177633Sdfr int nh_state; /* (s) last seen NSM state of host */ 243180025Sdfr enum nlm_host_state nh_monstate; /* (l) local NSM monitoring state */ 244177633Sdfr time_t nh_idle_timeout; /* (s) Time at which host is idle */ 245177633Sdfr struct sysctl_ctx_list nh_sysctl; /* (c) vfs.nlm.sysid nodes */ 246197840Szml uint32_t nh_grantcookie; /* (l) grant cookie counter */ 247177633Sdfr struct nlm_async_lock_list nh_pending; /* (l) pending async locks */ 248197840Szml struct nlm_async_lock_list nh_granted; /* (l) granted locks */ 249177633Sdfr struct nlm_async_lock_list nh_finished; /* (l) finished async locks */ 250177633Sdfr}; 251177633SdfrTAILQ_HEAD(nlm_host_list, nlm_host); 252177633Sdfr 253180025Sdfrstatic struct nlm_host_list nlm_hosts; /* (g) */ 254180025Sdfrstatic uint32_t nlm_next_sysid = 1; /* (g) */ 255177633Sdfr 256177633Sdfrstatic void nlm_host_unmonitor(struct nlm_host *); 257177633Sdfr 258197840Szmlstruct nlm_grantcookie { 259197840Szml uint32_t ng_sysid; 260197840Szml uint32_t ng_cookie; 261197840Szml}; 262197840Szml 263197840Szmlstatic inline uint32_t 264197840Szmlng_sysid(struct netobj *src) 265197840Szml{ 266197840Szml 267197840Szml return ((struct nlm_grantcookie *)src->n_bytes)->ng_sysid; 268197840Szml} 269197840Szml 270197840Szmlstatic inline uint32_t 271197840Szmlng_cookie(struct netobj *src) 272197840Szml{ 273197840Szml 274197840Szml return ((struct nlm_grantcookie *)src->n_bytes)->ng_cookie; 275197840Szml} 276197840Szml 277177633Sdfr/**********************************************************************/ 278177633Sdfr 279177633Sdfr/* 280177633Sdfr * Initialise NLM globals. 281177633Sdfr */ 282177633Sdfrstatic void 283177633Sdfrnlm_init(void *dummy) 284177633Sdfr{ 285177633Sdfr int error; 286177633Sdfr 287180025Sdfr mtx_init(&nlm_global_lock, "nlm_global_lock", NULL, MTX_DEF); 288180025Sdfr TAILQ_INIT(&nlm_waiting_locks); 289177633Sdfr TAILQ_INIT(&nlm_hosts); 290177633Sdfr 291177633Sdfr error = syscall_register(&nlm_syscall_offset, &nlm_syscall_sysent, 292177633Sdfr &nlm_syscall_prev_sysent); 293177633Sdfr if (error) 294191918Sdfr NLM_ERR("Can't register NLM syscall\n"); 295177633Sdfr else 296177633Sdfr nlm_syscall_registered = TRUE; 297177633Sdfr} 298177633SdfrSYSINIT(nlm_init, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_init, NULL); 299177633Sdfr 300177633Sdfrstatic void 301177633Sdfrnlm_uninit(void *dummy) 302177633Sdfr{ 303177633Sdfr 304177633Sdfr if (nlm_syscall_registered) 305177633Sdfr syscall_deregister(&nlm_syscall_offset, 306177633Sdfr &nlm_syscall_prev_sysent); 307177633Sdfr} 308177633SdfrSYSUNINIT(nlm_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_uninit, NULL); 309177633Sdfr 310177633Sdfr/* 311197840Szml * Create a netobj from an arbitrary source. 312197840Szml */ 313197840Szmlvoid 314197840Szmlnlm_make_netobj(struct netobj *dst, caddr_t src, size_t srcsize, 315197840Szml struct malloc_type *type) 316197840Szml{ 317197840Szml 318197840Szml dst->n_len = srcsize; 319197840Szml dst->n_bytes = malloc(srcsize, type, M_WAITOK); 320197840Szml memcpy(dst->n_bytes, src, srcsize); 321197840Szml} 322197840Szml 323197840Szml/* 324177633Sdfr * Copy a struct netobj. 325177633Sdfr */ 326177633Sdfrvoid 327177633Sdfrnlm_copy_netobj(struct netobj *dst, struct netobj *src, 328177633Sdfr struct malloc_type *type) 329177633Sdfr{ 330177633Sdfr 331197840Szml nlm_make_netobj(dst, src->n_bytes, src->n_len, type); 332177633Sdfr} 333177633Sdfr 334197840Szml 335177633Sdfr/* 336177633Sdfr * Create an RPC client handle for the given (address,prog,vers) 337177633Sdfr * triple using UDP. 338177633Sdfr */ 339177633Sdfrstatic CLIENT * 340177633Sdfrnlm_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers) 341177633Sdfr{ 342184588Sdfr char *wchan = "nlmrcv"; 343177633Sdfr const char* protofmly; 344177633Sdfr struct sockaddr_storage ss; 345177633Sdfr struct socket *so; 346177633Sdfr CLIENT *rpcb; 347177633Sdfr struct timeval timo; 348177633Sdfr RPCB parms; 349177633Sdfr char *uaddr; 350181683Sdfr enum clnt_stat stat = RPC_SUCCESS; 351181683Sdfr int rpcvers = RPCBVERS4; 352181683Sdfr bool_t do_tcp = FALSE; 353191937Sdfr bool_t tryagain = FALSE; 354182154Sdfr struct portmap mapping; 355181683Sdfr u_short port = 0; 356177633Sdfr 357177633Sdfr /* 358177633Sdfr * First we need to contact the remote RPCBIND service to find 359177633Sdfr * the right port. 360177633Sdfr */ 361177633Sdfr memcpy(&ss, sa, sa->sa_len); 362177633Sdfr switch (ss.ss_family) { 363177633Sdfr case AF_INET: 364177633Sdfr ((struct sockaddr_in *)&ss)->sin_port = htons(111); 365177633Sdfr protofmly = "inet"; 366177633Sdfr so = nlm_socket; 367177633Sdfr break; 368177633Sdfr 369177633Sdfr#ifdef INET6 370177633Sdfr case AF_INET6: 371177633Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111); 372177633Sdfr protofmly = "inet6"; 373177633Sdfr so = nlm_socket6; 374177633Sdfr break; 375177633Sdfr#endif 376177633Sdfr 377177633Sdfr default: 378177633Sdfr /* 379177633Sdfr * Unsupported address family - fail. 380177633Sdfr */ 381177633Sdfr return (NULL); 382177633Sdfr } 383177633Sdfr 384177633Sdfr rpcb = clnt_dg_create(so, (struct sockaddr *)&ss, 385181683Sdfr RPCBPROG, rpcvers, 0, 0); 386177633Sdfr if (!rpcb) 387177633Sdfr return (NULL); 388177633Sdfr 389181683Sdfrtry_tcp: 390177633Sdfr parms.r_prog = prog; 391177633Sdfr parms.r_vers = vers; 392181683Sdfr if (do_tcp) 393181683Sdfr parms.r_netid = "tcp"; 394181683Sdfr else 395181683Sdfr parms.r_netid = "udp"; 396177633Sdfr parms.r_addr = ""; 397177633Sdfr parms.r_owner = ""; 398177633Sdfr 399177633Sdfr /* 400177633Sdfr * Use the default timeout. 401177633Sdfr */ 402177633Sdfr timo.tv_sec = 25; 403177633Sdfr timo.tv_usec = 0; 404177633Sdfragain: 405181683Sdfr switch (rpcvers) { 406181683Sdfr case RPCBVERS4: 407181683Sdfr case RPCBVERS: 408177633Sdfr /* 409181683Sdfr * Try RPCBIND 4 then 3. 410177633Sdfr */ 411181683Sdfr uaddr = NULL; 412181683Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR, 413181683Sdfr (xdrproc_t) xdr_rpcb, &parms, 414181683Sdfr (xdrproc_t) xdr_wrapstring, &uaddr, timo); 415191937Sdfr if (stat == RPC_SUCCESS) { 416181683Sdfr /* 417181683Sdfr * We have a reply from the remote RPCBIND - turn it 418181683Sdfr * into an appropriate address and make a new client 419181683Sdfr * that can talk to the remote NLM. 420181683Sdfr * 421181683Sdfr * XXX fixup IPv6 scope ID. 422181683Sdfr */ 423181683Sdfr struct netbuf *a; 424181683Sdfr a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr); 425181683Sdfr if (!a) { 426191937Sdfr tryagain = TRUE; 427191937Sdfr } else { 428191937Sdfr tryagain = FALSE; 429191937Sdfr memcpy(&ss, a->buf, a->len); 430191937Sdfr free(a->buf, M_RPC); 431191937Sdfr free(a, M_RPC); 432191937Sdfr xdr_free((xdrproc_t) xdr_wrapstring, &uaddr); 433181683Sdfr } 434177633Sdfr } 435191937Sdfr if (tryagain || stat == RPC_PROGVERSMISMATCH) { 436191937Sdfr if (rpcvers == RPCBVERS4) 437191937Sdfr rpcvers = RPCBVERS; 438191937Sdfr else if (rpcvers == RPCBVERS) 439191937Sdfr rpcvers = PMAPVERS; 440191937Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers); 441191937Sdfr goto again; 442191937Sdfr } 443181683Sdfr break; 444181683Sdfr case PMAPVERS: 445177633Sdfr /* 446177633Sdfr * Try portmap. 447177633Sdfr */ 448177633Sdfr mapping.pm_prog = parms.r_prog; 449177633Sdfr mapping.pm_vers = parms.r_vers; 450181683Sdfr mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP; 451177633Sdfr mapping.pm_port = 0; 452177633Sdfr 453177633Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT, 454182154Sdfr (xdrproc_t) xdr_portmap, &mapping, 455177633Sdfr (xdrproc_t) xdr_u_short, &port, timo); 456177633Sdfr 457177633Sdfr if (stat == RPC_SUCCESS) { 458177633Sdfr switch (ss.ss_family) { 459177633Sdfr case AF_INET: 460177633Sdfr ((struct sockaddr_in *)&ss)->sin_port = 461177633Sdfr htons(port); 462177633Sdfr break; 463177633Sdfr 464177633Sdfr#ifdef INET6 465177633Sdfr case AF_INET6: 466177633Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = 467177633Sdfr htons(port); 468177633Sdfr break; 469177633Sdfr#endif 470177633Sdfr } 471177633Sdfr } 472181683Sdfr break; 473181683Sdfr default: 474181683Sdfr panic("invalid rpcvers %d", rpcvers); 475177633Sdfr } 476181683Sdfr /* 477181683Sdfr * We may have a positive response from the portmapper, but the NLM 478181683Sdfr * service was not found. Make sure we received a valid port. 479181683Sdfr */ 480181683Sdfr switch (ss.ss_family) { 481181683Sdfr case AF_INET: 482181683Sdfr port = ((struct sockaddr_in *)&ss)->sin_port; 483181683Sdfr break; 484181683Sdfr#ifdef INET6 485181683Sdfr case AF_INET6: 486181683Sdfr port = ((struct sockaddr_in6 *)&ss)->sin6_port; 487181683Sdfr break; 488181683Sdfr#endif 489181683Sdfr } 490181683Sdfr if (stat != RPC_SUCCESS || !port) { 491181683Sdfr /* 492181683Sdfr * If we were able to talk to rpcbind or portmap, but the udp 493181683Sdfr * variant wasn't available, ask about tcp. 494181683Sdfr * 495181683Sdfr * XXX - We could also check for a TCP portmapper, but 496181683Sdfr * if the host is running a portmapper at all, we should be able 497181683Sdfr * to hail it over UDP. 498181683Sdfr */ 499181683Sdfr if (stat == RPC_SUCCESS && !do_tcp) { 500181683Sdfr do_tcp = TRUE; 501181683Sdfr goto try_tcp; 502181683Sdfr } 503181683Sdfr 504181683Sdfr /* Otherwise, bad news. */ 505191918Sdfr NLM_ERR("NLM: failed to contact remote rpcbind, " 506191918Sdfr "stat = %d, port = %d\n", (int) stat, port); 507178241Sdfr CLNT_DESTROY(rpcb); 508177633Sdfr return (NULL); 509177633Sdfr } 510177633Sdfr 511181683Sdfr if (do_tcp) { 512181683Sdfr /* 513181683Sdfr * Destroy the UDP client we used to speak to rpcbind and 514181683Sdfr * recreate as a TCP client. 515181683Sdfr */ 516181683Sdfr struct netconfig *nconf = NULL; 517177633Sdfr 518181683Sdfr CLNT_DESTROY(rpcb); 519181683Sdfr 520181683Sdfr switch (ss.ss_family) { 521181683Sdfr case AF_INET: 522181683Sdfr nconf = getnetconfigent("tcp"); 523181683Sdfr break; 524181683Sdfr#ifdef INET6 525181683Sdfr case AF_INET6: 526181683Sdfr nconf = getnetconfigent("tcp6"); 527181683Sdfr break; 528181683Sdfr#endif 529181683Sdfr } 530181683Sdfr 531181683Sdfr rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss, 532181683Sdfr prog, vers, 0, 0); 533184588Sdfr CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan); 534181683Sdfr rpcb->cl_auth = nlm_auth; 535181683Sdfr 536181683Sdfr } else { 537181683Sdfr /* 538181683Sdfr * Re-use the client we used to speak to rpcbind. 539181683Sdfr */ 540181683Sdfr CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss); 541181683Sdfr CLNT_CONTROL(rpcb, CLSET_PROG, &prog); 542181683Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &vers); 543184588Sdfr CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan); 544181683Sdfr rpcb->cl_auth = nlm_auth; 545181683Sdfr } 546181683Sdfr 547177633Sdfr return (rpcb); 548177633Sdfr} 549177633Sdfr 550177633Sdfr/* 551177633Sdfr * This async callback after when an async lock request has been 552177633Sdfr * granted. We notify the host which initiated the request. 553177633Sdfr */ 554177633Sdfrstatic void 555177633Sdfrnlm_lock_callback(void *arg, int pending) 556177633Sdfr{ 557177633Sdfr struct nlm_async_lock *af = (struct nlm_async_lock *) arg; 558180025Sdfr struct rpc_callextra ext; 559177633Sdfr 560197840Szml NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) granted," 561197840Szml " cookie %d:%d\n", af, af->af_host->nh_caller_name, 562197840Szml af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie), 563197840Szml ng_cookie(&af->af_granted.cookie)); 564177633Sdfr 565177633Sdfr /* 566177633Sdfr * Send the results back to the host. 567177633Sdfr * 568177633Sdfr * Note: there is a possible race here with nlm_host_notify 569178241Sdfr * destroying the RPC client. To avoid problems, the first 570177633Sdfr * thing nlm_host_notify does is to cancel pending async lock 571177633Sdfr * requests. 572177633Sdfr */ 573180025Sdfr memset(&ext, 0, sizeof(ext)); 574180025Sdfr ext.rc_auth = nlm_auth; 575177633Sdfr if (af->af_host->nh_vers == NLM_VERS4) { 576177633Sdfr nlm4_granted_msg_4(&af->af_granted, 577180025Sdfr NULL, af->af_rpc, &ext, nlm_zero_tv); 578177633Sdfr } else { 579177633Sdfr /* 580177633Sdfr * Back-convert to legacy protocol 581177633Sdfr */ 582177633Sdfr nlm_testargs granted; 583177633Sdfr granted.cookie = af->af_granted.cookie; 584177633Sdfr granted.exclusive = af->af_granted.exclusive; 585177633Sdfr granted.alock.caller_name = 586177633Sdfr af->af_granted.alock.caller_name; 587177633Sdfr granted.alock.fh = af->af_granted.alock.fh; 588177633Sdfr granted.alock.oh = af->af_granted.alock.oh; 589177633Sdfr granted.alock.svid = af->af_granted.alock.svid; 590177633Sdfr granted.alock.l_offset = 591177633Sdfr af->af_granted.alock.l_offset; 592177633Sdfr granted.alock.l_len = 593177633Sdfr af->af_granted.alock.l_len; 594177633Sdfr 595177633Sdfr nlm_granted_msg_1(&granted, 596180025Sdfr NULL, af->af_rpc, &ext, nlm_zero_tv); 597177633Sdfr } 598177633Sdfr 599177633Sdfr /* 600197840Szml * Move this entry to the nh_granted list. 601177633Sdfr */ 602197840Szml af->af_expiretime = time_uptime + NLM_EXPIRE_TIMEOUT; 603177633Sdfr mtx_lock(&af->af_host->nh_lock); 604177633Sdfr TAILQ_REMOVE(&af->af_host->nh_pending, af, af_link); 605197840Szml TAILQ_INSERT_TAIL(&af->af_host->nh_granted, af, af_link); 606177633Sdfr mtx_unlock(&af->af_host->nh_lock); 607177633Sdfr} 608177633Sdfr 609177633Sdfr/* 610177633Sdfr * Free an async lock request. The request must have been removed from 611177633Sdfr * any list. 612177633Sdfr */ 613177633Sdfrstatic void 614177633Sdfrnlm_free_async_lock(struct nlm_async_lock *af) 615177633Sdfr{ 616177633Sdfr /* 617177633Sdfr * Free an async lock. 618177633Sdfr */ 619180025Sdfr if (af->af_rpc) 620180025Sdfr CLNT_RELEASE(af->af_rpc); 621177633Sdfr xdr_free((xdrproc_t) xdr_nlm4_testargs, &af->af_granted); 622177633Sdfr if (af->af_vp) 623177633Sdfr vrele(af->af_vp); 624177633Sdfr free(af, M_NLM); 625177633Sdfr} 626177633Sdfr 627177633Sdfr/* 628177633Sdfr * Cancel our async request - this must be called with 629177633Sdfr * af->nh_host->nh_lock held. This is slightly complicated by a 630177633Sdfr * potential race with our own callback. If we fail to cancel the 631177633Sdfr * lock, it must already have been granted - we make sure our async 632177633Sdfr * task has completed by calling taskqueue_drain in this case. 633177633Sdfr */ 634177633Sdfrstatic int 635177633Sdfrnlm_cancel_async_lock(struct nlm_async_lock *af) 636177633Sdfr{ 637177633Sdfr struct nlm_host *host = af->af_host; 638177633Sdfr int error; 639177633Sdfr 640177633Sdfr mtx_assert(&host->nh_lock, MA_OWNED); 641177633Sdfr 642177633Sdfr mtx_unlock(&host->nh_lock); 643177633Sdfr 644177633Sdfr error = VOP_ADVLOCKASYNC(af->af_vp, NULL, F_CANCEL, &af->af_fl, 645177633Sdfr F_REMOTE, NULL, &af->af_cookie); 646177633Sdfr 647177633Sdfr if (error) { 648177633Sdfr /* 649177633Sdfr * We failed to cancel - make sure our callback has 650177633Sdfr * completed before we continue. 651177633Sdfr */ 652177633Sdfr taskqueue_drain(taskqueue_thread, &af->af_task); 653177633Sdfr } 654177633Sdfr 655177633Sdfr mtx_lock(&host->nh_lock); 656177633Sdfr 657177633Sdfr if (!error) { 658191918Sdfr NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) " 659191918Sdfr "cancelled\n", af, host->nh_caller_name, host->nh_sysid); 660177633Sdfr 661177633Sdfr /* 662177633Sdfr * Remove from the nh_pending list and free now that 663177633Sdfr * we are safe from the callback. 664177633Sdfr */ 665177633Sdfr TAILQ_REMOVE(&host->nh_pending, af, af_link); 666177633Sdfr mtx_unlock(&host->nh_lock); 667177633Sdfr nlm_free_async_lock(af); 668177633Sdfr mtx_lock(&host->nh_lock); 669177633Sdfr } 670177633Sdfr 671177633Sdfr return (error); 672177633Sdfr} 673177633Sdfr 674177633Sdfrstatic void 675197840Szmlnlm_check_expired_locks(struct nlm_host *host) 676177633Sdfr{ 677177633Sdfr struct nlm_async_lock *af; 678197840Szml time_t uptime = time_uptime; 679177633Sdfr 680177633Sdfr mtx_lock(&host->nh_lock); 681197840Szml while ((af = TAILQ_FIRST(&host->nh_granted)) != NULL 682197840Szml && uptime >= af->af_expiretime) { 683197840Szml NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) expired," 684197840Szml " cookie %d:%d\n", af, af->af_host->nh_caller_name, 685197840Szml af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie), 686197840Szml ng_cookie(&af->af_granted.cookie)); 687197840Szml TAILQ_REMOVE(&host->nh_granted, af, af_link); 688197840Szml mtx_unlock(&host->nh_lock); 689197840Szml nlm_free_async_lock(af); 690197840Szml mtx_lock(&host->nh_lock); 691197840Szml } 692177633Sdfr while ((af = TAILQ_FIRST(&host->nh_finished)) != NULL) { 693177633Sdfr TAILQ_REMOVE(&host->nh_finished, af, af_link); 694177633Sdfr mtx_unlock(&host->nh_lock); 695177633Sdfr nlm_free_async_lock(af); 696177633Sdfr mtx_lock(&host->nh_lock); 697177633Sdfr } 698177633Sdfr mtx_unlock(&host->nh_lock); 699177633Sdfr} 700177633Sdfr 701177633Sdfr/* 702180025Sdfr * Free resources used by a host. This is called after the reference 703180025Sdfr * count has reached zero so it doesn't need to worry about locks. 704177633Sdfr */ 705177633Sdfrstatic void 706180025Sdfrnlm_host_destroy(struct nlm_host *host) 707177633Sdfr{ 708180025Sdfr 709180025Sdfr mtx_lock(&nlm_global_lock); 710180025Sdfr TAILQ_REMOVE(&nlm_hosts, host, nh_link); 711180025Sdfr mtx_unlock(&nlm_global_lock); 712180025Sdfr 713184588Sdfr if (host->nh_srvrpc.nr_client) 714184588Sdfr CLNT_RELEASE(host->nh_srvrpc.nr_client); 715184588Sdfr if (host->nh_clntrpc.nr_client) 716184588Sdfr CLNT_RELEASE(host->nh_clntrpc.nr_client); 717180025Sdfr mtx_destroy(&host->nh_lock); 718180025Sdfr sysctl_ctx_free(&host->nh_sysctl); 719180025Sdfr free(host, M_NLM); 720180025Sdfr} 721180025Sdfr 722180025Sdfr/* 723180025Sdfr * Thread start callback for client lock recovery 724180025Sdfr */ 725180025Sdfrstatic void 726180025Sdfrnlm_client_recovery_start(void *arg) 727180025Sdfr{ 728180025Sdfr struct nlm_host *host = (struct nlm_host *) arg; 729180025Sdfr 730191918Sdfr NLM_DEBUG(1, "NLM: client lock recovery for %s started\n", 731191918Sdfr host->nh_caller_name); 732180025Sdfr 733180025Sdfr nlm_client_recovery(host); 734180025Sdfr 735191918Sdfr NLM_DEBUG(1, "NLM: client lock recovery for %s completed\n", 736191918Sdfr host->nh_caller_name); 737180025Sdfr 738180025Sdfr host->nh_monstate = NLM_MONITORED; 739180025Sdfr nlm_host_release(host); 740180025Sdfr 741180025Sdfr kthread_exit(); 742180025Sdfr} 743180025Sdfr 744180025Sdfr/* 745180025Sdfr * This is called when we receive a host state change notification. We 746180025Sdfr * unlock any active locks owned by the host. When rpc.lockd is 747180025Sdfr * shutting down, this function is called with newstate set to zero 748180025Sdfr * which allows us to cancel any pending async locks and clear the 749180025Sdfr * locking state. 750180025Sdfr */ 751180025Sdfrstatic void 752180025Sdfrnlm_host_notify(struct nlm_host *host, int newstate) 753180025Sdfr{ 754177633Sdfr struct nlm_async_lock *af; 755177633Sdfr 756177633Sdfr if (newstate) { 757191918Sdfr NLM_DEBUG(1, "NLM: host %s (sysid %d) rebooted, new " 758191918Sdfr "state is %d\n", host->nh_caller_name, 759191918Sdfr host->nh_sysid, newstate); 760177633Sdfr } 761177633Sdfr 762177633Sdfr /* 763177633Sdfr * Cancel any pending async locks for this host. 764177633Sdfr */ 765177633Sdfr mtx_lock(&host->nh_lock); 766177633Sdfr while ((af = TAILQ_FIRST(&host->nh_pending)) != NULL) { 767177633Sdfr /* 768177633Sdfr * nlm_cancel_async_lock will remove the entry from 769177633Sdfr * nh_pending and free it. 770177633Sdfr */ 771177633Sdfr nlm_cancel_async_lock(af); 772177633Sdfr } 773177633Sdfr mtx_unlock(&host->nh_lock); 774197840Szml nlm_check_expired_locks(host); 775177633Sdfr 776177633Sdfr /* 777180025Sdfr * The host just rebooted - trash its locks. 778177633Sdfr */ 779177633Sdfr lf_clearremotesys(host->nh_sysid); 780177633Sdfr host->nh_state = newstate; 781177633Sdfr 782177633Sdfr /* 783180025Sdfr * If we have any remote locks for this host (i.e. it 784180025Sdfr * represents a remote NFS server that our local NFS client 785180025Sdfr * has locks for), start a recovery thread. 786177633Sdfr */ 787180025Sdfr if (newstate != 0 788180025Sdfr && host->nh_monstate != NLM_RECOVERING 789180025Sdfr && lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid) > 0) { 790180025Sdfr struct thread *td; 791180025Sdfr host->nh_monstate = NLM_RECOVERING; 792180025Sdfr refcount_acquire(&host->nh_refs); 793180025Sdfr kthread_add(nlm_client_recovery_start, host, curproc, &td, 0, 0, 794180025Sdfr "NFS lock recovery for %s", host->nh_caller_name); 795177633Sdfr } 796177633Sdfr} 797177633Sdfr 798177633Sdfr/* 799177633Sdfr * Sysctl handler to count the number of locks for a sysid. 800177633Sdfr */ 801177633Sdfrstatic int 802177633Sdfrnlm_host_lock_count_sysctl(SYSCTL_HANDLER_ARGS) 803177633Sdfr{ 804177633Sdfr struct nlm_host *host; 805177633Sdfr int count; 806177633Sdfr 807177633Sdfr host = oidp->oid_arg1; 808177633Sdfr count = lf_countlocks(host->nh_sysid); 809177633Sdfr return sysctl_handle_int(oidp, &count, 0, req); 810177633Sdfr} 811177633Sdfr 812177633Sdfr/* 813180025Sdfr * Sysctl handler to count the number of client locks for a sysid. 814180025Sdfr */ 815180025Sdfrstatic int 816180025Sdfrnlm_host_client_lock_count_sysctl(SYSCTL_HANDLER_ARGS) 817180025Sdfr{ 818180025Sdfr struct nlm_host *host; 819180025Sdfr int count; 820180025Sdfr 821180025Sdfr host = oidp->oid_arg1; 822180025Sdfr count = lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid); 823180025Sdfr return sysctl_handle_int(oidp, &count, 0, req); 824180025Sdfr} 825180025Sdfr 826180025Sdfr/* 827177633Sdfr * Create a new NLM host. 828177633Sdfr */ 829177633Sdfrstatic struct nlm_host * 830177633Sdfrnlm_create_host(const char* caller_name) 831177633Sdfr{ 832177633Sdfr struct nlm_host *host; 833177633Sdfr struct sysctl_oid *oid; 834177633Sdfr 835180025Sdfr mtx_assert(&nlm_global_lock, MA_OWNED); 836180025Sdfr 837191918Sdfr NLM_DEBUG(1, "NLM: new host %s (sysid %d)\n", 838191918Sdfr caller_name, nlm_next_sysid); 839180025Sdfr host = malloc(sizeof(struct nlm_host), M_NLM, M_NOWAIT|M_ZERO); 840180025Sdfr if (!host) 841180025Sdfr return (NULL); 842177633Sdfr mtx_init(&host->nh_lock, "nh_lock", NULL, MTX_DEF); 843180025Sdfr host->nh_refs = 1; 844180025Sdfr strlcpy(host->nh_caller_name, caller_name, MAXNAMELEN); 845177633Sdfr host->nh_sysid = nlm_next_sysid++; 846177633Sdfr snprintf(host->nh_sysid_string, sizeof(host->nh_sysid_string), 847177633Sdfr "%d", host->nh_sysid); 848177633Sdfr host->nh_vers = 0; 849177633Sdfr host->nh_state = 0; 850178112Sdfr host->nh_monstate = NLM_UNMONITORED; 851197840Szml host->nh_grantcookie = 1; 852177633Sdfr TAILQ_INIT(&host->nh_pending); 853197840Szml TAILQ_INIT(&host->nh_granted); 854177633Sdfr TAILQ_INIT(&host->nh_finished); 855177633Sdfr TAILQ_INSERT_TAIL(&nlm_hosts, host, nh_link); 856177633Sdfr 857180025Sdfr mtx_unlock(&nlm_global_lock); 858180025Sdfr 859177633Sdfr sysctl_ctx_init(&host->nh_sysctl); 860177633Sdfr oid = SYSCTL_ADD_NODE(&host->nh_sysctl, 861177633Sdfr SYSCTL_STATIC_CHILDREN(_vfs_nlm_sysid), 862177633Sdfr OID_AUTO, host->nh_sysid_string, CTLFLAG_RD, NULL, ""); 863177633Sdfr SYSCTL_ADD_STRING(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 864177633Sdfr "hostname", CTLFLAG_RD, host->nh_caller_name, 0, ""); 865217326Smdf SYSCTL_ADD_UINT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 866177633Sdfr "version", CTLFLAG_RD, &host->nh_vers, 0, ""); 867217326Smdf SYSCTL_ADD_UINT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 868178112Sdfr "monitored", CTLFLAG_RD, &host->nh_monstate, 0, ""); 869177633Sdfr SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 870177633Sdfr "lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0, 871177633Sdfr nlm_host_lock_count_sysctl, "I", ""); 872180025Sdfr SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 873180025Sdfr "client_lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0, 874180025Sdfr nlm_host_client_lock_count_sysctl, "I", ""); 875177633Sdfr 876180025Sdfr mtx_lock(&nlm_global_lock); 877180025Sdfr 878177633Sdfr return (host); 879177633Sdfr} 880177633Sdfr 881177633Sdfr/* 882192501Srmacklem * Acquire the next sysid for remote locks not handled by the NLM. 883192501Srmacklem */ 884192501Srmacklemuint32_t 885192501Srmacklemnlm_acquire_next_sysid(void) 886192501Srmacklem{ 887192501Srmacklem uint32_t next_sysid; 888192501Srmacklem 889192501Srmacklem mtx_lock(&nlm_global_lock); 890192501Srmacklem next_sysid = nlm_next_sysid++; 891192501Srmacklem mtx_unlock(&nlm_global_lock); 892192501Srmacklem return (next_sysid); 893192501Srmacklem} 894192501Srmacklem 895192501Srmacklem/* 896177633Sdfr * Return non-zero if the address parts of the two sockaddrs are the 897177633Sdfr * same. 898177633Sdfr */ 899177633Sdfrstatic int 900177633Sdfrnlm_compare_addr(const struct sockaddr *a, const struct sockaddr *b) 901177633Sdfr{ 902177633Sdfr const struct sockaddr_in *a4, *b4; 903177633Sdfr#ifdef INET6 904177633Sdfr const struct sockaddr_in6 *a6, *b6; 905177633Sdfr#endif 906177633Sdfr 907177633Sdfr if (a->sa_family != b->sa_family) 908177633Sdfr return (FALSE); 909177633Sdfr 910177633Sdfr switch (a->sa_family) { 911177633Sdfr case AF_INET: 912177633Sdfr a4 = (const struct sockaddr_in *) a; 913177633Sdfr b4 = (const struct sockaddr_in *) b; 914177633Sdfr return !memcmp(&a4->sin_addr, &b4->sin_addr, 915177633Sdfr sizeof(a4->sin_addr)); 916177633Sdfr#ifdef INET6 917177633Sdfr case AF_INET6: 918177633Sdfr a6 = (const struct sockaddr_in6 *) a; 919177633Sdfr b6 = (const struct sockaddr_in6 *) b; 920177633Sdfr return !memcmp(&a6->sin6_addr, &b6->sin6_addr, 921177633Sdfr sizeof(a6->sin6_addr)); 922177633Sdfr#endif 923177633Sdfr } 924177633Sdfr 925177633Sdfr return (0); 926177633Sdfr} 927177633Sdfr 928177633Sdfr/* 929177633Sdfr * Check for idle hosts and stop monitoring them. We could also free 930177633Sdfr * the host structure here, possibly after a larger timeout but that 931177633Sdfr * would require some care to avoid races with 932177633Sdfr * e.g. nlm_host_lock_count_sysctl. 933177633Sdfr */ 934177633Sdfrstatic void 935177633Sdfrnlm_check_idle(void) 936177633Sdfr{ 937177633Sdfr struct nlm_host *host; 938177633Sdfr 939180025Sdfr mtx_assert(&nlm_global_lock, MA_OWNED); 940180025Sdfr 941177633Sdfr if (time_uptime <= nlm_next_idle_check) 942177633Sdfr return; 943177633Sdfr 944177633Sdfr nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD; 945177633Sdfr 946177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 947178112Sdfr if (host->nh_monstate == NLM_MONITORED 948177633Sdfr && time_uptime > host->nh_idle_timeout) { 949180025Sdfr mtx_unlock(&nlm_global_lock); 950180025Sdfr if (lf_countlocks(host->nh_sysid) > 0 951180025Sdfr || lf_countlocks(NLM_SYSID_CLIENT 952180025Sdfr + host->nh_sysid)) { 953177633Sdfr host->nh_idle_timeout = 954177633Sdfr time_uptime + NLM_IDLE_TIMEOUT; 955180025Sdfr mtx_lock(&nlm_global_lock); 956177633Sdfr continue; 957177633Sdfr } 958177633Sdfr nlm_host_unmonitor(host); 959180025Sdfr mtx_lock(&nlm_global_lock); 960177633Sdfr } 961177633Sdfr } 962177633Sdfr} 963177633Sdfr 964177633Sdfr/* 965177633Sdfr * Search for an existing NLM host that matches the given name 966177633Sdfr * (typically the caller_name element of an nlm4_lock). If none is 967180025Sdfr * found, create a new host. If 'addr' is non-NULL, record the remote 968177633Sdfr * address of the host so that we can call it back for async 969180025Sdfr * responses. If 'vers' is greater than zero then record the NLM 970180025Sdfr * program version to use to communicate with this client. 971177633Sdfr */ 972177633Sdfrstruct nlm_host * 973180025Sdfrnlm_find_host_by_name(const char *name, const struct sockaddr *addr, 974180025Sdfr rpcvers_t vers) 975177633Sdfr{ 976177633Sdfr struct nlm_host *host; 977177633Sdfr 978180025Sdfr mtx_lock(&nlm_global_lock); 979177633Sdfr 980177633Sdfr /* 981177633Sdfr * The remote host is determined by caller_name. 982177633Sdfr */ 983177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 984177633Sdfr if (!strcmp(host->nh_caller_name, name)) 985177633Sdfr break; 986177633Sdfr } 987177633Sdfr 988180025Sdfr if (!host) { 989177633Sdfr host = nlm_create_host(name); 990180025Sdfr if (!host) { 991180025Sdfr mtx_unlock(&nlm_global_lock); 992180025Sdfr return (NULL); 993180025Sdfr } 994180025Sdfr } 995180025Sdfr refcount_acquire(&host->nh_refs); 996180025Sdfr 997177633Sdfr host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT; 998177633Sdfr 999177633Sdfr /* 1000180025Sdfr * If we have an address for the host, record it so that we 1001180025Sdfr * can send async replies etc. 1002177633Sdfr */ 1003180025Sdfr if (addr) { 1004177633Sdfr 1005180025Sdfr KASSERT(addr->sa_len < sizeof(struct sockaddr_storage), 1006177633Sdfr ("Strange remote transport address length")); 1007177633Sdfr 1008177633Sdfr /* 1009177633Sdfr * If we have seen an address before and we currently 1010177633Sdfr * have an RPC client handle, make sure the address is 1011177633Sdfr * the same, otherwise discard the client handle. 1012177633Sdfr */ 1013184588Sdfr if (host->nh_addr.ss_len && host->nh_srvrpc.nr_client) { 1014177633Sdfr if (!nlm_compare_addr( 1015177633Sdfr (struct sockaddr *) &host->nh_addr, 1016180025Sdfr addr) 1017180025Sdfr || host->nh_vers != vers) { 1018180025Sdfr CLIENT *client; 1019180025Sdfr mtx_lock(&host->nh_lock); 1020184588Sdfr client = host->nh_srvrpc.nr_client; 1021184588Sdfr host->nh_srvrpc.nr_client = NULL; 1022180025Sdfr mtx_unlock(&host->nh_lock); 1023180025Sdfr if (client) { 1024180025Sdfr CLNT_RELEASE(client); 1025180025Sdfr } 1026177633Sdfr } 1027177633Sdfr } 1028180025Sdfr memcpy(&host->nh_addr, addr, addr->sa_len); 1029180025Sdfr host->nh_vers = vers; 1030177633Sdfr } 1031177633Sdfr 1032180025Sdfr nlm_check_idle(); 1033180025Sdfr 1034180025Sdfr mtx_unlock(&nlm_global_lock); 1035180025Sdfr 1036177633Sdfr return (host); 1037177633Sdfr} 1038177633Sdfr 1039177633Sdfr/* 1040177633Sdfr * Search for an existing NLM host that matches the given remote 1041177633Sdfr * address. If none is found, create a new host with the requested 1042177633Sdfr * address and remember 'vers' as the NLM protocol version to use for 1043177633Sdfr * that host. 1044177633Sdfr */ 1045177633Sdfrstruct nlm_host * 1046177633Sdfrnlm_find_host_by_addr(const struct sockaddr *addr, int vers) 1047177633Sdfr{ 1048180025Sdfr /* 1049180025Sdfr * Fake up a name using inet_ntop. This buffer is 1050180025Sdfr * large enough for an IPv6 address. 1051180025Sdfr */ 1052180025Sdfr char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; 1053177633Sdfr struct nlm_host *host; 1054177633Sdfr 1055180025Sdfr switch (addr->sa_family) { 1056180025Sdfr case AF_INET: 1057213103Sattilio inet_ntop(AF_INET, 1058180025Sdfr &((const struct sockaddr_in *) addr)->sin_addr, 1059180025Sdfr tmp, sizeof tmp); 1060180025Sdfr break; 1061180025Sdfr#ifdef INET6 1062180025Sdfr case AF_INET6: 1063213103Sattilio inet_ntop(AF_INET6, 1064180025Sdfr &((const struct sockaddr_in6 *) addr)->sin6_addr, 1065180025Sdfr tmp, sizeof tmp); 1066180025Sdfr break; 1067180025Sdfr#endif 1068180025Sdfr default: 1069180025Sdfr strcmp(tmp, "<unknown>"); 1070180025Sdfr } 1071177633Sdfr 1072180025Sdfr 1073180025Sdfr mtx_lock(&nlm_global_lock); 1074180025Sdfr 1075177633Sdfr /* 1076177633Sdfr * The remote host is determined by caller_name. 1077177633Sdfr */ 1078177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 1079177633Sdfr if (nlm_compare_addr(addr, 1080177633Sdfr (const struct sockaddr *) &host->nh_addr)) 1081177633Sdfr break; 1082177633Sdfr } 1083177633Sdfr 1084177633Sdfr if (!host) { 1085180025Sdfr host = nlm_create_host(tmp); 1086180025Sdfr if (!host) { 1087180025Sdfr mtx_unlock(&nlm_global_lock); 1088180025Sdfr return (NULL); 1089177633Sdfr } 1090177633Sdfr memcpy(&host->nh_addr, addr, addr->sa_len); 1091177633Sdfr host->nh_vers = vers; 1092177633Sdfr } 1093180025Sdfr refcount_acquire(&host->nh_refs); 1094180025Sdfr 1095177633Sdfr host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT; 1096177633Sdfr 1097180025Sdfr nlm_check_idle(); 1098180025Sdfr 1099180025Sdfr mtx_unlock(&nlm_global_lock); 1100180025Sdfr 1101177633Sdfr return (host); 1102177633Sdfr} 1103177633Sdfr 1104177633Sdfr/* 1105177633Sdfr * Find the NLM host that matches the value of 'sysid'. If none 1106177633Sdfr * exists, return NULL. 1107177633Sdfr */ 1108177633Sdfrstatic struct nlm_host * 1109177633Sdfrnlm_find_host_by_sysid(int sysid) 1110177633Sdfr{ 1111177633Sdfr struct nlm_host *host; 1112177633Sdfr 1113177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 1114180025Sdfr if (host->nh_sysid == sysid) { 1115180025Sdfr refcount_acquire(&host->nh_refs); 1116177633Sdfr return (host); 1117180025Sdfr } 1118177633Sdfr } 1119177633Sdfr 1120177633Sdfr return (NULL); 1121177633Sdfr} 1122177633Sdfr 1123180025Sdfrvoid nlm_host_release(struct nlm_host *host) 1124180025Sdfr{ 1125180025Sdfr if (refcount_release(&host->nh_refs)) { 1126180025Sdfr /* 1127180025Sdfr * Free the host 1128180025Sdfr */ 1129180025Sdfr nlm_host_destroy(host); 1130180025Sdfr } 1131180025Sdfr} 1132180025Sdfr 1133177633Sdfr/* 1134177633Sdfr * Unregister this NLM host with the local NSM due to idleness. 1135177633Sdfr */ 1136177633Sdfrstatic void 1137177633Sdfrnlm_host_unmonitor(struct nlm_host *host) 1138177633Sdfr{ 1139177633Sdfr mon_id smmonid; 1140177633Sdfr sm_stat_res smstat; 1141177633Sdfr struct timeval timo; 1142177633Sdfr enum clnt_stat stat; 1143177633Sdfr 1144191918Sdfr NLM_DEBUG(1, "NLM: unmonitoring %s (sysid %d)\n", 1145191918Sdfr host->nh_caller_name, host->nh_sysid); 1146177633Sdfr 1147177633Sdfr /* 1148177633Sdfr * We put our assigned system ID value in the priv field to 1149177633Sdfr * make it simpler to find the host if we are notified of a 1150177633Sdfr * host restart. 1151177633Sdfr */ 1152177633Sdfr smmonid.mon_name = host->nh_caller_name; 1153177633Sdfr smmonid.my_id.my_name = "localhost"; 1154177633Sdfr smmonid.my_id.my_prog = NLM_PROG; 1155177633Sdfr smmonid.my_id.my_vers = NLM_SM; 1156177633Sdfr smmonid.my_id.my_proc = NLM_SM_NOTIFY; 1157177633Sdfr 1158177633Sdfr timo.tv_sec = 25; 1159177633Sdfr timo.tv_usec = 0; 1160177633Sdfr stat = CLNT_CALL(nlm_nsm, SM_UNMON, 1161177633Sdfr (xdrproc_t) xdr_mon, &smmonid, 1162177633Sdfr (xdrproc_t) xdr_sm_stat, &smstat, timo); 1163177633Sdfr 1164177633Sdfr if (stat != RPC_SUCCESS) { 1165191918Sdfr NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat); 1166177633Sdfr return; 1167177633Sdfr } 1168177633Sdfr if (smstat.res_stat == stat_fail) { 1169191918Sdfr NLM_ERR("Local NSM refuses to unmonitor %s\n", 1170177633Sdfr host->nh_caller_name); 1171177633Sdfr return; 1172177633Sdfr } 1173177633Sdfr 1174178112Sdfr host->nh_monstate = NLM_UNMONITORED; 1175177633Sdfr} 1176177633Sdfr 1177177633Sdfr/* 1178177633Sdfr * Register this NLM host with the local NSM so that we can be 1179177633Sdfr * notified if it reboots. 1180177633Sdfr */ 1181180025Sdfrvoid 1182177633Sdfrnlm_host_monitor(struct nlm_host *host, int state) 1183177633Sdfr{ 1184177633Sdfr mon smmon; 1185177633Sdfr sm_stat_res smstat; 1186177633Sdfr struct timeval timo; 1187177633Sdfr enum clnt_stat stat; 1188177633Sdfr 1189177633Sdfr if (state && !host->nh_state) { 1190177633Sdfr /* 1191177633Sdfr * This is the first time we have seen an NSM state 1192177633Sdfr * value for this host. We record it here to help 1193177633Sdfr * detect host reboots. 1194177633Sdfr */ 1195177633Sdfr host->nh_state = state; 1196191918Sdfr NLM_DEBUG(1, "NLM: host %s (sysid %d) has NSM state %d\n", 1197191918Sdfr host->nh_caller_name, host->nh_sysid, state); 1198177633Sdfr } 1199177633Sdfr 1200180025Sdfr mtx_lock(&host->nh_lock); 1201180025Sdfr if (host->nh_monstate != NLM_UNMONITORED) { 1202180025Sdfr mtx_unlock(&host->nh_lock); 1203177633Sdfr return; 1204180025Sdfr } 1205180025Sdfr host->nh_monstate = NLM_MONITORED; 1206180025Sdfr mtx_unlock(&host->nh_lock); 1207177633Sdfr 1208191918Sdfr NLM_DEBUG(1, "NLM: monitoring %s (sysid %d)\n", 1209191918Sdfr host->nh_caller_name, host->nh_sysid); 1210177633Sdfr 1211177633Sdfr /* 1212177633Sdfr * We put our assigned system ID value in the priv field to 1213177633Sdfr * make it simpler to find the host if we are notified of a 1214177633Sdfr * host restart. 1215177633Sdfr */ 1216177633Sdfr smmon.mon_id.mon_name = host->nh_caller_name; 1217177633Sdfr smmon.mon_id.my_id.my_name = "localhost"; 1218177633Sdfr smmon.mon_id.my_id.my_prog = NLM_PROG; 1219177633Sdfr smmon.mon_id.my_id.my_vers = NLM_SM; 1220177633Sdfr smmon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; 1221177633Sdfr memcpy(smmon.priv, &host->nh_sysid, sizeof(host->nh_sysid)); 1222177633Sdfr 1223177633Sdfr timo.tv_sec = 25; 1224177633Sdfr timo.tv_usec = 0; 1225177633Sdfr stat = CLNT_CALL(nlm_nsm, SM_MON, 1226177633Sdfr (xdrproc_t) xdr_mon, &smmon, 1227177633Sdfr (xdrproc_t) xdr_sm_stat, &smstat, timo); 1228177633Sdfr 1229177633Sdfr if (stat != RPC_SUCCESS) { 1230191918Sdfr NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat); 1231177633Sdfr return; 1232177633Sdfr } 1233177633Sdfr if (smstat.res_stat == stat_fail) { 1234191918Sdfr NLM_ERR("Local NSM refuses to monitor %s\n", 1235177633Sdfr host->nh_caller_name); 1236180025Sdfr mtx_lock(&host->nh_lock); 1237178112Sdfr host->nh_monstate = NLM_MONITOR_FAILED; 1238180025Sdfr mtx_unlock(&host->nh_lock); 1239177633Sdfr return; 1240177633Sdfr } 1241177633Sdfr 1242178112Sdfr host->nh_monstate = NLM_MONITORED; 1243177633Sdfr} 1244177633Sdfr 1245177633Sdfr/* 1246177633Sdfr * Return an RPC client handle that can be used to talk to the NLM 1247177633Sdfr * running on the given host. 1248177633Sdfr */ 1249177633SdfrCLIENT * 1250184588Sdfrnlm_host_get_rpc(struct nlm_host *host, bool_t isserver) 1251177633Sdfr{ 1252184588Sdfr struct nlm_rpc *rpc; 1253180025Sdfr CLIENT *client; 1254177633Sdfr 1255180025Sdfr mtx_lock(&host->nh_lock); 1256180025Sdfr 1257184588Sdfr if (isserver) 1258184588Sdfr rpc = &host->nh_srvrpc; 1259184588Sdfr else 1260184588Sdfr rpc = &host->nh_clntrpc; 1261184588Sdfr 1262179425Sdfr /* 1263180025Sdfr * We can't hold onto RPC handles for too long - the async 1264179425Sdfr * call/reply protocol used by some NLM clients makes it hard 1265179425Sdfr * to tell when they change port numbers (e.g. after a 1266179425Sdfr * reboot). Note that if a client reboots while it isn't 1267179425Sdfr * holding any locks, it won't bother to notify us. We 1268179425Sdfr * expire the RPC handles after two minutes. 1269179425Sdfr */ 1270184588Sdfr if (rpc->nr_client && time_uptime > rpc->nr_create_time + 2*60) { 1271184588Sdfr client = rpc->nr_client; 1272184588Sdfr rpc->nr_client = NULL; 1273180025Sdfr mtx_unlock(&host->nh_lock); 1274180025Sdfr CLNT_RELEASE(client); 1275180025Sdfr mtx_lock(&host->nh_lock); 1276179425Sdfr } 1277179425Sdfr 1278184588Sdfr if (!rpc->nr_client) { 1279180025Sdfr mtx_unlock(&host->nh_lock); 1280180025Sdfr client = nlm_get_rpc((struct sockaddr *)&host->nh_addr, 1281180025Sdfr NLM_PROG, host->nh_vers); 1282180025Sdfr mtx_lock(&host->nh_lock); 1283177633Sdfr 1284180025Sdfr if (client) { 1285184588Sdfr if (rpc->nr_client) { 1286180025Sdfr mtx_unlock(&host->nh_lock); 1287180025Sdfr CLNT_DESTROY(client); 1288180025Sdfr mtx_lock(&host->nh_lock); 1289180025Sdfr } else { 1290184588Sdfr rpc->nr_client = client; 1291184588Sdfr rpc->nr_create_time = time_uptime; 1292180025Sdfr } 1293180025Sdfr } 1294180025Sdfr } 1295180025Sdfr 1296184588Sdfr client = rpc->nr_client; 1297180025Sdfr if (client) 1298180025Sdfr CLNT_ACQUIRE(client); 1299180025Sdfr mtx_unlock(&host->nh_lock); 1300180025Sdfr 1301180025Sdfr return (client); 1302180025Sdfr 1303180025Sdfr} 1304180025Sdfr 1305180025Sdfrint nlm_host_get_sysid(struct nlm_host *host) 1306180025Sdfr{ 1307180025Sdfr 1308180025Sdfr return (host->nh_sysid); 1309180025Sdfr} 1310180025Sdfr 1311180025Sdfrint 1312180025Sdfrnlm_host_get_state(struct nlm_host *host) 1313180025Sdfr{ 1314180025Sdfr 1315180025Sdfr return (host->nh_state); 1316180025Sdfr} 1317180025Sdfr 1318180025Sdfrvoid * 1319180025Sdfrnlm_register_wait_lock(struct nlm4_lock *lock, struct vnode *vp) 1320180025Sdfr{ 1321180025Sdfr struct nlm_waiting_lock *nw; 1322180025Sdfr 1323180025Sdfr nw = malloc(sizeof(struct nlm_waiting_lock), M_NLM, M_WAITOK); 1324180025Sdfr nw->nw_lock = *lock; 1325180025Sdfr memcpy(&nw->nw_fh.fh_bytes, nw->nw_lock.fh.n_bytes, 1326180025Sdfr nw->nw_lock.fh.n_len); 1327180025Sdfr nw->nw_lock.fh.n_bytes = nw->nw_fh.fh_bytes; 1328180025Sdfr nw->nw_waiting = TRUE; 1329180025Sdfr nw->nw_vp = vp; 1330180025Sdfr mtx_lock(&nlm_global_lock); 1331180025Sdfr TAILQ_INSERT_TAIL(&nlm_waiting_locks, nw, nw_link); 1332180025Sdfr mtx_unlock(&nlm_global_lock); 1333180025Sdfr 1334180025Sdfr return nw; 1335180025Sdfr} 1336180025Sdfr 1337180025Sdfrvoid 1338180025Sdfrnlm_deregister_wait_lock(void *handle) 1339180025Sdfr{ 1340180025Sdfr struct nlm_waiting_lock *nw = handle; 1341180025Sdfr 1342180025Sdfr mtx_lock(&nlm_global_lock); 1343180025Sdfr TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link); 1344180025Sdfr mtx_unlock(&nlm_global_lock); 1345180025Sdfr 1346180025Sdfr free(nw, M_NLM); 1347180025Sdfr} 1348180025Sdfr 1349180025Sdfrint 1350180025Sdfrnlm_wait_lock(void *handle, int timo) 1351180025Sdfr{ 1352180025Sdfr struct nlm_waiting_lock *nw = handle; 1353180025Sdfr int error; 1354180025Sdfr 1355177633Sdfr /* 1356180025Sdfr * If the granted message arrived before we got here, 1357180025Sdfr * nw->nw_waiting will be FALSE - in that case, don't sleep. 1358177633Sdfr */ 1359180025Sdfr mtx_lock(&nlm_global_lock); 1360180025Sdfr error = 0; 1361180025Sdfr if (nw->nw_waiting) 1362180025Sdfr error = msleep(nw, &nlm_global_lock, PCATCH, "nlmlock", timo); 1363180025Sdfr TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link); 1364180025Sdfr if (error) { 1365180025Sdfr /* 1366180025Sdfr * The granted message may arrive after the 1367180025Sdfr * interrupt/timeout but before we manage to lock the 1368180025Sdfr * mutex. Detect this by examining nw_lock. 1369180025Sdfr */ 1370180025Sdfr if (!nw->nw_waiting) 1371180025Sdfr error = 0; 1372180025Sdfr } else { 1373180025Sdfr /* 1374180025Sdfr * If nlm_cancel_wait is called, then error will be 1375180025Sdfr * zero but nw_waiting will still be TRUE. We 1376180025Sdfr * translate this into EINTR. 1377180025Sdfr */ 1378180025Sdfr if (nw->nw_waiting) 1379180025Sdfr error = EINTR; 1380180025Sdfr } 1381180025Sdfr mtx_unlock(&nlm_global_lock); 1382177633Sdfr 1383180025Sdfr free(nw, M_NLM); 1384177633Sdfr 1385180025Sdfr return (error); 1386180025Sdfr} 1387180025Sdfr 1388180025Sdfrvoid 1389180025Sdfrnlm_cancel_wait(struct vnode *vp) 1390180025Sdfr{ 1391180025Sdfr struct nlm_waiting_lock *nw; 1392180025Sdfr 1393180025Sdfr mtx_lock(&nlm_global_lock); 1394180025Sdfr TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) { 1395180025Sdfr if (nw->nw_vp == vp) { 1396180025Sdfr wakeup(nw); 1397180025Sdfr } 1398177633Sdfr } 1399180025Sdfr mtx_unlock(&nlm_global_lock); 1400177633Sdfr} 1401177633Sdfr 1402180025Sdfr 1403177633Sdfr/**********************************************************************/ 1404177633Sdfr 1405177633Sdfr/* 1406177633Sdfr * Syscall interface with userland. 1407177633Sdfr */ 1408177633Sdfr 1409177633Sdfrextern void nlm_prog_0(struct svc_req *rqstp, SVCXPRT *transp); 1410177633Sdfrextern void nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp); 1411177633Sdfrextern void nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp); 1412177633Sdfrextern void nlm_prog_4(struct svc_req *rqstp, SVCXPRT *transp); 1413177633Sdfr 1414177633Sdfrstatic int 1415177633Sdfrnlm_register_services(SVCPOOL *pool, int addr_count, char **addrs) 1416177633Sdfr{ 1417177633Sdfr static rpcvers_t versions[] = { 1418177633Sdfr NLM_SM, NLM_VERS, NLM_VERSX, NLM_VERS4 1419177633Sdfr }; 1420177633Sdfr static void (*dispatchers[])(struct svc_req *, SVCXPRT *) = { 1421177633Sdfr nlm_prog_0, nlm_prog_1, nlm_prog_3, nlm_prog_4 1422177633Sdfr }; 1423177633Sdfr static const int version_count = sizeof(versions) / sizeof(versions[0]); 1424177633Sdfr 1425177633Sdfr SVCXPRT **xprts; 1426177633Sdfr char netid[16]; 1427177633Sdfr char uaddr[128]; 1428177633Sdfr struct netconfig *nconf; 1429177633Sdfr int i, j, error; 1430177633Sdfr 1431177633Sdfr if (!addr_count) { 1432191918Sdfr NLM_ERR("NLM: no service addresses given - can't start server"); 1433177633Sdfr return (EINVAL); 1434177633Sdfr } 1435177633Sdfr 1436194407Srmacklem xprts = malloc(addr_count * sizeof(SVCXPRT *), M_NLM, M_WAITOK|M_ZERO); 1437177633Sdfr for (i = 0; i < version_count; i++) { 1438177633Sdfr for (j = 0; j < addr_count; j++) { 1439177633Sdfr /* 1440177633Sdfr * Create transports for the first version and 1441177633Sdfr * then just register everything else to the 1442177633Sdfr * same transports. 1443177633Sdfr */ 1444177633Sdfr if (i == 0) { 1445177633Sdfr char *up; 1446177633Sdfr 1447177633Sdfr error = copyin(&addrs[2*j], &up, 1448177633Sdfr sizeof(char*)); 1449177633Sdfr if (error) 1450177633Sdfr goto out; 1451177633Sdfr error = copyinstr(up, netid, sizeof(netid), 1452177633Sdfr NULL); 1453177633Sdfr if (error) 1454177633Sdfr goto out; 1455177633Sdfr error = copyin(&addrs[2*j+1], &up, 1456177633Sdfr sizeof(char*)); 1457177633Sdfr if (error) 1458177633Sdfr goto out; 1459177633Sdfr error = copyinstr(up, uaddr, sizeof(uaddr), 1460177633Sdfr NULL); 1461177633Sdfr if (error) 1462177633Sdfr goto out; 1463177633Sdfr nconf = getnetconfigent(netid); 1464177633Sdfr if (!nconf) { 1465191918Sdfr NLM_ERR("Can't lookup netid %s\n", 1466177633Sdfr netid); 1467177633Sdfr error = EINVAL; 1468177633Sdfr goto out; 1469177633Sdfr } 1470177633Sdfr xprts[j] = svc_tp_create(pool, dispatchers[i], 1471177633Sdfr NLM_PROG, versions[i], uaddr, nconf); 1472177633Sdfr if (!xprts[j]) { 1473191918Sdfr NLM_ERR("NLM: unable to create " 1474177633Sdfr "(NLM_PROG, %d).\n", versions[i]); 1475177633Sdfr error = EINVAL; 1476177633Sdfr goto out; 1477177633Sdfr } 1478177633Sdfr freenetconfigent(nconf); 1479177633Sdfr } else { 1480177633Sdfr nconf = getnetconfigent(xprts[j]->xp_netid); 1481177633Sdfr rpcb_unset(NLM_PROG, versions[i], nconf); 1482177633Sdfr if (!svc_reg(xprts[j], NLM_PROG, versions[i], 1483177633Sdfr dispatchers[i], nconf)) { 1484191918Sdfr NLM_ERR("NLM: can't register " 1485177633Sdfr "(NLM_PROG, %d)\n", versions[i]); 1486177633Sdfr error = EINVAL; 1487177633Sdfr goto out; 1488177633Sdfr } 1489177633Sdfr } 1490177633Sdfr } 1491177633Sdfr } 1492177633Sdfr error = 0; 1493177633Sdfrout: 1494194407Srmacklem for (j = 0; j < addr_count; j++) { 1495194407Srmacklem if (xprts[j]) 1496194407Srmacklem SVC_RELEASE(xprts[j]); 1497194407Srmacklem } 1498177633Sdfr free(xprts, M_NLM); 1499177633Sdfr return (error); 1500177633Sdfr} 1501177633Sdfr 1502177633Sdfr/* 1503177633Sdfr * Main server entry point. Contacts the local NSM to get its current 1504177633Sdfr * state and send SM_UNMON_ALL. Registers the NLM services and then 1505177633Sdfr * services requests. Does not return until the server is interrupted 1506177633Sdfr * by a signal. 1507177633Sdfr */ 1508177633Sdfrstatic int 1509177633Sdfrnlm_server_main(int addr_count, char **addrs) 1510177633Sdfr{ 1511177633Sdfr struct thread *td = curthread; 1512177633Sdfr int error; 1513178033Sdfr SVCPOOL *pool = NULL; 1514177633Sdfr struct sockopt opt; 1515177633Sdfr int portlow; 1516177633Sdfr#ifdef INET6 1517177633Sdfr struct sockaddr_in6 sin6; 1518177633Sdfr#endif 1519177633Sdfr struct sockaddr_in sin; 1520177633Sdfr my_id id; 1521177633Sdfr sm_stat smstat; 1522177633Sdfr struct timeval timo; 1523177633Sdfr enum clnt_stat stat; 1524180025Sdfr struct nlm_host *host, *nhost; 1525180025Sdfr struct nlm_waiting_lock *nw; 1526180025Sdfr vop_advlock_t *old_nfs_advlock; 1527180025Sdfr vop_reclaim_t *old_nfs_reclaim; 1528180069Savatar int v4_used; 1529180069Savatar#ifdef INET6 1530180069Savatar int v6_used; 1531180069Savatar#endif 1532177633Sdfr 1533177633Sdfr if (nlm_socket) { 1534191918Sdfr NLM_ERR("NLM: can't start server - " 1535191918Sdfr "it appears to be running already\n"); 1536177633Sdfr return (EPERM); 1537177633Sdfr } 1538177633Sdfr 1539177633Sdfr memset(&opt, 0, sizeof(opt)); 1540177633Sdfr 1541177633Sdfr nlm_socket = NULL; 1542177633Sdfr error = socreate(AF_INET, &nlm_socket, SOCK_DGRAM, 0, 1543177633Sdfr td->td_ucred, td); 1544177633Sdfr if (error) { 1545191918Sdfr NLM_ERR("NLM: can't create IPv4 socket - error %d\n", error); 1546177633Sdfr return (error); 1547177633Sdfr } 1548177633Sdfr opt.sopt_dir = SOPT_SET; 1549177633Sdfr opt.sopt_level = IPPROTO_IP; 1550177633Sdfr opt.sopt_name = IP_PORTRANGE; 1551177633Sdfr portlow = IP_PORTRANGE_LOW; 1552177633Sdfr opt.sopt_val = &portlow; 1553177633Sdfr opt.sopt_valsize = sizeof(portlow); 1554177633Sdfr sosetopt(nlm_socket, &opt); 1555177633Sdfr 1556177633Sdfr#ifdef INET6 1557177633Sdfr nlm_socket6 = NULL; 1558177633Sdfr error = socreate(AF_INET6, &nlm_socket6, SOCK_DGRAM, 0, 1559177633Sdfr td->td_ucred, td); 1560177633Sdfr if (error) { 1561191918Sdfr NLM_ERR("NLM: can't create IPv6 socket - error %d\n", error); 1562180025Sdfr goto out; 1563177633Sdfr return (error); 1564177633Sdfr } 1565177633Sdfr opt.sopt_dir = SOPT_SET; 1566177633Sdfr opt.sopt_level = IPPROTO_IPV6; 1567177633Sdfr opt.sopt_name = IPV6_PORTRANGE; 1568177633Sdfr portlow = IPV6_PORTRANGE_LOW; 1569177633Sdfr opt.sopt_val = &portlow; 1570177633Sdfr opt.sopt_valsize = sizeof(portlow); 1571177633Sdfr sosetopt(nlm_socket6, &opt); 1572177633Sdfr#endif 1573177633Sdfr 1574180025Sdfr nlm_auth = authunix_create(curthread->td_ucred); 1575180025Sdfr 1576177633Sdfr#ifdef INET6 1577177633Sdfr memset(&sin6, 0, sizeof(sin6)); 1578177633Sdfr sin6.sin6_len = sizeof(sin6); 1579177633Sdfr sin6.sin6_family = AF_INET6; 1580177633Sdfr sin6.sin6_addr = in6addr_loopback; 1581177633Sdfr nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin6, SM_PROG, SM_VERS); 1582177633Sdfr if (!nlm_nsm) { 1583177633Sdfr#endif 1584177633Sdfr memset(&sin, 0, sizeof(sin)); 1585177633Sdfr sin.sin_len = sizeof(sin); 1586178033Sdfr sin.sin_family = AF_INET; 1587177633Sdfr sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 1588177633Sdfr nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin, SM_PROG, 1589177633Sdfr SM_VERS); 1590177633Sdfr#ifdef INET6 1591177633Sdfr } 1592177633Sdfr#endif 1593177633Sdfr 1594177633Sdfr if (!nlm_nsm) { 1595191918Sdfr NLM_ERR("Can't start NLM - unable to contact NSM\n"); 1596178033Sdfr error = EINVAL; 1597178033Sdfr goto out; 1598177633Sdfr } 1599177633Sdfr 1600184588Sdfr pool = svcpool_create("NLM", NULL); 1601177633Sdfr 1602177633Sdfr error = nlm_register_services(pool, addr_count, addrs); 1603177633Sdfr if (error) 1604177633Sdfr goto out; 1605177633Sdfr 1606177633Sdfr memset(&id, 0, sizeof(id)); 1607177633Sdfr id.my_name = "NFS NLM"; 1608177633Sdfr 1609177633Sdfr timo.tv_sec = 25; 1610177633Sdfr timo.tv_usec = 0; 1611177633Sdfr stat = CLNT_CALL(nlm_nsm, SM_UNMON_ALL, 1612177633Sdfr (xdrproc_t) xdr_my_id, &id, 1613177633Sdfr (xdrproc_t) xdr_sm_stat, &smstat, timo); 1614177633Sdfr 1615177633Sdfr if (stat != RPC_SUCCESS) { 1616177633Sdfr struct rpc_err err; 1617177633Sdfr 1618177633Sdfr CLNT_GETERR(nlm_nsm, &err); 1619191918Sdfr NLM_ERR("NLM: unexpected error contacting NSM, " 1620191918Sdfr "stat=%d, errno=%d\n", stat, err.re_errno); 1621177633Sdfr error = EINVAL; 1622177633Sdfr goto out; 1623177633Sdfr } 1624177633Sdfr 1625191918Sdfr NLM_DEBUG(1, "NLM: local NSM state is %d\n", smstat.state); 1626180025Sdfr nlm_nsm_state = smstat.state; 1627177633Sdfr 1628180025Sdfr old_nfs_advlock = nfs_advlock_p; 1629180025Sdfr nfs_advlock_p = nlm_advlock; 1630180025Sdfr old_nfs_reclaim = nfs_reclaim_p; 1631180025Sdfr nfs_reclaim_p = nlm_reclaim; 1632180025Sdfr 1633177633Sdfr svc_run(pool); 1634177633Sdfr error = 0; 1635177633Sdfr 1636180025Sdfr nfs_advlock_p = old_nfs_advlock; 1637180025Sdfr nfs_reclaim_p = old_nfs_reclaim; 1638180025Sdfr 1639177633Sdfrout: 1640177633Sdfr if (pool) 1641177633Sdfr svcpool_destroy(pool); 1642177633Sdfr 1643177633Sdfr /* 1644180025Sdfr * We are finished communicating with the NSM. 1645177633Sdfr */ 1646177633Sdfr if (nlm_nsm) { 1647180025Sdfr CLNT_RELEASE(nlm_nsm); 1648177633Sdfr nlm_nsm = NULL; 1649177633Sdfr } 1650180025Sdfr 1651180025Sdfr /* 1652180025Sdfr * Trash all the existing state so that if the server 1653180025Sdfr * restarts, it gets a clean slate. This is complicated by the 1654180025Sdfr * possibility that there may be other threads trying to make 1655180025Sdfr * client locking requests. 1656180025Sdfr * 1657180025Sdfr * First we fake a client reboot notification which will 1658180025Sdfr * cancel any pending async locks and purge remote lock state 1659180025Sdfr * from the local lock manager. We release the reference from 1660180025Sdfr * nlm_hosts to the host (which may remove it from the list 1661180025Sdfr * and free it). After this phase, the only entries in the 1662180025Sdfr * nlm_host list should be from other threads performing 1663180025Sdfr * client lock requests. We arrange to defer closing the 1664180025Sdfr * sockets until the last RPC client handle is released. 1665180025Sdfr */ 1666180025Sdfr v4_used = 0; 1667180025Sdfr#ifdef INET6 1668180025Sdfr v6_used = 0; 1669180025Sdfr#endif 1670180025Sdfr mtx_lock(&nlm_global_lock); 1671180025Sdfr TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) { 1672180025Sdfr wakeup(nw); 1673177633Sdfr } 1674180025Sdfr TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, nhost) { 1675180025Sdfr mtx_unlock(&nlm_global_lock); 1676180025Sdfr nlm_host_notify(host, 0); 1677180025Sdfr nlm_host_release(host); 1678180025Sdfr mtx_lock(&nlm_global_lock); 1679180025Sdfr } 1680180025Sdfr TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, nhost) { 1681180025Sdfr mtx_lock(&host->nh_lock); 1682184588Sdfr if (host->nh_srvrpc.nr_client 1683184588Sdfr || host->nh_clntrpc.nr_client) { 1684180025Sdfr if (host->nh_addr.ss_family == AF_INET) 1685180025Sdfr v4_used++; 1686180025Sdfr#ifdef INET6 1687180025Sdfr if (host->nh_addr.ss_family == AF_INET6) 1688180025Sdfr v6_used++; 1689180025Sdfr#endif 1690180025Sdfr /* 1691180025Sdfr * Note that the rpc over udp code copes 1692180025Sdfr * correctly with the fact that a socket may 1693180025Sdfr * be used by many rpc handles. 1694180025Sdfr */ 1695184588Sdfr if (host->nh_srvrpc.nr_client) 1696184588Sdfr CLNT_CONTROL(host->nh_srvrpc.nr_client, 1697184588Sdfr CLSET_FD_CLOSE, 0); 1698184588Sdfr if (host->nh_clntrpc.nr_client) 1699184588Sdfr CLNT_CONTROL(host->nh_clntrpc.nr_client, 1700184588Sdfr CLSET_FD_CLOSE, 0); 1701180025Sdfr } 1702180025Sdfr mtx_unlock(&host->nh_lock); 1703180025Sdfr } 1704180025Sdfr mtx_unlock(&nlm_global_lock); 1705177633Sdfr 1706180025Sdfr AUTH_DESTROY(nlm_auth); 1707180025Sdfr 1708180025Sdfr if (!v4_used) 1709180025Sdfr soclose(nlm_socket); 1710177633Sdfr nlm_socket = NULL; 1711177633Sdfr#ifdef INET6 1712180025Sdfr if (!v6_used) 1713180025Sdfr soclose(nlm_socket6); 1714177633Sdfr nlm_socket6 = NULL; 1715177633Sdfr#endif 1716177633Sdfr 1717177633Sdfr return (error); 1718177633Sdfr} 1719177633Sdfr 1720177633Sdfrint 1721225617Skmacysys_nlm_syscall(struct thread *td, struct nlm_syscall_args *uap) 1722177633Sdfr{ 1723177633Sdfr int error; 1724177633Sdfr 1725177685Sdfr#if __FreeBSD_version >= 700000 1726177633Sdfr error = priv_check(td, PRIV_NFS_LOCKD); 1727177685Sdfr#else 1728177685Sdfr error = suser(td); 1729177685Sdfr#endif 1730177633Sdfr if (error) 1731177633Sdfr return (error); 1732177633Sdfr 1733177633Sdfr nlm_debug_level = uap->debug_level; 1734177633Sdfr nlm_grace_threshold = time_uptime + uap->grace_period; 1735177633Sdfr nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD; 1736177633Sdfr 1737177633Sdfr return nlm_server_main(uap->addr_count, uap->addrs); 1738177633Sdfr} 1739177633Sdfr 1740177633Sdfr/**********************************************************************/ 1741177633Sdfr 1742177633Sdfr/* 1743177633Sdfr * NLM implementation details, called from the RPC stubs. 1744177633Sdfr */ 1745177633Sdfr 1746177633Sdfr 1747177633Sdfrvoid 1748177633Sdfrnlm_sm_notify(struct nlm_sm_status *argp) 1749177633Sdfr{ 1750177633Sdfr uint32_t sysid; 1751177633Sdfr struct nlm_host *host; 1752177633Sdfr 1753191918Sdfr NLM_DEBUG(3, "nlm_sm_notify(): mon_name = %s\n", argp->mon_name); 1754177633Sdfr memcpy(&sysid, &argp->priv, sizeof(sysid)); 1755177633Sdfr host = nlm_find_host_by_sysid(sysid); 1756180025Sdfr if (host) { 1757180025Sdfr nlm_host_notify(host, argp->state); 1758180025Sdfr nlm_host_release(host); 1759180025Sdfr } 1760177633Sdfr} 1761177633Sdfr 1762177633Sdfrstatic void 1763177633Sdfrnlm_convert_to_fhandle_t(fhandle_t *fhp, struct netobj *p) 1764177633Sdfr{ 1765177633Sdfr memcpy(fhp, p->n_bytes, sizeof(fhandle_t)); 1766177633Sdfr} 1767177633Sdfr 1768177633Sdfrstruct vfs_state { 1769177633Sdfr struct mount *vs_mp; 1770177633Sdfr struct vnode *vs_vp; 1771177633Sdfr int vs_vfslocked; 1772178112Sdfr int vs_vnlocked; 1773177633Sdfr}; 1774177633Sdfr 1775177633Sdfrstatic int 1776177633Sdfrnlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp, 1777177633Sdfr fhandle_t *fhp, struct vfs_state *vs) 1778177633Sdfr{ 1779184588Sdfr int error, exflags; 1780177633Sdfr struct ucred *cred = NULL, *credanon; 1781177633Sdfr 1782177633Sdfr memset(vs, 0, sizeof(*vs)); 1783177633Sdfr 1784177633Sdfr vs->vs_mp = vfs_getvfs(&fhp->fh_fsid); 1785177633Sdfr if (!vs->vs_mp) { 1786177633Sdfr return (ESTALE); 1787177633Sdfr } 1788177633Sdfr vs->vs_vfslocked = VFS_LOCK_GIANT(vs->vs_mp); 1789177633Sdfr 1790177633Sdfr error = VFS_CHECKEXP(vs->vs_mp, (struct sockaddr *)&host->nh_addr, 1791184588Sdfr &exflags, &credanon, NULL, NULL); 1792177633Sdfr if (error) 1793177633Sdfr goto out; 1794177633Sdfr 1795177633Sdfr if (exflags & MNT_EXRDONLY || (vs->vs_mp->mnt_flag & MNT_RDONLY)) { 1796177633Sdfr error = EROFS; 1797177633Sdfr goto out; 1798177633Sdfr } 1799177633Sdfr 1800222167Srmacklem error = VFS_FHTOVP(vs->vs_mp, &fhp->fh_fid, LK_EXCLUSIVE, &vs->vs_vp); 1801177633Sdfr if (error) 1802177633Sdfr goto out; 1803178112Sdfr vs->vs_vnlocked = TRUE; 1804177633Sdfr 1805184588Sdfr if (!svc_getcred(rqstp, &cred, NULL)) { 1806177633Sdfr error = EINVAL; 1807177633Sdfr goto out; 1808177633Sdfr } 1809177633Sdfr if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1810177633Sdfr crfree(cred); 1811191940Skan cred = credanon; 1812191940Skan credanon = NULL; 1813177633Sdfr } 1814177633Sdfr 1815177633Sdfr /* 1816177633Sdfr * Check cred. 1817177633Sdfr */ 1818177633Sdfr error = VOP_ACCESS(vs->vs_vp, VWRITE, cred, curthread); 1819177633Sdfr if (error) 1820177633Sdfr goto out; 1821177633Sdfr 1822178112Sdfr#if __FreeBSD_version < 800011 1823178112Sdfr VOP_UNLOCK(vs->vs_vp, 0, curthread); 1824178112Sdfr#else 1825178112Sdfr VOP_UNLOCK(vs->vs_vp, 0); 1826178112Sdfr#endif 1827178112Sdfr vs->vs_vnlocked = FALSE; 1828178112Sdfr 1829177633Sdfrout: 1830184588Sdfr if (cred) 1831177633Sdfr crfree(cred); 1832191940Skan if (credanon) 1833191940Skan crfree(credanon); 1834177633Sdfr 1835177633Sdfr return (error); 1836177633Sdfr} 1837177633Sdfr 1838177633Sdfrstatic void 1839177633Sdfrnlm_release_vfs_state(struct vfs_state *vs) 1840177633Sdfr{ 1841177633Sdfr 1842178112Sdfr if (vs->vs_vp) { 1843178112Sdfr if (vs->vs_vnlocked) 1844178112Sdfr vput(vs->vs_vp); 1845178112Sdfr else 1846178112Sdfr vrele(vs->vs_vp); 1847178112Sdfr } 1848177633Sdfr if (vs->vs_mp) 1849177633Sdfr vfs_rel(vs->vs_mp); 1850177633Sdfr VFS_UNLOCK_GIANT(vs->vs_vfslocked); 1851177633Sdfr} 1852177633Sdfr 1853177633Sdfrstatic nlm4_stats 1854177633Sdfrnlm_convert_error(int error) 1855177633Sdfr{ 1856177633Sdfr 1857177633Sdfr if (error == ESTALE) 1858177633Sdfr return nlm4_stale_fh; 1859177633Sdfr else if (error == EROFS) 1860177633Sdfr return nlm4_rofs; 1861177633Sdfr else 1862177633Sdfr return nlm4_failed; 1863177633Sdfr} 1864177633Sdfr 1865180025Sdfrint 1866180025Sdfrnlm_do_test(nlm4_testargs *argp, nlm4_testres *result, struct svc_req *rqstp, 1867180025Sdfr CLIENT **rpcp) 1868177633Sdfr{ 1869177633Sdfr fhandle_t fh; 1870177633Sdfr struct vfs_state vs; 1871177633Sdfr struct nlm_host *host, *bhost; 1872177633Sdfr int error, sysid; 1873177633Sdfr struct flock fl; 1874177633Sdfr 1875177633Sdfr memset(result, 0, sizeof(*result)); 1876180025Sdfr memset(&vs, 0, sizeof(vs)); 1877177633Sdfr 1878180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 1879184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 1880177633Sdfr if (!host) { 1881177633Sdfr result->stat.stat = nlm4_denied_nolocks; 1882180025Sdfr return (ENOMEM); 1883177633Sdfr } 1884177633Sdfr 1885191918Sdfr NLM_DEBUG(3, "nlm_do_test(): caller_name = %s (sysid = %d)\n", 1886191918Sdfr host->nh_caller_name, host->nh_sysid); 1887177633Sdfr 1888197840Szml nlm_check_expired_locks(host); 1889177633Sdfr sysid = host->nh_sysid; 1890177633Sdfr 1891177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1892177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1893177633Sdfr 1894177633Sdfr if (time_uptime < nlm_grace_threshold) { 1895177633Sdfr result->stat.stat = nlm4_denied_grace_period; 1896180025Sdfr goto out; 1897177633Sdfr } 1898177633Sdfr 1899177633Sdfr error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 1900177633Sdfr if (error) { 1901177633Sdfr result->stat.stat = nlm_convert_error(error); 1902177633Sdfr goto out; 1903177633Sdfr } 1904177633Sdfr 1905177633Sdfr fl.l_start = argp->alock.l_offset; 1906177633Sdfr fl.l_len = argp->alock.l_len; 1907177633Sdfr fl.l_pid = argp->alock.svid; 1908177633Sdfr fl.l_sysid = sysid; 1909177633Sdfr fl.l_whence = SEEK_SET; 1910177633Sdfr if (argp->exclusive) 1911177633Sdfr fl.l_type = F_WRLCK; 1912177633Sdfr else 1913177633Sdfr fl.l_type = F_RDLCK; 1914177633Sdfr error = VOP_ADVLOCK(vs.vs_vp, NULL, F_GETLK, &fl, F_REMOTE); 1915177633Sdfr if (error) { 1916177633Sdfr result->stat.stat = nlm4_failed; 1917177633Sdfr goto out; 1918177633Sdfr } 1919177633Sdfr 1920177633Sdfr if (fl.l_type == F_UNLCK) { 1921177633Sdfr result->stat.stat = nlm4_granted; 1922177633Sdfr } else { 1923177633Sdfr result->stat.stat = nlm4_denied; 1924177633Sdfr result->stat.nlm4_testrply_u.holder.exclusive = 1925177633Sdfr (fl.l_type == F_WRLCK); 1926177633Sdfr result->stat.nlm4_testrply_u.holder.svid = fl.l_pid; 1927177633Sdfr bhost = nlm_find_host_by_sysid(fl.l_sysid); 1928177633Sdfr if (bhost) { 1929177633Sdfr /* 1930177633Sdfr * We don't have any useful way of recording 1931177633Sdfr * the value of oh used in the original lock 1932177633Sdfr * request. Ideally, the test reply would have 1933177633Sdfr * a space for the owning host's name allowing 1934177633Sdfr * our caller's NLM to keep track. 1935177633Sdfr * 1936177633Sdfr * As far as I can see, Solaris uses an eight 1937177633Sdfr * byte structure for oh which contains a four 1938177633Sdfr * byte pid encoded in local byte order and 1939177633Sdfr * the first four bytes of the host 1940177633Sdfr * name. Linux uses a variable length string 1941177633Sdfr * 'pid@hostname' in ascii but doesn't even 1942177633Sdfr * return that in test replies. 1943177633Sdfr * 1944177633Sdfr * For the moment, return nothing in oh 1945177633Sdfr * (already zero'ed above). 1946177633Sdfr */ 1947180025Sdfr nlm_host_release(bhost); 1948177633Sdfr } 1949177633Sdfr result->stat.nlm4_testrply_u.holder.l_offset = fl.l_start; 1950177633Sdfr result->stat.nlm4_testrply_u.holder.l_len = fl.l_len; 1951177633Sdfr } 1952177633Sdfr 1953177633Sdfrout: 1954177633Sdfr nlm_release_vfs_state(&vs); 1955180025Sdfr if (rpcp) 1956184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 1957180025Sdfr nlm_host_release(host); 1958180025Sdfr return (0); 1959177633Sdfr} 1960177633Sdfr 1961180025Sdfrint 1962177633Sdfrnlm_do_lock(nlm4_lockargs *argp, nlm4_res *result, struct svc_req *rqstp, 1963180025Sdfr bool_t monitor, CLIENT **rpcp) 1964177633Sdfr{ 1965177633Sdfr fhandle_t fh; 1966177633Sdfr struct vfs_state vs; 1967177633Sdfr struct nlm_host *host; 1968177633Sdfr int error, sysid; 1969177633Sdfr struct flock fl; 1970177633Sdfr 1971177633Sdfr memset(result, 0, sizeof(*result)); 1972180025Sdfr memset(&vs, 0, sizeof(vs)); 1973177633Sdfr 1974180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 1975184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 1976177633Sdfr if (!host) { 1977177633Sdfr result->stat.stat = nlm4_denied_nolocks; 1978180025Sdfr return (ENOMEM); 1979177633Sdfr } 1980177633Sdfr 1981191918Sdfr NLM_DEBUG(3, "nlm_do_lock(): caller_name = %s (sysid = %d)\n", 1982191918Sdfr host->nh_caller_name, host->nh_sysid); 1983177633Sdfr 1984179488Sdfr if (monitor && host->nh_state && argp->state 1985179488Sdfr && host->nh_state != argp->state) { 1986179488Sdfr /* 1987179488Sdfr * The host rebooted without telling us. Trash its 1988179488Sdfr * locks. 1989179488Sdfr */ 1990180025Sdfr nlm_host_notify(host, argp->state); 1991179488Sdfr } 1992179488Sdfr 1993197840Szml nlm_check_expired_locks(host); 1994177633Sdfr sysid = host->nh_sysid; 1995177633Sdfr 1996177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1997177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1998177633Sdfr 1999177633Sdfr if (time_uptime < nlm_grace_threshold && !argp->reclaim) { 2000177633Sdfr result->stat.stat = nlm4_denied_grace_period; 2001180025Sdfr goto out; 2002177633Sdfr } 2003177633Sdfr 2004177633Sdfr error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 2005177633Sdfr if (error) { 2006177633Sdfr result->stat.stat = nlm_convert_error(error); 2007177633Sdfr goto out; 2008177633Sdfr } 2009177633Sdfr 2010177633Sdfr fl.l_start = argp->alock.l_offset; 2011177633Sdfr fl.l_len = argp->alock.l_len; 2012177633Sdfr fl.l_pid = argp->alock.svid; 2013177633Sdfr fl.l_sysid = sysid; 2014177633Sdfr fl.l_whence = SEEK_SET; 2015177633Sdfr if (argp->exclusive) 2016177633Sdfr fl.l_type = F_WRLCK; 2017177633Sdfr else 2018177633Sdfr fl.l_type = F_RDLCK; 2019177633Sdfr if (argp->block) { 2020177633Sdfr struct nlm_async_lock *af; 2021180025Sdfr CLIENT *client; 2022197840Szml struct nlm_grantcookie cookie; 2023177633Sdfr 2024177633Sdfr /* 2025177633Sdfr * First, make sure we can contact the host's NLM. 2026177633Sdfr */ 2027184588Sdfr client = nlm_host_get_rpc(host, TRUE); 2028180025Sdfr if (!client) { 2029177633Sdfr result->stat.stat = nlm4_failed; 2030177633Sdfr goto out; 2031177633Sdfr } 2032177633Sdfr 2033177633Sdfr /* 2034177633Sdfr * First we need to check and see if there is an 2035177633Sdfr * existing blocked lock that matches. This could be a 2036177633Sdfr * badly behaved client or an RPC re-send. If we find 2037177633Sdfr * one, just return nlm4_blocked. 2038177633Sdfr */ 2039177633Sdfr mtx_lock(&host->nh_lock); 2040177633Sdfr TAILQ_FOREACH(af, &host->nh_pending, af_link) { 2041177633Sdfr if (af->af_fl.l_start == fl.l_start 2042177633Sdfr && af->af_fl.l_len == fl.l_len 2043177633Sdfr && af->af_fl.l_pid == fl.l_pid 2044177633Sdfr && af->af_fl.l_type == fl.l_type) { 2045177633Sdfr break; 2046177633Sdfr } 2047177633Sdfr } 2048197840Szml if (!af) { 2049197840Szml cookie.ng_sysid = host->nh_sysid; 2050197840Szml cookie.ng_cookie = host->nh_grantcookie++; 2051197840Szml } 2052177633Sdfr mtx_unlock(&host->nh_lock); 2053177633Sdfr if (af) { 2054180025Sdfr CLNT_RELEASE(client); 2055177633Sdfr result->stat.stat = nlm4_blocked; 2056177633Sdfr goto out; 2057177633Sdfr } 2058177633Sdfr 2059177633Sdfr af = malloc(sizeof(struct nlm_async_lock), M_NLM, 2060177633Sdfr M_WAITOK|M_ZERO); 2061177633Sdfr TASK_INIT(&af->af_task, 0, nlm_lock_callback, af); 2062177633Sdfr af->af_vp = vs.vs_vp; 2063177633Sdfr af->af_fl = fl; 2064177633Sdfr af->af_host = host; 2065180025Sdfr af->af_rpc = client; 2066177633Sdfr /* 2067177633Sdfr * We use M_RPC here so that we can xdr_free the thing 2068177633Sdfr * later. 2069177633Sdfr */ 2070197840Szml nlm_make_netobj(&af->af_granted.cookie, 2071197840Szml (caddr_t)&cookie, sizeof(cookie), M_RPC); 2072177633Sdfr af->af_granted.exclusive = argp->exclusive; 2073177633Sdfr af->af_granted.alock.caller_name = 2074177633Sdfr strdup(argp->alock.caller_name, M_RPC); 2075177633Sdfr nlm_copy_netobj(&af->af_granted.alock.fh, 2076177633Sdfr &argp->alock.fh, M_RPC); 2077177633Sdfr nlm_copy_netobj(&af->af_granted.alock.oh, 2078177633Sdfr &argp->alock.oh, M_RPC); 2079177633Sdfr af->af_granted.alock.svid = argp->alock.svid; 2080177633Sdfr af->af_granted.alock.l_offset = argp->alock.l_offset; 2081177633Sdfr af->af_granted.alock.l_len = argp->alock.l_len; 2082177633Sdfr 2083177633Sdfr /* 2084177633Sdfr * Put the entry on the pending list before calling 2085177633Sdfr * VOP_ADVLOCKASYNC. We do this in case the lock 2086177633Sdfr * request was blocked (returning EINPROGRESS) but 2087177633Sdfr * then granted before we manage to run again. The 2088177633Sdfr * client may receive the granted message before we 2089177633Sdfr * send our blocked reply but thats their problem. 2090177633Sdfr */ 2091177633Sdfr mtx_lock(&host->nh_lock); 2092177633Sdfr TAILQ_INSERT_TAIL(&host->nh_pending, af, af_link); 2093177633Sdfr mtx_unlock(&host->nh_lock); 2094177633Sdfr 2095177633Sdfr error = VOP_ADVLOCKASYNC(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE, 2096177633Sdfr &af->af_task, &af->af_cookie); 2097177633Sdfr 2098177633Sdfr /* 2099177633Sdfr * If the lock completed synchronously, just free the 2100177633Sdfr * tracking structure now. 2101177633Sdfr */ 2102177633Sdfr if (error != EINPROGRESS) { 2103180025Sdfr CLNT_RELEASE(af->af_rpc); 2104177633Sdfr mtx_lock(&host->nh_lock); 2105177633Sdfr TAILQ_REMOVE(&host->nh_pending, af, af_link); 2106177633Sdfr mtx_unlock(&host->nh_lock); 2107177633Sdfr xdr_free((xdrproc_t) xdr_nlm4_testargs, 2108177633Sdfr &af->af_granted); 2109177633Sdfr free(af, M_NLM); 2110177633Sdfr } else { 2111191918Sdfr NLM_DEBUG(2, "NLM: pending async lock %p for %s " 2112191918Sdfr "(sysid %d)\n", af, host->nh_caller_name, sysid); 2113177633Sdfr /* 2114177633Sdfr * Don't vrele the vnode just yet - this must 2115177633Sdfr * wait until either the async callback 2116177633Sdfr * happens or the lock is cancelled. 2117177633Sdfr */ 2118177633Sdfr vs.vs_vp = NULL; 2119177633Sdfr } 2120177633Sdfr } else { 2121177633Sdfr error = VOP_ADVLOCK(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE); 2122177633Sdfr } 2123177633Sdfr 2124177633Sdfr if (error) { 2125177633Sdfr if (error == EINPROGRESS) { 2126177633Sdfr result->stat.stat = nlm4_blocked; 2127177633Sdfr } else if (error == EDEADLK) { 2128177633Sdfr result->stat.stat = nlm4_deadlck; 2129177633Sdfr } else if (error == EAGAIN) { 2130177633Sdfr result->stat.stat = nlm4_denied; 2131177633Sdfr } else { 2132177633Sdfr result->stat.stat = nlm4_failed; 2133177633Sdfr } 2134177633Sdfr } else { 2135177633Sdfr if (monitor) 2136177633Sdfr nlm_host_monitor(host, argp->state); 2137177633Sdfr result->stat.stat = nlm4_granted; 2138177633Sdfr } 2139177633Sdfr 2140177633Sdfrout: 2141177633Sdfr nlm_release_vfs_state(&vs); 2142180025Sdfr if (rpcp) 2143184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2144180025Sdfr nlm_host_release(host); 2145180025Sdfr return (0); 2146177633Sdfr} 2147177633Sdfr 2148180025Sdfrint 2149180025Sdfrnlm_do_cancel(nlm4_cancargs *argp, nlm4_res *result, struct svc_req *rqstp, 2150180025Sdfr CLIENT **rpcp) 2151177633Sdfr{ 2152177633Sdfr fhandle_t fh; 2153177633Sdfr struct vfs_state vs; 2154177633Sdfr struct nlm_host *host; 2155177633Sdfr int error, sysid; 2156177633Sdfr struct flock fl; 2157177633Sdfr struct nlm_async_lock *af; 2158177633Sdfr 2159177633Sdfr memset(result, 0, sizeof(*result)); 2160180025Sdfr memset(&vs, 0, sizeof(vs)); 2161177633Sdfr 2162180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 2163184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 2164177633Sdfr if (!host) { 2165177633Sdfr result->stat.stat = nlm4_denied_nolocks; 2166180025Sdfr return (ENOMEM); 2167177633Sdfr } 2168177633Sdfr 2169191918Sdfr NLM_DEBUG(3, "nlm_do_cancel(): caller_name = %s (sysid = %d)\n", 2170191918Sdfr host->nh_caller_name, host->nh_sysid); 2171177633Sdfr 2172197840Szml nlm_check_expired_locks(host); 2173177633Sdfr sysid = host->nh_sysid; 2174177633Sdfr 2175177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 2176177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 2177177633Sdfr 2178177633Sdfr if (time_uptime < nlm_grace_threshold) { 2179177633Sdfr result->stat.stat = nlm4_denied_grace_period; 2180180025Sdfr goto out; 2181177633Sdfr } 2182177633Sdfr 2183177633Sdfr error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 2184177633Sdfr if (error) { 2185177633Sdfr result->stat.stat = nlm_convert_error(error); 2186177633Sdfr goto out; 2187177633Sdfr } 2188177633Sdfr 2189177633Sdfr fl.l_start = argp->alock.l_offset; 2190177633Sdfr fl.l_len = argp->alock.l_len; 2191177633Sdfr fl.l_pid = argp->alock.svid; 2192177633Sdfr fl.l_sysid = sysid; 2193177633Sdfr fl.l_whence = SEEK_SET; 2194177633Sdfr if (argp->exclusive) 2195177633Sdfr fl.l_type = F_WRLCK; 2196177633Sdfr else 2197177633Sdfr fl.l_type = F_RDLCK; 2198177633Sdfr 2199177633Sdfr /* 2200177633Sdfr * First we need to try and find the async lock request - if 2201177633Sdfr * there isn't one, we give up and return nlm4_denied. 2202177633Sdfr */ 2203177633Sdfr mtx_lock(&host->nh_lock); 2204177633Sdfr 2205177633Sdfr TAILQ_FOREACH(af, &host->nh_pending, af_link) { 2206177633Sdfr if (af->af_fl.l_start == fl.l_start 2207177633Sdfr && af->af_fl.l_len == fl.l_len 2208177633Sdfr && af->af_fl.l_pid == fl.l_pid 2209177633Sdfr && af->af_fl.l_type == fl.l_type) { 2210177633Sdfr break; 2211177633Sdfr } 2212177633Sdfr } 2213177633Sdfr 2214177633Sdfr if (!af) { 2215177633Sdfr mtx_unlock(&host->nh_lock); 2216177633Sdfr result->stat.stat = nlm4_denied; 2217177633Sdfr goto out; 2218177633Sdfr } 2219177633Sdfr 2220177633Sdfr error = nlm_cancel_async_lock(af); 2221177633Sdfr 2222177633Sdfr if (error) { 2223177633Sdfr result->stat.stat = nlm4_denied; 2224177633Sdfr } else { 2225177633Sdfr result->stat.stat = nlm4_granted; 2226177633Sdfr } 2227177633Sdfr 2228177633Sdfr mtx_unlock(&host->nh_lock); 2229177633Sdfr 2230177633Sdfrout: 2231177633Sdfr nlm_release_vfs_state(&vs); 2232180025Sdfr if (rpcp) 2233184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2234180025Sdfr nlm_host_release(host); 2235180025Sdfr return (0); 2236177633Sdfr} 2237177633Sdfr 2238180025Sdfrint 2239180025Sdfrnlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *result, struct svc_req *rqstp, 2240180025Sdfr CLIENT **rpcp) 2241177633Sdfr{ 2242177633Sdfr fhandle_t fh; 2243177633Sdfr struct vfs_state vs; 2244177633Sdfr struct nlm_host *host; 2245177633Sdfr int error, sysid; 2246177633Sdfr struct flock fl; 2247177633Sdfr 2248177633Sdfr memset(result, 0, sizeof(*result)); 2249180025Sdfr memset(&vs, 0, sizeof(vs)); 2250177633Sdfr 2251180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 2252184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 2253177633Sdfr if (!host) { 2254177633Sdfr result->stat.stat = nlm4_denied_nolocks; 2255180025Sdfr return (ENOMEM); 2256177633Sdfr } 2257177633Sdfr 2258191918Sdfr NLM_DEBUG(3, "nlm_do_unlock(): caller_name = %s (sysid = %d)\n", 2259191918Sdfr host->nh_caller_name, host->nh_sysid); 2260177633Sdfr 2261197840Szml nlm_check_expired_locks(host); 2262177633Sdfr sysid = host->nh_sysid; 2263177633Sdfr 2264177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 2265177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 2266177633Sdfr 2267177633Sdfr if (time_uptime < nlm_grace_threshold) { 2268177633Sdfr result->stat.stat = nlm4_denied_grace_period; 2269180025Sdfr goto out; 2270177633Sdfr } 2271177633Sdfr 2272177633Sdfr error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 2273177633Sdfr if (error) { 2274177633Sdfr result->stat.stat = nlm_convert_error(error); 2275177633Sdfr goto out; 2276177633Sdfr } 2277177633Sdfr 2278177633Sdfr fl.l_start = argp->alock.l_offset; 2279177633Sdfr fl.l_len = argp->alock.l_len; 2280177633Sdfr fl.l_pid = argp->alock.svid; 2281177633Sdfr fl.l_sysid = sysid; 2282177633Sdfr fl.l_whence = SEEK_SET; 2283177633Sdfr fl.l_type = F_UNLCK; 2284177633Sdfr error = VOP_ADVLOCK(vs.vs_vp, NULL, F_UNLCK, &fl, F_REMOTE); 2285177633Sdfr 2286177633Sdfr /* 2287177633Sdfr * Ignore the error - there is no result code for failure, 2288177633Sdfr * only for grace period. 2289177633Sdfr */ 2290177633Sdfr result->stat.stat = nlm4_granted; 2291177633Sdfr 2292177633Sdfrout: 2293177633Sdfr nlm_release_vfs_state(&vs); 2294180025Sdfr if (rpcp) 2295184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2296180025Sdfr nlm_host_release(host); 2297180025Sdfr return (0); 2298180025Sdfr} 2299177633Sdfr 2300180025Sdfrint 2301180025Sdfrnlm_do_granted(nlm4_testargs *argp, nlm4_res *result, struct svc_req *rqstp, 2302180025Sdfr 2303180025Sdfr CLIENT **rpcp) 2304180025Sdfr{ 2305180025Sdfr struct nlm_host *host; 2306180025Sdfr struct nlm_waiting_lock *nw; 2307180025Sdfr 2308180025Sdfr memset(result, 0, sizeof(*result)); 2309180025Sdfr 2310184588Sdfr host = nlm_find_host_by_addr(svc_getrpccaller(rqstp), rqstp->rq_vers); 2311180025Sdfr if (!host) { 2312180025Sdfr result->stat.stat = nlm4_denied_nolocks; 2313180025Sdfr return (ENOMEM); 2314180025Sdfr } 2315180025Sdfr 2316180025Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 2317180025Sdfr result->stat.stat = nlm4_denied; 2318197840Szml KFAIL_POINT_CODE(DEBUG_FP, nlm_deny_grant, goto out); 2319180025Sdfr 2320180025Sdfr mtx_lock(&nlm_global_lock); 2321180025Sdfr TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) { 2322180025Sdfr if (!nw->nw_waiting) 2323180025Sdfr continue; 2324180025Sdfr if (argp->alock.svid == nw->nw_lock.svid 2325180025Sdfr && argp->alock.l_offset == nw->nw_lock.l_offset 2326180025Sdfr && argp->alock.l_len == nw->nw_lock.l_len 2327180025Sdfr && argp->alock.fh.n_len == nw->nw_lock.fh.n_len 2328180025Sdfr && !memcmp(argp->alock.fh.n_bytes, nw->nw_lock.fh.n_bytes, 2329180025Sdfr nw->nw_lock.fh.n_len)) { 2330180025Sdfr nw->nw_waiting = FALSE; 2331180025Sdfr wakeup(nw); 2332180025Sdfr result->stat.stat = nlm4_granted; 2333180025Sdfr break; 2334180025Sdfr } 2335180025Sdfr } 2336180025Sdfr mtx_unlock(&nlm_global_lock); 2337197840Szml 2338197840Szmlout: 2339180025Sdfr if (rpcp) 2340184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2341180025Sdfr nlm_host_release(host); 2342180025Sdfr return (0); 2343177633Sdfr} 2344177633Sdfr 2345177633Sdfrvoid 2346197840Szmlnlm_do_granted_res(nlm4_res *argp, struct svc_req *rqstp) 2347197840Szml{ 2348197840Szml struct nlm_host *host = NULL; 2349197840Szml struct nlm_async_lock *af = NULL; 2350197840Szml int error; 2351197840Szml 2352197840Szml if (argp->cookie.n_len != sizeof(struct nlm_grantcookie)) { 2353197840Szml NLM_DEBUG(1, "NLM: bogus grant cookie"); 2354197840Szml goto out; 2355197840Szml } 2356197840Szml 2357197840Szml host = nlm_find_host_by_sysid(ng_sysid(&argp->cookie)); 2358197840Szml if (!host) { 2359197840Szml NLM_DEBUG(1, "NLM: Unknown host rejected our grant"); 2360197840Szml goto out; 2361197840Szml } 2362197840Szml 2363197840Szml mtx_lock(&host->nh_lock); 2364197840Szml TAILQ_FOREACH(af, &host->nh_granted, af_link) 2365197840Szml if (ng_cookie(&argp->cookie) == 2366197840Szml ng_cookie(&af->af_granted.cookie)) 2367197840Szml break; 2368197840Szml if (af) 2369197840Szml TAILQ_REMOVE(&host->nh_granted, af, af_link); 2370197840Szml mtx_unlock(&host->nh_lock); 2371197840Szml 2372197840Szml if (!af) { 2373197840Szml NLM_DEBUG(1, "NLM: host %s (sysid %d) replied to our grant " 2374197840Szml "with unrecognized cookie %d:%d", host->nh_caller_name, 2375197840Szml host->nh_sysid, ng_sysid(&argp->cookie), 2376197840Szml ng_cookie(&argp->cookie)); 2377197840Szml goto out; 2378197840Szml } 2379197840Szml 2380197840Szml if (argp->stat.stat != nlm4_granted) { 2381197840Szml af->af_fl.l_type = F_UNLCK; 2382197840Szml error = VOP_ADVLOCK(af->af_vp, NULL, F_UNLCK, &af->af_fl, F_REMOTE); 2383197840Szml if (error) { 2384197840Szml NLM_DEBUG(1, "NLM: host %s (sysid %d) rejected our grant " 2385197840Szml "and we failed to unlock (%d)", host->nh_caller_name, 2386197840Szml host->nh_sysid, error); 2387197840Szml goto out; 2388197840Szml } 2389197840Szml 2390197840Szml NLM_DEBUG(5, "NLM: async lock %p rejected by host %s (sysid %d)", 2391197840Szml af, host->nh_caller_name, host->nh_sysid); 2392197840Szml } else { 2393197840Szml NLM_DEBUG(5, "NLM: async lock %p accepted by host %s (sysid %d)", 2394197840Szml af, host->nh_caller_name, host->nh_sysid); 2395197840Szml } 2396197840Szml 2397197840Szml out: 2398197840Szml if (af) 2399197840Szml nlm_free_async_lock(af); 2400197840Szml if (host) 2401197840Szml nlm_host_release(host); 2402197840Szml} 2403197840Szml 2404197840Szmlvoid 2405177633Sdfrnlm_do_free_all(nlm4_notify *argp) 2406177633Sdfr{ 2407177633Sdfr struct nlm_host *host, *thost; 2408177633Sdfr 2409177633Sdfr TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, thost) { 2410177633Sdfr if (!strcmp(host->nh_caller_name, argp->name)) 2411180025Sdfr nlm_host_notify(host, argp->state); 2412177633Sdfr } 2413177633Sdfr} 2414177633Sdfr 2415177633Sdfr/* 2416177662Sdfr * Kernel module glue 2417177662Sdfr */ 2418177662Sdfrstatic int 2419177662Sdfrnfslockd_modevent(module_t mod, int type, void *data) 2420177662Sdfr{ 2421177662Sdfr 2422177662Sdfr return (0); 2423177662Sdfr} 2424177662Sdfrstatic moduledata_t nfslockd_mod = { 2425177662Sdfr "nfslockd", 2426177662Sdfr nfslockd_modevent, 2427177662Sdfr NULL, 2428177662Sdfr}; 2429177662SdfrDECLARE_MODULE(nfslockd, nfslockd_mod, SI_SUB_VFS, SI_ORDER_ANY); 2430177662Sdfr 2431177662Sdfr/* So that loader and kldload(2) can find us, wherever we are.. */ 2432177662SdfrMODULE_DEPEND(nfslockd, krpc, 1, 1, 1); 2433214048SrmacklemMODULE_DEPEND(nfslockd, nfslock, 1, 1, 1); 2434177662SdfrMODULE_VERSION(nfslockd, 1); 2435