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: releng/10.2/sys/nlm/nlm_prot_impl.c 263781 2014-03-26 23:57:09Z delphij $"); 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 */ 87227309Sedstatic SYSCTL_NODE(_vfs, OID_AUTO, nlm, CTLFLAG_RW, NULL, 88227309Sed "Network Lock Manager"); 89227309Sedstatic SYSCTL_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/* 136255333Srmacklem * A flag to indicate the server is already running. 137255333Srmacklem */ 138255333Srmacklemstatic int nlm_is_running; 139255333Srmacklem 140255333Srmacklem/* 141177633Sdfr * A socket to use for RPC - shared by all IPv4 RPC clients. 142177633Sdfr */ 143177633Sdfrstatic struct socket *nlm_socket; 144177633Sdfr 145177633Sdfr#ifdef INET6 146177633Sdfr 147177633Sdfr/* 148177633Sdfr * A socket to use for RPC - shared by all IPv6 RPC clients. 149177633Sdfr */ 150177633Sdfrstatic struct socket *nlm_socket6; 151177633Sdfr 152177633Sdfr#endif 153177633Sdfr 154177633Sdfr/* 155177633Sdfr * An RPC client handle that can be used to communicate with the local 156177633Sdfr * NSM. 157177633Sdfr */ 158177633Sdfrstatic CLIENT *nlm_nsm; 159177633Sdfr 160177633Sdfr/* 161180025Sdfr * An AUTH handle for the server's creds. 162177633Sdfr */ 163180025Sdfrstatic AUTH *nlm_auth; 164177633Sdfr 165177633Sdfr/* 166180025Sdfr * A zero timeval for sending async RPC messages. 167180025Sdfr */ 168180025Sdfrstruct timeval nlm_zero_tv = { 0, 0 }; 169180025Sdfr 170180025Sdfr/* 171180025Sdfr * The local NSM state number 172180025Sdfr */ 173180025Sdfrint nlm_nsm_state; 174180025Sdfr 175180025Sdfr 176180025Sdfr/* 177180025Sdfr * A lock to protect the host list and waiting lock list. 178180025Sdfr */ 179180025Sdfrstatic struct mtx nlm_global_lock; 180180025Sdfr 181180025Sdfr/* 182177633Sdfr * Locks: 183177633Sdfr * (l) locked by nh_lock 184177633Sdfr * (s) only accessed via server RPC which is single threaded 185180025Sdfr * (g) locked by nlm_global_lock 186177633Sdfr * (c) const until freeing 187180025Sdfr * (a) modified using atomic ops 188177633Sdfr */ 189177633Sdfr 190177633Sdfr/* 191180025Sdfr * A pending client-side lock request, stored on the nlm_waiting_locks 192180025Sdfr * list. 193177633Sdfr */ 194180025Sdfrstruct nlm_waiting_lock { 195180025Sdfr TAILQ_ENTRY(nlm_waiting_lock) nw_link; /* (g) */ 196180025Sdfr bool_t nw_waiting; /* (g) */ 197180025Sdfr nlm4_lock nw_lock; /* (c) */ 198180025Sdfr union nfsfh nw_fh; /* (c) */ 199180025Sdfr struct vnode *nw_vp; /* (c) */ 200180025Sdfr}; 201180025SdfrTAILQ_HEAD(nlm_waiting_lock_list, nlm_waiting_lock); 202180025Sdfr 203180025Sdfrstruct nlm_waiting_lock_list nlm_waiting_locks; /* (g) */ 204180025Sdfr 205180025Sdfr/* 206180025Sdfr * A pending server-side asynchronous lock request, stored on the 207180025Sdfr * nh_pending list of the NLM host. 208180025Sdfr */ 209177633Sdfrstruct nlm_async_lock { 210177633Sdfr TAILQ_ENTRY(nlm_async_lock) af_link; /* (l) host's list of locks */ 211177633Sdfr struct task af_task; /* (c) async callback details */ 212177633Sdfr void *af_cookie; /* (l) lock manager cancel token */ 213177633Sdfr struct vnode *af_vp; /* (l) vnode to lock */ 214177633Sdfr struct flock af_fl; /* (c) lock details */ 215177633Sdfr struct nlm_host *af_host; /* (c) host which is locking */ 216180025Sdfr CLIENT *af_rpc; /* (c) rpc client to send message */ 217177633Sdfr nlm4_testargs af_granted; /* (c) notification details */ 218197840Szml time_t af_expiretime; /* (c) notification time */ 219177633Sdfr}; 220177633SdfrTAILQ_HEAD(nlm_async_lock_list, nlm_async_lock); 221177633Sdfr 222177633Sdfr/* 223177633Sdfr * NLM host. 224177633Sdfr */ 225178112Sdfrenum nlm_host_state { 226178112Sdfr NLM_UNMONITORED, 227178112Sdfr NLM_MONITORED, 228180025Sdfr NLM_MONITOR_FAILED, 229180025Sdfr NLM_RECOVERING 230178112Sdfr}; 231184588Sdfr 232184588Sdfrstruct nlm_rpc { 233184588Sdfr CLIENT *nr_client; /* (l) RPC client handle */ 234184588Sdfr time_t nr_create_time; /* (l) when client was created */ 235184588Sdfr}; 236184588Sdfr 237177633Sdfrstruct nlm_host { 238177633Sdfr struct mtx nh_lock; 239180025Sdfr volatile u_int nh_refs; /* (a) reference count */ 240180025Sdfr TAILQ_ENTRY(nlm_host) nh_link; /* (g) global list of hosts */ 241180025Sdfr char nh_caller_name[MAXNAMELEN]; /* (c) printable name of host */ 242177633Sdfr uint32_t nh_sysid; /* (c) our allocaed system ID */ 243177633Sdfr char nh_sysid_string[10]; /* (c) string rep. of sysid */ 244177633Sdfr struct sockaddr_storage nh_addr; /* (s) remote address of host */ 245184588Sdfr struct nlm_rpc nh_srvrpc; /* (l) RPC for server replies */ 246184588Sdfr struct nlm_rpc nh_clntrpc; /* (l) RPC for client requests */ 247177633Sdfr rpcvers_t nh_vers; /* (s) NLM version of host */ 248177633Sdfr int nh_state; /* (s) last seen NSM state of host */ 249180025Sdfr enum nlm_host_state nh_monstate; /* (l) local NSM monitoring state */ 250177633Sdfr time_t nh_idle_timeout; /* (s) Time at which host is idle */ 251177633Sdfr struct sysctl_ctx_list nh_sysctl; /* (c) vfs.nlm.sysid nodes */ 252197840Szml uint32_t nh_grantcookie; /* (l) grant cookie counter */ 253177633Sdfr struct nlm_async_lock_list nh_pending; /* (l) pending async locks */ 254197840Szml struct nlm_async_lock_list nh_granted; /* (l) granted locks */ 255177633Sdfr struct nlm_async_lock_list nh_finished; /* (l) finished async locks */ 256177633Sdfr}; 257177633SdfrTAILQ_HEAD(nlm_host_list, nlm_host); 258177633Sdfr 259180025Sdfrstatic struct nlm_host_list nlm_hosts; /* (g) */ 260180025Sdfrstatic uint32_t nlm_next_sysid = 1; /* (g) */ 261177633Sdfr 262177633Sdfrstatic void nlm_host_unmonitor(struct nlm_host *); 263177633Sdfr 264197840Szmlstruct nlm_grantcookie { 265197840Szml uint32_t ng_sysid; 266197840Szml uint32_t ng_cookie; 267197840Szml}; 268197840Szml 269197840Szmlstatic inline uint32_t 270197840Szmlng_sysid(struct netobj *src) 271197840Szml{ 272197840Szml 273197840Szml return ((struct nlm_grantcookie *)src->n_bytes)->ng_sysid; 274197840Szml} 275197840Szml 276197840Szmlstatic inline uint32_t 277197840Szmlng_cookie(struct netobj *src) 278197840Szml{ 279197840Szml 280197840Szml return ((struct nlm_grantcookie *)src->n_bytes)->ng_cookie; 281197840Szml} 282197840Szml 283177633Sdfr/**********************************************************************/ 284177633Sdfr 285177633Sdfr/* 286177633Sdfr * Initialise NLM globals. 287177633Sdfr */ 288177633Sdfrstatic void 289177633Sdfrnlm_init(void *dummy) 290177633Sdfr{ 291177633Sdfr int error; 292177633Sdfr 293180025Sdfr mtx_init(&nlm_global_lock, "nlm_global_lock", NULL, MTX_DEF); 294180025Sdfr TAILQ_INIT(&nlm_waiting_locks); 295177633Sdfr TAILQ_INIT(&nlm_hosts); 296177633Sdfr 297177633Sdfr error = syscall_register(&nlm_syscall_offset, &nlm_syscall_sysent, 298177633Sdfr &nlm_syscall_prev_sysent); 299177633Sdfr if (error) 300191918Sdfr NLM_ERR("Can't register NLM syscall\n"); 301177633Sdfr else 302177633Sdfr nlm_syscall_registered = TRUE; 303177633Sdfr} 304177633SdfrSYSINIT(nlm_init, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_init, NULL); 305177633Sdfr 306177633Sdfrstatic void 307177633Sdfrnlm_uninit(void *dummy) 308177633Sdfr{ 309177633Sdfr 310177633Sdfr if (nlm_syscall_registered) 311177633Sdfr syscall_deregister(&nlm_syscall_offset, 312177633Sdfr &nlm_syscall_prev_sysent); 313177633Sdfr} 314177633SdfrSYSUNINIT(nlm_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_uninit, NULL); 315177633Sdfr 316177633Sdfr/* 317197840Szml * Create a netobj from an arbitrary source. 318197840Szml */ 319197840Szmlvoid 320197840Szmlnlm_make_netobj(struct netobj *dst, caddr_t src, size_t srcsize, 321197840Szml struct malloc_type *type) 322197840Szml{ 323197840Szml 324197840Szml dst->n_len = srcsize; 325197840Szml dst->n_bytes = malloc(srcsize, type, M_WAITOK); 326197840Szml memcpy(dst->n_bytes, src, srcsize); 327197840Szml} 328197840Szml 329197840Szml/* 330177633Sdfr * Copy a struct netobj. 331177633Sdfr */ 332177633Sdfrvoid 333177633Sdfrnlm_copy_netobj(struct netobj *dst, struct netobj *src, 334177633Sdfr struct malloc_type *type) 335177633Sdfr{ 336177633Sdfr 337197840Szml nlm_make_netobj(dst, src->n_bytes, src->n_len, type); 338177633Sdfr} 339177633Sdfr 340197840Szml 341177633Sdfr/* 342177633Sdfr * Create an RPC client handle for the given (address,prog,vers) 343177633Sdfr * triple using UDP. 344177633Sdfr */ 345177633Sdfrstatic CLIENT * 346177633Sdfrnlm_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers) 347177633Sdfr{ 348184588Sdfr char *wchan = "nlmrcv"; 349177633Sdfr const char* protofmly; 350177633Sdfr struct sockaddr_storage ss; 351177633Sdfr struct socket *so; 352177633Sdfr CLIENT *rpcb; 353177633Sdfr struct timeval timo; 354177633Sdfr RPCB parms; 355177633Sdfr char *uaddr; 356181683Sdfr enum clnt_stat stat = RPC_SUCCESS; 357181683Sdfr int rpcvers = RPCBVERS4; 358181683Sdfr bool_t do_tcp = FALSE; 359191937Sdfr bool_t tryagain = FALSE; 360182154Sdfr struct portmap mapping; 361181683Sdfr u_short port = 0; 362177633Sdfr 363177633Sdfr /* 364177633Sdfr * First we need to contact the remote RPCBIND service to find 365177633Sdfr * the right port. 366177633Sdfr */ 367177633Sdfr memcpy(&ss, sa, sa->sa_len); 368177633Sdfr switch (ss.ss_family) { 369177633Sdfr case AF_INET: 370177633Sdfr ((struct sockaddr_in *)&ss)->sin_port = htons(111); 371177633Sdfr protofmly = "inet"; 372177633Sdfr so = nlm_socket; 373177633Sdfr break; 374177633Sdfr 375177633Sdfr#ifdef INET6 376177633Sdfr case AF_INET6: 377177633Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111); 378177633Sdfr protofmly = "inet6"; 379177633Sdfr so = nlm_socket6; 380177633Sdfr break; 381177633Sdfr#endif 382177633Sdfr 383177633Sdfr default: 384177633Sdfr /* 385177633Sdfr * Unsupported address family - fail. 386177633Sdfr */ 387177633Sdfr return (NULL); 388177633Sdfr } 389177633Sdfr 390177633Sdfr rpcb = clnt_dg_create(so, (struct sockaddr *)&ss, 391181683Sdfr RPCBPROG, rpcvers, 0, 0); 392177633Sdfr if (!rpcb) 393177633Sdfr return (NULL); 394177633Sdfr 395181683Sdfrtry_tcp: 396177633Sdfr parms.r_prog = prog; 397177633Sdfr parms.r_vers = vers; 398181683Sdfr if (do_tcp) 399181683Sdfr parms.r_netid = "tcp"; 400181683Sdfr else 401181683Sdfr parms.r_netid = "udp"; 402177633Sdfr parms.r_addr = ""; 403177633Sdfr parms.r_owner = ""; 404177633Sdfr 405177633Sdfr /* 406177633Sdfr * Use the default timeout. 407177633Sdfr */ 408177633Sdfr timo.tv_sec = 25; 409177633Sdfr timo.tv_usec = 0; 410177633Sdfragain: 411181683Sdfr switch (rpcvers) { 412181683Sdfr case RPCBVERS4: 413181683Sdfr case RPCBVERS: 414177633Sdfr /* 415181683Sdfr * Try RPCBIND 4 then 3. 416177633Sdfr */ 417181683Sdfr uaddr = NULL; 418181683Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR, 419181683Sdfr (xdrproc_t) xdr_rpcb, &parms, 420181683Sdfr (xdrproc_t) xdr_wrapstring, &uaddr, timo); 421191937Sdfr if (stat == RPC_SUCCESS) { 422181683Sdfr /* 423181683Sdfr * We have a reply from the remote RPCBIND - turn it 424181683Sdfr * into an appropriate address and make a new client 425181683Sdfr * that can talk to the remote NLM. 426181683Sdfr * 427181683Sdfr * XXX fixup IPv6 scope ID. 428181683Sdfr */ 429181683Sdfr struct netbuf *a; 430181683Sdfr a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr); 431181683Sdfr if (!a) { 432191937Sdfr tryagain = TRUE; 433191937Sdfr } else { 434191937Sdfr tryagain = FALSE; 435191937Sdfr memcpy(&ss, a->buf, a->len); 436191937Sdfr free(a->buf, M_RPC); 437191937Sdfr free(a, M_RPC); 438191937Sdfr xdr_free((xdrproc_t) xdr_wrapstring, &uaddr); 439181683Sdfr } 440177633Sdfr } 441191937Sdfr if (tryagain || stat == RPC_PROGVERSMISMATCH) { 442191937Sdfr if (rpcvers == RPCBVERS4) 443191937Sdfr rpcvers = RPCBVERS; 444191937Sdfr else if (rpcvers == RPCBVERS) 445191937Sdfr rpcvers = PMAPVERS; 446191937Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers); 447191937Sdfr goto again; 448191937Sdfr } 449181683Sdfr break; 450181683Sdfr case PMAPVERS: 451177633Sdfr /* 452177633Sdfr * Try portmap. 453177633Sdfr */ 454177633Sdfr mapping.pm_prog = parms.r_prog; 455177633Sdfr mapping.pm_vers = parms.r_vers; 456181683Sdfr mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP; 457177633Sdfr mapping.pm_port = 0; 458177633Sdfr 459177633Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT, 460182154Sdfr (xdrproc_t) xdr_portmap, &mapping, 461177633Sdfr (xdrproc_t) xdr_u_short, &port, timo); 462177633Sdfr 463177633Sdfr if (stat == RPC_SUCCESS) { 464177633Sdfr switch (ss.ss_family) { 465177633Sdfr case AF_INET: 466177633Sdfr ((struct sockaddr_in *)&ss)->sin_port = 467177633Sdfr htons(port); 468177633Sdfr break; 469177633Sdfr 470177633Sdfr#ifdef INET6 471177633Sdfr case AF_INET6: 472177633Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = 473177633Sdfr htons(port); 474177633Sdfr break; 475177633Sdfr#endif 476177633Sdfr } 477177633Sdfr } 478181683Sdfr break; 479181683Sdfr default: 480181683Sdfr panic("invalid rpcvers %d", rpcvers); 481177633Sdfr } 482181683Sdfr /* 483181683Sdfr * We may have a positive response from the portmapper, but the NLM 484181683Sdfr * service was not found. Make sure we received a valid port. 485181683Sdfr */ 486181683Sdfr switch (ss.ss_family) { 487181683Sdfr case AF_INET: 488181683Sdfr port = ((struct sockaddr_in *)&ss)->sin_port; 489181683Sdfr break; 490181683Sdfr#ifdef INET6 491181683Sdfr case AF_INET6: 492181683Sdfr port = ((struct sockaddr_in6 *)&ss)->sin6_port; 493181683Sdfr break; 494181683Sdfr#endif 495181683Sdfr } 496181683Sdfr if (stat != RPC_SUCCESS || !port) { 497181683Sdfr /* 498181683Sdfr * If we were able to talk to rpcbind or portmap, but the udp 499181683Sdfr * variant wasn't available, ask about tcp. 500181683Sdfr * 501181683Sdfr * XXX - We could also check for a TCP portmapper, but 502181683Sdfr * if the host is running a portmapper at all, we should be able 503181683Sdfr * to hail it over UDP. 504181683Sdfr */ 505181683Sdfr if (stat == RPC_SUCCESS && !do_tcp) { 506181683Sdfr do_tcp = TRUE; 507181683Sdfr goto try_tcp; 508181683Sdfr } 509181683Sdfr 510181683Sdfr /* Otherwise, bad news. */ 511191918Sdfr NLM_ERR("NLM: failed to contact remote rpcbind, " 512191918Sdfr "stat = %d, port = %d\n", (int) stat, port); 513178241Sdfr CLNT_DESTROY(rpcb); 514177633Sdfr return (NULL); 515177633Sdfr } 516177633Sdfr 517181683Sdfr if (do_tcp) { 518181683Sdfr /* 519181683Sdfr * Destroy the UDP client we used to speak to rpcbind and 520181683Sdfr * recreate as a TCP client. 521181683Sdfr */ 522181683Sdfr struct netconfig *nconf = NULL; 523177633Sdfr 524181683Sdfr CLNT_DESTROY(rpcb); 525181683Sdfr 526181683Sdfr switch (ss.ss_family) { 527181683Sdfr case AF_INET: 528181683Sdfr nconf = getnetconfigent("tcp"); 529181683Sdfr break; 530181683Sdfr#ifdef INET6 531181683Sdfr case AF_INET6: 532181683Sdfr nconf = getnetconfigent("tcp6"); 533181683Sdfr break; 534181683Sdfr#endif 535181683Sdfr } 536181683Sdfr 537181683Sdfr rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss, 538181683Sdfr prog, vers, 0, 0); 539184588Sdfr CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan); 540181683Sdfr rpcb->cl_auth = nlm_auth; 541181683Sdfr 542181683Sdfr } else { 543181683Sdfr /* 544181683Sdfr * Re-use the client we used to speak to rpcbind. 545181683Sdfr */ 546181683Sdfr CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss); 547181683Sdfr CLNT_CONTROL(rpcb, CLSET_PROG, &prog); 548181683Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &vers); 549184588Sdfr CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan); 550181683Sdfr rpcb->cl_auth = nlm_auth; 551181683Sdfr } 552181683Sdfr 553177633Sdfr return (rpcb); 554177633Sdfr} 555177633Sdfr 556177633Sdfr/* 557177633Sdfr * This async callback after when an async lock request has been 558177633Sdfr * granted. We notify the host which initiated the request. 559177633Sdfr */ 560177633Sdfrstatic void 561177633Sdfrnlm_lock_callback(void *arg, int pending) 562177633Sdfr{ 563177633Sdfr struct nlm_async_lock *af = (struct nlm_async_lock *) arg; 564180025Sdfr struct rpc_callextra ext; 565177633Sdfr 566197840Szml NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) granted," 567197840Szml " cookie %d:%d\n", af, af->af_host->nh_caller_name, 568197840Szml af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie), 569197840Szml ng_cookie(&af->af_granted.cookie)); 570177633Sdfr 571177633Sdfr /* 572177633Sdfr * Send the results back to the host. 573177633Sdfr * 574177633Sdfr * Note: there is a possible race here with nlm_host_notify 575178241Sdfr * destroying the RPC client. To avoid problems, the first 576177633Sdfr * thing nlm_host_notify does is to cancel pending async lock 577177633Sdfr * requests. 578177633Sdfr */ 579180025Sdfr memset(&ext, 0, sizeof(ext)); 580180025Sdfr ext.rc_auth = nlm_auth; 581177633Sdfr if (af->af_host->nh_vers == NLM_VERS4) { 582177633Sdfr nlm4_granted_msg_4(&af->af_granted, 583180025Sdfr NULL, af->af_rpc, &ext, nlm_zero_tv); 584177633Sdfr } else { 585177633Sdfr /* 586177633Sdfr * Back-convert to legacy protocol 587177633Sdfr */ 588177633Sdfr nlm_testargs granted; 589177633Sdfr granted.cookie = af->af_granted.cookie; 590177633Sdfr granted.exclusive = af->af_granted.exclusive; 591177633Sdfr granted.alock.caller_name = 592177633Sdfr af->af_granted.alock.caller_name; 593177633Sdfr granted.alock.fh = af->af_granted.alock.fh; 594177633Sdfr granted.alock.oh = af->af_granted.alock.oh; 595177633Sdfr granted.alock.svid = af->af_granted.alock.svid; 596177633Sdfr granted.alock.l_offset = 597177633Sdfr af->af_granted.alock.l_offset; 598177633Sdfr granted.alock.l_len = 599177633Sdfr af->af_granted.alock.l_len; 600177633Sdfr 601177633Sdfr nlm_granted_msg_1(&granted, 602180025Sdfr NULL, af->af_rpc, &ext, nlm_zero_tv); 603177633Sdfr } 604177633Sdfr 605177633Sdfr /* 606197840Szml * Move this entry to the nh_granted list. 607177633Sdfr */ 608197840Szml af->af_expiretime = time_uptime + NLM_EXPIRE_TIMEOUT; 609177633Sdfr mtx_lock(&af->af_host->nh_lock); 610177633Sdfr TAILQ_REMOVE(&af->af_host->nh_pending, af, af_link); 611197840Szml TAILQ_INSERT_TAIL(&af->af_host->nh_granted, af, af_link); 612177633Sdfr mtx_unlock(&af->af_host->nh_lock); 613177633Sdfr} 614177633Sdfr 615177633Sdfr/* 616177633Sdfr * Free an async lock request. The request must have been removed from 617177633Sdfr * any list. 618177633Sdfr */ 619177633Sdfrstatic void 620177633Sdfrnlm_free_async_lock(struct nlm_async_lock *af) 621177633Sdfr{ 622177633Sdfr /* 623177633Sdfr * Free an async lock. 624177633Sdfr */ 625180025Sdfr if (af->af_rpc) 626180025Sdfr CLNT_RELEASE(af->af_rpc); 627177633Sdfr xdr_free((xdrproc_t) xdr_nlm4_testargs, &af->af_granted); 628177633Sdfr if (af->af_vp) 629177633Sdfr vrele(af->af_vp); 630177633Sdfr free(af, M_NLM); 631177633Sdfr} 632177633Sdfr 633177633Sdfr/* 634177633Sdfr * Cancel our async request - this must be called with 635177633Sdfr * af->nh_host->nh_lock held. This is slightly complicated by a 636177633Sdfr * potential race with our own callback. If we fail to cancel the 637177633Sdfr * lock, it must already have been granted - we make sure our async 638177633Sdfr * task has completed by calling taskqueue_drain in this case. 639177633Sdfr */ 640177633Sdfrstatic int 641177633Sdfrnlm_cancel_async_lock(struct nlm_async_lock *af) 642177633Sdfr{ 643177633Sdfr struct nlm_host *host = af->af_host; 644177633Sdfr int error; 645177633Sdfr 646177633Sdfr mtx_assert(&host->nh_lock, MA_OWNED); 647177633Sdfr 648177633Sdfr mtx_unlock(&host->nh_lock); 649177633Sdfr 650177633Sdfr error = VOP_ADVLOCKASYNC(af->af_vp, NULL, F_CANCEL, &af->af_fl, 651177633Sdfr F_REMOTE, NULL, &af->af_cookie); 652177633Sdfr 653177633Sdfr if (error) { 654177633Sdfr /* 655177633Sdfr * We failed to cancel - make sure our callback has 656177633Sdfr * completed before we continue. 657177633Sdfr */ 658177633Sdfr taskqueue_drain(taskqueue_thread, &af->af_task); 659177633Sdfr } 660177633Sdfr 661177633Sdfr mtx_lock(&host->nh_lock); 662177633Sdfr 663177633Sdfr if (!error) { 664191918Sdfr NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) " 665191918Sdfr "cancelled\n", af, host->nh_caller_name, host->nh_sysid); 666177633Sdfr 667177633Sdfr /* 668177633Sdfr * Remove from the nh_pending list and free now that 669177633Sdfr * we are safe from the callback. 670177633Sdfr */ 671177633Sdfr TAILQ_REMOVE(&host->nh_pending, af, af_link); 672177633Sdfr mtx_unlock(&host->nh_lock); 673177633Sdfr nlm_free_async_lock(af); 674177633Sdfr mtx_lock(&host->nh_lock); 675177633Sdfr } 676177633Sdfr 677177633Sdfr return (error); 678177633Sdfr} 679177633Sdfr 680177633Sdfrstatic void 681197840Szmlnlm_check_expired_locks(struct nlm_host *host) 682177633Sdfr{ 683177633Sdfr struct nlm_async_lock *af; 684197840Szml time_t uptime = time_uptime; 685177633Sdfr 686177633Sdfr mtx_lock(&host->nh_lock); 687197840Szml while ((af = TAILQ_FIRST(&host->nh_granted)) != NULL 688197840Szml && uptime >= af->af_expiretime) { 689197840Szml NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) expired," 690197840Szml " cookie %d:%d\n", af, af->af_host->nh_caller_name, 691197840Szml af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie), 692197840Szml ng_cookie(&af->af_granted.cookie)); 693197840Szml TAILQ_REMOVE(&host->nh_granted, af, af_link); 694197840Szml mtx_unlock(&host->nh_lock); 695197840Szml nlm_free_async_lock(af); 696197840Szml mtx_lock(&host->nh_lock); 697197840Szml } 698177633Sdfr while ((af = TAILQ_FIRST(&host->nh_finished)) != NULL) { 699177633Sdfr TAILQ_REMOVE(&host->nh_finished, af, af_link); 700177633Sdfr mtx_unlock(&host->nh_lock); 701177633Sdfr nlm_free_async_lock(af); 702177633Sdfr mtx_lock(&host->nh_lock); 703177633Sdfr } 704177633Sdfr mtx_unlock(&host->nh_lock); 705177633Sdfr} 706177633Sdfr 707177633Sdfr/* 708180025Sdfr * Free resources used by a host. This is called after the reference 709180025Sdfr * count has reached zero so it doesn't need to worry about locks. 710177633Sdfr */ 711177633Sdfrstatic void 712180025Sdfrnlm_host_destroy(struct nlm_host *host) 713177633Sdfr{ 714180025Sdfr 715180025Sdfr mtx_lock(&nlm_global_lock); 716180025Sdfr TAILQ_REMOVE(&nlm_hosts, host, nh_link); 717180025Sdfr mtx_unlock(&nlm_global_lock); 718180025Sdfr 719184588Sdfr if (host->nh_srvrpc.nr_client) 720184588Sdfr CLNT_RELEASE(host->nh_srvrpc.nr_client); 721184588Sdfr if (host->nh_clntrpc.nr_client) 722184588Sdfr CLNT_RELEASE(host->nh_clntrpc.nr_client); 723180025Sdfr mtx_destroy(&host->nh_lock); 724180025Sdfr sysctl_ctx_free(&host->nh_sysctl); 725180025Sdfr free(host, M_NLM); 726180025Sdfr} 727180025Sdfr 728180025Sdfr/* 729180025Sdfr * Thread start callback for client lock recovery 730180025Sdfr */ 731180025Sdfrstatic void 732180025Sdfrnlm_client_recovery_start(void *arg) 733180025Sdfr{ 734180025Sdfr struct nlm_host *host = (struct nlm_host *) arg; 735180025Sdfr 736191918Sdfr NLM_DEBUG(1, "NLM: client lock recovery for %s started\n", 737191918Sdfr host->nh_caller_name); 738180025Sdfr 739180025Sdfr nlm_client_recovery(host); 740180025Sdfr 741191918Sdfr NLM_DEBUG(1, "NLM: client lock recovery for %s completed\n", 742191918Sdfr host->nh_caller_name); 743180025Sdfr 744180025Sdfr host->nh_monstate = NLM_MONITORED; 745180025Sdfr nlm_host_release(host); 746180025Sdfr 747180025Sdfr kthread_exit(); 748180025Sdfr} 749180025Sdfr 750180025Sdfr/* 751180025Sdfr * This is called when we receive a host state change notification. We 752180025Sdfr * unlock any active locks owned by the host. When rpc.lockd is 753180025Sdfr * shutting down, this function is called with newstate set to zero 754180025Sdfr * which allows us to cancel any pending async locks and clear the 755180025Sdfr * locking state. 756180025Sdfr */ 757180025Sdfrstatic void 758180025Sdfrnlm_host_notify(struct nlm_host *host, int newstate) 759180025Sdfr{ 760177633Sdfr struct nlm_async_lock *af; 761177633Sdfr 762177633Sdfr if (newstate) { 763191918Sdfr NLM_DEBUG(1, "NLM: host %s (sysid %d) rebooted, new " 764191918Sdfr "state is %d\n", host->nh_caller_name, 765191918Sdfr host->nh_sysid, newstate); 766177633Sdfr } 767177633Sdfr 768177633Sdfr /* 769177633Sdfr * Cancel any pending async locks for this host. 770177633Sdfr */ 771177633Sdfr mtx_lock(&host->nh_lock); 772177633Sdfr while ((af = TAILQ_FIRST(&host->nh_pending)) != NULL) { 773177633Sdfr /* 774177633Sdfr * nlm_cancel_async_lock will remove the entry from 775177633Sdfr * nh_pending and free it. 776177633Sdfr */ 777177633Sdfr nlm_cancel_async_lock(af); 778177633Sdfr } 779177633Sdfr mtx_unlock(&host->nh_lock); 780197840Szml nlm_check_expired_locks(host); 781177633Sdfr 782177633Sdfr /* 783180025Sdfr * The host just rebooted - trash its locks. 784177633Sdfr */ 785177633Sdfr lf_clearremotesys(host->nh_sysid); 786177633Sdfr host->nh_state = newstate; 787177633Sdfr 788177633Sdfr /* 789180025Sdfr * If we have any remote locks for this host (i.e. it 790180025Sdfr * represents a remote NFS server that our local NFS client 791180025Sdfr * has locks for), start a recovery thread. 792177633Sdfr */ 793180025Sdfr if (newstate != 0 794180025Sdfr && host->nh_monstate != NLM_RECOVERING 795180025Sdfr && lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid) > 0) { 796180025Sdfr struct thread *td; 797180025Sdfr host->nh_monstate = NLM_RECOVERING; 798180025Sdfr refcount_acquire(&host->nh_refs); 799180025Sdfr kthread_add(nlm_client_recovery_start, host, curproc, &td, 0, 0, 800180025Sdfr "NFS lock recovery for %s", host->nh_caller_name); 801177633Sdfr } 802177633Sdfr} 803177633Sdfr 804177633Sdfr/* 805177633Sdfr * Sysctl handler to count the number of locks for a sysid. 806177633Sdfr */ 807177633Sdfrstatic int 808177633Sdfrnlm_host_lock_count_sysctl(SYSCTL_HANDLER_ARGS) 809177633Sdfr{ 810177633Sdfr struct nlm_host *host; 811177633Sdfr int count; 812177633Sdfr 813177633Sdfr host = oidp->oid_arg1; 814177633Sdfr count = lf_countlocks(host->nh_sysid); 815177633Sdfr return sysctl_handle_int(oidp, &count, 0, req); 816177633Sdfr} 817177633Sdfr 818177633Sdfr/* 819180025Sdfr * Sysctl handler to count the number of client locks for a sysid. 820180025Sdfr */ 821180025Sdfrstatic int 822180025Sdfrnlm_host_client_lock_count_sysctl(SYSCTL_HANDLER_ARGS) 823180025Sdfr{ 824180025Sdfr struct nlm_host *host; 825180025Sdfr int count; 826180025Sdfr 827180025Sdfr host = oidp->oid_arg1; 828180025Sdfr count = lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid); 829180025Sdfr return sysctl_handle_int(oidp, &count, 0, req); 830180025Sdfr} 831180025Sdfr 832180025Sdfr/* 833177633Sdfr * Create a new NLM host. 834177633Sdfr */ 835177633Sdfrstatic struct nlm_host * 836177633Sdfrnlm_create_host(const char* caller_name) 837177633Sdfr{ 838177633Sdfr struct nlm_host *host; 839177633Sdfr struct sysctl_oid *oid; 840177633Sdfr 841180025Sdfr mtx_assert(&nlm_global_lock, MA_OWNED); 842180025Sdfr 843191918Sdfr NLM_DEBUG(1, "NLM: new host %s (sysid %d)\n", 844191918Sdfr caller_name, nlm_next_sysid); 845180025Sdfr host = malloc(sizeof(struct nlm_host), M_NLM, M_NOWAIT|M_ZERO); 846180025Sdfr if (!host) 847180025Sdfr return (NULL); 848177633Sdfr mtx_init(&host->nh_lock, "nh_lock", NULL, MTX_DEF); 849180025Sdfr host->nh_refs = 1; 850180025Sdfr strlcpy(host->nh_caller_name, caller_name, MAXNAMELEN); 851177633Sdfr host->nh_sysid = nlm_next_sysid++; 852177633Sdfr snprintf(host->nh_sysid_string, sizeof(host->nh_sysid_string), 853177633Sdfr "%d", host->nh_sysid); 854177633Sdfr host->nh_vers = 0; 855177633Sdfr host->nh_state = 0; 856178112Sdfr host->nh_monstate = NLM_UNMONITORED; 857197840Szml host->nh_grantcookie = 1; 858177633Sdfr TAILQ_INIT(&host->nh_pending); 859197840Szml TAILQ_INIT(&host->nh_granted); 860177633Sdfr TAILQ_INIT(&host->nh_finished); 861177633Sdfr TAILQ_INSERT_TAIL(&nlm_hosts, host, nh_link); 862177633Sdfr 863180025Sdfr mtx_unlock(&nlm_global_lock); 864180025Sdfr 865177633Sdfr sysctl_ctx_init(&host->nh_sysctl); 866177633Sdfr oid = SYSCTL_ADD_NODE(&host->nh_sysctl, 867177633Sdfr SYSCTL_STATIC_CHILDREN(_vfs_nlm_sysid), 868177633Sdfr OID_AUTO, host->nh_sysid_string, CTLFLAG_RD, NULL, ""); 869177633Sdfr SYSCTL_ADD_STRING(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 870177633Sdfr "hostname", CTLFLAG_RD, host->nh_caller_name, 0, ""); 871217326Smdf SYSCTL_ADD_UINT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 872177633Sdfr "version", CTLFLAG_RD, &host->nh_vers, 0, ""); 873217326Smdf SYSCTL_ADD_UINT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 874178112Sdfr "monitored", CTLFLAG_RD, &host->nh_monstate, 0, ""); 875177633Sdfr SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 876177633Sdfr "lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0, 877177633Sdfr nlm_host_lock_count_sysctl, "I", ""); 878180025Sdfr SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 879180025Sdfr "client_lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0, 880180025Sdfr nlm_host_client_lock_count_sysctl, "I", ""); 881177633Sdfr 882180025Sdfr mtx_lock(&nlm_global_lock); 883180025Sdfr 884177633Sdfr return (host); 885177633Sdfr} 886177633Sdfr 887177633Sdfr/* 888192501Srmacklem * Acquire the next sysid for remote locks not handled by the NLM. 889192501Srmacklem */ 890192501Srmacklemuint32_t 891192501Srmacklemnlm_acquire_next_sysid(void) 892192501Srmacklem{ 893192501Srmacklem uint32_t next_sysid; 894192501Srmacklem 895192501Srmacklem mtx_lock(&nlm_global_lock); 896192501Srmacklem next_sysid = nlm_next_sysid++; 897192501Srmacklem mtx_unlock(&nlm_global_lock); 898192501Srmacklem return (next_sysid); 899192501Srmacklem} 900192501Srmacklem 901192501Srmacklem/* 902177633Sdfr * Return non-zero if the address parts of the two sockaddrs are the 903177633Sdfr * same. 904177633Sdfr */ 905177633Sdfrstatic int 906177633Sdfrnlm_compare_addr(const struct sockaddr *a, const struct sockaddr *b) 907177633Sdfr{ 908177633Sdfr const struct sockaddr_in *a4, *b4; 909177633Sdfr#ifdef INET6 910177633Sdfr const struct sockaddr_in6 *a6, *b6; 911177633Sdfr#endif 912177633Sdfr 913177633Sdfr if (a->sa_family != b->sa_family) 914177633Sdfr return (FALSE); 915177633Sdfr 916177633Sdfr switch (a->sa_family) { 917177633Sdfr case AF_INET: 918177633Sdfr a4 = (const struct sockaddr_in *) a; 919177633Sdfr b4 = (const struct sockaddr_in *) b; 920177633Sdfr return !memcmp(&a4->sin_addr, &b4->sin_addr, 921177633Sdfr sizeof(a4->sin_addr)); 922177633Sdfr#ifdef INET6 923177633Sdfr case AF_INET6: 924177633Sdfr a6 = (const struct sockaddr_in6 *) a; 925177633Sdfr b6 = (const struct sockaddr_in6 *) b; 926177633Sdfr return !memcmp(&a6->sin6_addr, &b6->sin6_addr, 927177633Sdfr sizeof(a6->sin6_addr)); 928177633Sdfr#endif 929177633Sdfr } 930177633Sdfr 931177633Sdfr return (0); 932177633Sdfr} 933177633Sdfr 934177633Sdfr/* 935177633Sdfr * Check for idle hosts and stop monitoring them. We could also free 936177633Sdfr * the host structure here, possibly after a larger timeout but that 937177633Sdfr * would require some care to avoid races with 938177633Sdfr * e.g. nlm_host_lock_count_sysctl. 939177633Sdfr */ 940177633Sdfrstatic void 941177633Sdfrnlm_check_idle(void) 942177633Sdfr{ 943177633Sdfr struct nlm_host *host; 944177633Sdfr 945180025Sdfr mtx_assert(&nlm_global_lock, MA_OWNED); 946180025Sdfr 947177633Sdfr if (time_uptime <= nlm_next_idle_check) 948177633Sdfr return; 949177633Sdfr 950177633Sdfr nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD; 951177633Sdfr 952177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 953178112Sdfr if (host->nh_monstate == NLM_MONITORED 954177633Sdfr && time_uptime > host->nh_idle_timeout) { 955180025Sdfr mtx_unlock(&nlm_global_lock); 956180025Sdfr if (lf_countlocks(host->nh_sysid) > 0 957180025Sdfr || lf_countlocks(NLM_SYSID_CLIENT 958180025Sdfr + host->nh_sysid)) { 959177633Sdfr host->nh_idle_timeout = 960177633Sdfr time_uptime + NLM_IDLE_TIMEOUT; 961180025Sdfr mtx_lock(&nlm_global_lock); 962177633Sdfr continue; 963177633Sdfr } 964177633Sdfr nlm_host_unmonitor(host); 965180025Sdfr mtx_lock(&nlm_global_lock); 966177633Sdfr } 967177633Sdfr } 968177633Sdfr} 969177633Sdfr 970177633Sdfr/* 971177633Sdfr * Search for an existing NLM host that matches the given name 972177633Sdfr * (typically the caller_name element of an nlm4_lock). If none is 973180025Sdfr * found, create a new host. If 'addr' is non-NULL, record the remote 974177633Sdfr * address of the host so that we can call it back for async 975180025Sdfr * responses. If 'vers' is greater than zero then record the NLM 976180025Sdfr * program version to use to communicate with this client. 977177633Sdfr */ 978177633Sdfrstruct nlm_host * 979180025Sdfrnlm_find_host_by_name(const char *name, const struct sockaddr *addr, 980180025Sdfr rpcvers_t vers) 981177633Sdfr{ 982177633Sdfr struct nlm_host *host; 983177633Sdfr 984180025Sdfr mtx_lock(&nlm_global_lock); 985177633Sdfr 986177633Sdfr /* 987177633Sdfr * The remote host is determined by caller_name. 988177633Sdfr */ 989177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 990177633Sdfr if (!strcmp(host->nh_caller_name, name)) 991177633Sdfr break; 992177633Sdfr } 993177633Sdfr 994180025Sdfr if (!host) { 995177633Sdfr host = nlm_create_host(name); 996180025Sdfr if (!host) { 997180025Sdfr mtx_unlock(&nlm_global_lock); 998180025Sdfr return (NULL); 999180025Sdfr } 1000180025Sdfr } 1001180025Sdfr refcount_acquire(&host->nh_refs); 1002180025Sdfr 1003177633Sdfr host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT; 1004177633Sdfr 1005177633Sdfr /* 1006180025Sdfr * If we have an address for the host, record it so that we 1007180025Sdfr * can send async replies etc. 1008177633Sdfr */ 1009180025Sdfr if (addr) { 1010177633Sdfr 1011180025Sdfr KASSERT(addr->sa_len < sizeof(struct sockaddr_storage), 1012177633Sdfr ("Strange remote transport address length")); 1013177633Sdfr 1014177633Sdfr /* 1015177633Sdfr * If we have seen an address before and we currently 1016177633Sdfr * have an RPC client handle, make sure the address is 1017177633Sdfr * the same, otherwise discard the client handle. 1018177633Sdfr */ 1019184588Sdfr if (host->nh_addr.ss_len && host->nh_srvrpc.nr_client) { 1020177633Sdfr if (!nlm_compare_addr( 1021177633Sdfr (struct sockaddr *) &host->nh_addr, 1022180025Sdfr addr) 1023180025Sdfr || host->nh_vers != vers) { 1024180025Sdfr CLIENT *client; 1025180025Sdfr mtx_lock(&host->nh_lock); 1026184588Sdfr client = host->nh_srvrpc.nr_client; 1027184588Sdfr host->nh_srvrpc.nr_client = NULL; 1028180025Sdfr mtx_unlock(&host->nh_lock); 1029180025Sdfr if (client) { 1030180025Sdfr CLNT_RELEASE(client); 1031180025Sdfr } 1032177633Sdfr } 1033177633Sdfr } 1034180025Sdfr memcpy(&host->nh_addr, addr, addr->sa_len); 1035180025Sdfr host->nh_vers = vers; 1036177633Sdfr } 1037177633Sdfr 1038180025Sdfr nlm_check_idle(); 1039180025Sdfr 1040180025Sdfr mtx_unlock(&nlm_global_lock); 1041180025Sdfr 1042177633Sdfr return (host); 1043177633Sdfr} 1044177633Sdfr 1045177633Sdfr/* 1046177633Sdfr * Search for an existing NLM host that matches the given remote 1047177633Sdfr * address. If none is found, create a new host with the requested 1048177633Sdfr * address and remember 'vers' as the NLM protocol version to use for 1049177633Sdfr * that host. 1050177633Sdfr */ 1051177633Sdfrstruct nlm_host * 1052177633Sdfrnlm_find_host_by_addr(const struct sockaddr *addr, int vers) 1053177633Sdfr{ 1054180025Sdfr /* 1055180025Sdfr * Fake up a name using inet_ntop. This buffer is 1056180025Sdfr * large enough for an IPv6 address. 1057180025Sdfr */ 1058180025Sdfr char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; 1059177633Sdfr struct nlm_host *host; 1060177633Sdfr 1061180025Sdfr switch (addr->sa_family) { 1062180025Sdfr case AF_INET: 1063213103Sattilio inet_ntop(AF_INET, 1064180025Sdfr &((const struct sockaddr_in *) addr)->sin_addr, 1065180025Sdfr tmp, sizeof tmp); 1066180025Sdfr break; 1067180025Sdfr#ifdef INET6 1068180025Sdfr case AF_INET6: 1069213103Sattilio inet_ntop(AF_INET6, 1070180025Sdfr &((const struct sockaddr_in6 *) addr)->sin6_addr, 1071180025Sdfr tmp, sizeof tmp); 1072180025Sdfr break; 1073180025Sdfr#endif 1074180025Sdfr default: 1075263781Sdelphij strlcpy(tmp, "<unknown>", sizeof(tmp)); 1076180025Sdfr } 1077177633Sdfr 1078180025Sdfr 1079180025Sdfr mtx_lock(&nlm_global_lock); 1080180025Sdfr 1081177633Sdfr /* 1082177633Sdfr * The remote host is determined by caller_name. 1083177633Sdfr */ 1084177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 1085177633Sdfr if (nlm_compare_addr(addr, 1086177633Sdfr (const struct sockaddr *) &host->nh_addr)) 1087177633Sdfr break; 1088177633Sdfr } 1089177633Sdfr 1090177633Sdfr if (!host) { 1091180025Sdfr host = nlm_create_host(tmp); 1092180025Sdfr if (!host) { 1093180025Sdfr mtx_unlock(&nlm_global_lock); 1094180025Sdfr return (NULL); 1095177633Sdfr } 1096177633Sdfr memcpy(&host->nh_addr, addr, addr->sa_len); 1097177633Sdfr host->nh_vers = vers; 1098177633Sdfr } 1099180025Sdfr refcount_acquire(&host->nh_refs); 1100180025Sdfr 1101177633Sdfr host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT; 1102177633Sdfr 1103180025Sdfr nlm_check_idle(); 1104180025Sdfr 1105180025Sdfr mtx_unlock(&nlm_global_lock); 1106180025Sdfr 1107177633Sdfr return (host); 1108177633Sdfr} 1109177633Sdfr 1110177633Sdfr/* 1111177633Sdfr * Find the NLM host that matches the value of 'sysid'. If none 1112177633Sdfr * exists, return NULL. 1113177633Sdfr */ 1114177633Sdfrstatic struct nlm_host * 1115177633Sdfrnlm_find_host_by_sysid(int sysid) 1116177633Sdfr{ 1117177633Sdfr struct nlm_host *host; 1118177633Sdfr 1119177633Sdfr TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 1120180025Sdfr if (host->nh_sysid == sysid) { 1121180025Sdfr refcount_acquire(&host->nh_refs); 1122177633Sdfr return (host); 1123180025Sdfr } 1124177633Sdfr } 1125177633Sdfr 1126177633Sdfr return (NULL); 1127177633Sdfr} 1128177633Sdfr 1129180025Sdfrvoid nlm_host_release(struct nlm_host *host) 1130180025Sdfr{ 1131180025Sdfr if (refcount_release(&host->nh_refs)) { 1132180025Sdfr /* 1133180025Sdfr * Free the host 1134180025Sdfr */ 1135180025Sdfr nlm_host_destroy(host); 1136180025Sdfr } 1137180025Sdfr} 1138180025Sdfr 1139177633Sdfr/* 1140177633Sdfr * Unregister this NLM host with the local NSM due to idleness. 1141177633Sdfr */ 1142177633Sdfrstatic void 1143177633Sdfrnlm_host_unmonitor(struct nlm_host *host) 1144177633Sdfr{ 1145177633Sdfr mon_id smmonid; 1146177633Sdfr sm_stat_res smstat; 1147177633Sdfr struct timeval timo; 1148177633Sdfr enum clnt_stat stat; 1149177633Sdfr 1150191918Sdfr NLM_DEBUG(1, "NLM: unmonitoring %s (sysid %d)\n", 1151191918Sdfr host->nh_caller_name, host->nh_sysid); 1152177633Sdfr 1153177633Sdfr /* 1154177633Sdfr * We put our assigned system ID value in the priv field to 1155177633Sdfr * make it simpler to find the host if we are notified of a 1156177633Sdfr * host restart. 1157177633Sdfr */ 1158177633Sdfr smmonid.mon_name = host->nh_caller_name; 1159177633Sdfr smmonid.my_id.my_name = "localhost"; 1160177633Sdfr smmonid.my_id.my_prog = NLM_PROG; 1161177633Sdfr smmonid.my_id.my_vers = NLM_SM; 1162177633Sdfr smmonid.my_id.my_proc = NLM_SM_NOTIFY; 1163177633Sdfr 1164177633Sdfr timo.tv_sec = 25; 1165177633Sdfr timo.tv_usec = 0; 1166177633Sdfr stat = CLNT_CALL(nlm_nsm, SM_UNMON, 1167177633Sdfr (xdrproc_t) xdr_mon, &smmonid, 1168177633Sdfr (xdrproc_t) xdr_sm_stat, &smstat, timo); 1169177633Sdfr 1170177633Sdfr if (stat != RPC_SUCCESS) { 1171191918Sdfr NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat); 1172177633Sdfr return; 1173177633Sdfr } 1174177633Sdfr if (smstat.res_stat == stat_fail) { 1175191918Sdfr NLM_ERR("Local NSM refuses to unmonitor %s\n", 1176177633Sdfr host->nh_caller_name); 1177177633Sdfr return; 1178177633Sdfr } 1179177633Sdfr 1180178112Sdfr host->nh_monstate = NLM_UNMONITORED; 1181177633Sdfr} 1182177633Sdfr 1183177633Sdfr/* 1184177633Sdfr * Register this NLM host with the local NSM so that we can be 1185177633Sdfr * notified if it reboots. 1186177633Sdfr */ 1187180025Sdfrvoid 1188177633Sdfrnlm_host_monitor(struct nlm_host *host, int state) 1189177633Sdfr{ 1190177633Sdfr mon smmon; 1191177633Sdfr sm_stat_res smstat; 1192177633Sdfr struct timeval timo; 1193177633Sdfr enum clnt_stat stat; 1194177633Sdfr 1195177633Sdfr if (state && !host->nh_state) { 1196177633Sdfr /* 1197177633Sdfr * This is the first time we have seen an NSM state 1198177633Sdfr * value for this host. We record it here to help 1199177633Sdfr * detect host reboots. 1200177633Sdfr */ 1201177633Sdfr host->nh_state = state; 1202191918Sdfr NLM_DEBUG(1, "NLM: host %s (sysid %d) has NSM state %d\n", 1203191918Sdfr host->nh_caller_name, host->nh_sysid, state); 1204177633Sdfr } 1205177633Sdfr 1206180025Sdfr mtx_lock(&host->nh_lock); 1207180025Sdfr if (host->nh_monstate != NLM_UNMONITORED) { 1208180025Sdfr mtx_unlock(&host->nh_lock); 1209177633Sdfr return; 1210180025Sdfr } 1211180025Sdfr host->nh_monstate = NLM_MONITORED; 1212180025Sdfr mtx_unlock(&host->nh_lock); 1213177633Sdfr 1214191918Sdfr NLM_DEBUG(1, "NLM: monitoring %s (sysid %d)\n", 1215191918Sdfr host->nh_caller_name, host->nh_sysid); 1216177633Sdfr 1217177633Sdfr /* 1218177633Sdfr * We put our assigned system ID value in the priv field to 1219177633Sdfr * make it simpler to find the host if we are notified of a 1220177633Sdfr * host restart. 1221177633Sdfr */ 1222177633Sdfr smmon.mon_id.mon_name = host->nh_caller_name; 1223177633Sdfr smmon.mon_id.my_id.my_name = "localhost"; 1224177633Sdfr smmon.mon_id.my_id.my_prog = NLM_PROG; 1225177633Sdfr smmon.mon_id.my_id.my_vers = NLM_SM; 1226177633Sdfr smmon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; 1227177633Sdfr memcpy(smmon.priv, &host->nh_sysid, sizeof(host->nh_sysid)); 1228177633Sdfr 1229177633Sdfr timo.tv_sec = 25; 1230177633Sdfr timo.tv_usec = 0; 1231177633Sdfr stat = CLNT_CALL(nlm_nsm, SM_MON, 1232177633Sdfr (xdrproc_t) xdr_mon, &smmon, 1233177633Sdfr (xdrproc_t) xdr_sm_stat, &smstat, timo); 1234177633Sdfr 1235177633Sdfr if (stat != RPC_SUCCESS) { 1236191918Sdfr NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat); 1237177633Sdfr return; 1238177633Sdfr } 1239177633Sdfr if (smstat.res_stat == stat_fail) { 1240191918Sdfr NLM_ERR("Local NSM refuses to monitor %s\n", 1241177633Sdfr host->nh_caller_name); 1242180025Sdfr mtx_lock(&host->nh_lock); 1243178112Sdfr host->nh_monstate = NLM_MONITOR_FAILED; 1244180025Sdfr mtx_unlock(&host->nh_lock); 1245177633Sdfr return; 1246177633Sdfr } 1247177633Sdfr 1248178112Sdfr host->nh_monstate = NLM_MONITORED; 1249177633Sdfr} 1250177633Sdfr 1251177633Sdfr/* 1252177633Sdfr * Return an RPC client handle that can be used to talk to the NLM 1253177633Sdfr * running on the given host. 1254177633Sdfr */ 1255177633SdfrCLIENT * 1256184588Sdfrnlm_host_get_rpc(struct nlm_host *host, bool_t isserver) 1257177633Sdfr{ 1258184588Sdfr struct nlm_rpc *rpc; 1259180025Sdfr CLIENT *client; 1260177633Sdfr 1261180025Sdfr mtx_lock(&host->nh_lock); 1262180025Sdfr 1263184588Sdfr if (isserver) 1264184588Sdfr rpc = &host->nh_srvrpc; 1265184588Sdfr else 1266184588Sdfr rpc = &host->nh_clntrpc; 1267184588Sdfr 1268179425Sdfr /* 1269180025Sdfr * We can't hold onto RPC handles for too long - the async 1270179425Sdfr * call/reply protocol used by some NLM clients makes it hard 1271179425Sdfr * to tell when they change port numbers (e.g. after a 1272179425Sdfr * reboot). Note that if a client reboots while it isn't 1273179425Sdfr * holding any locks, it won't bother to notify us. We 1274179425Sdfr * expire the RPC handles after two minutes. 1275179425Sdfr */ 1276184588Sdfr if (rpc->nr_client && time_uptime > rpc->nr_create_time + 2*60) { 1277184588Sdfr client = rpc->nr_client; 1278184588Sdfr rpc->nr_client = NULL; 1279180025Sdfr mtx_unlock(&host->nh_lock); 1280180025Sdfr CLNT_RELEASE(client); 1281180025Sdfr mtx_lock(&host->nh_lock); 1282179425Sdfr } 1283179425Sdfr 1284184588Sdfr if (!rpc->nr_client) { 1285180025Sdfr mtx_unlock(&host->nh_lock); 1286180025Sdfr client = nlm_get_rpc((struct sockaddr *)&host->nh_addr, 1287180025Sdfr NLM_PROG, host->nh_vers); 1288180025Sdfr mtx_lock(&host->nh_lock); 1289177633Sdfr 1290180025Sdfr if (client) { 1291184588Sdfr if (rpc->nr_client) { 1292180025Sdfr mtx_unlock(&host->nh_lock); 1293180025Sdfr CLNT_DESTROY(client); 1294180025Sdfr mtx_lock(&host->nh_lock); 1295180025Sdfr } else { 1296184588Sdfr rpc->nr_client = client; 1297184588Sdfr rpc->nr_create_time = time_uptime; 1298180025Sdfr } 1299180025Sdfr } 1300180025Sdfr } 1301180025Sdfr 1302184588Sdfr client = rpc->nr_client; 1303180025Sdfr if (client) 1304180025Sdfr CLNT_ACQUIRE(client); 1305180025Sdfr mtx_unlock(&host->nh_lock); 1306180025Sdfr 1307180025Sdfr return (client); 1308180025Sdfr 1309180025Sdfr} 1310180025Sdfr 1311180025Sdfrint nlm_host_get_sysid(struct nlm_host *host) 1312180025Sdfr{ 1313180025Sdfr 1314180025Sdfr return (host->nh_sysid); 1315180025Sdfr} 1316180025Sdfr 1317180025Sdfrint 1318180025Sdfrnlm_host_get_state(struct nlm_host *host) 1319180025Sdfr{ 1320180025Sdfr 1321180025Sdfr return (host->nh_state); 1322180025Sdfr} 1323180025Sdfr 1324180025Sdfrvoid * 1325180025Sdfrnlm_register_wait_lock(struct nlm4_lock *lock, struct vnode *vp) 1326180025Sdfr{ 1327180025Sdfr struct nlm_waiting_lock *nw; 1328180025Sdfr 1329180025Sdfr nw = malloc(sizeof(struct nlm_waiting_lock), M_NLM, M_WAITOK); 1330180025Sdfr nw->nw_lock = *lock; 1331180025Sdfr memcpy(&nw->nw_fh.fh_bytes, nw->nw_lock.fh.n_bytes, 1332180025Sdfr nw->nw_lock.fh.n_len); 1333180025Sdfr nw->nw_lock.fh.n_bytes = nw->nw_fh.fh_bytes; 1334180025Sdfr nw->nw_waiting = TRUE; 1335180025Sdfr nw->nw_vp = vp; 1336180025Sdfr mtx_lock(&nlm_global_lock); 1337180025Sdfr TAILQ_INSERT_TAIL(&nlm_waiting_locks, nw, nw_link); 1338180025Sdfr mtx_unlock(&nlm_global_lock); 1339180025Sdfr 1340180025Sdfr return nw; 1341180025Sdfr} 1342180025Sdfr 1343180025Sdfrvoid 1344180025Sdfrnlm_deregister_wait_lock(void *handle) 1345180025Sdfr{ 1346180025Sdfr struct nlm_waiting_lock *nw = handle; 1347180025Sdfr 1348180025Sdfr mtx_lock(&nlm_global_lock); 1349180025Sdfr TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link); 1350180025Sdfr mtx_unlock(&nlm_global_lock); 1351180025Sdfr 1352180025Sdfr free(nw, M_NLM); 1353180025Sdfr} 1354180025Sdfr 1355180025Sdfrint 1356180025Sdfrnlm_wait_lock(void *handle, int timo) 1357180025Sdfr{ 1358180025Sdfr struct nlm_waiting_lock *nw = handle; 1359180025Sdfr int error; 1360180025Sdfr 1361177633Sdfr /* 1362180025Sdfr * If the granted message arrived before we got here, 1363180025Sdfr * nw->nw_waiting will be FALSE - in that case, don't sleep. 1364177633Sdfr */ 1365180025Sdfr mtx_lock(&nlm_global_lock); 1366180025Sdfr error = 0; 1367180025Sdfr if (nw->nw_waiting) 1368180025Sdfr error = msleep(nw, &nlm_global_lock, PCATCH, "nlmlock", timo); 1369180025Sdfr TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link); 1370180025Sdfr if (error) { 1371180025Sdfr /* 1372180025Sdfr * The granted message may arrive after the 1373180025Sdfr * interrupt/timeout but before we manage to lock the 1374180025Sdfr * mutex. Detect this by examining nw_lock. 1375180025Sdfr */ 1376180025Sdfr if (!nw->nw_waiting) 1377180025Sdfr error = 0; 1378180025Sdfr } else { 1379180025Sdfr /* 1380180025Sdfr * If nlm_cancel_wait is called, then error will be 1381180025Sdfr * zero but nw_waiting will still be TRUE. We 1382180025Sdfr * translate this into EINTR. 1383180025Sdfr */ 1384180025Sdfr if (nw->nw_waiting) 1385180025Sdfr error = EINTR; 1386180025Sdfr } 1387180025Sdfr mtx_unlock(&nlm_global_lock); 1388177633Sdfr 1389180025Sdfr free(nw, M_NLM); 1390177633Sdfr 1391180025Sdfr return (error); 1392180025Sdfr} 1393180025Sdfr 1394180025Sdfrvoid 1395180025Sdfrnlm_cancel_wait(struct vnode *vp) 1396180025Sdfr{ 1397180025Sdfr struct nlm_waiting_lock *nw; 1398180025Sdfr 1399180025Sdfr mtx_lock(&nlm_global_lock); 1400180025Sdfr TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) { 1401180025Sdfr if (nw->nw_vp == vp) { 1402180025Sdfr wakeup(nw); 1403180025Sdfr } 1404177633Sdfr } 1405180025Sdfr mtx_unlock(&nlm_global_lock); 1406177633Sdfr} 1407177633Sdfr 1408180025Sdfr 1409177633Sdfr/**********************************************************************/ 1410177633Sdfr 1411177633Sdfr/* 1412177633Sdfr * Syscall interface with userland. 1413177633Sdfr */ 1414177633Sdfr 1415177633Sdfrextern void nlm_prog_0(struct svc_req *rqstp, SVCXPRT *transp); 1416177633Sdfrextern void nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp); 1417177633Sdfrextern void nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp); 1418177633Sdfrextern void nlm_prog_4(struct svc_req *rqstp, SVCXPRT *transp); 1419177633Sdfr 1420177633Sdfrstatic int 1421177633Sdfrnlm_register_services(SVCPOOL *pool, int addr_count, char **addrs) 1422177633Sdfr{ 1423177633Sdfr static rpcvers_t versions[] = { 1424177633Sdfr NLM_SM, NLM_VERS, NLM_VERSX, NLM_VERS4 1425177633Sdfr }; 1426177633Sdfr static void (*dispatchers[])(struct svc_req *, SVCXPRT *) = { 1427177633Sdfr nlm_prog_0, nlm_prog_1, nlm_prog_3, nlm_prog_4 1428177633Sdfr }; 1429177633Sdfr static const int version_count = sizeof(versions) / sizeof(versions[0]); 1430177633Sdfr 1431177633Sdfr SVCXPRT **xprts; 1432177633Sdfr char netid[16]; 1433177633Sdfr char uaddr[128]; 1434177633Sdfr struct netconfig *nconf; 1435177633Sdfr int i, j, error; 1436177633Sdfr 1437177633Sdfr if (!addr_count) { 1438191918Sdfr NLM_ERR("NLM: no service addresses given - can't start server"); 1439177633Sdfr return (EINVAL); 1440177633Sdfr } 1441177633Sdfr 1442194407Srmacklem xprts = malloc(addr_count * sizeof(SVCXPRT *), M_NLM, M_WAITOK|M_ZERO); 1443177633Sdfr for (i = 0; i < version_count; i++) { 1444177633Sdfr for (j = 0; j < addr_count; j++) { 1445177633Sdfr /* 1446177633Sdfr * Create transports for the first version and 1447177633Sdfr * then just register everything else to the 1448177633Sdfr * same transports. 1449177633Sdfr */ 1450177633Sdfr if (i == 0) { 1451177633Sdfr char *up; 1452177633Sdfr 1453177633Sdfr error = copyin(&addrs[2*j], &up, 1454177633Sdfr sizeof(char*)); 1455177633Sdfr if (error) 1456177633Sdfr goto out; 1457177633Sdfr error = copyinstr(up, netid, sizeof(netid), 1458177633Sdfr NULL); 1459177633Sdfr if (error) 1460177633Sdfr goto out; 1461177633Sdfr error = copyin(&addrs[2*j+1], &up, 1462177633Sdfr sizeof(char*)); 1463177633Sdfr if (error) 1464177633Sdfr goto out; 1465177633Sdfr error = copyinstr(up, uaddr, sizeof(uaddr), 1466177633Sdfr NULL); 1467177633Sdfr if (error) 1468177633Sdfr goto out; 1469177633Sdfr nconf = getnetconfigent(netid); 1470177633Sdfr if (!nconf) { 1471191918Sdfr NLM_ERR("Can't lookup netid %s\n", 1472177633Sdfr netid); 1473177633Sdfr error = EINVAL; 1474177633Sdfr goto out; 1475177633Sdfr } 1476177633Sdfr xprts[j] = svc_tp_create(pool, dispatchers[i], 1477177633Sdfr NLM_PROG, versions[i], uaddr, nconf); 1478177633Sdfr if (!xprts[j]) { 1479191918Sdfr NLM_ERR("NLM: unable to create " 1480177633Sdfr "(NLM_PROG, %d).\n", versions[i]); 1481177633Sdfr error = EINVAL; 1482177633Sdfr goto out; 1483177633Sdfr } 1484177633Sdfr freenetconfigent(nconf); 1485177633Sdfr } else { 1486177633Sdfr nconf = getnetconfigent(xprts[j]->xp_netid); 1487177633Sdfr rpcb_unset(NLM_PROG, versions[i], nconf); 1488177633Sdfr if (!svc_reg(xprts[j], NLM_PROG, versions[i], 1489177633Sdfr dispatchers[i], nconf)) { 1490191918Sdfr NLM_ERR("NLM: can't register " 1491177633Sdfr "(NLM_PROG, %d)\n", versions[i]); 1492177633Sdfr error = EINVAL; 1493177633Sdfr goto out; 1494177633Sdfr } 1495177633Sdfr } 1496177633Sdfr } 1497177633Sdfr } 1498177633Sdfr error = 0; 1499177633Sdfrout: 1500194407Srmacklem for (j = 0; j < addr_count; j++) { 1501194407Srmacklem if (xprts[j]) 1502194407Srmacklem SVC_RELEASE(xprts[j]); 1503194407Srmacklem } 1504177633Sdfr free(xprts, M_NLM); 1505177633Sdfr return (error); 1506177633Sdfr} 1507177633Sdfr 1508177633Sdfr/* 1509177633Sdfr * Main server entry point. Contacts the local NSM to get its current 1510177633Sdfr * state and send SM_UNMON_ALL. Registers the NLM services and then 1511177633Sdfr * services requests. Does not return until the server is interrupted 1512177633Sdfr * by a signal. 1513177633Sdfr */ 1514177633Sdfrstatic int 1515177633Sdfrnlm_server_main(int addr_count, char **addrs) 1516177633Sdfr{ 1517177633Sdfr struct thread *td = curthread; 1518177633Sdfr int error; 1519178033Sdfr SVCPOOL *pool = NULL; 1520177633Sdfr struct sockopt opt; 1521177633Sdfr int portlow; 1522177633Sdfr#ifdef INET6 1523177633Sdfr struct sockaddr_in6 sin6; 1524177633Sdfr#endif 1525177633Sdfr struct sockaddr_in sin; 1526177633Sdfr my_id id; 1527177633Sdfr sm_stat smstat; 1528177633Sdfr struct timeval timo; 1529177633Sdfr enum clnt_stat stat; 1530180025Sdfr struct nlm_host *host, *nhost; 1531180025Sdfr struct nlm_waiting_lock *nw; 1532180025Sdfr vop_advlock_t *old_nfs_advlock; 1533180025Sdfr vop_reclaim_t *old_nfs_reclaim; 1534177633Sdfr 1535255333Srmacklem if (nlm_is_running != 0) { 1536191918Sdfr NLM_ERR("NLM: can't start server - " 1537191918Sdfr "it appears to be running already\n"); 1538177633Sdfr return (EPERM); 1539177633Sdfr } 1540177633Sdfr 1541255333Srmacklem if (nlm_socket == NULL) { 1542255333Srmacklem memset(&opt, 0, sizeof(opt)); 1543177633Sdfr 1544255333Srmacklem error = socreate(AF_INET, &nlm_socket, SOCK_DGRAM, 0, 1545255333Srmacklem td->td_ucred, td); 1546255333Srmacklem if (error) { 1547255333Srmacklem NLM_ERR("NLM: can't create IPv4 socket - error %d\n", 1548255333Srmacklem error); 1549255333Srmacklem return (error); 1550255333Srmacklem } 1551255333Srmacklem opt.sopt_dir = SOPT_SET; 1552255333Srmacklem opt.sopt_level = IPPROTO_IP; 1553255333Srmacklem opt.sopt_name = IP_PORTRANGE; 1554255333Srmacklem portlow = IP_PORTRANGE_LOW; 1555255333Srmacklem opt.sopt_val = &portlow; 1556255333Srmacklem opt.sopt_valsize = sizeof(portlow); 1557255333Srmacklem sosetopt(nlm_socket, &opt); 1558177633Sdfr 1559177633Sdfr#ifdef INET6 1560255333Srmacklem nlm_socket6 = NULL; 1561255333Srmacklem error = socreate(AF_INET6, &nlm_socket6, SOCK_DGRAM, 0, 1562255333Srmacklem td->td_ucred, td); 1563255333Srmacklem if (error) { 1564255333Srmacklem NLM_ERR("NLM: can't create IPv6 socket - error %d\n", 1565255333Srmacklem error); 1566255333Srmacklem soclose(nlm_socket); 1567255333Srmacklem nlm_socket = NULL; 1568255333Srmacklem return (error); 1569255333Srmacklem } 1570255333Srmacklem opt.sopt_dir = SOPT_SET; 1571255333Srmacklem opt.sopt_level = IPPROTO_IPV6; 1572255333Srmacklem opt.sopt_name = IPV6_PORTRANGE; 1573255333Srmacklem portlow = IPV6_PORTRANGE_LOW; 1574255333Srmacklem opt.sopt_val = &portlow; 1575255333Srmacklem opt.sopt_valsize = sizeof(portlow); 1576255333Srmacklem sosetopt(nlm_socket6, &opt); 1577255333Srmacklem#endif 1578177633Sdfr } 1579177633Sdfr 1580180025Sdfr nlm_auth = authunix_create(curthread->td_ucred); 1581180025Sdfr 1582177633Sdfr#ifdef INET6 1583177633Sdfr memset(&sin6, 0, sizeof(sin6)); 1584177633Sdfr sin6.sin6_len = sizeof(sin6); 1585177633Sdfr sin6.sin6_family = AF_INET6; 1586177633Sdfr sin6.sin6_addr = in6addr_loopback; 1587177633Sdfr nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin6, SM_PROG, SM_VERS); 1588177633Sdfr if (!nlm_nsm) { 1589177633Sdfr#endif 1590177633Sdfr memset(&sin, 0, sizeof(sin)); 1591177633Sdfr sin.sin_len = sizeof(sin); 1592178033Sdfr sin.sin_family = AF_INET; 1593177633Sdfr sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 1594177633Sdfr nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin, SM_PROG, 1595177633Sdfr SM_VERS); 1596177633Sdfr#ifdef INET6 1597177633Sdfr } 1598177633Sdfr#endif 1599177633Sdfr 1600177633Sdfr if (!nlm_nsm) { 1601191918Sdfr NLM_ERR("Can't start NLM - unable to contact NSM\n"); 1602178033Sdfr error = EINVAL; 1603178033Sdfr goto out; 1604177633Sdfr } 1605177633Sdfr 1606184588Sdfr pool = svcpool_create("NLM", NULL); 1607177633Sdfr 1608177633Sdfr error = nlm_register_services(pool, addr_count, addrs); 1609177633Sdfr if (error) 1610177633Sdfr goto out; 1611177633Sdfr 1612177633Sdfr memset(&id, 0, sizeof(id)); 1613177633Sdfr id.my_name = "NFS NLM"; 1614177633Sdfr 1615177633Sdfr timo.tv_sec = 25; 1616177633Sdfr timo.tv_usec = 0; 1617177633Sdfr stat = CLNT_CALL(nlm_nsm, SM_UNMON_ALL, 1618177633Sdfr (xdrproc_t) xdr_my_id, &id, 1619177633Sdfr (xdrproc_t) xdr_sm_stat, &smstat, timo); 1620177633Sdfr 1621177633Sdfr if (stat != RPC_SUCCESS) { 1622177633Sdfr struct rpc_err err; 1623177633Sdfr 1624177633Sdfr CLNT_GETERR(nlm_nsm, &err); 1625191918Sdfr NLM_ERR("NLM: unexpected error contacting NSM, " 1626191918Sdfr "stat=%d, errno=%d\n", stat, err.re_errno); 1627177633Sdfr error = EINVAL; 1628177633Sdfr goto out; 1629177633Sdfr } 1630255333Srmacklem nlm_is_running = 1; 1631177633Sdfr 1632191918Sdfr NLM_DEBUG(1, "NLM: local NSM state is %d\n", smstat.state); 1633180025Sdfr nlm_nsm_state = smstat.state; 1634177633Sdfr 1635180025Sdfr old_nfs_advlock = nfs_advlock_p; 1636180025Sdfr nfs_advlock_p = nlm_advlock; 1637180025Sdfr old_nfs_reclaim = nfs_reclaim_p; 1638180025Sdfr nfs_reclaim_p = nlm_reclaim; 1639180025Sdfr 1640177633Sdfr svc_run(pool); 1641177633Sdfr error = 0; 1642177633Sdfr 1643180025Sdfr nfs_advlock_p = old_nfs_advlock; 1644180025Sdfr nfs_reclaim_p = old_nfs_reclaim; 1645180025Sdfr 1646177633Sdfrout: 1647255333Srmacklem nlm_is_running = 0; 1648177633Sdfr if (pool) 1649177633Sdfr svcpool_destroy(pool); 1650177633Sdfr 1651177633Sdfr /* 1652180025Sdfr * We are finished communicating with the NSM. 1653177633Sdfr */ 1654177633Sdfr if (nlm_nsm) { 1655180025Sdfr CLNT_RELEASE(nlm_nsm); 1656177633Sdfr nlm_nsm = NULL; 1657177633Sdfr } 1658180025Sdfr 1659180025Sdfr /* 1660180025Sdfr * Trash all the existing state so that if the server 1661180025Sdfr * restarts, it gets a clean slate. This is complicated by the 1662180025Sdfr * possibility that there may be other threads trying to make 1663180025Sdfr * client locking requests. 1664180025Sdfr * 1665180025Sdfr * First we fake a client reboot notification which will 1666180025Sdfr * cancel any pending async locks and purge remote lock state 1667180025Sdfr * from the local lock manager. We release the reference from 1668180025Sdfr * nlm_hosts to the host (which may remove it from the list 1669180025Sdfr * and free it). After this phase, the only entries in the 1670180025Sdfr * nlm_host list should be from other threads performing 1671255333Srmacklem * client lock requests. 1672180025Sdfr */ 1673180025Sdfr mtx_lock(&nlm_global_lock); 1674180025Sdfr TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) { 1675180025Sdfr wakeup(nw); 1676177633Sdfr } 1677180025Sdfr TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, nhost) { 1678180025Sdfr mtx_unlock(&nlm_global_lock); 1679180025Sdfr nlm_host_notify(host, 0); 1680180025Sdfr nlm_host_release(host); 1681180025Sdfr mtx_lock(&nlm_global_lock); 1682180025Sdfr } 1683180025Sdfr mtx_unlock(&nlm_global_lock); 1684177633Sdfr 1685180025Sdfr AUTH_DESTROY(nlm_auth); 1686180025Sdfr 1687177633Sdfr return (error); 1688177633Sdfr} 1689177633Sdfr 1690177633Sdfrint 1691225617Skmacysys_nlm_syscall(struct thread *td, struct nlm_syscall_args *uap) 1692177633Sdfr{ 1693177633Sdfr int error; 1694177633Sdfr 1695177685Sdfr#if __FreeBSD_version >= 700000 1696177633Sdfr error = priv_check(td, PRIV_NFS_LOCKD); 1697177685Sdfr#else 1698177685Sdfr error = suser(td); 1699177685Sdfr#endif 1700177633Sdfr if (error) 1701177633Sdfr return (error); 1702177633Sdfr 1703177633Sdfr nlm_debug_level = uap->debug_level; 1704177633Sdfr nlm_grace_threshold = time_uptime + uap->grace_period; 1705177633Sdfr nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD; 1706177633Sdfr 1707177633Sdfr return nlm_server_main(uap->addr_count, uap->addrs); 1708177633Sdfr} 1709177633Sdfr 1710177633Sdfr/**********************************************************************/ 1711177633Sdfr 1712177633Sdfr/* 1713177633Sdfr * NLM implementation details, called from the RPC stubs. 1714177633Sdfr */ 1715177633Sdfr 1716177633Sdfr 1717177633Sdfrvoid 1718177633Sdfrnlm_sm_notify(struct nlm_sm_status *argp) 1719177633Sdfr{ 1720177633Sdfr uint32_t sysid; 1721177633Sdfr struct nlm_host *host; 1722177633Sdfr 1723191918Sdfr NLM_DEBUG(3, "nlm_sm_notify(): mon_name = %s\n", argp->mon_name); 1724177633Sdfr memcpy(&sysid, &argp->priv, sizeof(sysid)); 1725177633Sdfr host = nlm_find_host_by_sysid(sysid); 1726180025Sdfr if (host) { 1727180025Sdfr nlm_host_notify(host, argp->state); 1728180025Sdfr nlm_host_release(host); 1729180025Sdfr } 1730177633Sdfr} 1731177633Sdfr 1732177633Sdfrstatic void 1733177633Sdfrnlm_convert_to_fhandle_t(fhandle_t *fhp, struct netobj *p) 1734177633Sdfr{ 1735177633Sdfr memcpy(fhp, p->n_bytes, sizeof(fhandle_t)); 1736177633Sdfr} 1737177633Sdfr 1738177633Sdfrstruct vfs_state { 1739177633Sdfr struct mount *vs_mp; 1740177633Sdfr struct vnode *vs_vp; 1741178112Sdfr int vs_vnlocked; 1742177633Sdfr}; 1743177633Sdfr 1744177633Sdfrstatic int 1745177633Sdfrnlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp, 1746230801Srmacklem fhandle_t *fhp, struct vfs_state *vs, accmode_t accmode) 1747177633Sdfr{ 1748184588Sdfr int error, exflags; 1749230801Srmacklem struct ucred *cred = NULL, *credanon = NULL; 1750177633Sdfr 1751177633Sdfr memset(vs, 0, sizeof(*vs)); 1752177633Sdfr 1753177633Sdfr vs->vs_mp = vfs_getvfs(&fhp->fh_fsid); 1754177633Sdfr if (!vs->vs_mp) { 1755177633Sdfr return (ESTALE); 1756177633Sdfr } 1757177633Sdfr 1758230801Srmacklem /* accmode == 0 means don't check, since it is an unlock. */ 1759230801Srmacklem if (accmode != 0) { 1760230801Srmacklem error = VFS_CHECKEXP(vs->vs_mp, 1761230801Srmacklem (struct sockaddr *)&host->nh_addr, &exflags, &credanon, 1762230801Srmacklem NULL, NULL); 1763230801Srmacklem if (error) 1764230801Srmacklem goto out; 1765177633Sdfr 1766230801Srmacklem if (exflags & MNT_EXRDONLY || 1767230801Srmacklem (vs->vs_mp->mnt_flag & MNT_RDONLY)) { 1768230801Srmacklem error = EROFS; 1769230801Srmacklem goto out; 1770230801Srmacklem } 1771177633Sdfr } 1772177633Sdfr 1773222167Srmacklem error = VFS_FHTOVP(vs->vs_mp, &fhp->fh_fid, LK_EXCLUSIVE, &vs->vs_vp); 1774177633Sdfr if (error) 1775177633Sdfr goto out; 1776178112Sdfr vs->vs_vnlocked = TRUE; 1777177633Sdfr 1778230801Srmacklem if (accmode != 0) { 1779230801Srmacklem if (!svc_getcred(rqstp, &cred, NULL)) { 1780230801Srmacklem error = EINVAL; 1781230801Srmacklem goto out; 1782230801Srmacklem } 1783230801Srmacklem if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1784230801Srmacklem crfree(cred); 1785230801Srmacklem cred = credanon; 1786230801Srmacklem credanon = NULL; 1787230801Srmacklem } 1788230801Srmacklem 1789230801Srmacklem /* 1790230801Srmacklem * Check cred. 1791230801Srmacklem */ 1792230801Srmacklem error = VOP_ACCESS(vs->vs_vp, accmode, cred, curthread); 1793230801Srmacklem /* 1794230801Srmacklem * If this failed and accmode != VWRITE, try again with 1795230801Srmacklem * VWRITE to maintain backwards compatibility with the 1796230801Srmacklem * old code that always used VWRITE. 1797230801Srmacklem */ 1798230801Srmacklem if (error != 0 && accmode != VWRITE) 1799230801Srmacklem error = VOP_ACCESS(vs->vs_vp, VWRITE, cred, curthread); 1800230801Srmacklem if (error) 1801230801Srmacklem goto out; 1802177633Sdfr } 1803177633Sdfr 1804178112Sdfr#if __FreeBSD_version < 800011 1805178112Sdfr VOP_UNLOCK(vs->vs_vp, 0, curthread); 1806178112Sdfr#else 1807178112Sdfr VOP_UNLOCK(vs->vs_vp, 0); 1808178112Sdfr#endif 1809178112Sdfr vs->vs_vnlocked = FALSE; 1810178112Sdfr 1811177633Sdfrout: 1812184588Sdfr if (cred) 1813177633Sdfr crfree(cred); 1814191940Skan if (credanon) 1815191940Skan crfree(credanon); 1816177633Sdfr 1817177633Sdfr return (error); 1818177633Sdfr} 1819177633Sdfr 1820177633Sdfrstatic void 1821177633Sdfrnlm_release_vfs_state(struct vfs_state *vs) 1822177633Sdfr{ 1823177633Sdfr 1824178112Sdfr if (vs->vs_vp) { 1825178112Sdfr if (vs->vs_vnlocked) 1826178112Sdfr vput(vs->vs_vp); 1827178112Sdfr else 1828178112Sdfr vrele(vs->vs_vp); 1829178112Sdfr } 1830177633Sdfr if (vs->vs_mp) 1831177633Sdfr vfs_rel(vs->vs_mp); 1832177633Sdfr} 1833177633Sdfr 1834177633Sdfrstatic nlm4_stats 1835177633Sdfrnlm_convert_error(int error) 1836177633Sdfr{ 1837177633Sdfr 1838177633Sdfr if (error == ESTALE) 1839177633Sdfr return nlm4_stale_fh; 1840177633Sdfr else if (error == EROFS) 1841177633Sdfr return nlm4_rofs; 1842177633Sdfr else 1843177633Sdfr return nlm4_failed; 1844177633Sdfr} 1845177633Sdfr 1846180025Sdfrint 1847180025Sdfrnlm_do_test(nlm4_testargs *argp, nlm4_testres *result, struct svc_req *rqstp, 1848180025Sdfr CLIENT **rpcp) 1849177633Sdfr{ 1850177633Sdfr fhandle_t fh; 1851177633Sdfr struct vfs_state vs; 1852177633Sdfr struct nlm_host *host, *bhost; 1853177633Sdfr int error, sysid; 1854177633Sdfr struct flock fl; 1855230801Srmacklem accmode_t accmode; 1856177633Sdfr 1857177633Sdfr memset(result, 0, sizeof(*result)); 1858180025Sdfr memset(&vs, 0, sizeof(vs)); 1859177633Sdfr 1860180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 1861184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 1862177633Sdfr if (!host) { 1863177633Sdfr result->stat.stat = nlm4_denied_nolocks; 1864180025Sdfr return (ENOMEM); 1865177633Sdfr } 1866177633Sdfr 1867191918Sdfr NLM_DEBUG(3, "nlm_do_test(): caller_name = %s (sysid = %d)\n", 1868191918Sdfr host->nh_caller_name, host->nh_sysid); 1869177633Sdfr 1870197840Szml nlm_check_expired_locks(host); 1871177633Sdfr sysid = host->nh_sysid; 1872177633Sdfr 1873177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1874177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1875177633Sdfr 1876177633Sdfr if (time_uptime < nlm_grace_threshold) { 1877177633Sdfr result->stat.stat = nlm4_denied_grace_period; 1878180025Sdfr goto out; 1879177633Sdfr } 1880177633Sdfr 1881230801Srmacklem accmode = argp->exclusive ? VWRITE : VREAD; 1882230801Srmacklem error = nlm_get_vfs_state(host, rqstp, &fh, &vs, accmode); 1883177633Sdfr if (error) { 1884177633Sdfr result->stat.stat = nlm_convert_error(error); 1885177633Sdfr goto out; 1886177633Sdfr } 1887177633Sdfr 1888177633Sdfr fl.l_start = argp->alock.l_offset; 1889177633Sdfr fl.l_len = argp->alock.l_len; 1890177633Sdfr fl.l_pid = argp->alock.svid; 1891177633Sdfr fl.l_sysid = sysid; 1892177633Sdfr fl.l_whence = SEEK_SET; 1893177633Sdfr if (argp->exclusive) 1894177633Sdfr fl.l_type = F_WRLCK; 1895177633Sdfr else 1896177633Sdfr fl.l_type = F_RDLCK; 1897177633Sdfr error = VOP_ADVLOCK(vs.vs_vp, NULL, F_GETLK, &fl, F_REMOTE); 1898177633Sdfr if (error) { 1899177633Sdfr result->stat.stat = nlm4_failed; 1900177633Sdfr goto out; 1901177633Sdfr } 1902177633Sdfr 1903177633Sdfr if (fl.l_type == F_UNLCK) { 1904177633Sdfr result->stat.stat = nlm4_granted; 1905177633Sdfr } else { 1906177633Sdfr result->stat.stat = nlm4_denied; 1907177633Sdfr result->stat.nlm4_testrply_u.holder.exclusive = 1908177633Sdfr (fl.l_type == F_WRLCK); 1909177633Sdfr result->stat.nlm4_testrply_u.holder.svid = fl.l_pid; 1910177633Sdfr bhost = nlm_find_host_by_sysid(fl.l_sysid); 1911177633Sdfr if (bhost) { 1912177633Sdfr /* 1913177633Sdfr * We don't have any useful way of recording 1914177633Sdfr * the value of oh used in the original lock 1915177633Sdfr * request. Ideally, the test reply would have 1916177633Sdfr * a space for the owning host's name allowing 1917177633Sdfr * our caller's NLM to keep track. 1918177633Sdfr * 1919177633Sdfr * As far as I can see, Solaris uses an eight 1920177633Sdfr * byte structure for oh which contains a four 1921177633Sdfr * byte pid encoded in local byte order and 1922177633Sdfr * the first four bytes of the host 1923177633Sdfr * name. Linux uses a variable length string 1924177633Sdfr * 'pid@hostname' in ascii but doesn't even 1925177633Sdfr * return that in test replies. 1926177633Sdfr * 1927177633Sdfr * For the moment, return nothing in oh 1928177633Sdfr * (already zero'ed above). 1929177633Sdfr */ 1930180025Sdfr nlm_host_release(bhost); 1931177633Sdfr } 1932177633Sdfr result->stat.nlm4_testrply_u.holder.l_offset = fl.l_start; 1933177633Sdfr result->stat.nlm4_testrply_u.holder.l_len = fl.l_len; 1934177633Sdfr } 1935177633Sdfr 1936177633Sdfrout: 1937177633Sdfr nlm_release_vfs_state(&vs); 1938180025Sdfr if (rpcp) 1939184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 1940180025Sdfr nlm_host_release(host); 1941180025Sdfr return (0); 1942177633Sdfr} 1943177633Sdfr 1944180025Sdfrint 1945177633Sdfrnlm_do_lock(nlm4_lockargs *argp, nlm4_res *result, struct svc_req *rqstp, 1946180025Sdfr bool_t monitor, CLIENT **rpcp) 1947177633Sdfr{ 1948177633Sdfr fhandle_t fh; 1949177633Sdfr struct vfs_state vs; 1950177633Sdfr struct nlm_host *host; 1951177633Sdfr int error, sysid; 1952177633Sdfr struct flock fl; 1953230801Srmacklem accmode_t accmode; 1954177633Sdfr 1955177633Sdfr memset(result, 0, sizeof(*result)); 1956180025Sdfr memset(&vs, 0, sizeof(vs)); 1957177633Sdfr 1958180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 1959184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 1960177633Sdfr if (!host) { 1961177633Sdfr result->stat.stat = nlm4_denied_nolocks; 1962180025Sdfr return (ENOMEM); 1963177633Sdfr } 1964177633Sdfr 1965191918Sdfr NLM_DEBUG(3, "nlm_do_lock(): caller_name = %s (sysid = %d)\n", 1966191918Sdfr host->nh_caller_name, host->nh_sysid); 1967177633Sdfr 1968179488Sdfr if (monitor && host->nh_state && argp->state 1969179488Sdfr && host->nh_state != argp->state) { 1970179488Sdfr /* 1971179488Sdfr * The host rebooted without telling us. Trash its 1972179488Sdfr * locks. 1973179488Sdfr */ 1974180025Sdfr nlm_host_notify(host, argp->state); 1975179488Sdfr } 1976179488Sdfr 1977197840Szml nlm_check_expired_locks(host); 1978177633Sdfr sysid = host->nh_sysid; 1979177633Sdfr 1980177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1981177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1982177633Sdfr 1983177633Sdfr if (time_uptime < nlm_grace_threshold && !argp->reclaim) { 1984177633Sdfr result->stat.stat = nlm4_denied_grace_period; 1985180025Sdfr goto out; 1986177633Sdfr } 1987177633Sdfr 1988230801Srmacklem accmode = argp->exclusive ? VWRITE : VREAD; 1989230801Srmacklem error = nlm_get_vfs_state(host, rqstp, &fh, &vs, accmode); 1990177633Sdfr if (error) { 1991177633Sdfr result->stat.stat = nlm_convert_error(error); 1992177633Sdfr goto out; 1993177633Sdfr } 1994177633Sdfr 1995177633Sdfr fl.l_start = argp->alock.l_offset; 1996177633Sdfr fl.l_len = argp->alock.l_len; 1997177633Sdfr fl.l_pid = argp->alock.svid; 1998177633Sdfr fl.l_sysid = sysid; 1999177633Sdfr fl.l_whence = SEEK_SET; 2000177633Sdfr if (argp->exclusive) 2001177633Sdfr fl.l_type = F_WRLCK; 2002177633Sdfr else 2003177633Sdfr fl.l_type = F_RDLCK; 2004177633Sdfr if (argp->block) { 2005177633Sdfr struct nlm_async_lock *af; 2006180025Sdfr CLIENT *client; 2007197840Szml struct nlm_grantcookie cookie; 2008177633Sdfr 2009177633Sdfr /* 2010177633Sdfr * First, make sure we can contact the host's NLM. 2011177633Sdfr */ 2012184588Sdfr client = nlm_host_get_rpc(host, TRUE); 2013180025Sdfr if (!client) { 2014177633Sdfr result->stat.stat = nlm4_failed; 2015177633Sdfr goto out; 2016177633Sdfr } 2017177633Sdfr 2018177633Sdfr /* 2019177633Sdfr * First we need to check and see if there is an 2020177633Sdfr * existing blocked lock that matches. This could be a 2021177633Sdfr * badly behaved client or an RPC re-send. If we find 2022177633Sdfr * one, just return nlm4_blocked. 2023177633Sdfr */ 2024177633Sdfr mtx_lock(&host->nh_lock); 2025177633Sdfr TAILQ_FOREACH(af, &host->nh_pending, af_link) { 2026177633Sdfr if (af->af_fl.l_start == fl.l_start 2027177633Sdfr && af->af_fl.l_len == fl.l_len 2028177633Sdfr && af->af_fl.l_pid == fl.l_pid 2029177633Sdfr && af->af_fl.l_type == fl.l_type) { 2030177633Sdfr break; 2031177633Sdfr } 2032177633Sdfr } 2033197840Szml if (!af) { 2034197840Szml cookie.ng_sysid = host->nh_sysid; 2035197840Szml cookie.ng_cookie = host->nh_grantcookie++; 2036197840Szml } 2037177633Sdfr mtx_unlock(&host->nh_lock); 2038177633Sdfr if (af) { 2039180025Sdfr CLNT_RELEASE(client); 2040177633Sdfr result->stat.stat = nlm4_blocked; 2041177633Sdfr goto out; 2042177633Sdfr } 2043177633Sdfr 2044177633Sdfr af = malloc(sizeof(struct nlm_async_lock), M_NLM, 2045177633Sdfr M_WAITOK|M_ZERO); 2046177633Sdfr TASK_INIT(&af->af_task, 0, nlm_lock_callback, af); 2047177633Sdfr af->af_vp = vs.vs_vp; 2048177633Sdfr af->af_fl = fl; 2049177633Sdfr af->af_host = host; 2050180025Sdfr af->af_rpc = client; 2051177633Sdfr /* 2052177633Sdfr * We use M_RPC here so that we can xdr_free the thing 2053177633Sdfr * later. 2054177633Sdfr */ 2055197840Szml nlm_make_netobj(&af->af_granted.cookie, 2056197840Szml (caddr_t)&cookie, sizeof(cookie), M_RPC); 2057177633Sdfr af->af_granted.exclusive = argp->exclusive; 2058177633Sdfr af->af_granted.alock.caller_name = 2059177633Sdfr strdup(argp->alock.caller_name, M_RPC); 2060177633Sdfr nlm_copy_netobj(&af->af_granted.alock.fh, 2061177633Sdfr &argp->alock.fh, M_RPC); 2062177633Sdfr nlm_copy_netobj(&af->af_granted.alock.oh, 2063177633Sdfr &argp->alock.oh, M_RPC); 2064177633Sdfr af->af_granted.alock.svid = argp->alock.svid; 2065177633Sdfr af->af_granted.alock.l_offset = argp->alock.l_offset; 2066177633Sdfr af->af_granted.alock.l_len = argp->alock.l_len; 2067177633Sdfr 2068177633Sdfr /* 2069177633Sdfr * Put the entry on the pending list before calling 2070177633Sdfr * VOP_ADVLOCKASYNC. We do this in case the lock 2071177633Sdfr * request was blocked (returning EINPROGRESS) but 2072177633Sdfr * then granted before we manage to run again. The 2073177633Sdfr * client may receive the granted message before we 2074177633Sdfr * send our blocked reply but thats their problem. 2075177633Sdfr */ 2076177633Sdfr mtx_lock(&host->nh_lock); 2077177633Sdfr TAILQ_INSERT_TAIL(&host->nh_pending, af, af_link); 2078177633Sdfr mtx_unlock(&host->nh_lock); 2079177633Sdfr 2080177633Sdfr error = VOP_ADVLOCKASYNC(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE, 2081177633Sdfr &af->af_task, &af->af_cookie); 2082177633Sdfr 2083177633Sdfr /* 2084177633Sdfr * If the lock completed synchronously, just free the 2085177633Sdfr * tracking structure now. 2086177633Sdfr */ 2087177633Sdfr if (error != EINPROGRESS) { 2088180025Sdfr CLNT_RELEASE(af->af_rpc); 2089177633Sdfr mtx_lock(&host->nh_lock); 2090177633Sdfr TAILQ_REMOVE(&host->nh_pending, af, af_link); 2091177633Sdfr mtx_unlock(&host->nh_lock); 2092177633Sdfr xdr_free((xdrproc_t) xdr_nlm4_testargs, 2093177633Sdfr &af->af_granted); 2094177633Sdfr free(af, M_NLM); 2095177633Sdfr } else { 2096191918Sdfr NLM_DEBUG(2, "NLM: pending async lock %p for %s " 2097191918Sdfr "(sysid %d)\n", af, host->nh_caller_name, sysid); 2098177633Sdfr /* 2099177633Sdfr * Don't vrele the vnode just yet - this must 2100177633Sdfr * wait until either the async callback 2101177633Sdfr * happens or the lock is cancelled. 2102177633Sdfr */ 2103177633Sdfr vs.vs_vp = NULL; 2104177633Sdfr } 2105177633Sdfr } else { 2106177633Sdfr error = VOP_ADVLOCK(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE); 2107177633Sdfr } 2108177633Sdfr 2109177633Sdfr if (error) { 2110177633Sdfr if (error == EINPROGRESS) { 2111177633Sdfr result->stat.stat = nlm4_blocked; 2112177633Sdfr } else if (error == EDEADLK) { 2113177633Sdfr result->stat.stat = nlm4_deadlck; 2114177633Sdfr } else if (error == EAGAIN) { 2115177633Sdfr result->stat.stat = nlm4_denied; 2116177633Sdfr } else { 2117177633Sdfr result->stat.stat = nlm4_failed; 2118177633Sdfr } 2119177633Sdfr } else { 2120177633Sdfr if (monitor) 2121177633Sdfr nlm_host_monitor(host, argp->state); 2122177633Sdfr result->stat.stat = nlm4_granted; 2123177633Sdfr } 2124177633Sdfr 2125177633Sdfrout: 2126177633Sdfr nlm_release_vfs_state(&vs); 2127180025Sdfr if (rpcp) 2128184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2129180025Sdfr nlm_host_release(host); 2130180025Sdfr return (0); 2131177633Sdfr} 2132177633Sdfr 2133180025Sdfrint 2134180025Sdfrnlm_do_cancel(nlm4_cancargs *argp, nlm4_res *result, struct svc_req *rqstp, 2135180025Sdfr CLIENT **rpcp) 2136177633Sdfr{ 2137177633Sdfr fhandle_t fh; 2138177633Sdfr struct vfs_state vs; 2139177633Sdfr struct nlm_host *host; 2140177633Sdfr int error, sysid; 2141177633Sdfr struct flock fl; 2142177633Sdfr struct nlm_async_lock *af; 2143177633Sdfr 2144177633Sdfr memset(result, 0, sizeof(*result)); 2145180025Sdfr memset(&vs, 0, sizeof(vs)); 2146177633Sdfr 2147180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 2148184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 2149177633Sdfr if (!host) { 2150177633Sdfr result->stat.stat = nlm4_denied_nolocks; 2151180025Sdfr return (ENOMEM); 2152177633Sdfr } 2153177633Sdfr 2154191918Sdfr NLM_DEBUG(3, "nlm_do_cancel(): caller_name = %s (sysid = %d)\n", 2155191918Sdfr host->nh_caller_name, host->nh_sysid); 2156177633Sdfr 2157197840Szml nlm_check_expired_locks(host); 2158177633Sdfr sysid = host->nh_sysid; 2159177633Sdfr 2160177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 2161177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 2162177633Sdfr 2163177633Sdfr if (time_uptime < nlm_grace_threshold) { 2164177633Sdfr result->stat.stat = nlm4_denied_grace_period; 2165180025Sdfr goto out; 2166177633Sdfr } 2167177633Sdfr 2168230801Srmacklem error = nlm_get_vfs_state(host, rqstp, &fh, &vs, (accmode_t)0); 2169177633Sdfr if (error) { 2170177633Sdfr result->stat.stat = nlm_convert_error(error); 2171177633Sdfr goto out; 2172177633Sdfr } 2173177633Sdfr 2174177633Sdfr fl.l_start = argp->alock.l_offset; 2175177633Sdfr fl.l_len = argp->alock.l_len; 2176177633Sdfr fl.l_pid = argp->alock.svid; 2177177633Sdfr fl.l_sysid = sysid; 2178177633Sdfr fl.l_whence = SEEK_SET; 2179177633Sdfr if (argp->exclusive) 2180177633Sdfr fl.l_type = F_WRLCK; 2181177633Sdfr else 2182177633Sdfr fl.l_type = F_RDLCK; 2183177633Sdfr 2184177633Sdfr /* 2185177633Sdfr * First we need to try and find the async lock request - if 2186177633Sdfr * there isn't one, we give up and return nlm4_denied. 2187177633Sdfr */ 2188177633Sdfr mtx_lock(&host->nh_lock); 2189177633Sdfr 2190177633Sdfr TAILQ_FOREACH(af, &host->nh_pending, af_link) { 2191177633Sdfr if (af->af_fl.l_start == fl.l_start 2192177633Sdfr && af->af_fl.l_len == fl.l_len 2193177633Sdfr && af->af_fl.l_pid == fl.l_pid 2194177633Sdfr && af->af_fl.l_type == fl.l_type) { 2195177633Sdfr break; 2196177633Sdfr } 2197177633Sdfr } 2198177633Sdfr 2199177633Sdfr if (!af) { 2200177633Sdfr mtx_unlock(&host->nh_lock); 2201177633Sdfr result->stat.stat = nlm4_denied; 2202177633Sdfr goto out; 2203177633Sdfr } 2204177633Sdfr 2205177633Sdfr error = nlm_cancel_async_lock(af); 2206177633Sdfr 2207177633Sdfr if (error) { 2208177633Sdfr result->stat.stat = nlm4_denied; 2209177633Sdfr } else { 2210177633Sdfr result->stat.stat = nlm4_granted; 2211177633Sdfr } 2212177633Sdfr 2213177633Sdfr mtx_unlock(&host->nh_lock); 2214177633Sdfr 2215177633Sdfrout: 2216177633Sdfr nlm_release_vfs_state(&vs); 2217180025Sdfr if (rpcp) 2218184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2219180025Sdfr nlm_host_release(host); 2220180025Sdfr return (0); 2221177633Sdfr} 2222177633Sdfr 2223180025Sdfrint 2224180025Sdfrnlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *result, struct svc_req *rqstp, 2225180025Sdfr CLIENT **rpcp) 2226177633Sdfr{ 2227177633Sdfr fhandle_t fh; 2228177633Sdfr struct vfs_state vs; 2229177633Sdfr struct nlm_host *host; 2230177633Sdfr int error, sysid; 2231177633Sdfr struct flock fl; 2232177633Sdfr 2233177633Sdfr memset(result, 0, sizeof(*result)); 2234180025Sdfr memset(&vs, 0, sizeof(vs)); 2235177633Sdfr 2236180025Sdfr host = nlm_find_host_by_name(argp->alock.caller_name, 2237184588Sdfr svc_getrpccaller(rqstp), rqstp->rq_vers); 2238177633Sdfr if (!host) { 2239177633Sdfr result->stat.stat = nlm4_denied_nolocks; 2240180025Sdfr return (ENOMEM); 2241177633Sdfr } 2242177633Sdfr 2243191918Sdfr NLM_DEBUG(3, "nlm_do_unlock(): caller_name = %s (sysid = %d)\n", 2244191918Sdfr host->nh_caller_name, host->nh_sysid); 2245177633Sdfr 2246197840Szml nlm_check_expired_locks(host); 2247177633Sdfr sysid = host->nh_sysid; 2248177633Sdfr 2249177633Sdfr nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 2250177633Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 2251177633Sdfr 2252177633Sdfr if (time_uptime < nlm_grace_threshold) { 2253177633Sdfr result->stat.stat = nlm4_denied_grace_period; 2254180025Sdfr goto out; 2255177633Sdfr } 2256177633Sdfr 2257230801Srmacklem error = nlm_get_vfs_state(host, rqstp, &fh, &vs, (accmode_t)0); 2258177633Sdfr if (error) { 2259177633Sdfr result->stat.stat = nlm_convert_error(error); 2260177633Sdfr goto out; 2261177633Sdfr } 2262177633Sdfr 2263177633Sdfr fl.l_start = argp->alock.l_offset; 2264177633Sdfr fl.l_len = argp->alock.l_len; 2265177633Sdfr fl.l_pid = argp->alock.svid; 2266177633Sdfr fl.l_sysid = sysid; 2267177633Sdfr fl.l_whence = SEEK_SET; 2268177633Sdfr fl.l_type = F_UNLCK; 2269177633Sdfr error = VOP_ADVLOCK(vs.vs_vp, NULL, F_UNLCK, &fl, F_REMOTE); 2270177633Sdfr 2271177633Sdfr /* 2272177633Sdfr * Ignore the error - there is no result code for failure, 2273177633Sdfr * only for grace period. 2274177633Sdfr */ 2275177633Sdfr result->stat.stat = nlm4_granted; 2276177633Sdfr 2277177633Sdfrout: 2278177633Sdfr nlm_release_vfs_state(&vs); 2279180025Sdfr if (rpcp) 2280184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2281180025Sdfr nlm_host_release(host); 2282180025Sdfr return (0); 2283180025Sdfr} 2284177633Sdfr 2285180025Sdfrint 2286180025Sdfrnlm_do_granted(nlm4_testargs *argp, nlm4_res *result, struct svc_req *rqstp, 2287180025Sdfr 2288180025Sdfr CLIENT **rpcp) 2289180025Sdfr{ 2290180025Sdfr struct nlm_host *host; 2291180025Sdfr struct nlm_waiting_lock *nw; 2292180025Sdfr 2293180025Sdfr memset(result, 0, sizeof(*result)); 2294180025Sdfr 2295184588Sdfr host = nlm_find_host_by_addr(svc_getrpccaller(rqstp), rqstp->rq_vers); 2296180025Sdfr if (!host) { 2297180025Sdfr result->stat.stat = nlm4_denied_nolocks; 2298180025Sdfr return (ENOMEM); 2299180025Sdfr } 2300180025Sdfr 2301180025Sdfr nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 2302180025Sdfr result->stat.stat = nlm4_denied; 2303197840Szml KFAIL_POINT_CODE(DEBUG_FP, nlm_deny_grant, goto out); 2304180025Sdfr 2305180025Sdfr mtx_lock(&nlm_global_lock); 2306180025Sdfr TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) { 2307180025Sdfr if (!nw->nw_waiting) 2308180025Sdfr continue; 2309180025Sdfr if (argp->alock.svid == nw->nw_lock.svid 2310180025Sdfr && argp->alock.l_offset == nw->nw_lock.l_offset 2311180025Sdfr && argp->alock.l_len == nw->nw_lock.l_len 2312180025Sdfr && argp->alock.fh.n_len == nw->nw_lock.fh.n_len 2313180025Sdfr && !memcmp(argp->alock.fh.n_bytes, nw->nw_lock.fh.n_bytes, 2314180025Sdfr nw->nw_lock.fh.n_len)) { 2315180025Sdfr nw->nw_waiting = FALSE; 2316180025Sdfr wakeup(nw); 2317180025Sdfr result->stat.stat = nlm4_granted; 2318180025Sdfr break; 2319180025Sdfr } 2320180025Sdfr } 2321180025Sdfr mtx_unlock(&nlm_global_lock); 2322197840Szml 2323197840Szmlout: 2324180025Sdfr if (rpcp) 2325184588Sdfr *rpcp = nlm_host_get_rpc(host, TRUE); 2326180025Sdfr nlm_host_release(host); 2327180025Sdfr return (0); 2328177633Sdfr} 2329177633Sdfr 2330177633Sdfrvoid 2331197840Szmlnlm_do_granted_res(nlm4_res *argp, struct svc_req *rqstp) 2332197840Szml{ 2333197840Szml struct nlm_host *host = NULL; 2334197840Szml struct nlm_async_lock *af = NULL; 2335197840Szml int error; 2336197840Szml 2337197840Szml if (argp->cookie.n_len != sizeof(struct nlm_grantcookie)) { 2338197840Szml NLM_DEBUG(1, "NLM: bogus grant cookie"); 2339197840Szml goto out; 2340197840Szml } 2341197840Szml 2342197840Szml host = nlm_find_host_by_sysid(ng_sysid(&argp->cookie)); 2343197840Szml if (!host) { 2344197840Szml NLM_DEBUG(1, "NLM: Unknown host rejected our grant"); 2345197840Szml goto out; 2346197840Szml } 2347197840Szml 2348197840Szml mtx_lock(&host->nh_lock); 2349197840Szml TAILQ_FOREACH(af, &host->nh_granted, af_link) 2350197840Szml if (ng_cookie(&argp->cookie) == 2351197840Szml ng_cookie(&af->af_granted.cookie)) 2352197840Szml break; 2353197840Szml if (af) 2354197840Szml TAILQ_REMOVE(&host->nh_granted, af, af_link); 2355197840Szml mtx_unlock(&host->nh_lock); 2356197840Szml 2357197840Szml if (!af) { 2358197840Szml NLM_DEBUG(1, "NLM: host %s (sysid %d) replied to our grant " 2359197840Szml "with unrecognized cookie %d:%d", host->nh_caller_name, 2360197840Szml host->nh_sysid, ng_sysid(&argp->cookie), 2361197840Szml ng_cookie(&argp->cookie)); 2362197840Szml goto out; 2363197840Szml } 2364197840Szml 2365197840Szml if (argp->stat.stat != nlm4_granted) { 2366197840Szml af->af_fl.l_type = F_UNLCK; 2367197840Szml error = VOP_ADVLOCK(af->af_vp, NULL, F_UNLCK, &af->af_fl, F_REMOTE); 2368197840Szml if (error) { 2369197840Szml NLM_DEBUG(1, "NLM: host %s (sysid %d) rejected our grant " 2370197840Szml "and we failed to unlock (%d)", host->nh_caller_name, 2371197840Szml host->nh_sysid, error); 2372197840Szml goto out; 2373197840Szml } 2374197840Szml 2375197840Szml NLM_DEBUG(5, "NLM: async lock %p rejected by host %s (sysid %d)", 2376197840Szml af, host->nh_caller_name, host->nh_sysid); 2377197840Szml } else { 2378197840Szml NLM_DEBUG(5, "NLM: async lock %p accepted by host %s (sysid %d)", 2379197840Szml af, host->nh_caller_name, host->nh_sysid); 2380197840Szml } 2381197840Szml 2382197840Szml out: 2383197840Szml if (af) 2384197840Szml nlm_free_async_lock(af); 2385197840Szml if (host) 2386197840Szml nlm_host_release(host); 2387197840Szml} 2388197840Szml 2389197840Szmlvoid 2390177633Sdfrnlm_do_free_all(nlm4_notify *argp) 2391177633Sdfr{ 2392177633Sdfr struct nlm_host *host, *thost; 2393177633Sdfr 2394177633Sdfr TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, thost) { 2395177633Sdfr if (!strcmp(host->nh_caller_name, argp->name)) 2396180025Sdfr nlm_host_notify(host, argp->state); 2397177633Sdfr } 2398177633Sdfr} 2399177633Sdfr 2400177633Sdfr/* 2401177662Sdfr * Kernel module glue 2402177662Sdfr */ 2403177662Sdfrstatic int 2404177662Sdfrnfslockd_modevent(module_t mod, int type, void *data) 2405177662Sdfr{ 2406177662Sdfr 2407255333Srmacklem switch (type) { 2408255333Srmacklem case MOD_LOAD: 2409255333Srmacklem return (0); 2410255333Srmacklem case MOD_UNLOAD: 2411255333Srmacklem /* The NLM module cannot be safely unloaded. */ 2412255333Srmacklem /* FALLTHROUGH */ 2413255333Srmacklem default: 2414255333Srmacklem return (EOPNOTSUPP); 2415255333Srmacklem } 2416177662Sdfr} 2417177662Sdfrstatic moduledata_t nfslockd_mod = { 2418177662Sdfr "nfslockd", 2419177662Sdfr nfslockd_modevent, 2420177662Sdfr NULL, 2421177662Sdfr}; 2422177662SdfrDECLARE_MODULE(nfslockd, nfslockd_mod, SI_SUB_VFS, SI_ORDER_ANY); 2423177662Sdfr 2424177662Sdfr/* So that loader and kldload(2) can find us, wherever we are.. */ 2425177662SdfrMODULE_DEPEND(nfslockd, krpc, 1, 1, 1); 2426214048SrmacklemMODULE_DEPEND(nfslockd, nfslock, 1, 1, 1); 2427177662SdfrMODULE_VERSION(nfslockd, 1); 2428