nlm_prot_impl.c revision 197840
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 197840 2009-10-07 19:50:14Z zml $"); 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> 58180025Sdfr#include <nfsclient/nfs.h> 59180025Sdfr#include <nfsclient/nfsnode.h> 60180025Sdfr 61177685Sdfr#include <nlm/nlm_prot.h> 62177685Sdfr#include <nlm/sm_inter.h> 63177685Sdfr#include <nlm/nlm.h> 64177633Sdfr#include <rpc/rpc_com.h> 65177633Sdfr#include <rpc/rpcb_prot.h> 66177633Sdfr 67177633SdfrMALLOC_DEFINE(M_NLM, "NLM", "Network Lock Manager"); 68177633Sdfr 69177633Sdfr/* 70177633Sdfr * If a host is inactive (and holds no locks) for this amount of 71177633Sdfr * seconds, we consider it idle and stop tracking it. 72177633Sdfr */ 73177633Sdfr#define NLM_IDLE_TIMEOUT 30 74177633Sdfr 75177633Sdfr/* 76177633Sdfr * We check the host list for idle every few seconds. 77177633Sdfr */ 78177633Sdfr#define NLM_IDLE_PERIOD 5 79177633Sdfr 80177633Sdfr/* 81197840Szml * We only look for GRANTED_RES messages for a little while. 82197840Szml */ 83197840Szml#define NLM_EXPIRE_TIMEOUT 10 84197840Szml 85197840Szml/* 86177633Sdfr * Support for sysctl vfs.nlm.sysid 87177633Sdfr */ 88177633SdfrSYSCTL_NODE(_vfs, OID_AUTO, nlm, CTLFLAG_RW, NULL, "Network Lock Manager"); 89177633SdfrSYSCTL_NODE(_vfs_nlm, OID_AUTO, sysid, CTLFLAG_RW, NULL, ""); 90177633Sdfr 91177633Sdfr/* 92177633Sdfr * Syscall hooks 93177633Sdfr */ 94177633Sdfrstatic int nlm_syscall_offset = SYS_nlm_syscall; 95177633Sdfrstatic struct sysent nlm_syscall_prev_sysent; 96177685Sdfr#if __FreeBSD_version < 700000 97177685Sdfrstatic struct sysent nlm_syscall_sysent = { 98177685Sdfr (sizeof(struct nlm_syscall_args) / sizeof(register_t)) | SYF_MPSAFE, 99177685Sdfr (sy_call_t *) nlm_syscall 100177685Sdfr}; 101177685Sdfr#else 102177633SdfrMAKE_SYSENT(nlm_syscall); 103177685Sdfr#endif 104177633Sdfrstatic bool_t nlm_syscall_registered = FALSE; 105177633Sdfr 106177633Sdfr/* 107177633Sdfr * Debug level passed in from userland. We also support a sysctl hook 108177633Sdfr * so that it can be changed on a live system. 109177633Sdfr */ 110177633Sdfrstatic int nlm_debug_level; 111177633SdfrSYSCTL_INT(_debug, OID_AUTO, nlm_debug, CTLFLAG_RW, &nlm_debug_level, 0, ""); 112177633Sdfr 113191918Sdfr#define NLM_DEBUG(_level, args...) \ 114191918Sdfr do { \ 115191918Sdfr if (nlm_debug_level >= (_level)) \ 116191918Sdfr log(LOG_DEBUG, args); \ 117191918Sdfr } while(0) 118191918Sdfr#define NLM_ERR(args...) \ 119191918Sdfr do { \ 120191918Sdfr log(LOG_ERR, args); \ 121191918Sdfr } while(0) 122191918Sdfr 123177633Sdfr/* 124177633Sdfr * Grace period handling. The value of nlm_grace_threshold is the 125177633Sdfr * value of time_uptime after which we are serving requests normally. 126177633Sdfr */ 127177633Sdfrstatic time_t nlm_grace_threshold; 128177633Sdfr 129177633Sdfr/* 130177633Sdfr * We check for idle hosts if time_uptime is greater than 131177633Sdfr * nlm_next_idle_check, 132177633Sdfr */ 133177633Sdfrstatic time_t nlm_next_idle_check; 134177633Sdfr 135177633Sdfr/* 136177633Sdfr * A socket to use for RPC - shared by all IPv4 RPC clients. 137177633Sdfr */ 138177633Sdfrstatic struct socket *nlm_socket; 139177633Sdfr 140177633Sdfr#ifdef INET6 141177633Sdfr 142177633Sdfr/* 143177633Sdfr * A socket to use for RPC - shared by all IPv6 RPC clients. 144177633Sdfr */ 145177633Sdfrstatic struct socket *nlm_socket6; 146177633Sdfr 147177633Sdfr#endif 148177633Sdfr 149177633Sdfr/* 150177633Sdfr * An RPC client handle that can be used to communicate with the local 151177633Sdfr * NSM. 152177633Sdfr */ 153177633Sdfrstatic CLIENT *nlm_nsm; 154177633Sdfr 155177633Sdfr/* 156180025Sdfr * An AUTH handle for the server's creds. 157177633Sdfr */ 158180025Sdfrstatic AUTH *nlm_auth; 159177633Sdfr 160177633Sdfr/* 161180025Sdfr * A zero timeval for sending async RPC messages. 162180025Sdfr */ 163180025Sdfrstruct timeval nlm_zero_tv = { 0, 0 }; 164180025Sdfr 165180025Sdfr/* 166180025Sdfr * The local NSM state number 167180025Sdfr */ 168180025Sdfrint nlm_nsm_state; 169180025Sdfr 170180025Sdfr 171180025Sdfr/* 172180025Sdfr * A lock to protect the host list and waiting lock list. 173180025Sdfr */ 174180025Sdfrstatic struct mtx nlm_global_lock; 175180025Sdfr 176180025Sdfr/* 177177633Sdfr * Locks: 178177633Sdfr * (l) locked by nh_lock 179177633Sdfr * (s) only accessed via server RPC which is single threaded 180180025Sdfr * (g) locked by nlm_global_lock 181177633Sdfr * (c) const until freeing 182180025Sdfr * (a) modified using atomic ops 183177633Sdfr */ 184177633Sdfr 185177633Sdfr/* 186180025Sdfr * A pending client-side lock request, stored on the nlm_waiting_locks 187180025Sdfr * list. 188177633Sdfr */ 189180025Sdfrstruct nlm_waiting_lock { 190180025Sdfr TAILQ_ENTRY(nlm_waiting_lock) nw_link; /* (g) */ 191180025Sdfr bool_t nw_waiting; /* (g) */ 192180025Sdfr nlm4_lock nw_lock; /* (c) */ 193180025Sdfr union nfsfh nw_fh; /* (c) */ 194180025Sdfr struct vnode *nw_vp; /* (c) */ 195180025Sdfr}; 196180025SdfrTAILQ_HEAD(nlm_waiting_lock_list, nlm_waiting_lock); 197180025Sdfr 198180025Sdfrstruct nlm_waiting_lock_list nlm_waiting_locks; /* (g) */ 199180025Sdfr 200180025Sdfr/* 201180025Sdfr * A pending server-side asynchronous lock request, stored on the 202180025Sdfr * nh_pending list of the NLM host. 203180025Sdfr */ 204177633Sdfrstruct nlm_async_lock { 205177633Sdfr TAILQ_ENTRY(nlm_async_lock) af_link; /* (l) host's list of locks */ 206177633Sdfr struct task af_task; /* (c) async callback details */ 207177633Sdfr void *af_cookie; /* (l) lock manager cancel token */ 208177633Sdfr struct vnode *af_vp; /* (l) vnode to lock */ 209177633Sdfr struct flock af_fl; /* (c) lock details */ 210177633Sdfr struct nlm_host *af_host; /* (c) host which is locking */ 211180025Sdfr CLIENT *af_rpc; /* (c) rpc client to send message */ 212177633Sdfr nlm4_testargs af_granted; /* (c) notification details */ 213197840Szml time_t af_expiretime; /* (c) notification time */ 214177633Sdfr}; 215177633SdfrTAILQ_HEAD(nlm_async_lock_list, nlm_async_lock); 216177633Sdfr 217177633Sdfr/* 218177633Sdfr * NLM host. 219177633Sdfr */ 220178112Sdfrenum nlm_host_state { 221178112Sdfr NLM_UNMONITORED, 222178112Sdfr NLM_MONITORED, 223180025Sdfr NLM_MONITOR_FAILED, 224180025Sdfr NLM_RECOVERING 225178112Sdfr}; 226184588Sdfr 227184588Sdfrstruct nlm_rpc { 228184588Sdfr CLIENT *nr_client; /* (l) RPC client handle */ 229184588Sdfr time_t nr_create_time; /* (l) when client was created */ 230184588Sdfr}; 231184588Sdfr 232177633Sdfrstruct nlm_host { 233177633Sdfr struct mtx nh_lock; 234180025Sdfr volatile u_int nh_refs; /* (a) reference count */ 235180025Sdfr TAILQ_ENTRY(nlm_host) nh_link; /* (g) global list of hosts */ 236180025Sdfr char nh_caller_name[MAXNAMELEN]; /* (c) printable name of host */ 237177633Sdfr uint32_t nh_sysid; /* (c) our allocaed system ID */ 238177633Sdfr char nh_sysid_string[10]; /* (c) string rep. of sysid */ 239177633Sdfr struct sockaddr_storage nh_addr; /* (s) remote address of host */ 240184588Sdfr struct nlm_rpc nh_srvrpc; /* (l) RPC for server replies */ 241184588Sdfr struct nlm_rpc nh_clntrpc; /* (l) RPC for client requests */ 242177633Sdfr rpcvers_t nh_vers; /* (s) NLM version of host */ 243177633Sdfr int nh_state; /* (s) last seen NSM state of host */ 244180025Sdfr enum nlm_host_state nh_monstate; /* (l) local NSM monitoring state */ 245177633Sdfr time_t nh_idle_timeout; /* (s) Time at which host is idle */ 246177633Sdfr struct sysctl_ctx_list nh_sysctl; /* (c) vfs.nlm.sysid nodes */ 247197840Szml uint32_t nh_grantcookie; /* (l) grant cookie counter */ 248177633Sdfr struct nlm_async_lock_list nh_pending; /* (l) pending async locks */ 249197840Szml struct nlm_async_lock_list nh_granted; /* (l) granted locks */ 250177633Sdfr struct nlm_async_lock_list nh_finished; /* (l) finished async locks */ 251177633Sdfr}; 252177633SdfrTAILQ_HEAD(nlm_host_list, nlm_host); 253177633Sdfr 254180025Sdfrstatic struct nlm_host_list nlm_hosts; /* (g) */ 255180025Sdfrstatic uint32_t nlm_next_sysid = 1; /* (g) */ 256177633Sdfr 257177633Sdfrstatic void nlm_host_unmonitor(struct nlm_host *); 258177633Sdfr 259197840Szmlstruct nlm_grantcookie { 260197840Szml uint32_t ng_sysid; 261197840Szml uint32_t ng_cookie; 262197840Szml}; 263197840Szml 264197840Szmlstatic inline uint32_t 265197840Szmlng_sysid(struct netobj *src) 266197840Szml{ 267197840Szml 268197840Szml return ((struct nlm_grantcookie *)src->n_bytes)->ng_sysid; 269197840Szml} 270197840Szml 271197840Szmlstatic inline uint32_t 272197840Szmlng_cookie(struct netobj *src) 273197840Szml{ 274197840Szml 275197840Szml return ((struct nlm_grantcookie *)src->n_bytes)->ng_cookie; 276197840Szml} 277197840Szml 278177633Sdfr/**********************************************************************/ 279177633Sdfr 280177633Sdfr/* 281177633Sdfr * Initialise NLM globals. 282177633Sdfr */ 283177633Sdfrstatic void 284177633Sdfrnlm_init(void *dummy) 285177633Sdfr{ 286177633Sdfr int error; 287177633Sdfr 288180025Sdfr mtx_init(&nlm_global_lock, "nlm_global_lock", NULL, MTX_DEF); 289180025Sdfr TAILQ_INIT(&nlm_waiting_locks); 290177633Sdfr TAILQ_INIT(&nlm_hosts); 291177633Sdfr 292177633Sdfr error = syscall_register(&nlm_syscall_offset, &nlm_syscall_sysent, 293177633Sdfr &nlm_syscall_prev_sysent); 294177633Sdfr if (error) 295191918Sdfr NLM_ERR("Can't register NLM syscall\n"); 296177633Sdfr else 297177633Sdfr nlm_syscall_registered = TRUE; 298177633Sdfr} 299177633SdfrSYSINIT(nlm_init, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_init, NULL); 300177633Sdfr 301177633Sdfrstatic void 302177633Sdfrnlm_uninit(void *dummy) 303177633Sdfr{ 304177633Sdfr 305177633Sdfr if (nlm_syscall_registered) 306177633Sdfr syscall_deregister(&nlm_syscall_offset, 307177633Sdfr &nlm_syscall_prev_sysent); 308177633Sdfr} 309177633SdfrSYSUNINIT(nlm_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_uninit, NULL); 310177633Sdfr 311177633Sdfr/* 312197840Szml * Create a netobj from an arbitrary source. 313197840Szml */ 314197840Szmlvoid 315197840Szmlnlm_make_netobj(struct netobj *dst, caddr_t src, size_t srcsize, 316197840Szml struct malloc_type *type) 317197840Szml{ 318197840Szml 319197840Szml dst->n_len = srcsize; 320197840Szml dst->n_bytes = malloc(srcsize, type, M_WAITOK); 321197840Szml memcpy(dst->n_bytes, src, srcsize); 322197840Szml} 323197840Szml 324197840Szml/* 325177633Sdfr * Copy a struct netobj. 326177633Sdfr */ 327177633Sdfrvoid 328177633Sdfrnlm_copy_netobj(struct netobj *dst, struct netobj *src, 329177633Sdfr struct malloc_type *type) 330177633Sdfr{ 331177633Sdfr 332197840Szml nlm_make_netobj(dst, src->n_bytes, src->n_len, type); 333177633Sdfr} 334177633Sdfr 335197840Szml 336177633Sdfr/* 337177633Sdfr * Create an RPC client handle for the given (address,prog,vers) 338177633Sdfr * triple using UDP. 339177633Sdfr */ 340177633Sdfrstatic CLIENT * 341177633Sdfrnlm_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers) 342177633Sdfr{ 343184588Sdfr char *wchan = "nlmrcv"; 344177633Sdfr const char* protofmly; 345177633Sdfr struct sockaddr_storage ss; 346177633Sdfr struct socket *so; 347177633Sdfr CLIENT *rpcb; 348177633Sdfr struct timeval timo; 349177633Sdfr RPCB parms; 350177633Sdfr char *uaddr; 351181683Sdfr enum clnt_stat stat = RPC_SUCCESS; 352181683Sdfr int rpcvers = RPCBVERS4; 353181683Sdfr bool_t do_tcp = FALSE; 354191937Sdfr bool_t tryagain = FALSE; 355182154Sdfr struct portmap mapping; 356181683Sdfr u_short port = 0; 357177633Sdfr 358177633Sdfr /* 359177633Sdfr * First we need to contact the remote RPCBIND service to find 360177633Sdfr * the right port. 361177633Sdfr */ 362177633Sdfr memcpy(&ss, sa, sa->sa_len); 363177633Sdfr switch (ss.ss_family) { 364177633Sdfr case AF_INET: 365177633Sdfr ((struct sockaddr_in *)&ss)->sin_port = htons(111); 366177633Sdfr protofmly = "inet"; 367177633Sdfr so = nlm_socket; 368177633Sdfr break; 369177633Sdfr 370177633Sdfr#ifdef INET6 371177633Sdfr case AF_INET6: 372177633Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111); 373177633Sdfr protofmly = "inet6"; 374177633Sdfr so = nlm_socket6; 375177633Sdfr break; 376177633Sdfr#endif 377177633Sdfr 378177633Sdfr default: 379177633Sdfr /* 380177633Sdfr * Unsupported address family - fail. 381177633Sdfr */ 382177633Sdfr return (NULL); 383177633Sdfr } 384177633Sdfr 385177633Sdfr rpcb = clnt_dg_create(so, (struct sockaddr *)&ss, 386181683Sdfr RPCBPROG, rpcvers, 0, 0); 387177633Sdfr if (!rpcb) 388177633Sdfr return (NULL); 389177633Sdfr 390181683Sdfrtry_tcp: 391177633Sdfr parms.r_prog = prog; 392177633Sdfr parms.r_vers = vers; 393181683Sdfr if (do_tcp) 394181683Sdfr parms.r_netid = "tcp"; 395181683Sdfr else 396181683Sdfr parms.r_netid = "udp"; 397177633Sdfr parms.r_addr = ""; 398177633Sdfr parms.r_owner = ""; 399177633Sdfr 400177633Sdfr /* 401177633Sdfr * Use the default timeout. 402177633Sdfr */ 403177633Sdfr timo.tv_sec = 25; 404177633Sdfr timo.tv_usec = 0; 405177633Sdfragain: 406181683Sdfr switch (rpcvers) { 407181683Sdfr case RPCBVERS4: 408181683Sdfr case RPCBVERS: 409177633Sdfr /* 410181683Sdfr * Try RPCBIND 4 then 3. 411177633Sdfr */ 412181683Sdfr uaddr = NULL; 413181683Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR, 414181683Sdfr (xdrproc_t) xdr_rpcb, &parms, 415181683Sdfr (xdrproc_t) xdr_wrapstring, &uaddr, timo); 416191937Sdfr if (stat == RPC_SUCCESS) { 417181683Sdfr /* 418181683Sdfr * We have a reply from the remote RPCBIND - turn it 419181683Sdfr * into an appropriate address and make a new client 420181683Sdfr * that can talk to the remote NLM. 421181683Sdfr * 422181683Sdfr * XXX fixup IPv6 scope ID. 423181683Sdfr */ 424181683Sdfr struct netbuf *a; 425181683Sdfr a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr); 426181683Sdfr if (!a) { 427191937Sdfr tryagain = TRUE; 428191937Sdfr } else { 429191937Sdfr tryagain = FALSE; 430191937Sdfr memcpy(&ss, a->buf, a->len); 431191937Sdfr free(a->buf, M_RPC); 432191937Sdfr free(a, M_RPC); 433191937Sdfr xdr_free((xdrproc_t) xdr_wrapstring, &uaddr); 434181683Sdfr } 435177633Sdfr } 436191937Sdfr if (tryagain || stat == RPC_PROGVERSMISMATCH) { 437191937Sdfr if (rpcvers == RPCBVERS4) 438191937Sdfr rpcvers = RPCBVERS; 439191937Sdfr else if (rpcvers == RPCBVERS) 440191937Sdfr rpcvers = PMAPVERS; 441191937Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers); 442191937Sdfr goto again; 443191937Sdfr } 444181683Sdfr break; 445181683Sdfr case PMAPVERS: 446177633Sdfr /* 447177633Sdfr * Try portmap. 448177633Sdfr */ 449177633Sdfr mapping.pm_prog = parms.r_prog; 450177633Sdfr mapping.pm_vers = parms.r_vers; 451181683Sdfr mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP; 452177633Sdfr mapping.pm_port = 0; 453177633Sdfr 454177633Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT, 455182154Sdfr (xdrproc_t) xdr_portmap, &mapping, 456177633Sdfr (xdrproc_t) xdr_u_short, &port, timo); 457177633Sdfr 458177633Sdfr if (stat == RPC_SUCCESS) { 459177633Sdfr switch (ss.ss_family) { 460177633Sdfr case AF_INET: 461177633Sdfr ((struct sockaddr_in *)&ss)->sin_port = 462177633Sdfr htons(port); 463177633Sdfr break; 464177633Sdfr 465177633Sdfr#ifdef INET6 466177633Sdfr case AF_INET6: 467177633Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = 468177633Sdfr htons(port); 469177633Sdfr break; 470177633Sdfr#endif 471177633Sdfr } 472177633Sdfr } 473181683Sdfr break; 474181683Sdfr default: 475181683Sdfr panic("invalid rpcvers %d", rpcvers); 476177633Sdfr } 477181683Sdfr /* 478181683Sdfr * We may have a positive response from the portmapper, but the NLM 479181683Sdfr * service was not found. Make sure we received a valid port. 480181683Sdfr */ 481181683Sdfr switch (ss.ss_family) { 482181683Sdfr case AF_INET: 483181683Sdfr port = ((struct sockaddr_in *)&ss)->sin_port; 484181683Sdfr break; 485181683Sdfr#ifdef INET6 486181683Sdfr case AF_INET6: 487181683Sdfr port = ((struct sockaddr_in6 *)&ss)->sin6_port; 488181683Sdfr break; 489181683Sdfr#endif 490181683Sdfr } 491181683Sdfr if (stat != RPC_SUCCESS || !port) { 492181683Sdfr /* 493181683Sdfr * If we were able to talk to rpcbind or portmap, but the udp 494181683Sdfr * variant wasn't available, ask about tcp. 495181683Sdfr * 496181683Sdfr * XXX - We could also check for a TCP portmapper, but 497181683Sdfr * if the host is running a portmapper at all, we should be able 498181683Sdfr * to hail it over UDP. 499181683Sdfr */ 500181683Sdfr if (stat == RPC_SUCCESS && !do_tcp) { 501181683Sdfr do_tcp = TRUE; 502181683Sdfr goto try_tcp; 503181683Sdfr } 504181683Sdfr 505181683Sdfr /* Otherwise, bad news. */ 506191918Sdfr NLM_ERR("NLM: failed to contact remote rpcbind, " 507191918Sdfr "stat = %d, port = %d\n", (int) stat, port); 508178241Sdfr CLNT_DESTROY(rpcb); 509177633Sdfr return (NULL); 510177633Sdfr } 511177633Sdfr 512181683Sdfr if (do_tcp) { 513181683Sdfr /* 514181683Sdfr * Destroy the UDP client we used to speak to rpcbind and 515181683Sdfr * recreate as a TCP client. 516181683Sdfr */ 517181683Sdfr struct netconfig *nconf = NULL; 518177633Sdfr 519181683Sdfr CLNT_DESTROY(rpcb); 520181683Sdfr 521181683Sdfr switch (ss.ss_family) { 522181683Sdfr case AF_INET: 523181683Sdfr nconf = getnetconfigent("tcp"); 524181683Sdfr break; 525181683Sdfr#ifdef INET6 526181683Sdfr case AF_INET6: 527181683Sdfr nconf = getnetconfigent("tcp6"); 528181683Sdfr break; 529181683Sdfr#endif 530181683Sdfr } 531181683Sdfr 532181683Sdfr rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss, 533181683Sdfr prog, vers, 0, 0); 534184588Sdfr CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan); 535181683Sdfr rpcb->cl_auth = nlm_auth; 536181683Sdfr 537181683Sdfr } else { 538181683Sdfr /* 539181683Sdfr * Re-use the client we used to speak to rpcbind. 540181683Sdfr */ 541181683Sdfr CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss); 542181683Sdfr CLNT_CONTROL(rpcb, CLSET_PROG, &prog); 543181683Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &vers); 544184588Sdfr CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan); 545181683Sdfr rpcb->cl_auth = nlm_auth; 546181683Sdfr } 547181683Sdfr 548177633Sdfr return (rpcb); 549177633Sdfr} 550177633Sdfr 551177633Sdfr/* 552177633Sdfr * This async callback after when an async lock request has been 553177633Sdfr * granted. We notify the host which initiated the request. 554177633Sdfr */ 555177633Sdfrstatic void 556177633Sdfrnlm_lock_callback(void *arg, int pending) 557177633Sdfr{ 558177633Sdfr struct nlm_async_lock *af = (struct nlm_async_lock *) arg; 559180025Sdfr struct rpc_callextra ext; 560177633Sdfr 561197840Szml NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) granted," 562197840Szml " cookie %d:%d\n", af, af->af_host->nh_caller_name, 563197840Szml af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie), 564197840Szml ng_cookie(&af->af_granted.cookie)); 565177633Sdfr 566177633Sdfr /* 567177633Sdfr * Send the results back to the host. 568177633Sdfr * 569177633Sdfr * Note: there is a possible race here with nlm_host_notify 570178241Sdfr * destroying the RPC client. To avoid problems, the first 571177633Sdfr * thing nlm_host_notify does is to cancel pending async lock 572177633Sdfr * requests. 573177633Sdfr */ 574180025Sdfr memset(&ext, 0, sizeof(ext)); 575180025Sdfr ext.rc_auth = nlm_auth; 576177633Sdfr if (af->af_host->nh_vers == NLM_VERS4) { 577177633Sdfr nlm4_granted_msg_4(&af->af_granted, 578180025Sdfr NULL, af->af_rpc, &ext, nlm_zero_tv); 579177633Sdfr } else { 580177633Sdfr /* 581177633Sdfr * Back-convert to legacy protocol 582177633Sdfr */ 583177633Sdfr nlm_testargs granted; 584177633Sdfr granted.cookie = af->af_granted.cookie; 585177633Sdfr granted.exclusive = af->af_granted.exclusive; 586177633Sdfr granted.alock.caller_name = 587177633Sdfr af->af_granted.alock.caller_name; 588177633Sdfr granted.alock.fh = af->af_granted.alock.fh; 589177633Sdfr granted.alock.oh = af->af_granted.alock.oh; 590177633Sdfr granted.alock.svid = af->af_granted.alock.svid; 591177633Sdfr granted.alock.l_offset = 592177633Sdfr af->af_granted.alock.l_offset; 593177633Sdfr granted.alock.l_len = 594177633Sdfr af->af_granted.alock.l_len; 595177633Sdfr 596177633Sdfr nlm_granted_msg_1(&granted, 597180025Sdfr NULL, af->af_rpc, &ext, nlm_zero_tv); 598177633Sdfr } 599177633Sdfr 600177633Sdfr /* 601197840Szml * Move this entry to the nh_granted list. 602177633Sdfr */ 603197840Szml af->af_expiretime = time_uptime + NLM_EXPIRE_TIMEOUT; 604177633Sdfr mtx_lock(&af->af_host->nh_lock); 605177633Sdfr TAILQ_REMOVE(&af->af_host->nh_pending, af, af_link); 606197840Szml TAILQ_INSERT_TAIL(&af->af_host->nh_granted, af, af_link); 607177633Sdfr mtx_unlock(&af->af_host->nh_lock); 608177633Sdfr} 609177633Sdfr 610177633Sdfr/* 611177633Sdfr * Free an async lock request. The request must have been removed from 612177633Sdfr * any list. 613177633Sdfr */ 614177633Sdfrstatic void 615177633Sdfrnlm_free_async_lock(struct nlm_async_lock *af) 616177633Sdfr{ 617177633Sdfr /* 618177633Sdfr * Free an async lock. 619177633Sdfr */ 620180025Sdfr if (af->af_rpc) 621180025Sdfr CLNT_RELEASE(af->af_rpc); 622177633Sdfr xdr_free((xdrproc_t) xdr_nlm4_testargs, &af->af_granted); 623177633Sdfr if (af->af_vp) 624177633Sdfr vrele(af->af_vp); 625177633Sdfr free(af, M_NLM); 626177633Sdfr} 627177633Sdfr 628177633Sdfr/* 629177633Sdfr * Cancel our async request - this must be called with 630177633Sdfr * af->nh_host->nh_lock held. This is slightly complicated by a 631177633Sdfr * potential race with our own callback. If we fail to cancel the 632177633Sdfr * lock, it must already have been granted - we make sure our async 633177633Sdfr * task has completed by calling taskqueue_drain in this case. 634177633Sdfr */ 635177633Sdfrstatic int 636177633Sdfrnlm_cancel_async_lock(struct nlm_async_lock *af) 637177633Sdfr{ 638177633Sdfr struct nlm_host *host = af->af_host; 639177633Sdfr int error; 640177633Sdfr 641177633Sdfr mtx_assert(&host->nh_lock, MA_OWNED); 642177633Sdfr 643177633Sdfr mtx_unlock(&host->nh_lock); 644177633Sdfr 645177633Sdfr error = VOP_ADVLOCKASYNC(af->af_vp, NULL, F_CANCEL, &af->af_fl, 646177633Sdfr F_REMOTE, NULL, &af->af_cookie); 647177633Sdfr 648177633Sdfr if (error) { 649177633Sdfr /* 650177633Sdfr * We failed to cancel - make sure our callback has 651177633Sdfr * completed before we continue. 652177633Sdfr */ 653177633Sdfr taskqueue_drain(taskqueue_thread, &af->af_task); 654177633Sdfr } 655177633Sdfr 656177633Sdfr mtx_lock(&host->nh_lock); 657177633Sdfr 658177633Sdfr if (!error) { 659191918Sdfr NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) " 660191918Sdfr "cancelled\n", af, host->nh_caller_name, host->nh_sysid); 661177633Sdfr 662177633Sdfr /* 663177633Sdfr * Remove from the nh_pending list and free now that 664177633Sdfr * we are safe from the callback. 665177633Sdfr */ 666177633Sdfr TAILQ_REMOVE(&host->nh_pending, af, af_link); 667177633Sdfr mtx_unlock(&host->nh_lock); 668177633Sdfr nlm_free_async_lock(af); 669177633Sdfr mtx_lock(&host->nh_lock); 670177633Sdfr } 671177633Sdfr 672177633Sdfr return (error); 673177633Sdfr} 674177633Sdfr 675177633Sdfrstatic void 676197840Szmlnlm_check_expired_locks(struct nlm_host *host) 677177633Sdfr{ 678177633Sdfr struct nlm_async_lock *af; 679197840Szml time_t uptime = time_uptime; 680177633Sdfr 681177633Sdfr mtx_lock(&host->nh_lock); 682197840Szml while ((af = TAILQ_FIRST(&host->nh_granted)) != NULL 683197840Szml && uptime >= af->af_expiretime) { 684197840Szml NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) expired," 685197840Szml " cookie %d:%d\n", af, af->af_host->nh_caller_name, 686197840Szml af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie), 687197840Szml ng_cookie(&af->af_granted.cookie)); 688197840Szml TAILQ_REMOVE(&host->nh_granted, af, af_link); 689197840Szml mtx_unlock(&host->nh_lock); 690197840Szml nlm_free_async_lock(af); 691197840Szml mtx_lock(&host->nh_lock); 692197840Szml } 693177633Sdfr while ((af = TAILQ_FIRST(&host->nh_finished)) != NULL) { 694177633Sdfr TAILQ_REMOVE(&host->nh_finished, af, af_link); 695177633Sdfr mtx_unlock(&host->nh_lock); 696177633Sdfr nlm_free_async_lock(af); 697177633Sdfr mtx_lock(&host->nh_lock); 698177633Sdfr } 699177633Sdfr mtx_unlock(&host->nh_lock); 700177633Sdfr} 701177633Sdfr 702177633Sdfr/* 703180025Sdfr * Free resources used by a host. This is called after the reference 704180025Sdfr * count has reached zero so it doesn't need to worry about locks. 705177633Sdfr */ 706177633Sdfrstatic void 707180025Sdfrnlm_host_destroy(struct nlm_host *host) 708177633Sdfr{ 709180025Sdfr 710180025Sdfr mtx_lock(&nlm_global_lock); 711180025Sdfr TAILQ_REMOVE(&nlm_hosts, host, nh_link); 712180025Sdfr mtx_unlock(&nlm_global_lock); 713180025Sdfr 714184588Sdfr if (host->nh_srvrpc.nr_client) 715184588Sdfr CLNT_RELEASE(host->nh_srvrpc.nr_client); 716184588Sdfr if (host->nh_clntrpc.nr_client) 717184588Sdfr CLNT_RELEASE(host->nh_clntrpc.nr_client); 718180025Sdfr mtx_destroy(&host->nh_lock); 719180025Sdfr sysctl_ctx_free(&host->nh_sysctl); 720180025Sdfr free(host, M_NLM); 721180025Sdfr} 722180025Sdfr 723180025Sdfr/* 724180025Sdfr * Thread start callback for client lock recovery 725180025Sdfr */ 726180025Sdfrstatic void 727180025Sdfrnlm_client_recovery_start(void *arg) 728180025Sdfr{ 729180025Sdfr struct nlm_host *host = (struct nlm_host *) arg; 730180025Sdfr 731191918Sdfr NLM_DEBUG(1, "NLM: client lock recovery for %s started\n", 732191918Sdfr host->nh_caller_name); 733180025Sdfr 734180025Sdfr nlm_client_recovery(host); 735180025Sdfr 736191918Sdfr NLM_DEBUG(1, "NLM: client lock recovery for %s completed\n", 737191918Sdfr host->nh_caller_name); 738180025Sdfr 739180025Sdfr host->nh_monstate = NLM_MONITORED; 740180025Sdfr nlm_host_release(host); 741180025Sdfr 742180025Sdfr kthread_exit(); 743180025Sdfr} 744180025Sdfr 745180025Sdfr/* 746180025Sdfr * This is called when we receive a host state change notification. We 747180025Sdfr * unlock any active locks owned by the host. When rpc.lockd is 748180025Sdfr * shutting down, this function is called with newstate set to zero 749180025Sdfr * which allows us to cancel any pending async locks and clear the 750180025Sdfr * locking state. 751180025Sdfr */ 752180025Sdfrstatic void 753180025Sdfrnlm_host_notify(struct nlm_host *host, int newstate) 754180025Sdfr{ 755177633Sdfr struct nlm_async_lock *af; 756177633Sdfr 757177633Sdfr if (newstate) { 758191918Sdfr NLM_DEBUG(1, "NLM: host %s (sysid %d) rebooted, new " 759191918Sdfr "state is %d\n", host->nh_caller_name, 760191918Sdfr host->nh_sysid, newstate); 761177633Sdfr } 762177633Sdfr 763177633Sdfr /* 764177633Sdfr * Cancel any pending async locks for this host. 765177633Sdfr */ 766177633Sdfr mtx_lock(&host->nh_lock); 767177633Sdfr while ((af = TAILQ_FIRST(&host->nh_pending)) != NULL) { 768177633Sdfr /* 769177633Sdfr * nlm_cancel_async_lock will remove the entry from 770177633Sdfr * nh_pending and free it. 771177633Sdfr */ 772177633Sdfr nlm_cancel_async_lock(af); 773177633Sdfr } 774177633Sdfr mtx_unlock(&host->nh_lock); 775197840Szml nlm_check_expired_locks(host); 776177633Sdfr 777177633Sdfr /* 778180025Sdfr * The host just rebooted - trash its locks. 779177633Sdfr */ 780177633Sdfr lf_clearremotesys(host->nh_sysid); 781177633Sdfr host->nh_state = newstate; 782177633Sdfr 783177633Sdfr /* 784180025Sdfr * If we have any remote locks for this host (i.e. it 785180025Sdfr * represents a remote NFS server that our local NFS client 786180025Sdfr * has locks for), start a recovery thread. 787177633Sdfr */ 788180025Sdfr if (newstate != 0 789180025Sdfr && host->nh_monstate != NLM_RECOVERING 790180025Sdfr && lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid) > 0) { 791180025Sdfr struct thread *td; 792180025Sdfr host->nh_monstate = NLM_RECOVERING; 793180025Sdfr refcount_acquire(&host->nh_refs); 794180025Sdfr kthread_add(nlm_client_recovery_start, host, curproc, &td, 0, 0, 795180025Sdfr "NFS lock recovery for %s", host->nh_caller_name); 796177633Sdfr } 797177633Sdfr} 798177633Sdfr 799177633Sdfr/* 800177633Sdfr * Sysctl handler to count the number of locks for a sysid. 801177633Sdfr */ 802177633Sdfrstatic int 803177633Sdfrnlm_host_lock_count_sysctl(SYSCTL_HANDLER_ARGS) 804177633Sdfr{ 805177633Sdfr struct nlm_host *host; 806177633Sdfr int count; 807177633Sdfr 808177633Sdfr host = oidp->oid_arg1; 809177633Sdfr count = lf_countlocks(host->nh_sysid); 810177633Sdfr return sysctl_handle_int(oidp, &count, 0, req); 811177633Sdfr} 812177633Sdfr 813177633Sdfr/* 814180025Sdfr * Sysctl handler to count the number of client locks for a sysid. 815180025Sdfr */ 816180025Sdfrstatic int 817180025Sdfrnlm_host_client_lock_count_sysctl(SYSCTL_HANDLER_ARGS) 818180025Sdfr{ 819180025Sdfr struct nlm_host *host; 820180025Sdfr int count; 821180025Sdfr 822180025Sdfr host = oidp->oid_arg1; 823180025Sdfr count = lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid); 824180025Sdfr return sysctl_handle_int(oidp, &count, 0, req); 825180025Sdfr} 826180025Sdfr 827180025Sdfr/* 828177633Sdfr * Create a new NLM host. 829177633Sdfr */ 830177633Sdfrstatic struct nlm_host * 831177633Sdfrnlm_create_host(const char* caller_name) 832177633Sdfr{ 833177633Sdfr struct nlm_host *host; 834177633Sdfr struct sysctl_oid *oid; 835177633Sdfr 836180025Sdfr mtx_assert(&nlm_global_lock, MA_OWNED); 837180025Sdfr 838191918Sdfr NLM_DEBUG(1, "NLM: new host %s (sysid %d)\n", 839191918Sdfr caller_name, nlm_next_sysid); 840180025Sdfr host = malloc(sizeof(struct nlm_host), M_NLM, M_NOWAIT|M_ZERO); 841180025Sdfr if (!host) 842180025Sdfr return (NULL); 843177633Sdfr mtx_init(&host->nh_lock, "nh_lock", NULL, MTX_DEF); 844180025Sdfr host->nh_refs = 1; 845180025Sdfr strlcpy(host->nh_caller_name, caller_name, MAXNAMELEN); 846177633Sdfr host->nh_sysid = nlm_next_sysid++; 847177633Sdfr snprintf(host->nh_sysid_string, sizeof(host->nh_sysid_string), 848177633Sdfr "%d", host->nh_sysid); 849177633Sdfr host->nh_vers = 0; 850177633Sdfr host->nh_state = 0; 851178112Sdfr host->nh_monstate = NLM_UNMONITORED; 852197840Szml host->nh_grantcookie = 1; 853177633Sdfr TAILQ_INIT(&host->nh_pending); 854197840Szml TAILQ_INIT(&host->nh_granted); 855177633Sdfr TAILQ_INIT(&host->nh_finished); 856177633Sdfr TAILQ_INSERT_TAIL(&nlm_hosts, host, nh_link); 857177633Sdfr 858180025Sdfr mtx_unlock(&nlm_global_lock); 859180025Sdfr 860177633Sdfr sysctl_ctx_init(&host->nh_sysctl); 861177633Sdfr oid = SYSCTL_ADD_NODE(&host->nh_sysctl, 862177633Sdfr SYSCTL_STATIC_CHILDREN(_vfs_nlm_sysid), 863177633Sdfr OID_AUTO, host->nh_sysid_string, CTLFLAG_RD, NULL, ""); 864177633Sdfr SYSCTL_ADD_STRING(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 865177633Sdfr "hostname", CTLFLAG_RD, host->nh_caller_name, 0, ""); 866177633Sdfr SYSCTL_ADD_INT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 867177633Sdfr "version", CTLFLAG_RD, &host->nh_vers, 0, ""); 868177633Sdfr SYSCTL_ADD_INT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 869178112Sdfr "monitored", CTLFLAG_RD, &host->nh_monstate, 0, ""); 870177633Sdfr SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 871177633Sdfr "lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0, 872177633Sdfr nlm_host_lock_count_sysctl, "I", ""); 873180025Sdfr SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 874180025Sdfr "client_lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0, 875180025Sdfr nlm_host_client_lock_count_sysctl, "I", ""); 876177633Sdfr 877180025Sdfr mtx_lock(&nlm_global_lock); 878180025Sdfr 879177633Sdfr return (host); 880177633Sdfr} 881177633Sdfr 882177633Sdfr/* 883192501Srmacklem * Acquire the next sysid for remote locks not handled by the NLM. 884192501Srmacklem */ 885192501Srmacklemuint32_t 886192501Srmacklemnlm_acquire_next_sysid(void) 887192501Srmacklem{ 888192501Srmacklem uint32_t next_sysid; 889192501Srmacklem 890192501Srmacklem mtx_lock(&nlm_global_lock); 891192501Srmacklem next_sysid = nlm_next_sysid++; 892192501Srmacklem mtx_unlock(&nlm_global_lock); 893192501Srmacklem return (next_sysid); 894192501Srmacklem} 895192501Srmacklem 896192501Srmacklem/* 897177633Sdfr * Return non-zero if the address parts of the two sockaddrs are the 898177633Sdfr * same. 899177633Sdfr */ 900177633Sdfrstatic int 901177633Sdfrnlm_compare_addr(const struct sockaddr *a, const struct sockaddr *b) 902177633Sdfr{ 903177633Sdfr const struct sockaddr_in *a4, *b4; 904177633Sdfr#ifdef INET6 905177633Sdfr const struct sockaddr_in6 *a6, *b6; 906177633Sdfr#endif 907177633Sdfr 908177633Sdfr if (a->sa_family != b->sa_family) 909177633Sdfr return (FALSE); 910177633Sdfr 911177633Sdfr switch (a->sa_family) { 912177633Sdfr case AF_INET: 913177633Sdfr a4 = (const struct sockaddr_in *) a; 914177633Sdfr b4 = (const struct sockaddr_in *) b; 915177633Sdfr return !memcmp(&a4->sin_addr, &b4->sin_addr, 916177633Sdfr sizeof(a4->sin_addr)); 917177633Sdfr#ifdef INET6 918177633Sdfr case AF_INET6: 919177633Sdfr a6 = (const struct sockaddr_in6 *) a; 920177633Sdfr b6 = (const struct sockaddr_in6 *) b; 921177633Sdfr return !memcmp(&a6->sin6_addr, &b6->sin6_addr, 922177633Sdfr sizeof(a6->sin6_addr)); 923177633Sdfr#endif 924177633Sdfr } 925177633Sdfr 926177633Sdfr return (0); 927177633Sdfr} 928177633Sdfr 929177633Sdfr/* 930177633Sdfr * Check for idle hosts and stop monitoring them. We could also free 931177633Sdfr * the host structure here, possibly after a larger timeout but that 932177633Sdfr * would require some care to avoid races with 933177633Sdfr * e.g. nlm_host_lock_count_sysctl. 934177633Sdfr */ 935177633Sdfrstatic void 936177633Sdfrnlm_check_idle(void) 937177633Sdfr{ 938177633Sdfr struct nlm_host *host; 939177633Sdfr 940180025Sdfr mtx_assert(&nlm_global_lock, MA_OWNED); 941180025Sdfr 942177633Sdfr if (time_uptime <= nlm_next_idle_check) 943177633Sdfr return; 944177633Sdfr 945177633Sdfr nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD; 946177633Sdfr 947177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 948178112Sdfr if (host->nh_monstate == NLM_MONITORED 949177633Sdfr && time_uptime > host->nh_idle_timeout) { 950180025Sdfr mtx_unlock(&nlm_global_lock); 951180025Sdfr if (lf_countlocks(host->nh_sysid) > 0 952180025Sdfr || lf_countlocks(NLM_SYSID_CLIENT 953180025Sdfr + host->nh_sysid)) { 954177633Sdfr host->nh_idle_timeout = 955177633Sdfr time_uptime + NLM_IDLE_TIMEOUT; 956180025Sdfr mtx_lock(&nlm_global_lock); 957177633Sdfr continue; 958177633Sdfr } 959177633Sdfr nlm_host_unmonitor(host); 960180025Sdfr mtx_lock(&nlm_global_lock); 961177633Sdfr } 962177633Sdfr } 963177633Sdfr} 964177633Sdfr 965177633Sdfr/* 966177633Sdfr * Search for an existing NLM host that matches the given name 967177633Sdfr * (typically the caller_name element of an nlm4_lock). If none is 968180025Sdfr * found, create a new host. If 'addr' is non-NULL, record the remote 969177633Sdfr * address of the host so that we can call it back for async 970180025Sdfr * responses. If 'vers' is greater than zero then record the NLM 971180025Sdfr * program version to use to communicate with this client. 972177633Sdfr */ 973177633Sdfrstruct nlm_host * 974180025Sdfrnlm_find_host_by_name(const char *name, const struct sockaddr *addr, 975180025Sdfr rpcvers_t vers) 976177633Sdfr{ 977177633Sdfr struct nlm_host *host; 978177633Sdfr 979180025Sdfr mtx_lock(&nlm_global_lock); 980177633Sdfr 981177633Sdfr /* 982177633Sdfr * The remote host is determined by caller_name. 983177633Sdfr */ 984177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 985177633Sdfr if (!strcmp(host->nh_caller_name, name)) 986177633Sdfr break; 987177633Sdfr } 988177633Sdfr 989180025Sdfr if (!host) { 990177633Sdfr host = nlm_create_host(name); 991180025Sdfr if (!host) { 992180025Sdfr mtx_unlock(&nlm_global_lock); 993180025Sdfr return (NULL); 994180025Sdfr } 995180025Sdfr } 996180025Sdfr refcount_acquire(&host->nh_refs); 997180025Sdfr 998177633Sdfr host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT; 999177633Sdfr 1000177633Sdfr /* 1001180025Sdfr * If we have an address for the host, record it so that we 1002180025Sdfr * can send async replies etc. 1003177633Sdfr */ 1004180025Sdfr if (addr) { 1005177633Sdfr 1006180025Sdfr KASSERT(addr->sa_len < sizeof(struct sockaddr_storage), 1007177633Sdfr ("Strange remote transport address length")); 1008177633Sdfr 1009177633Sdfr /* 1010177633Sdfr * If we have seen an address before and we currently 1011177633Sdfr * have an RPC client handle, make sure the address is 1012177633Sdfr * the same, otherwise discard the client handle. 1013177633Sdfr */ 1014184588Sdfr if (host->nh_addr.ss_len && host->nh_srvrpc.nr_client) { 1015177633Sdfr if (!nlm_compare_addr( 1016177633Sdfr (struct sockaddr *) &host->nh_addr, 1017180025Sdfr addr) 1018180025Sdfr || host->nh_vers != vers) { 1019180025Sdfr CLIENT *client; 1020180025Sdfr mtx_lock(&host->nh_lock); 1021184588Sdfr client = host->nh_srvrpc.nr_client; 1022184588Sdfr host->nh_srvrpc.nr_client = NULL; 1023180025Sdfr mtx_unlock(&host->nh_lock); 1024180025Sdfr if (client) { 1025180025Sdfr CLNT_RELEASE(client); 1026180025Sdfr } 1027177633Sdfr } 1028177633Sdfr } 1029180025Sdfr memcpy(&host->nh_addr, addr, addr->sa_len); 1030180025Sdfr host->nh_vers = vers; 1031177633Sdfr } 1032177633Sdfr 1033180025Sdfr nlm_check_idle(); 1034180025Sdfr 1035180025Sdfr mtx_unlock(&nlm_global_lock); 1036180025Sdfr 1037177633Sdfr return (host); 1038177633Sdfr} 1039177633Sdfr 1040177633Sdfr/* 1041177633Sdfr * Search for an existing NLM host that matches the given remote 1042177633Sdfr * address. If none is found, create a new host with the requested 1043177633Sdfr * address and remember 'vers' as the NLM protocol version to use for 1044177633Sdfr * that host. 1045177633Sdfr */ 1046177633Sdfrstruct nlm_host * 1047177633Sdfrnlm_find_host_by_addr(const struct sockaddr *addr, int vers) 1048177633Sdfr{ 1049180025Sdfr /* 1050180025Sdfr * Fake up a name using inet_ntop. This buffer is 1051180025Sdfr * large enough for an IPv6 address. 1052180025Sdfr */ 1053180025Sdfr char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; 1054177633Sdfr struct nlm_host *host; 1055177633Sdfr 1056180025Sdfr switch (addr->sa_family) { 1057180025Sdfr case AF_INET: 1058180025Sdfr __rpc_inet_ntop(AF_INET, 1059180025Sdfr &((const struct sockaddr_in *) addr)->sin_addr, 1060180025Sdfr tmp, sizeof tmp); 1061180025Sdfr break; 1062180025Sdfr#ifdef INET6 1063180025Sdfr case AF_INET6: 1064180025Sdfr __rpc_inet_ntop(AF_INET6, 1065180025Sdfr &((const struct sockaddr_in6 *) addr)->sin6_addr, 1066180025Sdfr tmp, sizeof tmp); 1067180025Sdfr break; 1068180025Sdfr#endif 1069180025Sdfr default: 1070180025Sdfr strcmp(tmp, "<unknown>"); 1071180025Sdfr } 1072177633Sdfr 1073180025Sdfr 1074180025Sdfr mtx_lock(&nlm_global_lock); 1075180025Sdfr 1076177633Sdfr /* 1077177633Sdfr * The remote host is determined by caller_name. 1078177633Sdfr */ 1079177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 1080177633Sdfr if (nlm_compare_addr(addr, 1081177633Sdfr (const struct sockaddr *) &host->nh_addr)) 1082177633Sdfr break; 1083177633Sdfr } 1084177633Sdfr 1085177633Sdfr if (!host) { 1086180025Sdfr host = nlm_create_host(tmp); 1087180025Sdfr if (!host) { 1088180025Sdfr mtx_unlock(&nlm_global_lock); 1089180025Sdfr return (NULL); 1090177633Sdfr } 1091177633Sdfr memcpy(&host->nh_addr, addr, addr->sa_len); 1092177633Sdfr host->nh_vers = vers; 1093177633Sdfr } 1094180025Sdfr refcount_acquire(&host->nh_refs); 1095180025Sdfr 1096177633Sdfr host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT; 1097177633Sdfr 1098180025Sdfr nlm_check_idle(); 1099180025Sdfr 1100180025Sdfr mtx_unlock(&nlm_global_lock); 1101180025Sdfr 1102177633Sdfr return (host); 1103177633Sdfr} 1104177633Sdfr 1105177633Sdfr/* 1106177633Sdfr * Find the NLM host that matches the value of 'sysid'. If none 1107177633Sdfr * exists, return NULL. 1108177633Sdfr */ 1109177633Sdfrstatic struct nlm_host * 1110177633Sdfrnlm_find_host_by_sysid(int sysid) 1111177633Sdfr{ 1112177633Sdfr struct nlm_host *host; 1113177633Sdfr 1114177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 1115180025Sdfr if (host->nh_sysid == sysid) { 1116180025Sdfr refcount_acquire(&host->nh_refs); 1117177633Sdfr return (host); 1118180025Sdfr } 1119177633Sdfr } 1120177633Sdfr 1121177633Sdfr return (NULL); 1122177633Sdfr} 1123177633Sdfr 1124180025Sdfrvoid nlm_host_release(struct nlm_host *host) 1125180025Sdfr{ 1126180025Sdfr if (refcount_release(&host->nh_refs)) { 1127180025Sdfr /* 1128180025Sdfr * Free the host 1129180025Sdfr */ 1130180025Sdfr nlm_host_destroy(host); 1131180025Sdfr } 1132180025Sdfr} 1133180025Sdfr 1134177633Sdfr/* 1135177633Sdfr * Unregister this NLM host with the local NSM due to idleness. 1136177633Sdfr */ 1137177633Sdfrstatic void 1138177633Sdfrnlm_host_unmonitor(struct nlm_host *host) 1139177633Sdfr{ 1140177633Sdfr mon_id smmonid; 1141177633Sdfr sm_stat_res smstat; 1142177633Sdfr struct timeval timo; 1143177633Sdfr enum clnt_stat stat; 1144177633Sdfr 1145191918Sdfr NLM_DEBUG(1, "NLM: unmonitoring %s (sysid %d)\n", 1146191918Sdfr host->nh_caller_name, host->nh_sysid); 1147177633Sdfr 1148177633Sdfr /* 1149177633Sdfr * We put our assigned system ID value in the priv field to 1150177633Sdfr * make it simpler to find the host if we are notified of a 1151177633Sdfr * host restart. 1152177633Sdfr */ 1153177633Sdfr smmonid.mon_name = host->nh_caller_name; 1154177633Sdfr smmonid.my_id.my_name = "localhost"; 1155177633Sdfr smmonid.my_id.my_prog = NLM_PROG; 1156177633Sdfr smmonid.my_id.my_vers = NLM_SM; 1157177633Sdfr smmonid.my_id.my_proc = NLM_SM_NOTIFY; 1158177633Sdfr 1159177633Sdfr timo.tv_sec = 25; 1160177633Sdfr timo.tv_usec = 0; 1161177633Sdfr stat = CLNT_CALL(nlm_nsm, SM_UNMON, 1162177633Sdfr (xdrproc_t) xdr_mon, &smmonid, 1163177633Sdfr (xdrproc_t) xdr_sm_stat, &smstat, timo); 1164177633Sdfr 1165177633Sdfr if (stat != RPC_SUCCESS) { 1166191918Sdfr NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat); 1167177633Sdfr return; 1168177633Sdfr } 1169177633Sdfr if (smstat.res_stat == stat_fail) { 1170191918Sdfr NLM_ERR("Local NSM refuses to unmonitor %s\n", 1171177633Sdfr host->nh_caller_name); 1172177633Sdfr return; 1173177633Sdfr } 1174177633Sdfr 1175178112Sdfr host->nh_monstate = NLM_UNMONITORED; 1176177633Sdfr} 1177177633Sdfr 1178177633Sdfr/* 1179177633Sdfr * Register this NLM host with the local NSM so that we can be 1180177633Sdfr * notified if it reboots. 1181177633Sdfr */ 1182180025Sdfrvoid 1183177633Sdfrnlm_host_monitor(struct nlm_host *host, int state) 1184177633Sdfr{ 1185177633Sdfr mon smmon; 1186177633Sdfr sm_stat_res smstat; 1187177633Sdfr struct timeval timo; 1188177633Sdfr enum clnt_stat stat; 1189177633Sdfr 1190177633Sdfr if (state && !host->nh_state) { 1191177633Sdfr /* 1192177633Sdfr * This is the first time we have seen an NSM state 1193177633Sdfr * value for this host. We record it here to help 1194177633Sdfr * detect host reboots. 1195177633Sdfr */ 1196177633Sdfr host->nh_state = state; 1197191918Sdfr NLM_DEBUG(1, "NLM: host %s (sysid %d) has NSM state %d\n", 1198191918Sdfr host->nh_caller_name, host->nh_sysid, state); 1199177633Sdfr } 1200177633Sdfr 1201180025Sdfr mtx_lock(&host->nh_lock); 1202180025Sdfr if (host->nh_monstate != NLM_UNMONITORED) { 1203180025Sdfr mtx_unlock(&host->nh_lock); 1204177633Sdfr return; 1205180025Sdfr } 1206180025Sdfr host->nh_monstate = NLM_MONITORED; 1207180025Sdfr mtx_unlock(&host->nh_lock); 1208177633Sdfr 1209191918Sdfr NLM_DEBUG(1, "NLM: monitoring %s (sysid %d)\n", 1210191918Sdfr host->nh_caller_name, host->nh_sysid); 1211177633Sdfr 1212177633Sdfr /* 1213177633Sdfr * We put our assigned system ID value in the priv field to 1214177633Sdfr * make it simpler to find the host if we are notified of a 1215177633Sdfr * host restart. 1216177633Sdfr */ 1217177633Sdfr smmon.mon_id.mon_name = host->nh_caller_name; 1218177633Sdfr smmon.mon_id.my_id.my_name = "localhost"; 1219177633Sdfr smmon.mon_id.my_id.my_prog = NLM_PROG; 1220177633Sdfr smmon.mon_id.my_id.my_vers = NLM_SM; 1221177633Sdfr smmon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; 1222177633Sdfr memcpy(smmon.priv, &host->nh_sysid, sizeof(host->nh_sysid)); 1223177633Sdfr 1224177633Sdfr timo.tv_sec = 25; 1225177633Sdfr timo.tv_usec = 0; 1226177633Sdfr stat = CLNT_CALL(nlm_nsm, SM_MON, 1227177633Sdfr (xdrproc_t) xdr_mon, &smmon, 1228177633Sdfr (xdrproc_t) xdr_sm_stat, &smstat, timo); 1229177633Sdfr 1230177633Sdfr if (stat != RPC_SUCCESS) { 1231191918Sdfr NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat); 1232177633Sdfr return; 1233177633Sdfr } 1234177633Sdfr if (smstat.res_stat == stat_fail) { 1235191918Sdfr NLM_ERR("Local NSM refuses to monitor %s\n", 1236177633Sdfr host->nh_caller_name); 1237180025Sdfr mtx_lock(&host->nh_lock); 1238178112Sdfr host->nh_monstate = NLM_MONITOR_FAILED; 1239180025Sdfr mtx_unlock(&host->nh_lock); 1240177633Sdfr return; 1241177633Sdfr } 1242177633Sdfr 1243178112Sdfr host->nh_monstate = NLM_MONITORED; 1244177633Sdfr} 1245177633Sdfr 1246177633Sdfr/* 1247177633Sdfr * Return an RPC client handle that can be used to talk to the NLM 1248177633Sdfr * running on the given host. 1249177633Sdfr */ 1250177633SdfrCLIENT * 1251184588Sdfrnlm_host_get_rpc(struct nlm_host *host, bool_t isserver) 1252177633Sdfr{ 1253184588Sdfr struct nlm_rpc *rpc; 1254180025Sdfr CLIENT *client; 1255177633Sdfr 1256180025Sdfr mtx_lock(&host->nh_lock); 1257180025Sdfr 1258184588Sdfr if (isserver) 1259184588Sdfr rpc = &host->nh_srvrpc; 1260184588Sdfr else 1261184588Sdfr rpc = &host->nh_clntrpc; 1262184588Sdfr 1263179425Sdfr /* 1264180025Sdfr * We can't hold onto RPC handles for too long - the async 1265179425Sdfr * call/reply protocol used by some NLM clients makes it hard 1266179425Sdfr * to tell when they change port numbers (e.g. after a 1267179425Sdfr * reboot). Note that if a client reboots while it isn't 1268179425Sdfr * holding any locks, it won't bother to notify us. We 1269179425Sdfr * expire the RPC handles after two minutes. 1270179425Sdfr */ 1271184588Sdfr if (rpc->nr_client && time_uptime > rpc->nr_create_time + 2*60) { 1272184588Sdfr client = rpc->nr_client; 1273184588Sdfr rpc->nr_client = NULL; 1274180025Sdfr mtx_unlock(&host->nh_lock); 1275180025Sdfr CLNT_RELEASE(client); 1276180025Sdfr mtx_lock(&host->nh_lock); 1277179425Sdfr } 1278179425Sdfr 1279184588Sdfr if (!rpc->nr_client) { 1280180025Sdfr mtx_unlock(&host->nh_lock); 1281180025Sdfr client = nlm_get_rpc((struct sockaddr *)&host->nh_addr, 1282180025Sdfr NLM_PROG, host->nh_vers); 1283180025Sdfr mtx_lock(&host->nh_lock); 1284177633Sdfr 1285180025Sdfr if (client) { 1286184588Sdfr if (rpc->nr_client) { 1287180025Sdfr mtx_unlock(&host->nh_lock); 1288180025Sdfr CLNT_DESTROY(client); 1289180025Sdfr mtx_lock(&host->nh_lock); 1290180025Sdfr } else { 1291184588Sdfr rpc->nr_client = client; 1292184588Sdfr rpc->nr_create_time = time_uptime; 1293180025Sdfr } 1294180025Sdfr } 1295180025Sdfr } 1296180025Sdfr 1297184588Sdfr client = rpc->nr_client; 1298180025Sdfr if (client) 1299180025Sdfr CLNT_ACQUIRE(client); 1300180025Sdfr mtx_unlock(&host->nh_lock); 1301180025Sdfr 1302180025Sdfr return (client); 1303180025Sdfr 1304180025Sdfr} 1305180025Sdfr 1306180025Sdfrint nlm_host_get_sysid(struct nlm_host *host) 1307180025Sdfr{ 1308180025Sdfr 1309180025Sdfr return (host->nh_sysid); 1310180025Sdfr} 1311180025Sdfr 1312180025Sdfrint 1313180025Sdfrnlm_host_get_state(struct nlm_host *host) 1314180025Sdfr{ 1315180025Sdfr 1316180025Sdfr return (host->nh_state); 1317180025Sdfr} 1318180025Sdfr 1319180025Sdfrvoid * 1320180025Sdfrnlm_register_wait_lock(struct nlm4_lock *lock, struct vnode *vp) 1321180025Sdfr{ 1322180025Sdfr struct nlm_waiting_lock *nw; 1323180025Sdfr 1324180025Sdfr nw = malloc(sizeof(struct nlm_waiting_lock), M_NLM, M_WAITOK); 1325180025Sdfr nw->nw_lock = *lock; 1326180025Sdfr memcpy(&nw->nw_fh.fh_bytes, nw->nw_lock.fh.n_bytes, 1327180025Sdfr nw->nw_lock.fh.n_len); 1328180025Sdfr nw->nw_lock.fh.n_bytes = nw->nw_fh.fh_bytes; 1329180025Sdfr nw->nw_waiting = TRUE; 1330180025Sdfr nw->nw_vp = vp; 1331180025Sdfr mtx_lock(&nlm_global_lock); 1332180025Sdfr TAILQ_INSERT_TAIL(&nlm_waiting_locks, nw, nw_link); 1333180025Sdfr mtx_unlock(&nlm_global_lock); 1334180025Sdfr 1335180025Sdfr return nw; 1336180025Sdfr} 1337180025Sdfr 1338180025Sdfrvoid 1339180025Sdfrnlm_deregister_wait_lock(void *handle) 1340180025Sdfr{ 1341180025Sdfr struct nlm_waiting_lock *nw = handle; 1342180025Sdfr 1343180025Sdfr mtx_lock(&nlm_global_lock); 1344180025Sdfr TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link); 1345180025Sdfr mtx_unlock(&nlm_global_lock); 1346180025Sdfr 1347180025Sdfr free(nw, M_NLM); 1348180025Sdfr} 1349180025Sdfr 1350180025Sdfrint 1351180025Sdfrnlm_wait_lock(void *handle, int timo) 1352180025Sdfr{ 1353180025Sdfr struct nlm_waiting_lock *nw = handle; 1354180025Sdfr int error; 1355180025Sdfr 1356177633Sdfr /* 1357180025Sdfr * If the granted message arrived before we got here, 1358180025Sdfr * nw->nw_waiting will be FALSE - in that case, don't sleep. 1359177633Sdfr */ 1360180025Sdfr mtx_lock(&nlm_global_lock); 1361180025Sdfr error = 0; 1362180025Sdfr if (nw->nw_waiting) 1363180025Sdfr error = msleep(nw, &nlm_global_lock, PCATCH, "nlmlock", timo); 1364180025Sdfr TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link); 1365180025Sdfr if (error) { 1366180025Sdfr /* 1367180025Sdfr * The granted message may arrive after the 1368180025Sdfr * interrupt/timeout but before we manage to lock the 1369180025Sdfr * mutex. Detect this by examining nw_lock. 1370180025Sdfr */ 1371180025Sdfr if (!nw->nw_waiting) 1372180025Sdfr error = 0; 1373180025Sdfr } else { 1374180025Sdfr /* 1375180025Sdfr * If nlm_cancel_wait is called, then error will be 1376180025Sdfr * zero but nw_waiting will still be TRUE. We 1377180025Sdfr * translate this into EINTR. 1378180025Sdfr */ 1379180025Sdfr if (nw->nw_waiting) 1380180025Sdfr error = EINTR; 1381180025Sdfr } 1382180025Sdfr mtx_unlock(&nlm_global_lock); 1383177633Sdfr 1384180025Sdfr free(nw, M_NLM); 1385177633Sdfr 1386180025Sdfr return (error); 1387180025Sdfr} 1388180025Sdfr 1389180025Sdfrvoid 1390180025Sdfrnlm_cancel_wait(struct vnode *vp) 1391180025Sdfr{ 1392180025Sdfr struct nlm_waiting_lock *nw; 1393180025Sdfr 1394180025Sdfr mtx_lock(&nlm_global_lock); 1395180025Sdfr TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) { 1396180025Sdfr if (nw->nw_vp == vp) { 1397180025Sdfr wakeup(nw); 1398180025Sdfr } 1399177633Sdfr } 1400180025Sdfr mtx_unlock(&nlm_global_lock); 1401177633Sdfr} 1402177633Sdfr 1403180025Sdfr 1404177633Sdfr/**********************************************************************/ 1405177633Sdfr 1406177633Sdfr/* 1407177633Sdfr * Syscall interface with userland. 1408177633Sdfr */ 1409177633Sdfr 1410177633Sdfrextern void nlm_prog_0(struct svc_req *rqstp, SVCXPRT *transp); 1411177633Sdfrextern void nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp); 1412177633Sdfrextern void nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp); 1413177633Sdfrextern void nlm_prog_4(struct svc_req *rqstp, SVCXPRT *transp); 1414177633Sdfr 1415177633Sdfrstatic int 1416177633Sdfrnlm_register_services(SVCPOOL *pool, int addr_count, char **addrs) 1417177633Sdfr{ 1418177633Sdfr static rpcvers_t versions[] = { 1419177633Sdfr NLM_SM, NLM_VERS, NLM_VERSX, NLM_VERS4 1420177633Sdfr }; 1421177633Sdfr static void (*dispatchers[])(struct svc_req *, SVCXPRT *) = { 1422177633Sdfr nlm_prog_0, nlm_prog_1, nlm_prog_3, nlm_prog_4 1423177633Sdfr }; 1424177633Sdfr static const int version_count = sizeof(versions) / sizeof(versions[0]); 1425177633Sdfr 1426177633Sdfr SVCXPRT **xprts; 1427177633Sdfr char netid[16]; 1428177633Sdfr char uaddr[128]; 1429177633Sdfr struct netconfig *nconf; 1430177633Sdfr int i, j, error; 1431177633Sdfr 1432177633Sdfr if (!addr_count) { 1433191918Sdfr NLM_ERR("NLM: no service addresses given - can't start server"); 1434177633Sdfr return (EINVAL); 1435177633Sdfr } 1436177633Sdfr 1437194407Srmacklem xprts = malloc(addr_count * sizeof(SVCXPRT *), M_NLM, M_WAITOK|M_ZERO); 1438177633Sdfr for (i = 0; i < version_count; i++) { 1439177633Sdfr for (j = 0; j < addr_count; j++) { 1440177633Sdfr /* 1441177633Sdfr * Create transports for the first version and 1442177633Sdfr * then just register everything else to the 1443177633Sdfr * same transports. 1444177633Sdfr */ 1445177633Sdfr if (i == 0) { 1446177633Sdfr char *up; 1447177633Sdfr 1448177633Sdfr error = copyin(&addrs[2*j], &up, 1449177633Sdfr sizeof(char*)); 1450177633Sdfr if (error) 1451177633Sdfr goto out; 1452177633Sdfr error = copyinstr(up, netid, sizeof(netid), 1453177633Sdfr NULL); 1454177633Sdfr if (error) 1455177633Sdfr goto out; 1456177633Sdfr error = copyin(&addrs[2*j+1], &up, 1457177633Sdfr sizeof(char*)); 1458177633Sdfr if (error) 1459177633Sdfr goto out; 1460177633Sdfr error = copyinstr(up, uaddr, sizeof(uaddr), 1461177633Sdfr NULL); 1462177633Sdfr if (error) 1463177633Sdfr goto out; 1464177633Sdfr nconf = getnetconfigent(netid); 1465177633Sdfr if (!nconf) { 1466191918Sdfr NLM_ERR("Can't lookup netid %s\n", 1467177633Sdfr netid); 1468177633Sdfr error = EINVAL; 1469177633Sdfr goto out; 1470177633Sdfr } 1471177633Sdfr xprts[j] = svc_tp_create(pool, dispatchers[i], 1472177633Sdfr NLM_PROG, versions[i], uaddr, nconf); 1473177633Sdfr if (!xprts[j]) { 1474191918Sdfr NLM_ERR("NLM: unable to create " 1475177633Sdfr "(NLM_PROG, %d).\n", versions[i]); 1476177633Sdfr error = EINVAL; 1477177633Sdfr goto out; 1478177633Sdfr } 1479177633Sdfr freenetconfigent(nconf); 1480177633Sdfr } else { 1481177633Sdfr nconf = getnetconfigent(xprts[j]->xp_netid); 1482177633Sdfr rpcb_unset(NLM_PROG, versions[i], nconf); 1483177633Sdfr if (!svc_reg(xprts[j], NLM_PROG, versions[i], 1484177633Sdfr dispatchers[i], nconf)) { 1485191918Sdfr NLM_ERR("NLM: can't register " 1486177633Sdfr "(NLM_PROG, %d)\n", versions[i]); 1487177633Sdfr error = EINVAL; 1488177633Sdfr goto out; 1489177633Sdfr } 1490177633Sdfr } 1491177633Sdfr } 1492177633Sdfr } 1493177633Sdfr error = 0; 1494177633Sdfrout: 1495194407Srmacklem for (j = 0; j < addr_count; j++) { 1496194407Srmacklem if (xprts[j]) 1497194407Srmacklem SVC_RELEASE(xprts[j]); 1498194407Srmacklem } 1499177633Sdfr free(xprts, M_NLM); 1500177633Sdfr return (error); 1501177633Sdfr} 1502177633Sdfr 1503177633Sdfr/* 1504177633Sdfr * Main server entry point. Contacts the local NSM to get its current 1505177633Sdfr * state and send SM_UNMON_ALL. Registers the NLM services and then 1506177633Sdfr * services requests. Does not return until the server is interrupted 1507177633Sdfr * by a signal. 1508177633Sdfr */ 1509177633Sdfrstatic int 1510177633Sdfrnlm_server_main(int addr_count, char **addrs) 1511177633Sdfr{ 1512177633Sdfr struct thread *td = curthread; 1513177633Sdfr int error; 1514178033Sdfr SVCPOOL *pool = NULL; 1515177633Sdfr struct sockopt opt; 1516177633Sdfr int portlow; 1517177633Sdfr#ifdef INET6 1518177633Sdfr struct sockaddr_in6 sin6; 1519177633Sdfr#endif 1520177633Sdfr struct sockaddr_in sin; 1521177633Sdfr my_id id; 1522177633Sdfr sm_stat smstat; 1523177633Sdfr struct timeval timo; 1524177633Sdfr enum clnt_stat stat; 1525180025Sdfr struct nlm_host *host, *nhost; 1526180025Sdfr struct nlm_waiting_lock *nw; 1527180025Sdfr vop_advlock_t *old_nfs_advlock; 1528180025Sdfr vop_reclaim_t *old_nfs_reclaim; 1529180069Savatar int v4_used; 1530180069Savatar#ifdef INET6 1531180069Savatar int v6_used; 1532180069Savatar#endif 1533177633Sdfr 1534177633Sdfr if (nlm_socket) { 1535191918Sdfr NLM_ERR("NLM: can't start server - " 1536191918Sdfr "it appears to be running already\n"); 1537177633Sdfr return (EPERM); 1538177633Sdfr } 1539177633Sdfr 1540177633Sdfr memset(&opt, 0, sizeof(opt)); 1541177633Sdfr 1542177633Sdfr nlm_socket = NULL; 1543177633Sdfr error = socreate(AF_INET, &nlm_socket, SOCK_DGRAM, 0, 1544177633Sdfr td->td_ucred, td); 1545177633Sdfr if (error) { 1546191918Sdfr NLM_ERR("NLM: can't create IPv4 socket - error %d\n", error); 1547177633Sdfr return (error); 1548177633Sdfr } 1549177633Sdfr opt.sopt_dir = SOPT_SET; 1550177633Sdfr opt.sopt_level = IPPROTO_IP; 1551177633Sdfr opt.sopt_name = IP_PORTRANGE; 1552177633Sdfr portlow = IP_PORTRANGE_LOW; 1553177633Sdfr opt.sopt_val = &portlow; 1554177633Sdfr opt.sopt_valsize = sizeof(portlow); 1555177633Sdfr sosetopt(nlm_socket, &opt); 1556177633Sdfr 1557177633Sdfr#ifdef INET6 1558177633Sdfr nlm_socket6 = NULL; 1559177633Sdfr error = socreate(AF_INET6, &nlm_socket6, SOCK_DGRAM, 0, 1560177633Sdfr td->td_ucred, td); 1561177633Sdfr if (error) { 1562191918Sdfr NLM_ERR("NLM: can't create IPv6 socket - error %d\n", error); 1563180025Sdfr goto out; 1564177633Sdfr return (error); 1565177633Sdfr } 1566177633Sdfr opt.sopt_dir = SOPT_SET; 1567177633Sdfr opt.sopt_level = IPPROTO_IPV6; 1568177633Sdfr opt.sopt_name = IPV6_PORTRANGE; 1569177633Sdfr portlow = IPV6_PORTRANGE_LOW; 1570177633Sdfr opt.sopt_val = &portlow; 1571177633Sdfr opt.sopt_valsize = sizeof(portlow); 1572177633Sdfr sosetopt(nlm_socket6, &opt); 1573177633Sdfr#endif 1574177633Sdfr 1575180025Sdfr nlm_auth = authunix_create(curthread->td_ucred); 1576180025Sdfr 1577177633Sdfr#ifdef INET6 1578177633Sdfr memset(&sin6, 0, sizeof(sin6)); 1579177633Sdfr sin6.sin6_len = sizeof(sin6); 1580177633Sdfr sin6.sin6_family = AF_INET6; 1581177633Sdfr sin6.sin6_addr = in6addr_loopback; 1582177633Sdfr nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin6, SM_PROG, SM_VERS); 1583177633Sdfr if (!nlm_nsm) { 1584177633Sdfr#endif 1585177633Sdfr memset(&sin, 0, sizeof(sin)); 1586177633Sdfr sin.sin_len = sizeof(sin); 1587178033Sdfr sin.sin_family = AF_INET; 1588177633Sdfr sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 1589177633Sdfr nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin, SM_PROG, 1590177633Sdfr SM_VERS); 1591177633Sdfr#ifdef INET6 1592177633Sdfr } 1593177633Sdfr#endif 1594177633Sdfr 1595177633Sdfr if (!nlm_nsm) { 1596191918Sdfr NLM_ERR("Can't start NLM - unable to contact NSM\n"); 1597178033Sdfr error = EINVAL; 1598178033Sdfr goto out; 1599177633Sdfr } 1600177633Sdfr 1601184588Sdfr pool = svcpool_create("NLM", NULL); 1602177633Sdfr 1603177633Sdfr error = nlm_register_services(pool, addr_count, addrs); 1604177633Sdfr if (error) 1605177633Sdfr goto out; 1606177633Sdfr 1607177633Sdfr memset(&id, 0, sizeof(id)); 1608177633Sdfr id.my_name = "NFS NLM"; 1609177633Sdfr 1610177633Sdfr timo.tv_sec = 25; 1611177633Sdfr timo.tv_usec = 0; 1612177633Sdfr stat = CLNT_CALL(nlm_nsm, SM_UNMON_ALL, 1613177633Sdfr (xdrproc_t) xdr_my_id, &id, 1614177633Sdfr (xdrproc_t) xdr_sm_stat, &smstat, timo); 1615177633Sdfr 1616177633Sdfr if (stat != RPC_SUCCESS) { 1617177633Sdfr struct rpc_err err; 1618177633Sdfr 1619177633Sdfr CLNT_GETERR(nlm_nsm, &err); 1620191918Sdfr NLM_ERR("NLM: unexpected error contacting NSM, " 1621191918Sdfr "stat=%d, errno=%d\n", stat, err.re_errno); 1622177633Sdfr error = EINVAL; 1623177633Sdfr goto out; 1624177633Sdfr } 1625177633Sdfr 1626191918Sdfr NLM_DEBUG(1, "NLM: local NSM state is %d\n", smstat.state); 1627180025Sdfr nlm_nsm_state = smstat.state; 1628177633Sdfr 1629180025Sdfr old_nfs_advlock = nfs_advlock_p; 1630180025Sdfr nfs_advlock_p = nlm_advlock; 1631180025Sdfr old_nfs_reclaim = nfs_reclaim_p; 1632180025Sdfr nfs_reclaim_p = nlm_reclaim; 1633180025Sdfr 1634177633Sdfr svc_run(pool); 1635177633Sdfr error = 0; 1636177633Sdfr 1637180025Sdfr nfs_advlock_p = old_nfs_advlock; 1638180025Sdfr nfs_reclaim_p = old_nfs_reclaim; 1639180025Sdfr 1640177633Sdfrout: 1641177633Sdfr if (pool) 1642177633Sdfr svcpool_destroy(pool); 1643177633Sdfr 1644177633Sdfr /* 1645180025Sdfr * We are finished communicating with the NSM. 1646177633Sdfr */ 1647177633Sdfr if (nlm_nsm) { 1648180025Sdfr CLNT_RELEASE(nlm_nsm); 1649177633Sdfr nlm_nsm = NULL; 1650177633Sdfr } 1651180025Sdfr 1652180025Sdfr /* 1653180025Sdfr * Trash all the existing state so that if the server 1654180025Sdfr * restarts, it gets a clean slate. This is complicated by the 1655180025Sdfr * possibility that there may be other threads trying to make 1656180025Sdfr * client locking requests. 1657180025Sdfr * 1658180025Sdfr * First we fake a client reboot notification which will 1659180025Sdfr * cancel any pending async locks and purge remote lock state 1660180025Sdfr * from the local lock manager. We release the reference from 1661180025Sdfr * nlm_hosts to the host (which may remove it from the list 1662180025Sdfr * and free it). After this phase, the only entries in the 1663180025Sdfr * nlm_host list should be from other threads performing 1664180025Sdfr * client lock requests. We arrange to defer closing the 1665180025Sdfr * sockets until the last RPC client handle is released. 1666180025Sdfr */ 1667180025Sdfr v4_used = 0; 1668180025Sdfr#ifdef INET6 1669180025Sdfr v6_used = 0; 1670180025Sdfr#endif 1671180025Sdfr mtx_lock(&nlm_global_lock); 1672180025Sdfr TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) { 1673180025Sdfr wakeup(nw); 1674177633Sdfr } 1675180025Sdfr TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, nhost) { 1676180025Sdfr mtx_unlock(&nlm_global_lock); 1677180025Sdfr nlm_host_notify(host, 0); 1678180025Sdfr nlm_host_release(host); 1679180025Sdfr mtx_lock(&nlm_global_lock); 1680180025Sdfr } 1681180025Sdfr TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, nhost) { 1682180025Sdfr mtx_lock(&host->nh_lock); 1683184588Sdfr if (host->nh_srvrpc.nr_client 1684184588Sdfr || host->nh_clntrpc.nr_client) { 1685180025Sdfr if (host->nh_addr.ss_family == AF_INET) 1686180025Sdfr v4_used++; 1687180025Sdfr#ifdef INET6 1688180025Sdfr if (host->nh_addr.ss_family == AF_INET6) 1689180025Sdfr v6_used++; 1690180025Sdfr#endif 1691180025Sdfr /* 1692180025Sdfr * Note that the rpc over udp code copes 1693180025Sdfr * correctly with the fact that a socket may 1694180025Sdfr * be used by many rpc handles. 1695180025Sdfr */ 1696184588Sdfr if (host->nh_srvrpc.nr_client) 1697184588Sdfr CLNT_CONTROL(host->nh_srvrpc.nr_client, 1698184588Sdfr CLSET_FD_CLOSE, 0); 1699184588Sdfr if (host->nh_clntrpc.nr_client) 1700184588Sdfr CLNT_CONTROL(host->nh_clntrpc.nr_client, 1701184588Sdfr CLSET_FD_CLOSE, 0); 1702180025Sdfr } 1703180025Sdfr mtx_unlock(&host->nh_lock); 1704180025Sdfr } 1705180025Sdfr mtx_unlock(&nlm_global_lock); 1706177633Sdfr 1707180025Sdfr AUTH_DESTROY(nlm_auth); 1708180025Sdfr 1709180025Sdfr if (!v4_used) 1710180025Sdfr soclose(nlm_socket); 1711177633Sdfr nlm_socket = NULL; 1712177633Sdfr#ifdef INET6 1713180025Sdfr if (!v6_used) 1714180025Sdfr soclose(nlm_socket6); 1715177633Sdfr nlm_socket6 = NULL; 1716177633Sdfr#endif 1717177633Sdfr 1718177633Sdfr return (error); 1719177633Sdfr} 1720177633Sdfr 1721177633Sdfrint 1722177633Sdfrnlm_syscall(struct thread *td, struct nlm_syscall_args *uap) 1723177633Sdfr{ 1724177633Sdfr int error; 1725177633Sdfr 1726177685Sdfr#if __FreeBSD_version >= 700000 1727177633Sdfr error = priv_check(td, PRIV_NFS_LOCKD); 1728177685Sdfr#else 1729177685Sdfr error = suser(td); 1730177685Sdfr#endif 1731177633Sdfr if (error) 1732177633Sdfr return (error); 1733177633Sdfr 1734177633Sdfr nlm_debug_level = uap->debug_level; 1735177633Sdfr nlm_grace_threshold = time_uptime + uap->grace_period; 1736177633Sdfr nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD; 1737177633Sdfr 1738177633Sdfr return nlm_server_main(uap->addr_count, uap->addrs); 1739177633Sdfr} 1740177633Sdfr 1741177633Sdfr/**********************************************************************/ 1742177633Sdfr 1743177633Sdfr/* 1744177633Sdfr * NLM implementation details, called from the RPC stubs. 1745177633Sdfr */ 1746177633Sdfr 1747177633Sdfr 1748177633Sdfrvoid 1749177633Sdfrnlm_sm_notify(struct nlm_sm_status *argp) 1750177633Sdfr{ 1751177633Sdfr uint32_t sysid; 1752177633Sdfr struct nlm_host *host; 1753177633Sdfr 1754191918Sdfr NLM_DEBUG(3, "nlm_sm_notify(): mon_name = %s\n", argp->mon_name); 1755177633Sdfr memcpy(&sysid, &argp->priv, sizeof(sysid)); 1756177633Sdfr host = nlm_find_host_by_sysid(sysid); 1757180025Sdfr if (host) { 1758180025Sdfr nlm_host_notify(host, argp->state); 1759180025Sdfr nlm_host_release(host); 1760180025Sdfr } 1761177633Sdfr} 1762177633Sdfr 1763177633Sdfrstatic void 1764177633Sdfrnlm_convert_to_fhandle_t(fhandle_t *fhp, struct netobj *p) 1765177633Sdfr{ 1766177633Sdfr memcpy(fhp, p->n_bytes, sizeof(fhandle_t)); 1767177633Sdfr} 1768177633Sdfr 1769177633Sdfrstruct vfs_state { 1770177633Sdfr struct mount *vs_mp; 1771177633Sdfr struct vnode *vs_vp; 1772177633Sdfr int vs_vfslocked; 1773178112Sdfr int vs_vnlocked; 1774177633Sdfr}; 1775177633Sdfr 1776177633Sdfrstatic int 1777177633Sdfrnlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp, 1778177633Sdfr fhandle_t *fhp, struct vfs_state *vs) 1779177633Sdfr{ 1780184588Sdfr int error, exflags; 1781177633Sdfr struct ucred *cred = NULL, *credanon; 1782177633Sdfr 1783177633Sdfr memset(vs, 0, sizeof(*vs)); 1784177633Sdfr 1785177633Sdfr vs->vs_mp = vfs_getvfs(&fhp->fh_fsid); 1786177633Sdfr if (!vs->vs_mp) { 1787177633Sdfr return (ESTALE); 1788177633Sdfr } 1789177633Sdfr vs->vs_vfslocked = VFS_LOCK_GIANT(vs->vs_mp); 1790177633Sdfr 1791177633Sdfr error = VFS_CHECKEXP(vs->vs_mp, (struct sockaddr *)&host->nh_addr, 1792184588Sdfr &exflags, &credanon, NULL, NULL); 1793177633Sdfr if (error) 1794177633Sdfr goto out; 1795177633Sdfr 1796177633Sdfr if (exflags & MNT_EXRDONLY || (vs->vs_mp->mnt_flag & MNT_RDONLY)) { 1797177633Sdfr error = EROFS; 1798177633Sdfr goto out; 1799177633Sdfr } 1800177633Sdfr 1801177633Sdfr error = VFS_FHTOVP(vs->vs_mp, &fhp->fh_fid, &vs->vs_vp); 1802177633Sdfr if (error) 1803177633Sdfr goto out; 1804178112Sdfr vs->vs_vnlocked = TRUE; 1805177633Sdfr 1806184588Sdfr if (!svc_getcred(rqstp, &cred, NULL)) { 1807177633Sdfr error = EINVAL; 1808177633Sdfr goto out; 1809177633Sdfr } 1810177633Sdfr if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1811177633Sdfr crfree(cred); 1812191940Skan cred = credanon; 1813191940Skan credanon = NULL; 1814177633Sdfr } 1815177633Sdfr 1816177633Sdfr /* 1817177633Sdfr * Check cred. 1818177633Sdfr */ 1819177633Sdfr error = VOP_ACCESS(vs->vs_vp, VWRITE, cred, curthread); 1820177633Sdfr if (error) 1821177633Sdfr goto out; 1822177633Sdfr 1823178112Sdfr#if __FreeBSD_version < 800011 1824178112Sdfr VOP_UNLOCK(vs->vs_vp, 0, curthread); 1825178112Sdfr#else 1826178112Sdfr VOP_UNLOCK(vs->vs_vp, 0); 1827178112Sdfr#endif 1828178112Sdfr vs->vs_vnlocked = FALSE; 1829178112Sdfr 1830177633Sdfrout: 1831184588Sdfr if (cred) 1832177633Sdfr crfree(cred); 1833191940Skan if (credanon) 1834191940Skan crfree(credanon); 1835177633Sdfr 1836177633Sdfr return (error); 1837177633Sdfr} 1838177633Sdfr 1839177633Sdfrstatic void 1840177633Sdfrnlm_release_vfs_state(struct vfs_state *vs) 1841177633Sdfr{ 1842177633Sdfr 1843178112Sdfr if (vs->vs_vp) { 1844178112Sdfr if (vs->vs_vnlocked) 1845178112Sdfr vput(vs->vs_vp); 1846178112Sdfr else 1847178112Sdfr vrele(vs->vs_vp); 1848178112Sdfr } 1849177633Sdfr if (vs->vs_mp) 1850177633Sdfr vfs_rel(vs->vs_mp); 1851177633Sdfr VFS_UNLOCK_GIANT(vs->vs_vfslocked); 1852177633Sdfr} 1853177633Sdfr 1854177633Sdfrstatic nlm4_stats 1855177633Sdfrnlm_convert_error(int error) 1856177633Sdfr{ 1857177633Sdfr 1858177633Sdfr if (error == ESTALE) 1859177633Sdfr return nlm4_stale_fh; 1860177633Sdfr else if (error == EROFS) 1861177633Sdfr return nlm4_rofs; 1862177633Sdfr else 1863177633Sdfr return nlm4_failed; 1864177633Sdfr} 1865177633Sdfr 1866180025Sdfrint 1867180025Sdfrnlm_do_test(nlm4_testargs *argp, nlm4_testres *result, struct svc_req *rqstp, 1868180025Sdfr CLIENT **rpcp) 1869177633Sdfr{ 1870177633Sdfr fhandle_t fh; 1871177633Sdfr struct vfs_state vs; 1872177633Sdfr struct nlm_host *host, *bhost; 1873177633Sdfr int error, sysid; 1874177633Sdfr struct flock fl; 1875177633Sdfr 1876177633Sdfr memset(result, 0, sizeof(*result)); 1877180025Sdfr memset(&vs, 0, sizeof(vs)); 1878177633Sdfr 1879180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 1880184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 1881177633Sdfr if (!host) { 1882177633Sdfr result->stat.stat = nlm4_denied_nolocks; 1883180025Sdfr return (ENOMEM); 1884177633Sdfr } 1885177633Sdfr 1886191918Sdfr NLM_DEBUG(3, "nlm_do_test(): caller_name = %s (sysid = %d)\n", 1887191918Sdfr host->nh_caller_name, host->nh_sysid); 1888177633Sdfr 1889197840Szml nlm_check_expired_locks(host); 1890177633Sdfr sysid = host->nh_sysid; 1891177633Sdfr 1892177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1893177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1894177633Sdfr 1895177633Sdfr if (time_uptime < nlm_grace_threshold) { 1896177633Sdfr result->stat.stat = nlm4_denied_grace_period; 1897180025Sdfr goto out; 1898177633Sdfr } 1899177633Sdfr 1900177633Sdfr error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 1901177633Sdfr if (error) { 1902177633Sdfr result->stat.stat = nlm_convert_error(error); 1903177633Sdfr goto out; 1904177633Sdfr } 1905177633Sdfr 1906177633Sdfr fl.l_start = argp->alock.l_offset; 1907177633Sdfr fl.l_len = argp->alock.l_len; 1908177633Sdfr fl.l_pid = argp->alock.svid; 1909177633Sdfr fl.l_sysid = sysid; 1910177633Sdfr fl.l_whence = SEEK_SET; 1911177633Sdfr if (argp->exclusive) 1912177633Sdfr fl.l_type = F_WRLCK; 1913177633Sdfr else 1914177633Sdfr fl.l_type = F_RDLCK; 1915177633Sdfr error = VOP_ADVLOCK(vs.vs_vp, NULL, F_GETLK, &fl, F_REMOTE); 1916177633Sdfr if (error) { 1917177633Sdfr result->stat.stat = nlm4_failed; 1918177633Sdfr goto out; 1919177633Sdfr } 1920177633Sdfr 1921177633Sdfr if (fl.l_type == F_UNLCK) { 1922177633Sdfr result->stat.stat = nlm4_granted; 1923177633Sdfr } else { 1924177633Sdfr result->stat.stat = nlm4_denied; 1925177633Sdfr result->stat.nlm4_testrply_u.holder.exclusive = 1926177633Sdfr (fl.l_type == F_WRLCK); 1927177633Sdfr result->stat.nlm4_testrply_u.holder.svid = fl.l_pid; 1928177633Sdfr bhost = nlm_find_host_by_sysid(fl.l_sysid); 1929177633Sdfr if (bhost) { 1930177633Sdfr /* 1931177633Sdfr * We don't have any useful way of recording 1932177633Sdfr * the value of oh used in the original lock 1933177633Sdfr * request. Ideally, the test reply would have 1934177633Sdfr * a space for the owning host's name allowing 1935177633Sdfr * our caller's NLM to keep track. 1936177633Sdfr * 1937177633Sdfr * As far as I can see, Solaris uses an eight 1938177633Sdfr * byte structure for oh which contains a four 1939177633Sdfr * byte pid encoded in local byte order and 1940177633Sdfr * the first four bytes of the host 1941177633Sdfr * name. Linux uses a variable length string 1942177633Sdfr * 'pid@hostname' in ascii but doesn't even 1943177633Sdfr * return that in test replies. 1944177633Sdfr * 1945177633Sdfr * For the moment, return nothing in oh 1946177633Sdfr * (already zero'ed above). 1947177633Sdfr */ 1948180025Sdfr nlm_host_release(bhost); 1949177633Sdfr } 1950177633Sdfr result->stat.nlm4_testrply_u.holder.l_offset = fl.l_start; 1951177633Sdfr result->stat.nlm4_testrply_u.holder.l_len = fl.l_len; 1952177633Sdfr } 1953177633Sdfr 1954177633Sdfrout: 1955177633Sdfr nlm_release_vfs_state(&vs); 1956180025Sdfr if (rpcp) 1957184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 1958180025Sdfr nlm_host_release(host); 1959180025Sdfr return (0); 1960177633Sdfr} 1961177633Sdfr 1962180025Sdfrint 1963177633Sdfrnlm_do_lock(nlm4_lockargs *argp, nlm4_res *result, struct svc_req *rqstp, 1964180025Sdfr bool_t monitor, CLIENT **rpcp) 1965177633Sdfr{ 1966177633Sdfr fhandle_t fh; 1967177633Sdfr struct vfs_state vs; 1968177633Sdfr struct nlm_host *host; 1969177633Sdfr int error, sysid; 1970177633Sdfr struct flock fl; 1971177633Sdfr 1972177633Sdfr memset(result, 0, sizeof(*result)); 1973180025Sdfr memset(&vs, 0, sizeof(vs)); 1974177633Sdfr 1975180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 1976184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 1977177633Sdfr if (!host) { 1978177633Sdfr result->stat.stat = nlm4_denied_nolocks; 1979180025Sdfr return (ENOMEM); 1980177633Sdfr } 1981177633Sdfr 1982191918Sdfr NLM_DEBUG(3, "nlm_do_lock(): caller_name = %s (sysid = %d)\n", 1983191918Sdfr host->nh_caller_name, host->nh_sysid); 1984177633Sdfr 1985179488Sdfr if (monitor && host->nh_state && argp->state 1986179488Sdfr && host->nh_state != argp->state) { 1987179488Sdfr /* 1988179488Sdfr * The host rebooted without telling us. Trash its 1989179488Sdfr * locks. 1990179488Sdfr */ 1991180025Sdfr nlm_host_notify(host, argp->state); 1992179488Sdfr } 1993179488Sdfr 1994197840Szml nlm_check_expired_locks(host); 1995177633Sdfr sysid = host->nh_sysid; 1996177633Sdfr 1997177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1998177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1999177633Sdfr 2000177633Sdfr if (time_uptime < nlm_grace_threshold && !argp->reclaim) { 2001177633Sdfr result->stat.stat = nlm4_denied_grace_period; 2002180025Sdfr goto out; 2003177633Sdfr } 2004177633Sdfr 2005177633Sdfr error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 2006177633Sdfr if (error) { 2007177633Sdfr result->stat.stat = nlm_convert_error(error); 2008177633Sdfr goto out; 2009177633Sdfr } 2010177633Sdfr 2011177633Sdfr fl.l_start = argp->alock.l_offset; 2012177633Sdfr fl.l_len = argp->alock.l_len; 2013177633Sdfr fl.l_pid = argp->alock.svid; 2014177633Sdfr fl.l_sysid = sysid; 2015177633Sdfr fl.l_whence = SEEK_SET; 2016177633Sdfr if (argp->exclusive) 2017177633Sdfr fl.l_type = F_WRLCK; 2018177633Sdfr else 2019177633Sdfr fl.l_type = F_RDLCK; 2020177633Sdfr if (argp->block) { 2021177633Sdfr struct nlm_async_lock *af; 2022180025Sdfr CLIENT *client; 2023197840Szml struct nlm_grantcookie cookie; 2024177633Sdfr 2025177633Sdfr /* 2026177633Sdfr * First, make sure we can contact the host's NLM. 2027177633Sdfr */ 2028184588Sdfr client = nlm_host_get_rpc(host, TRUE); 2029180025Sdfr if (!client) { 2030177633Sdfr result->stat.stat = nlm4_failed; 2031177633Sdfr goto out; 2032177633Sdfr } 2033177633Sdfr 2034177633Sdfr /* 2035177633Sdfr * First we need to check and see if there is an 2036177633Sdfr * existing blocked lock that matches. This could be a 2037177633Sdfr * badly behaved client or an RPC re-send. If we find 2038177633Sdfr * one, just return nlm4_blocked. 2039177633Sdfr */ 2040177633Sdfr mtx_lock(&host->nh_lock); 2041177633Sdfr TAILQ_FOREACH(af, &host->nh_pending, af_link) { 2042177633Sdfr if (af->af_fl.l_start == fl.l_start 2043177633Sdfr && af->af_fl.l_len == fl.l_len 2044177633Sdfr && af->af_fl.l_pid == fl.l_pid 2045177633Sdfr && af->af_fl.l_type == fl.l_type) { 2046177633Sdfr break; 2047177633Sdfr } 2048177633Sdfr } 2049197840Szml if (!af) { 2050197840Szml cookie.ng_sysid = host->nh_sysid; 2051197840Szml cookie.ng_cookie = host->nh_grantcookie++; 2052197840Szml } 2053177633Sdfr mtx_unlock(&host->nh_lock); 2054177633Sdfr if (af) { 2055180025Sdfr CLNT_RELEASE(client); 2056177633Sdfr result->stat.stat = nlm4_blocked; 2057177633Sdfr goto out; 2058177633Sdfr } 2059177633Sdfr 2060177633Sdfr af = malloc(sizeof(struct nlm_async_lock), M_NLM, 2061177633Sdfr M_WAITOK|M_ZERO); 2062177633Sdfr TASK_INIT(&af->af_task, 0, nlm_lock_callback, af); 2063177633Sdfr af->af_vp = vs.vs_vp; 2064177633Sdfr af->af_fl = fl; 2065177633Sdfr af->af_host = host; 2066180025Sdfr af->af_rpc = client; 2067177633Sdfr /* 2068177633Sdfr * We use M_RPC here so that we can xdr_free the thing 2069177633Sdfr * later. 2070177633Sdfr */ 2071197840Szml nlm_make_netobj(&af->af_granted.cookie, 2072197840Szml (caddr_t)&cookie, sizeof(cookie), M_RPC); 2073177633Sdfr af->af_granted.exclusive = argp->exclusive; 2074177633Sdfr af->af_granted.alock.caller_name = 2075177633Sdfr strdup(argp->alock.caller_name, M_RPC); 2076177633Sdfr nlm_copy_netobj(&af->af_granted.alock.fh, 2077177633Sdfr &argp->alock.fh, M_RPC); 2078177633Sdfr nlm_copy_netobj(&af->af_granted.alock.oh, 2079177633Sdfr &argp->alock.oh, M_RPC); 2080177633Sdfr af->af_granted.alock.svid = argp->alock.svid; 2081177633Sdfr af->af_granted.alock.l_offset = argp->alock.l_offset; 2082177633Sdfr af->af_granted.alock.l_len = argp->alock.l_len; 2083177633Sdfr 2084177633Sdfr /* 2085177633Sdfr * Put the entry on the pending list before calling 2086177633Sdfr * VOP_ADVLOCKASYNC. We do this in case the lock 2087177633Sdfr * request was blocked (returning EINPROGRESS) but 2088177633Sdfr * then granted before we manage to run again. The 2089177633Sdfr * client may receive the granted message before we 2090177633Sdfr * send our blocked reply but thats their problem. 2091177633Sdfr */ 2092177633Sdfr mtx_lock(&host->nh_lock); 2093177633Sdfr TAILQ_INSERT_TAIL(&host->nh_pending, af, af_link); 2094177633Sdfr mtx_unlock(&host->nh_lock); 2095177633Sdfr 2096177633Sdfr error = VOP_ADVLOCKASYNC(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE, 2097177633Sdfr &af->af_task, &af->af_cookie); 2098177633Sdfr 2099177633Sdfr /* 2100177633Sdfr * If the lock completed synchronously, just free the 2101177633Sdfr * tracking structure now. 2102177633Sdfr */ 2103177633Sdfr if (error != EINPROGRESS) { 2104180025Sdfr CLNT_RELEASE(af->af_rpc); 2105177633Sdfr mtx_lock(&host->nh_lock); 2106177633Sdfr TAILQ_REMOVE(&host->nh_pending, af, af_link); 2107177633Sdfr mtx_unlock(&host->nh_lock); 2108177633Sdfr xdr_free((xdrproc_t) xdr_nlm4_testargs, 2109177633Sdfr &af->af_granted); 2110177633Sdfr free(af, M_NLM); 2111177633Sdfr } else { 2112191918Sdfr NLM_DEBUG(2, "NLM: pending async lock %p for %s " 2113191918Sdfr "(sysid %d)\n", af, host->nh_caller_name, sysid); 2114177633Sdfr /* 2115177633Sdfr * Don't vrele the vnode just yet - this must 2116177633Sdfr * wait until either the async callback 2117177633Sdfr * happens or the lock is cancelled. 2118177633Sdfr */ 2119177633Sdfr vs.vs_vp = NULL; 2120177633Sdfr } 2121177633Sdfr } else { 2122177633Sdfr error = VOP_ADVLOCK(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE); 2123177633Sdfr } 2124177633Sdfr 2125177633Sdfr if (error) { 2126177633Sdfr if (error == EINPROGRESS) { 2127177633Sdfr result->stat.stat = nlm4_blocked; 2128177633Sdfr } else if (error == EDEADLK) { 2129177633Sdfr result->stat.stat = nlm4_deadlck; 2130177633Sdfr } else if (error == EAGAIN) { 2131177633Sdfr result->stat.stat = nlm4_denied; 2132177633Sdfr } else { 2133177633Sdfr result->stat.stat = nlm4_failed; 2134177633Sdfr } 2135177633Sdfr } else { 2136177633Sdfr if (monitor) 2137177633Sdfr nlm_host_monitor(host, argp->state); 2138177633Sdfr result->stat.stat = nlm4_granted; 2139177633Sdfr } 2140177633Sdfr 2141177633Sdfrout: 2142177633Sdfr nlm_release_vfs_state(&vs); 2143180025Sdfr if (rpcp) 2144184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2145180025Sdfr nlm_host_release(host); 2146180025Sdfr return (0); 2147177633Sdfr} 2148177633Sdfr 2149180025Sdfrint 2150180025Sdfrnlm_do_cancel(nlm4_cancargs *argp, nlm4_res *result, struct svc_req *rqstp, 2151180025Sdfr CLIENT **rpcp) 2152177633Sdfr{ 2153177633Sdfr fhandle_t fh; 2154177633Sdfr struct vfs_state vs; 2155177633Sdfr struct nlm_host *host; 2156177633Sdfr int error, sysid; 2157177633Sdfr struct flock fl; 2158177633Sdfr struct nlm_async_lock *af; 2159177633Sdfr 2160177633Sdfr memset(result, 0, sizeof(*result)); 2161180025Sdfr memset(&vs, 0, sizeof(vs)); 2162177633Sdfr 2163180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 2164184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 2165177633Sdfr if (!host) { 2166177633Sdfr result->stat.stat = nlm4_denied_nolocks; 2167180025Sdfr return (ENOMEM); 2168177633Sdfr } 2169177633Sdfr 2170191918Sdfr NLM_DEBUG(3, "nlm_do_cancel(): caller_name = %s (sysid = %d)\n", 2171191918Sdfr host->nh_caller_name, host->nh_sysid); 2172177633Sdfr 2173197840Szml nlm_check_expired_locks(host); 2174177633Sdfr sysid = host->nh_sysid; 2175177633Sdfr 2176177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 2177177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 2178177633Sdfr 2179177633Sdfr if (time_uptime < nlm_grace_threshold) { 2180177633Sdfr result->stat.stat = nlm4_denied_grace_period; 2181180025Sdfr goto out; 2182177633Sdfr } 2183177633Sdfr 2184177633Sdfr error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 2185177633Sdfr if (error) { 2186177633Sdfr result->stat.stat = nlm_convert_error(error); 2187177633Sdfr goto out; 2188177633Sdfr } 2189177633Sdfr 2190177633Sdfr fl.l_start = argp->alock.l_offset; 2191177633Sdfr fl.l_len = argp->alock.l_len; 2192177633Sdfr fl.l_pid = argp->alock.svid; 2193177633Sdfr fl.l_sysid = sysid; 2194177633Sdfr fl.l_whence = SEEK_SET; 2195177633Sdfr if (argp->exclusive) 2196177633Sdfr fl.l_type = F_WRLCK; 2197177633Sdfr else 2198177633Sdfr fl.l_type = F_RDLCK; 2199177633Sdfr 2200177633Sdfr /* 2201177633Sdfr * First we need to try and find the async lock request - if 2202177633Sdfr * there isn't one, we give up and return nlm4_denied. 2203177633Sdfr */ 2204177633Sdfr mtx_lock(&host->nh_lock); 2205177633Sdfr 2206177633Sdfr TAILQ_FOREACH(af, &host->nh_pending, af_link) { 2207177633Sdfr if (af->af_fl.l_start == fl.l_start 2208177633Sdfr && af->af_fl.l_len == fl.l_len 2209177633Sdfr && af->af_fl.l_pid == fl.l_pid 2210177633Sdfr && af->af_fl.l_type == fl.l_type) { 2211177633Sdfr break; 2212177633Sdfr } 2213177633Sdfr } 2214177633Sdfr 2215177633Sdfr if (!af) { 2216177633Sdfr mtx_unlock(&host->nh_lock); 2217177633Sdfr result->stat.stat = nlm4_denied; 2218177633Sdfr goto out; 2219177633Sdfr } 2220177633Sdfr 2221177633Sdfr error = nlm_cancel_async_lock(af); 2222177633Sdfr 2223177633Sdfr if (error) { 2224177633Sdfr result->stat.stat = nlm4_denied; 2225177633Sdfr } else { 2226177633Sdfr result->stat.stat = nlm4_granted; 2227177633Sdfr } 2228177633Sdfr 2229177633Sdfr mtx_unlock(&host->nh_lock); 2230177633Sdfr 2231177633Sdfrout: 2232177633Sdfr nlm_release_vfs_state(&vs); 2233180025Sdfr if (rpcp) 2234184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2235180025Sdfr nlm_host_release(host); 2236180025Sdfr return (0); 2237177633Sdfr} 2238177633Sdfr 2239180025Sdfrint 2240180025Sdfrnlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *result, struct svc_req *rqstp, 2241180025Sdfr CLIENT **rpcp) 2242177633Sdfr{ 2243177633Sdfr fhandle_t fh; 2244177633Sdfr struct vfs_state vs; 2245177633Sdfr struct nlm_host *host; 2246177633Sdfr int error, sysid; 2247177633Sdfr struct flock fl; 2248177633Sdfr 2249177633Sdfr memset(result, 0, sizeof(*result)); 2250180025Sdfr memset(&vs, 0, sizeof(vs)); 2251177633Sdfr 2252180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 2253184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 2254177633Sdfr if (!host) { 2255177633Sdfr result->stat.stat = nlm4_denied_nolocks; 2256180025Sdfr return (ENOMEM); 2257177633Sdfr } 2258177633Sdfr 2259191918Sdfr NLM_DEBUG(3, "nlm_do_unlock(): caller_name = %s (sysid = %d)\n", 2260191918Sdfr host->nh_caller_name, host->nh_sysid); 2261177633Sdfr 2262197840Szml nlm_check_expired_locks(host); 2263177633Sdfr sysid = host->nh_sysid; 2264177633Sdfr 2265177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 2266177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 2267177633Sdfr 2268177633Sdfr if (time_uptime < nlm_grace_threshold) { 2269177633Sdfr result->stat.stat = nlm4_denied_grace_period; 2270180025Sdfr goto out; 2271177633Sdfr } 2272177633Sdfr 2273177633Sdfr error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 2274177633Sdfr if (error) { 2275177633Sdfr result->stat.stat = nlm_convert_error(error); 2276177633Sdfr goto out; 2277177633Sdfr } 2278177633Sdfr 2279177633Sdfr fl.l_start = argp->alock.l_offset; 2280177633Sdfr fl.l_len = argp->alock.l_len; 2281177633Sdfr fl.l_pid = argp->alock.svid; 2282177633Sdfr fl.l_sysid = sysid; 2283177633Sdfr fl.l_whence = SEEK_SET; 2284177633Sdfr fl.l_type = F_UNLCK; 2285177633Sdfr error = VOP_ADVLOCK(vs.vs_vp, NULL, F_UNLCK, &fl, F_REMOTE); 2286177633Sdfr 2287177633Sdfr /* 2288177633Sdfr * Ignore the error - there is no result code for failure, 2289177633Sdfr * only for grace period. 2290177633Sdfr */ 2291177633Sdfr result->stat.stat = nlm4_granted; 2292177633Sdfr 2293177633Sdfrout: 2294177633Sdfr nlm_release_vfs_state(&vs); 2295180025Sdfr if (rpcp) 2296184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2297180025Sdfr nlm_host_release(host); 2298180025Sdfr return (0); 2299180025Sdfr} 2300177633Sdfr 2301180025Sdfrint 2302180025Sdfrnlm_do_granted(nlm4_testargs *argp, nlm4_res *result, struct svc_req *rqstp, 2303180025Sdfr 2304180025Sdfr CLIENT **rpcp) 2305180025Sdfr{ 2306180025Sdfr struct nlm_host *host; 2307180025Sdfr struct nlm_waiting_lock *nw; 2308180025Sdfr 2309180025Sdfr memset(result, 0, sizeof(*result)); 2310180025Sdfr 2311184588Sdfr host = nlm_find_host_by_addr(svc_getrpccaller(rqstp), rqstp->rq_vers); 2312180025Sdfr if (!host) { 2313180025Sdfr result->stat.stat = nlm4_denied_nolocks; 2314180025Sdfr return (ENOMEM); 2315180025Sdfr } 2316180025Sdfr 2317180025Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 2318180025Sdfr result->stat.stat = nlm4_denied; 2319197840Szml KFAIL_POINT_CODE(DEBUG_FP, nlm_deny_grant, goto out); 2320180025Sdfr 2321180025Sdfr mtx_lock(&nlm_global_lock); 2322180025Sdfr TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) { 2323180025Sdfr if (!nw->nw_waiting) 2324180025Sdfr continue; 2325180025Sdfr if (argp->alock.svid == nw->nw_lock.svid 2326180025Sdfr && argp->alock.l_offset == nw->nw_lock.l_offset 2327180025Sdfr && argp->alock.l_len == nw->nw_lock.l_len 2328180025Sdfr && argp->alock.fh.n_len == nw->nw_lock.fh.n_len 2329180025Sdfr && !memcmp(argp->alock.fh.n_bytes, nw->nw_lock.fh.n_bytes, 2330180025Sdfr nw->nw_lock.fh.n_len)) { 2331180025Sdfr nw->nw_waiting = FALSE; 2332180025Sdfr wakeup(nw); 2333180025Sdfr result->stat.stat = nlm4_granted; 2334180025Sdfr break; 2335180025Sdfr } 2336180025Sdfr } 2337180025Sdfr mtx_unlock(&nlm_global_lock); 2338197840Szml 2339197840Szmlout: 2340180025Sdfr if (rpcp) 2341184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2342180025Sdfr nlm_host_release(host); 2343180025Sdfr return (0); 2344177633Sdfr} 2345177633Sdfr 2346177633Sdfrvoid 2347197840Szmlnlm_do_granted_res(nlm4_res *argp, struct svc_req *rqstp) 2348197840Szml{ 2349197840Szml struct nlm_host *host = NULL; 2350197840Szml struct nlm_async_lock *af = NULL; 2351197840Szml int error; 2352197840Szml 2353197840Szml if (argp->cookie.n_len != sizeof(struct nlm_grantcookie)) { 2354197840Szml NLM_DEBUG(1, "NLM: bogus grant cookie"); 2355197840Szml goto out; 2356197840Szml } 2357197840Szml 2358197840Szml host = nlm_find_host_by_sysid(ng_sysid(&argp->cookie)); 2359197840Szml if (!host) { 2360197840Szml NLM_DEBUG(1, "NLM: Unknown host rejected our grant"); 2361197840Szml goto out; 2362197840Szml } 2363197840Szml 2364197840Szml mtx_lock(&host->nh_lock); 2365197840Szml TAILQ_FOREACH(af, &host->nh_granted, af_link) 2366197840Szml if (ng_cookie(&argp->cookie) == 2367197840Szml ng_cookie(&af->af_granted.cookie)) 2368197840Szml break; 2369197840Szml if (af) 2370197840Szml TAILQ_REMOVE(&host->nh_granted, af, af_link); 2371197840Szml mtx_unlock(&host->nh_lock); 2372197840Szml 2373197840Szml if (!af) { 2374197840Szml NLM_DEBUG(1, "NLM: host %s (sysid %d) replied to our grant " 2375197840Szml "with unrecognized cookie %d:%d", host->nh_caller_name, 2376197840Szml host->nh_sysid, ng_sysid(&argp->cookie), 2377197840Szml ng_cookie(&argp->cookie)); 2378197840Szml goto out; 2379197840Szml } 2380197840Szml 2381197840Szml if (argp->stat.stat != nlm4_granted) { 2382197840Szml af->af_fl.l_type = F_UNLCK; 2383197840Szml error = VOP_ADVLOCK(af->af_vp, NULL, F_UNLCK, &af->af_fl, F_REMOTE); 2384197840Szml if (error) { 2385197840Szml NLM_DEBUG(1, "NLM: host %s (sysid %d) rejected our grant " 2386197840Szml "and we failed to unlock (%d)", host->nh_caller_name, 2387197840Szml host->nh_sysid, error); 2388197840Szml goto out; 2389197840Szml } 2390197840Szml 2391197840Szml NLM_DEBUG(5, "NLM: async lock %p rejected by host %s (sysid %d)", 2392197840Szml af, host->nh_caller_name, host->nh_sysid); 2393197840Szml } else { 2394197840Szml NLM_DEBUG(5, "NLM: async lock %p accepted by host %s (sysid %d)", 2395197840Szml af, host->nh_caller_name, host->nh_sysid); 2396197840Szml } 2397197840Szml 2398197840Szml out: 2399197840Szml if (af) 2400197840Szml nlm_free_async_lock(af); 2401197840Szml if (host) 2402197840Szml nlm_host_release(host); 2403197840Szml} 2404197840Szml 2405197840Szmlvoid 2406177633Sdfrnlm_do_free_all(nlm4_notify *argp) 2407177633Sdfr{ 2408177633Sdfr struct nlm_host *host, *thost; 2409177633Sdfr 2410177633Sdfr TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, thost) { 2411177633Sdfr if (!strcmp(host->nh_caller_name, argp->name)) 2412180025Sdfr nlm_host_notify(host, argp->state); 2413177633Sdfr } 2414177633Sdfr} 2415177633Sdfr 2416177633Sdfr/* 2417177662Sdfr * Kernel module glue 2418177662Sdfr */ 2419177662Sdfrstatic int 2420177662Sdfrnfslockd_modevent(module_t mod, int type, void *data) 2421177662Sdfr{ 2422177662Sdfr 2423177662Sdfr return (0); 2424177662Sdfr} 2425177662Sdfrstatic moduledata_t nfslockd_mod = { 2426177662Sdfr "nfslockd", 2427177662Sdfr nfslockd_modevent, 2428177662Sdfr NULL, 2429177662Sdfr}; 2430177662SdfrDECLARE_MODULE(nfslockd, nfslockd_mod, SI_SUB_VFS, SI_ORDER_ANY); 2431177662Sdfr 2432177662Sdfr/* So that loader and kldload(2) can find us, wherever we are.. */ 2433177662SdfrMODULE_DEPEND(nfslockd, krpc, 1, 1, 1); 2434180217SdfrMODULE_DEPEND(nfslockd, nfs, 1, 1, 1); 2435177662SdfrMODULE_VERSION(nfslockd, 1); 2436