nlm_prot_impl.c revision 179488
179697Snon/*- 2119418Sobrien * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3119418Sobrien * Authors: Doug Rabson <dfr@rabson.org> 4119418Sobrien * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 573149Snyan * 673149Snyan * Redistribution and use in source and binary forms, with or without 7139749Simp * modification, are permitted provided that the following conditions 873149Snyan * are met: 979697Snon * 1. Redistributions of source code must retain the above copyright 1073149Snyan * notice, this list of conditions and the following disclaimer. 1173149Snyan * 2. Redistributions in binary form must reproduce the above copyright 1279697Snon * notice, this list of conditions and the following disclaimer in the 1373149Snyan * documentation and/or other materials provided with the distribution. 1473149Snyan * 1573149Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1673149Snyan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1773149Snyan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1873149Snyan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1973149Snyan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2073149Snyan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2173149Snyan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2273149Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2373149Snyan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2473149Snyan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2573149Snyan * SUCH DAMAGE. 2673149Snyan */ 2773149Snyan 2873149Snyan#include "opt_inet6.h" 2973149Snyan 3073149Snyan#include <sys/cdefs.h> 3173149Snyan__FBSDID("$FreeBSD: head/sys/nlm/nlm_prot_impl.c 179488 2008-06-02 15:59:10Z dfr $"); 3273149Snyan 3373149Snyan#include <sys/param.h> 3473149Snyan#include <sys/fcntl.h> 3573149Snyan#include <sys/kernel.h> 3673149Snyan#include <sys/lockf.h> 3773149Snyan#include <sys/malloc.h> 3873149Snyan#include <sys/mount.h> 3973149Snyan#if __FreeBSD_version >= 700000 4073149Snyan#include <sys/priv.h> 4173149Snyan#endif 4273149Snyan#include <sys/proc.h> 4373149Snyan#include <sys/socket.h> 4473149Snyan#include <sys/socketvar.h> 4573149Snyan#include <sys/syscall.h> 4673149Snyan#include <sys/sysctl.h> 4773149Snyan#include <sys/sysent.h> 4873149Snyan#include <sys/sysproto.h> 4973149Snyan#include <sys/systm.h> 5073149Snyan#include <sys/taskqueue.h> 5173149Snyan#include <sys/unistd.h> 5273149Snyan#include <sys/vnode.h> 5373149Snyan 5473149Snyan#include <nlm/nlm_prot.h> 55126928Speter#include <nlm/sm_inter.h> 5673149Snyan#include <nlm/nlm.h> 5773149Snyan#include <rpc/rpc_com.h> 5873149Snyan#include <rpc/rpcb_prot.h> 5978209Snyan 6073149SnyanMALLOC_DEFINE(M_NLM, "NLM", "Network Lock Manager"); 6179697Snon 6273149Snyan/* 6379697Snon * If a host is inactive (and holds no locks) for this amount of 6479697Snon * seconds, we consider it idle and stop tracking it. 6573149Snyan */ 6679697Snon#define NLM_IDLE_TIMEOUT 30 6779697Snon 6879697Snon/* 6979697Snon * We check the host list for idle every few seconds. 7079697Snon */ 7179697Snon#define NLM_IDLE_PERIOD 5 7273149Snyan 7379697Snon/* 7479697Snon * Support for sysctl vfs.nlm.sysid 7579697Snon */ 7679697SnonSYSCTL_NODE(_vfs, OID_AUTO, nlm, CTLFLAG_RW, NULL, "Network Lock Manager"); 7779697SnonSYSCTL_NODE(_vfs_nlm, OID_AUTO, sysid, CTLFLAG_RW, NULL, ""); 7873149Snyan 7973149Snyan/* 8073149Snyan * Syscall hooks 81242871Snyan */ 8273149Snyanstatic int nlm_syscall_offset = SYS_nlm_syscall; 8379697Snonstatic struct sysent nlm_syscall_prev_sysent; 8473149Snyan#if __FreeBSD_version < 700000 8573149Snyanstatic struct sysent nlm_syscall_sysent = { 8673149Snyan (sizeof(struct nlm_syscall_args) / sizeof(register_t)) | SYF_MPSAFE, 8773149Snyan (sy_call_t *) nlm_syscall 8879697Snon}; 8973149Snyan#else 9073149SnyanMAKE_SYSENT(nlm_syscall); 9179697Snon#endif 9273149Snyanstatic bool_t nlm_syscall_registered = FALSE; 9373149Snyan 9479697Snon/* 9573149Snyan * Debug level passed in from userland. We also support a sysctl hook 9673149Snyan * so that it can be changed on a live system. 9773149Snyan */ 9873149Snyanstatic int nlm_debug_level; 9973149SnyanSYSCTL_INT(_debug, OID_AUTO, nlm_debug, CTLFLAG_RW, &nlm_debug_level, 0, ""); 100242871Snyan 10173149Snyan/* 10273149Snyan * Grace period handling. The value of nlm_grace_threshold is the 10379697Snon * value of time_uptime after which we are serving requests normally. 10473149Snyan */ 10573149Snyanstatic time_t nlm_grace_threshold; 10673149Snyan 10773149Snyan/* 10873149Snyan * We check for idle hosts if time_uptime is greater than 10973149Snyan * nlm_next_idle_check, 11073149Snyan */ 11179697Snonstatic time_t nlm_next_idle_check; 11273149Snyan 113240325Sjhb/* 114240325Sjhb * A socket to use for RPC - shared by all IPv4 RPC clients. 115240325Sjhb */ 11673149Snyanstatic struct socket *nlm_socket; 11773149Snyan 11873149Snyan#ifdef INET6 11979697Snon 12073149Snyan/* 12173149Snyan * A socket to use for RPC - shared by all IPv6 RPC clients. 12273149Snyan */ 12373149Snyanstatic struct socket *nlm_socket6; 12479697Snon 12573149Snyan#endif 12679697Snon 12773149Snyan/* 12873149Snyan * An RPC client handle that can be used to communicate with the local 12973149Snyan * NSM. 13073149Snyan */ 13179697Snonstatic CLIENT *nlm_nsm; 13273149Snyan 13373149Snyan/* 13479697Snon * An RPC client handle that can be used to communicate with the 13573149Snyan * userland part of lockd. 136240172Sjhb */ 13773149Snyanstatic CLIENT *nlm_lockd; 13873149Snyan 13973149Snyan/* 14079697Snon * Locks: 14173149Snyan * (l) locked by nh_lock 14273149Snyan * (s) only accessed via server RPC which is single threaded 14373149Snyan * (c) const until freeing 14479697Snon */ 14573149Snyan 14673149Snyan/* 14773149Snyan * A pending asynchronous lock request, stored on the nh_pending list 14873149Snyan * of the NLM host. 149242871Snyan */ 15073149Snyanstruct nlm_async_lock { 15173149Snyan TAILQ_ENTRY(nlm_async_lock) af_link; /* (l) host's list of locks */ 15273149Snyan struct task af_task; /* (c) async callback details */ 15379697Snon void *af_cookie; /* (l) lock manager cancel token */ 15479697Snon struct vnode *af_vp; /* (l) vnode to lock */ 15579697Snon struct flock af_fl; /* (c) lock details */ 15673149Snyan struct nlm_host *af_host; /* (c) host which is locking */ 15773149Snyan nlm4_testargs af_granted; /* (c) notification details */ 15873149Snyan}; 15973149SnyanTAILQ_HEAD(nlm_async_lock_list, nlm_async_lock); 16073149Snyan 16173149Snyan/* 16273149Snyan * NLM host. 16373149Snyan */ 16473149Snyanenum nlm_host_state { 16573149Snyan NLM_UNMONITORED, 16673149Snyan NLM_MONITORED, 16773149Snyan NLM_MONITOR_FAILED 16873149Snyan}; 16973149Snyanstruct nlm_host { 17073149Snyan struct mtx nh_lock; 17173149Snyan TAILQ_ENTRY(nlm_host) nh_link; /* (s) global list of hosts */ 17273149Snyan char *nh_caller_name; /* (c) printable name of host */ 17373149Snyan uint32_t nh_sysid; /* (c) our allocaed system ID */ 17473149Snyan char nh_sysid_string[10]; /* (c) string rep. of sysid */ 17573149Snyan struct sockaddr_storage nh_addr; /* (s) remote address of host */ 17692739Salfred CLIENT *nh_rpc; /* (s) RPC handle to send to host */ 17792739Salfred rpcvers_t nh_vers; /* (s) NLM version of host */ 17892739Salfred int nh_state; /* (s) last seen NSM state of host */ 17973149Snyan enum nlm_host_state nh_monstate; /* (s) local NSM monitoring state */ 18073149Snyan time_t nh_idle_timeout; /* (s) Time at which host is idle */ 181242871Snyan time_t nh_rpc_create_time; /* (s) Time we create RPC client */ 18273149Snyan struct sysctl_ctx_list nh_sysctl; /* (c) vfs.nlm.sysid nodes */ 18379697Snon struct nlm_async_lock_list nh_pending; /* (l) pending async locks */ 18473149Snyan struct nlm_async_lock_list nh_finished; /* (l) finished async locks */ 18579697Snon}; 18679697SnonTAILQ_HEAD(nlm_host_list, nlm_host); 18773149Snyan 18873149Snyanstatic struct nlm_host_list nlm_hosts; 18973149Snyanstatic uint32_t nlm_next_sysid = 1; 190242871Snyan 19173149Snyanstatic void nlm_host_unmonitor(struct nlm_host *); 19279697Snon 19373149Snyan/**********************************************************************/ 19473149Snyan 19579697Snon/* 19679697Snon * Initialise NLM globals. 19773149Snyan */ 19873149Snyanstatic void 19973149Snyannlm_init(void *dummy) 20073149Snyan{ 20179697Snon int error; 20279697Snon 20373149Snyan TAILQ_INIT(&nlm_hosts); 20473149Snyan 20573149Snyan error = syscall_register(&nlm_syscall_offset, &nlm_syscall_sysent, 206242871Snyan &nlm_syscall_prev_sysent); 20773149Snyan if (error) 20879697Snon printf("Can't register NLM syscall\n"); 20973149Snyan else 21073149Snyan nlm_syscall_registered = TRUE; 21173149Snyan} 21273149SnyanSYSINIT(nlm_init, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_init, NULL); 21379697Snon 21479697Snonstatic void 21573149Snyannlm_uninit(void *dummy) 21673149Snyan{ 21773149Snyan 21873149Snyan if (nlm_syscall_registered) 21973149Snyan syscall_deregister(&nlm_syscall_offset, 22073149Snyan &nlm_syscall_prev_sysent); 22173149Snyan} 22273149SnyanSYSUNINIT(nlm_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_uninit, NULL); 22373149Snyan 22473149Snyan/* 22573149Snyan * Copy a struct netobj. 22673149Snyan */ 22773149Snyanvoid 22873149Snyannlm_copy_netobj(struct netobj *dst, struct netobj *src, 22973149Snyan struct malloc_type *type) 23073149Snyan{ 231240325Sjhb 23273149Snyan dst->n_len = src->n_len; 23373149Snyan dst->n_bytes = malloc(src->n_len, type, M_WAITOK); 23473149Snyan memcpy(dst->n_bytes, src->n_bytes, src->n_len); 23573149Snyan} 236242871Snyan 23773149Snyan/* 23873149Snyan * Create an RPC client handle for the given (address,prog,vers) 23973149Snyan * triple using UDP. 24073149Snyan */ 24173149Snyanstatic CLIENT * 24273149Snyannlm_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers) 24373149Snyan{ 24473149Snyan const char *wchan = "nlmrcv"; 24573149Snyan const char* protofmly; 24679697Snon struct sockaddr_storage ss; 24773149Snyan struct socket *so; 24873149Snyan CLIENT *rpcb; 24973149Snyan struct timeval timo; 25073149Snyan RPCB parms; 25173149Snyan char *uaddr; 25279697Snon enum clnt_stat stat; 25379697Snon int rpcvers; 25473149Snyan 25573149Snyan /* 25679697Snon * First we need to contact the remote RPCBIND service to find 25773149Snyan * the right port. 25879697Snon */ 25979697Snon memcpy(&ss, sa, sa->sa_len); 26079697Snon switch (ss.ss_family) { 26179697Snon case AF_INET: 26279697Snon ((struct sockaddr_in *)&ss)->sin_port = htons(111); 26379697Snon protofmly = "inet"; 26479697Snon so = nlm_socket; 26573149Snyan break; 26679697Snon 26773149Snyan#ifdef INET6 26879697Snon case AF_INET6: 269240325Sjhb ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111); 270240325Sjhb protofmly = "inet6"; 27179697Snon so = nlm_socket6; 27273149Snyan break; 27379697Snon#endif 27473149Snyan 27573149Snyan default: 27679697Snon /* 277240325Sjhb * Unsupported address family - fail. 27879697Snon */ 27979697Snon return (NULL); 28073149Snyan } 28173149Snyan 28279697Snon rpcb = clnt_dg_create(so, (struct sockaddr *)&ss, 283242871Snyan RPCBPROG, RPCBVERS4, 0, 0); 28473149Snyan if (!rpcb) 28573149Snyan return (NULL); 28679697Snon 28773149Snyan parms.r_prog = prog; 28873149Snyan parms.r_vers = vers; 28979697Snon parms.r_netid = "udp"; 29073149Snyan parms.r_addr = ""; 29179697Snon parms.r_owner = ""; 29279697Snon 29373149Snyan /* 29473149Snyan * Use the default timeout. 29579697Snon */ 29679697Snon timo.tv_sec = 25; 29779697Snon timo.tv_usec = 0; 29879697Snonagain: 29979697Snon uaddr = NULL; 30079697Snon stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR, 30179697Snon (xdrproc_t) xdr_rpcb, &parms, 30273149Snyan (xdrproc_t) xdr_wrapstring, &uaddr, timo); 30379697Snon if (stat == RPC_PROGVERSMISMATCH) { 30479697Snon /* 30579697Snon * Try RPCBIND version 3 if we haven't already. 30679697Snon * 30779697Snon * XXX fall back to portmap? 30879697Snon */ 30979697Snon CLNT_CONTROL(rpcb, CLGET_VERS, &rpcvers); 31079697Snon if (rpcvers == RPCBVERS4) { 31179697Snon rpcvers = RPCBVERS; 31279697Snon CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers); 31379697Snon goto again; 31479697Snon } 31573149Snyan } 31679697Snon 31779697Snon if (stat == RPC_SUCCESS) { 31879697Snon /* 31973149Snyan * We have a reply from the remote RPCBIND - turn it into an 32079697Snon * appropriate address and make a new client that can talk to 32179697Snon * the remote NLM. 32279697Snon * 32373149Snyan * XXX fixup IPv6 scope ID. 32473149Snyan */ 32573149Snyan struct netbuf *a; 32673149Snyan a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr); 32773149Snyan if (!a) { 32873149Snyan CLNT_DESTROY(rpcb); 32973149Snyan return (NULL); 33073149Snyan } 33179697Snon memcpy(&ss, a->buf, a->len); 33273149Snyan free(a->buf, M_RPC); 33373149Snyan free(a, M_RPC); 33473149Snyan xdr_free((xdrproc_t) xdr_wrapstring, &uaddr); 33573149Snyan } else if (stat == RPC_PROGVERSMISMATCH) { 33673149Snyan /* 33773149Snyan * Try portmap. 33879697Snon */ 33973149Snyan struct pmap mapping; 34073149Snyan u_short port; 34173149Snyan 34273149Snyan rpcvers = PMAPVERS; 34373149Snyan CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers); 34473149Snyan 34573149Snyan mapping.pm_prog = parms.r_prog; 34673149Snyan mapping.pm_vers = parms.r_vers; 34773149Snyan mapping.pm_prot = IPPROTO_UDP; 34873149Snyan mapping.pm_port = 0; 34973149Snyan 35073149Snyan stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT, 35173149Snyan (xdrproc_t) xdr_pmap, &mapping, 35273149Snyan (xdrproc_t) xdr_u_short, &port, timo); 35373149Snyan 35473149Snyan if (stat == RPC_SUCCESS) { 35573149Snyan switch (ss.ss_family) { 35673149Snyan case AF_INET: 35779697Snon ((struct sockaddr_in *)&ss)->sin_port = 35873149Snyan htons(port); 35973149Snyan break; 36073149Snyan 36173149Snyan#ifdef INET6 36273149Snyan case AF_INET6: 36373149Snyan ((struct sockaddr_in6 *)&ss)->sin6_port = 36473149Snyan htons(port); 36573149Snyan break; 36679697Snon#endif 36773149Snyan } 36873149Snyan } 36973149Snyan } 37073149Snyan if (stat != RPC_SUCCESS) { 37173149Snyan printf("NLM: failed to contact remote rpcbind, stat = %d\n", 37273149Snyan (int) stat); 37373149Snyan CLNT_DESTROY(rpcb); 37479697Snon return (NULL); 37573149Snyan } 37673149Snyan 37773149Snyan /* 37873149Snyan * Re-use the client we used to speak to rpcbind. 37973149Snyan */ 38079697Snon CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss); 38192739Salfred CLNT_CONTROL(rpcb, CLSET_PROG, &prog); 38292739Salfred CLNT_CONTROL(rpcb, CLSET_VERS, &vers); 38392739Salfred CLNT_CONTROL(rpcb, CLSET_WAITCHAN, &wchan); 38473149Snyan rpcb->cl_auth = authunix_create(curthread->td_ucred); 38579697Snon 386242871Snyan return (rpcb); 38773149Snyan} 38873149Snyan 38973149Snyan/* 39079697Snon * This async callback after when an async lock request has been 39173149Snyan * granted. We notify the host which initiated the request. 39273149Snyan */ 39379697Snonstatic void 39473149Snyannlm_lock_callback(void *arg, int pending) 39579697Snon{ 39679697Snon struct nlm_async_lock *af = (struct nlm_async_lock *) arg; 39779697Snon 39879697Snon if (nlm_debug_level >= 2) 39979697Snon printf("NLM: async lock %p for %s (sysid %d) granted\n", 40073149Snyan af, af->af_host->nh_caller_name, 40173149Snyan af->af_host->nh_sysid); 40273149Snyan 40373149Snyan /* 40473149Snyan * Send the results back to the host. 40573149Snyan * 40673149Snyan * Note: there is a possible race here with nlm_host_notify 40773149Snyan * destroying the RPC client. To avoid problems, the first 40873149Snyan * thing nlm_host_notify does is to cancel pending async lock 40973149Snyan * requests. 41073149Snyan */ 41173149Snyan if (af->af_host->nh_vers == NLM_VERS4) { 41273149Snyan nlm4_granted_msg_4(&af->af_granted, 41373149Snyan NULL, af->af_host->nh_rpc); 41473149Snyan } else { 41573149Snyan /* 41673149Snyan * Back-convert to legacy protocol 41773149Snyan */ 41873149Snyan nlm_testargs granted; 41979697Snon granted.cookie = af->af_granted.cookie; 42073149Snyan granted.exclusive = af->af_granted.exclusive; 42173149Snyan granted.alock.caller_name = 422240172Sjhb af->af_granted.alock.caller_name; 42373149Snyan granted.alock.fh = af->af_granted.alock.fh; 42473149Snyan granted.alock.oh = af->af_granted.alock.oh; 42573149Snyan granted.alock.svid = af->af_granted.alock.svid; 42673149Snyan granted.alock.l_offset = 42773149Snyan af->af_granted.alock.l_offset; 42873149Snyan granted.alock.l_len = 429240172Sjhb af->af_granted.alock.l_len; 43073149Snyan 43173149Snyan nlm_granted_msg_1(&granted, 43273149Snyan NULL, af->af_host->nh_rpc); 43373149Snyan } 43473149Snyan 43573149Snyan /* 43673149Snyan * Move this entry to the nh_finished list. Someone else will 43773149Snyan * free it later - its too hard to do it here safely without 43873149Snyan * racing with cancel. 43973149Snyan * 44073149Snyan * XXX possibly we should have a third "granted sent but not 44179697Snon * ack'ed" list so that we can re-send the granted message. 44279697Snon */ 44379697Snon mtx_lock(&af->af_host->nh_lock); 44473149Snyan TAILQ_REMOVE(&af->af_host->nh_pending, af, af_link); 44573149Snyan TAILQ_INSERT_TAIL(&af->af_host->nh_finished, af, af_link); 44673149Snyan mtx_unlock(&af->af_host->nh_lock); 447242871Snyan} 44873149Snyan 44973149Snyan/* 45073149Snyan * Free an async lock request. The request must have been removed from 45173149Snyan * any list. 45273149Snyan */ 45373149Snyanstatic void 45473149Snyannlm_free_async_lock(struct nlm_async_lock *af) 45573149Snyan{ 45673149Snyan /* 45779697Snon * Free an async lock. 45873149Snyan */ 45973149Snyan xdr_free((xdrproc_t) xdr_nlm4_testargs, &af->af_granted); 46073149Snyan if (af->af_vp) 46173149Snyan vrele(af->af_vp); 46273149Snyan free(af, M_NLM); 46379697Snon} 46473149Snyan 46573149Snyan/* 46673149Snyan * Cancel our async request - this must be called with 46773149Snyan * af->nh_host->nh_lock held. This is slightly complicated by a 46873149Snyan * potential race with our own callback. If we fail to cancel the 46973149Snyan * lock, it must already have been granted - we make sure our async 47073149Snyan * task has completed by calling taskqueue_drain in this case. 47173149Snyan */ 47273149Snyanstatic int 47373149Snyannlm_cancel_async_lock(struct nlm_async_lock *af) 47479697Snon{ 47573149Snyan struct nlm_host *host = af->af_host; 476240325Sjhb int error; 477240325Sjhb 478240325Sjhb mtx_assert(&host->nh_lock, MA_OWNED); 47979697Snon 48073149Snyan mtx_unlock(&host->nh_lock); 48173149Snyan 48279697Snon error = VOP_ADVLOCKASYNC(af->af_vp, NULL, F_CANCEL, &af->af_fl, 48373149Snyan F_REMOTE, NULL, &af->af_cookie); 48473149Snyan 48573149Snyan if (error) { 486240325Sjhb /* 48779697Snon * We failed to cancel - make sure our callback has 48873149Snyan * completed before we continue. 48973149Snyan */ 49073149Snyan taskqueue_drain(taskqueue_thread, &af->af_task); 49173149Snyan } 49273149Snyan 49373149Snyan mtx_lock(&host->nh_lock); 49473149Snyan 49573149Snyan if (!error) { 49673149Snyan if (nlm_debug_level >= 2) 49773149Snyan printf("NLM: async lock %p for %s (sysid %d) " 49873149Snyan "cancelled\n", 49973149Snyan af, host->nh_caller_name, host->nh_sysid); 50073149Snyan 50173149Snyan /* 50273149Snyan * Remove from the nh_pending list and free now that 50373149Snyan * we are safe from the callback. 50473149Snyan */ 50573149Snyan TAILQ_REMOVE(&host->nh_pending, af, af_link); 50673149Snyan mtx_unlock(&host->nh_lock); 50773149Snyan nlm_free_async_lock(af); 50879697Snon mtx_lock(&host->nh_lock); 50979697Snon } 51079697Snon 511242871Snyan return (error); 512242871Snyan} 51379697Snon 51479697Snonstatic void 51579697Snonnlm_free_finished_locks(struct nlm_host *host) 51679697Snon{ 51779697Snon struct nlm_async_lock *af; 51879697Snon 51973149Snyan mtx_lock(&host->nh_lock); 520242871Snyan while ((af = TAILQ_FIRST(&host->nh_finished)) != NULL) { 52173149Snyan TAILQ_REMOVE(&host->nh_finished, af, af_link); 52273149Snyan mtx_unlock(&host->nh_lock); 52373149Snyan nlm_free_async_lock(af); 52479697Snon mtx_lock(&host->nh_lock); 52573149Snyan } 52679697Snon mtx_unlock(&host->nh_lock); 52779697Snon} 52873149Snyan 52973149Snyan/* 53079697Snon * This is called when we receive a host state change 53179697Snon * notification. We unlock any active locks owned by the host. 53279697Snon */ 53373149Snyanstatic void 53473149Snyannlm_host_notify(struct nlm_host *host, int newstate, bool_t destroy) 53573149Snyan{ 53673149Snyan struct nlm_async_lock *af; 53773149Snyan 53873149Snyan if (newstate) { 53973149Snyan if (nlm_debug_level >= 1) 54079697Snon printf("NLM: host %s (sysid %d) rebooted, new " 54173149Snyan "state is %d\n", 54279697Snon host->nh_caller_name, host->nh_sysid, newstate); 54373149Snyan } 54479697Snon 54579697Snon /* 54679697Snon * Cancel any pending async locks for this host. 54773149Snyan */ 54873149Snyan mtx_lock(&host->nh_lock); 54979697Snon while ((af = TAILQ_FIRST(&host->nh_pending)) != NULL) { 55079697Snon /* 55179697Snon * nlm_cancel_async_lock will remove the entry from 55273149Snyan * nh_pending and free it. 55373149Snyan */ 55479697Snon nlm_cancel_async_lock(af); 55579697Snon } 55673149Snyan mtx_unlock(&host->nh_lock); 55773149Snyan nlm_free_finished_locks(host); 55879697Snon 55979697Snon /* 56073149Snyan * The host just rebooted - trash its locks and forget any 56179697Snon * RPC client handle that we may have for it. 56279697Snon */ 56373149Snyan lf_clearremotesys(host->nh_sysid); 56473149Snyan if (host->nh_rpc) { 56573149Snyan AUTH_DESTROY(host->nh_rpc->cl_auth); 566242871Snyan CLNT_DESTROY(host->nh_rpc); 56773149Snyan host->nh_rpc = NULL; 56873149Snyan } 56979697Snon host->nh_state = newstate; 57073149Snyan 57179697Snon /* 57279697Snon * Destroy the host if the caller believes that it won't be 57373149Snyan * used again. This is safe enough - if we see the same name 57473149Snyan * again, we will just create a new host. 57579697Snon */ 57679697Snon if (destroy) { 57773149Snyan TAILQ_REMOVE(&nlm_hosts, host, nh_link); 57879697Snon mtx_destroy(&host->nh_lock); 57979697Snon sysctl_ctx_free(&host->nh_sysctl); 58073149Snyan free(host->nh_caller_name, M_NLM); 58173149Snyan free(host, M_NLM); 58273149Snyan } 58373149Snyan} 58473149Snyan 58592739Salfred/* 58692739Salfred * Sysctl handler to count the number of locks for a sysid. 58792739Salfred */ 58892739Salfredstatic int 58992739Salfrednlm_host_lock_count_sysctl(SYSCTL_HANDLER_ARGS) 59092739Salfred{ 59173149Snyan struct nlm_host *host; 59273149Snyan int count; 593242871Snyan 59473149Snyan host = oidp->oid_arg1; 59579697Snon count = lf_countlocks(host->nh_sysid); 59673149Snyan return sysctl_handle_int(oidp, &count, 0, req); 59773149Snyan} 59879697Snon 59973149Snyan/* 60073149Snyan * Create a new NLM host. 60179697Snon */ 60279697Snonstatic struct nlm_host * 60379697Snonnlm_create_host(const char* caller_name) 60473149Snyan{ 60573149Snyan struct nlm_host *host; 60673149Snyan struct sysctl_oid *oid; 60773149Snyan 608242871Snyan if (nlm_debug_level >= 1) 60973149Snyan printf("NLM: new host %s (sysid %d)\n", 61079697Snon caller_name, nlm_next_sysid); 61173149Snyan host = malloc(sizeof(struct nlm_host), M_NLM, M_WAITOK|M_ZERO); 61279697Snon mtx_init(&host->nh_lock, "nh_lock", NULL, MTX_DEF); 61373149Snyan host->nh_caller_name = strdup(caller_name, M_NLM); 61473149Snyan host->nh_sysid = nlm_next_sysid++; 61573149Snyan snprintf(host->nh_sysid_string, sizeof(host->nh_sysid_string), 61679697Snon "%d", host->nh_sysid); 61779697Snon host->nh_rpc = NULL; 61873149Snyan host->nh_vers = 0; 61973149Snyan host->nh_state = 0; 62079697Snon host->nh_monstate = NLM_UNMONITORED; 62179697Snon TAILQ_INIT(&host->nh_pending); 62279697Snon TAILQ_INIT(&host->nh_finished); 62379697Snon TAILQ_INSERT_TAIL(&nlm_hosts, host, nh_link); 62473149Snyan 62579697Snon sysctl_ctx_init(&host->nh_sysctl); 62679697Snon oid = SYSCTL_ADD_NODE(&host->nh_sysctl, 62779697Snon SYSCTL_STATIC_CHILDREN(_vfs_nlm_sysid), 62879697Snon OID_AUTO, host->nh_sysid_string, CTLFLAG_RD, NULL, ""); 62973149Snyan SYSCTL_ADD_STRING(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 63073149Snyan "hostname", CTLFLAG_RD, host->nh_caller_name, 0, ""); 63173149Snyan SYSCTL_ADD_INT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 63273149Snyan "version", CTLFLAG_RD, &host->nh_vers, 0, ""); 63373149Snyan SYSCTL_ADD_INT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 634242871Snyan "monitored", CTLFLAG_RD, &host->nh_monstate, 0, ""); 63573149Snyan SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO, 63679697Snon "lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0, 63773149Snyan nlm_host_lock_count_sysctl, "I", ""); 63879697Snon 63979697Snon return (host); 64073149Snyan} 64173149Snyan 64273149Snyan/* 643242871Snyan * Return non-zero if the address parts of the two sockaddrs are the 64473149Snyan * same. 64579697Snon */ 64673149Snyanstatic int 64779697Snonnlm_compare_addr(const struct sockaddr *a, const struct sockaddr *b) 64879697Snon{ 64973149Snyan const struct sockaddr_in *a4, *b4; 65073149Snyan#ifdef INET6 65173149Snyan const struct sockaddr_in6 *a6, *b6; 652242871Snyan#endif 65373149Snyan 65479697Snon if (a->sa_family != b->sa_family) 65579697Snon return (FALSE); 65673149Snyan 65779697Snon switch (a->sa_family) { 65873149Snyan case AF_INET: 65973149Snyan a4 = (const struct sockaddr_in *) a; 66073149Snyan b4 = (const struct sockaddr_in *) b; 661242871Snyan return !memcmp(&a4->sin_addr, &b4->sin_addr, 66273149Snyan sizeof(a4->sin_addr)); 66379697Snon#ifdef INET6 66479697Snon case AF_INET6: 66573149Snyan a6 = (const struct sockaddr_in6 *) a; 66679697Snon b6 = (const struct sockaddr_in6 *) b; 66773149Snyan return !memcmp(&a6->sin6_addr, &b6->sin6_addr, 66873149Snyan sizeof(a6->sin6_addr)); 66973149Snyan#endif 67073149Snyan } 67173149Snyan 67273149Snyan return (0); 67373149Snyan} 67473149Snyan 67573149Snyan/* 67673149Snyan * Check for idle hosts and stop monitoring them. We could also free 67773149Snyan * the host structure here, possibly after a larger timeout but that 67873149Snyan * would require some care to avoid races with 67973149Snyan * e.g. nlm_host_lock_count_sysctl. 68073149Snyan */ 68173149Snyanstatic void 68273149Snyannlm_check_idle(void) 68373149Snyan{ 68473149Snyan struct nlm_host *host; 68573149Snyan 68673149Snyan if (time_uptime <= nlm_next_idle_check) 68773149Snyan return; 68873149Snyan 68973149Snyan nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD; 69073149Snyan 69173149Snyan TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 69273149Snyan if (host->nh_monstate == NLM_MONITORED 69373149Snyan && time_uptime > host->nh_idle_timeout) { 69473149Snyan if (lf_countlocks(host->nh_sysid) > 0) { 69573149Snyan host->nh_idle_timeout = 69673149Snyan time_uptime + NLM_IDLE_TIMEOUT; 69773149Snyan mtx_lock(&nlm_global_lock); 69873149Snyan continue; 69973149Snyan } 70073149Snyan nlm_host_unmonitor(host); 70173149Snyan } 70273149Snyan } 70373149Snyan} 70473149Snyan 70573149Snyan/* 70673149Snyan * Search for an existing NLM host that matches the given name 70773149Snyan * (typically the caller_name element of an nlm4_lock). If none is 70873149Snyan * found, create a new host. If 'rqstp' is non-NULL, record the remote 70973149Snyan * address of the host so that we can call it back for async 71073149Snyan * responses. 71173149Snyan */ 71273149Snyanstruct nlm_host * 71373149Snyannlm_find_host_by_name(const char *name, struct svc_req *rqstp) 71473149Snyan{ 71573149Snyan struct nlm_host *host; 71673149Snyan 71773149Snyan nlm_check_idle(); 71873149Snyan 71973149Snyan /* 72073149Snyan * The remote host is determined by caller_name. 72173149Snyan */ 72273149Snyan TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 72373149Snyan if (!strcmp(host->nh_caller_name, name)) 72473149Snyan break; 72573149Snyan } 72673149Snyan 72773149Snyan if (!host) 72873149Snyan host = nlm_create_host(name); 72973149Snyan host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT; 73073149Snyan 73173149Snyan /* 73273149Snyan * If we have an RPC request, record the remote address so 73373149Snyan * that can send async replies etc. 73473149Snyan */ 73573149Snyan if (rqstp) { 73673149Snyan struct netbuf *addr = &rqstp->rq_xprt->xp_rtaddr; 73773149Snyan 73873149Snyan KASSERT(addr->len < sizeof(struct sockaddr_storage), 73973149Snyan ("Strange remote transport address length")); 74073149Snyan 74173149Snyan /* 74273149Snyan * If we have seen an address before and we currently 743 * have an RPC client handle, make sure the address is 744 * the same, otherwise discard the client handle. 745 */ 746 if (host->nh_addr.ss_len && host->nh_rpc) { 747 if (!nlm_compare_addr( 748 (struct sockaddr *) &host->nh_addr, 749 (struct sockaddr *) addr->buf) 750 || host->nh_vers != rqstp->rq_vers) { 751 AUTH_DESTROY(host->nh_rpc->cl_auth); 752 CLNT_DESTROY(host->nh_rpc); 753 host->nh_rpc = NULL; 754 } 755 } 756 memcpy(&host->nh_addr, addr->buf, addr->len); 757 host->nh_vers = rqstp->rq_vers; 758 } 759 760 return (host); 761} 762 763/* 764 * Search for an existing NLM host that matches the given remote 765 * address. If none is found, create a new host with the requested 766 * address and remember 'vers' as the NLM protocol version to use for 767 * that host. 768 */ 769struct nlm_host * 770nlm_find_host_by_addr(const struct sockaddr *addr, int vers) 771{ 772 struct nlm_host *host; 773 774 nlm_check_idle(); 775 776 /* 777 * The remote host is determined by caller_name. 778 */ 779 TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 780 if (nlm_compare_addr(addr, 781 (const struct sockaddr *) &host->nh_addr)) 782 break; 783 } 784 785 if (!host) { 786 /* 787 * Fake up a name using inet_ntop. This buffer is 788 * large enough for an IPv6 address. 789 */ 790 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; 791 switch (addr->sa_family) { 792 case AF_INET: 793 __rpc_inet_ntop(AF_INET, 794 &((const struct sockaddr_in *) addr)->sin_addr, 795 tmp, sizeof tmp); 796 break; 797#ifdef INET6 798 case AF_INET6: 799 __rpc_inet_ntop(AF_INET6, 800 &((const struct sockaddr_in6 *) addr)->sin6_addr, 801 tmp, sizeof tmp); 802 break; 803#endif 804 default: 805 strcmp(tmp, "<unknown>"); 806 } 807 host = nlm_create_host(tmp); 808 memcpy(&host->nh_addr, addr, addr->sa_len); 809 host->nh_vers = vers; 810 } 811 host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT; 812 813 return (host); 814} 815 816/* 817 * Find the NLM host that matches the value of 'sysid'. If none 818 * exists, return NULL. 819 */ 820static struct nlm_host * 821nlm_find_host_by_sysid(int sysid) 822{ 823 struct nlm_host *host; 824 825 TAILQ_FOREACH(host, &nlm_hosts, nh_link) { 826 if (host->nh_sysid == sysid) 827 return (host); 828 } 829 830 return (NULL); 831} 832 833/* 834 * Unregister this NLM host with the local NSM due to idleness. 835 */ 836static void 837nlm_host_unmonitor(struct nlm_host *host) 838{ 839 mon_id smmonid; 840 sm_stat_res smstat; 841 struct timeval timo; 842 enum clnt_stat stat; 843 844 if (nlm_debug_level >= 1) 845 printf("NLM: unmonitoring %s (sysid %d)\n", 846 host->nh_caller_name, host->nh_sysid); 847 848 /* 849 * We put our assigned system ID value in the priv field to 850 * make it simpler to find the host if we are notified of a 851 * host restart. 852 */ 853 smmonid.mon_name = host->nh_caller_name; 854 smmonid.my_id.my_name = "localhost"; 855 smmonid.my_id.my_prog = NLM_PROG; 856 smmonid.my_id.my_vers = NLM_SM; 857 smmonid.my_id.my_proc = NLM_SM_NOTIFY; 858 859 timo.tv_sec = 25; 860 timo.tv_usec = 0; 861 stat = CLNT_CALL(nlm_nsm, SM_UNMON, 862 (xdrproc_t) xdr_mon, &smmonid, 863 (xdrproc_t) xdr_sm_stat, &smstat, timo); 864 865 if (stat != RPC_SUCCESS) { 866 printf("Failed to contact local NSM - rpc error %d\n", stat); 867 return; 868 } 869 if (smstat.res_stat == stat_fail) { 870 printf("Local NSM refuses to unmonitor %s\n", 871 host->nh_caller_name); 872 return; 873 } 874 875 host->nh_monstate = NLM_UNMONITORED; 876} 877 878/* 879 * Register this NLM host with the local NSM so that we can be 880 * notified if it reboots. 881 */ 882static void 883nlm_host_monitor(struct nlm_host *host, int state) 884{ 885 mon smmon; 886 sm_stat_res smstat; 887 struct timeval timo; 888 enum clnt_stat stat; 889 890 if (state && !host->nh_state) { 891 /* 892 * This is the first time we have seen an NSM state 893 * value for this host. We record it here to help 894 * detect host reboots. 895 */ 896 host->nh_state = state; 897 if (nlm_debug_level >= 1) 898 printf("NLM: host %s (sysid %d) has NSM state %d\n", 899 host->nh_caller_name, host->nh_sysid, state); 900 } 901 902 if (host->nh_monstate != NLM_UNMONITORED) 903 return; 904 905 if (nlm_debug_level >= 1) 906 printf("NLM: monitoring %s (sysid %d)\n", 907 host->nh_caller_name, host->nh_sysid); 908 909 /* 910 * We put our assigned system ID value in the priv field to 911 * make it simpler to find the host if we are notified of a 912 * host restart. 913 */ 914 smmon.mon_id.mon_name = host->nh_caller_name; 915 smmon.mon_id.my_id.my_name = "localhost"; 916 smmon.mon_id.my_id.my_prog = NLM_PROG; 917 smmon.mon_id.my_id.my_vers = NLM_SM; 918 smmon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; 919 memcpy(smmon.priv, &host->nh_sysid, sizeof(host->nh_sysid)); 920 921 timo.tv_sec = 25; 922 timo.tv_usec = 0; 923 stat = CLNT_CALL(nlm_nsm, SM_MON, 924 (xdrproc_t) xdr_mon, &smmon, 925 (xdrproc_t) xdr_sm_stat, &smstat, timo); 926 927 if (stat != RPC_SUCCESS) { 928 printf("Failed to contact local NSM - rpc error %d\n", stat); 929 return; 930 } 931 if (smstat.res_stat == stat_fail) { 932 printf("Local NSM refuses to monitor %s\n", 933 host->nh_caller_name); 934 host->nh_monstate = NLM_MONITOR_FAILED; 935 return; 936 } 937 938 host->nh_monstate = NLM_MONITORED; 939} 940 941/* 942 * Return an RPC client handle that can be used to talk to the NLM 943 * running on the given host. 944 */ 945CLIENT * 946nlm_host_get_rpc(struct nlm_host *host) 947{ 948 struct timeval zero; 949 950 /* 951 * We can't hold onto RPC handles for too long - the async 952 * call/reply protocol used by some NLM clients makes it hard 953 * to tell when they change port numbers (e.g. after a 954 * reboot). Note that if a client reboots while it isn't 955 * holding any locks, it won't bother to notify us. We 956 * expire the RPC handles after two minutes. 957 */ 958 if (host->nh_rpc && time_uptime > host->nh_rpc_create_time + 2*60) { 959 CLIENT *client; 960 client = host->nh_rpc; 961 host->nh_rpc = NULL; 962 CLNT_DESTROY(client); 963 } 964 965 if (host->nh_rpc) 966 return (host->nh_rpc); 967 968 /* 969 * Set the send timeout to zero - we only use this rpc handle 970 * for sending async replies which have no return value. 971 */ 972 host->nh_rpc = nlm_get_rpc((struct sockaddr *)&host->nh_addr, 973 NLM_PROG, host->nh_vers); 974 975 if (host->nh_rpc) { 976 zero.tv_sec = 0; 977 zero.tv_usec = 0; 978 CLNT_CONTROL(host->nh_rpc, CLSET_TIMEOUT, &zero); 979 980 host->nh_rpc_create_time = time_uptime; 981 } 982 983 return (host->nh_rpc); 984} 985 986/**********************************************************************/ 987 988/* 989 * Syscall interface with userland. 990 */ 991 992extern void nlm_prog_0(struct svc_req *rqstp, SVCXPRT *transp); 993extern void nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp); 994extern void nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp); 995extern void nlm_prog_4(struct svc_req *rqstp, SVCXPRT *transp); 996 997static int 998nlm_register_services(SVCPOOL *pool, int addr_count, char **addrs) 999{ 1000 static rpcvers_t versions[] = { 1001 NLM_SM, NLM_VERS, NLM_VERSX, NLM_VERS4 1002 }; 1003 static void (*dispatchers[])(struct svc_req *, SVCXPRT *) = { 1004 nlm_prog_0, nlm_prog_1, nlm_prog_3, nlm_prog_4 1005 }; 1006 static const int version_count = sizeof(versions) / sizeof(versions[0]); 1007 1008 SVCXPRT **xprts; 1009 char netid[16]; 1010 char uaddr[128]; 1011 struct netconfig *nconf; 1012 int i, j, error; 1013 1014 if (!addr_count) { 1015 printf("NLM: no service addresses given - can't start server"); 1016 return (EINVAL); 1017 } 1018 1019 xprts = malloc(addr_count * sizeof(SVCXPRT *), M_NLM, M_WAITOK); 1020 for (i = 0; i < version_count; i++) { 1021 for (j = 0; j < addr_count; j++) { 1022 /* 1023 * Create transports for the first version and 1024 * then just register everything else to the 1025 * same transports. 1026 */ 1027 if (i == 0) { 1028 char *up; 1029 1030 error = copyin(&addrs[2*j], &up, 1031 sizeof(char*)); 1032 if (error) 1033 goto out; 1034 error = copyinstr(up, netid, sizeof(netid), 1035 NULL); 1036 if (error) 1037 goto out; 1038 error = copyin(&addrs[2*j+1], &up, 1039 sizeof(char*)); 1040 if (error) 1041 goto out; 1042 error = copyinstr(up, uaddr, sizeof(uaddr), 1043 NULL); 1044 if (error) 1045 goto out; 1046 nconf = getnetconfigent(netid); 1047 if (!nconf) { 1048 printf("Can't lookup netid %s\n", 1049 netid); 1050 error = EINVAL; 1051 goto out; 1052 } 1053 xprts[j] = svc_tp_create(pool, dispatchers[i], 1054 NLM_PROG, versions[i], uaddr, nconf); 1055 if (!xprts[j]) { 1056 printf("NLM: unable to create " 1057 "(NLM_PROG, %d).\n", versions[i]); 1058 error = EINVAL; 1059 goto out; 1060 } 1061 freenetconfigent(nconf); 1062 } else { 1063 nconf = getnetconfigent(xprts[j]->xp_netid); 1064 rpcb_unset(NLM_PROG, versions[i], nconf); 1065 if (!svc_reg(xprts[j], NLM_PROG, versions[i], 1066 dispatchers[i], nconf)) { 1067 printf("NLM: can't register " 1068 "(NLM_PROG, %d)\n", versions[i]); 1069 error = EINVAL; 1070 goto out; 1071 } 1072 } 1073 } 1074 } 1075 error = 0; 1076out: 1077 free(xprts, M_NLM); 1078 return (error); 1079} 1080 1081/* 1082 * Main server entry point. Contacts the local NSM to get its current 1083 * state and send SM_UNMON_ALL. Registers the NLM services and then 1084 * services requests. Does not return until the server is interrupted 1085 * by a signal. 1086 */ 1087static int 1088nlm_server_main(int addr_count, char **addrs) 1089{ 1090 struct thread *td = curthread; 1091 int error; 1092 SVCPOOL *pool = NULL; 1093 struct sockopt opt; 1094 int portlow; 1095#ifdef INET6 1096 struct sockaddr_in6 sin6; 1097#endif 1098 struct sockaddr_in sin; 1099 my_id id; 1100 sm_stat smstat; 1101 struct timeval timo; 1102 enum clnt_stat stat; 1103 struct nlm_host *host; 1104 1105 if (nlm_socket) { 1106 printf("NLM: can't start server - it appears to be running already\n"); 1107 return (EPERM); 1108 } 1109 1110 memset(&opt, 0, sizeof(opt)); 1111 1112 nlm_socket = NULL; 1113 error = socreate(AF_INET, &nlm_socket, SOCK_DGRAM, 0, 1114 td->td_ucred, td); 1115 if (error) { 1116 printf("NLM: can't create IPv4 socket - error %d\n", error); 1117 return (error); 1118 } 1119 opt.sopt_dir = SOPT_SET; 1120 opt.sopt_level = IPPROTO_IP; 1121 opt.sopt_name = IP_PORTRANGE; 1122 portlow = IP_PORTRANGE_LOW; 1123 opt.sopt_val = &portlow; 1124 opt.sopt_valsize = sizeof(portlow); 1125 sosetopt(nlm_socket, &opt); 1126 1127#ifdef INET6 1128 nlm_socket6 = NULL; 1129 error = socreate(AF_INET6, &nlm_socket6, SOCK_DGRAM, 0, 1130 td->td_ucred, td); 1131 if (error) { 1132 printf("NLM: can't create IPv6 socket - error %d\n", error); 1133 return (error); 1134 } 1135 opt.sopt_dir = SOPT_SET; 1136 opt.sopt_level = IPPROTO_IPV6; 1137 opt.sopt_name = IPV6_PORTRANGE; 1138 portlow = IPV6_PORTRANGE_LOW; 1139 opt.sopt_val = &portlow; 1140 opt.sopt_valsize = sizeof(portlow); 1141 sosetopt(nlm_socket6, &opt); 1142#endif 1143 1144#ifdef INET6 1145 memset(&sin6, 0, sizeof(sin6)); 1146 sin6.sin6_len = sizeof(sin6); 1147 sin6.sin6_family = AF_INET6; 1148 sin6.sin6_addr = in6addr_loopback; 1149 nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin6, SM_PROG, SM_VERS); 1150 if (!nlm_nsm) { 1151#endif 1152 memset(&sin, 0, sizeof(sin)); 1153 sin.sin_len = sizeof(sin); 1154 sin.sin_family = AF_INET; 1155 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 1156 nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin, SM_PROG, 1157 SM_VERS); 1158#ifdef INET6 1159 } 1160#endif 1161 1162 if (!nlm_nsm) { 1163 printf("Can't start NLM - unable to contact NSM\n"); 1164 error = EINVAL; 1165 goto out; 1166 } 1167 1168 pool = svcpool_create(); 1169 1170 error = nlm_register_services(pool, addr_count, addrs); 1171 if (error) 1172 goto out; 1173 1174 memset(&id, 0, sizeof(id)); 1175 id.my_name = "NFS NLM"; 1176 1177 timo.tv_sec = 25; 1178 timo.tv_usec = 0; 1179 stat = CLNT_CALL(nlm_nsm, SM_UNMON_ALL, 1180 (xdrproc_t) xdr_my_id, &id, 1181 (xdrproc_t) xdr_sm_stat, &smstat, timo); 1182 1183 if (stat != RPC_SUCCESS) { 1184 struct rpc_err err; 1185 1186 CLNT_GETERR(nlm_nsm, &err); 1187 printf("NLM: unexpected error contacting NSM, stat=%d, errno=%d\n", 1188 stat, err.re_errno); 1189 error = EINVAL; 1190 goto out; 1191 } 1192 1193 if (nlm_debug_level >= 1) 1194 printf("NLM: local NSM state is %d\n", smstat.state); 1195 1196 svc_run(pool); 1197 error = 0; 1198 1199out: 1200 if (pool) 1201 svcpool_destroy(pool); 1202 1203 /* 1204 * Trash all the existing state so that if the server 1205 * restarts, it gets a clean slate. 1206 */ 1207 while ((host = TAILQ_FIRST(&nlm_hosts)) != NULL) { 1208 nlm_host_notify(host, 0, TRUE); 1209 } 1210 if (nlm_nsm) { 1211 AUTH_DESTROY(nlm_nsm->cl_auth); 1212 CLNT_DESTROY(nlm_nsm); 1213 nlm_nsm = NULL; 1214 } 1215 if (nlm_lockd) { 1216 AUTH_DESTROY(nlm_lockd->cl_auth); 1217 CLNT_DESTROY(nlm_lockd); 1218 nlm_lockd = NULL; 1219 } 1220 1221 soclose(nlm_socket); 1222 nlm_socket = NULL; 1223#ifdef INET6 1224 soclose(nlm_socket6); 1225 nlm_socket6 = NULL; 1226#endif 1227 1228 return (error); 1229} 1230 1231int 1232nlm_syscall(struct thread *td, struct nlm_syscall_args *uap) 1233{ 1234 int error; 1235 1236#if __FreeBSD_version >= 700000 1237 error = priv_check(td, PRIV_NFS_LOCKD); 1238#else 1239 error = suser(td); 1240#endif 1241 if (error) 1242 return (error); 1243 1244 nlm_debug_level = uap->debug_level; 1245 nlm_grace_threshold = time_uptime + uap->grace_period; 1246 nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD; 1247 1248 return nlm_server_main(uap->addr_count, uap->addrs); 1249} 1250 1251/**********************************************************************/ 1252 1253/* 1254 * NLM implementation details, called from the RPC stubs. 1255 */ 1256 1257 1258void 1259nlm_sm_notify(struct nlm_sm_status *argp) 1260{ 1261 uint32_t sysid; 1262 struct nlm_host *host; 1263 1264 if (nlm_debug_level >= 3) 1265 printf("nlm_sm_notify(): mon_name = %s\n", argp->mon_name); 1266 memcpy(&sysid, &argp->priv, sizeof(sysid)); 1267 host = nlm_find_host_by_sysid(sysid); 1268 if (host) 1269 nlm_host_notify(host, argp->state, FALSE); 1270} 1271 1272static void 1273nlm_convert_to_fhandle_t(fhandle_t *fhp, struct netobj *p) 1274{ 1275 memcpy(fhp, p->n_bytes, sizeof(fhandle_t)); 1276} 1277 1278struct vfs_state { 1279 struct mount *vs_mp; 1280 struct vnode *vs_vp; 1281 int vs_vfslocked; 1282 int vs_vnlocked; 1283}; 1284 1285static int 1286nlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp, 1287 fhandle_t *fhp, struct vfs_state *vs) 1288{ 1289 int error, exflags, freecred; 1290 struct ucred *cred = NULL, *credanon; 1291 1292 memset(vs, 0, sizeof(*vs)); 1293 freecred = FALSE; 1294 1295 vs->vs_mp = vfs_getvfs(&fhp->fh_fsid); 1296 if (!vs->vs_mp) { 1297 return (ESTALE); 1298 } 1299 vs->vs_vfslocked = VFS_LOCK_GIANT(vs->vs_mp); 1300 1301 error = VFS_CHECKEXP(vs->vs_mp, (struct sockaddr *)&host->nh_addr, 1302 &exflags, &credanon); 1303 if (error) 1304 goto out; 1305 1306 if (exflags & MNT_EXRDONLY || (vs->vs_mp->mnt_flag & MNT_RDONLY)) { 1307 error = EROFS; 1308 goto out; 1309 } 1310 1311 error = VFS_FHTOVP(vs->vs_mp, &fhp->fh_fid, &vs->vs_vp); 1312 if (error) 1313 goto out; 1314 vs->vs_vnlocked = TRUE; 1315 1316 cred = crget(); 1317 freecred = TRUE; 1318 if (!svc_getcred(rqstp, cred, NULL)) { 1319 error = EINVAL; 1320 goto out; 1321 } 1322 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1323 crfree(cred); 1324 cred = credanon; 1325 freecred = FALSE; 1326 } 1327 1328 /* 1329 * Check cred. 1330 */ 1331 error = VOP_ACCESS(vs->vs_vp, VWRITE, cred, curthread); 1332 if (error) 1333 goto out; 1334 1335#if __FreeBSD_version < 800011 1336 VOP_UNLOCK(vs->vs_vp, 0, curthread); 1337#else 1338 VOP_UNLOCK(vs->vs_vp, 0); 1339#endif 1340 vs->vs_vnlocked = FALSE; 1341 1342out: 1343 if (freecred) 1344 crfree(cred); 1345 1346 return (error); 1347} 1348 1349static void 1350nlm_release_vfs_state(struct vfs_state *vs) 1351{ 1352 1353 if (vs->vs_vp) { 1354 if (vs->vs_vnlocked) 1355 vput(vs->vs_vp); 1356 else 1357 vrele(vs->vs_vp); 1358 } 1359 if (vs->vs_mp) 1360 vfs_rel(vs->vs_mp); 1361 VFS_UNLOCK_GIANT(vs->vs_vfslocked); 1362} 1363 1364static nlm4_stats 1365nlm_convert_error(int error) 1366{ 1367 1368 if (error == ESTALE) 1369 return nlm4_stale_fh; 1370 else if (error == EROFS) 1371 return nlm4_rofs; 1372 else 1373 return nlm4_failed; 1374} 1375 1376struct nlm_host * 1377nlm_do_test(nlm4_testargs *argp, nlm4_testres *result, struct svc_req *rqstp) 1378{ 1379 fhandle_t fh; 1380 struct vfs_state vs; 1381 struct nlm_host *host, *bhost; 1382 int error, sysid; 1383 struct flock fl; 1384 1385 memset(result, 0, sizeof(*result)); 1386 1387 host = nlm_find_host_by_name(argp->alock.caller_name, rqstp); 1388 if (!host) { 1389 result->stat.stat = nlm4_denied_nolocks; 1390 return (NULL); 1391 } 1392 1393 if (nlm_debug_level >= 3) 1394 printf("nlm_do_test(): caller_name = %s (sysid = %d)\n", 1395 host->nh_caller_name, host->nh_sysid); 1396 1397 nlm_free_finished_locks(host); 1398 sysid = host->nh_sysid; 1399 1400 nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1401 nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1402 1403 if (time_uptime < nlm_grace_threshold) { 1404 result->stat.stat = nlm4_denied_grace_period; 1405 return (host); 1406 } 1407 1408 error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 1409 if (error) { 1410 result->stat.stat = nlm_convert_error(error); 1411 goto out; 1412 } 1413 1414 fl.l_start = argp->alock.l_offset; 1415 fl.l_len = argp->alock.l_len; 1416 fl.l_pid = argp->alock.svid; 1417 fl.l_sysid = sysid; 1418 fl.l_whence = SEEK_SET; 1419 if (argp->exclusive) 1420 fl.l_type = F_WRLCK; 1421 else 1422 fl.l_type = F_RDLCK; 1423 error = VOP_ADVLOCK(vs.vs_vp, NULL, F_GETLK, &fl, F_REMOTE); 1424 if (error) { 1425 result->stat.stat = nlm4_failed; 1426 goto out; 1427 } 1428 1429 if (fl.l_type == F_UNLCK) { 1430 result->stat.stat = nlm4_granted; 1431 } else { 1432 result->stat.stat = nlm4_denied; 1433 result->stat.nlm4_testrply_u.holder.exclusive = 1434 (fl.l_type == F_WRLCK); 1435 result->stat.nlm4_testrply_u.holder.svid = fl.l_pid; 1436 bhost = nlm_find_host_by_sysid(fl.l_sysid); 1437 if (bhost) { 1438 /* 1439 * We don't have any useful way of recording 1440 * the value of oh used in the original lock 1441 * request. Ideally, the test reply would have 1442 * a space for the owning host's name allowing 1443 * our caller's NLM to keep track. 1444 * 1445 * As far as I can see, Solaris uses an eight 1446 * byte structure for oh which contains a four 1447 * byte pid encoded in local byte order and 1448 * the first four bytes of the host 1449 * name. Linux uses a variable length string 1450 * 'pid@hostname' in ascii but doesn't even 1451 * return that in test replies. 1452 * 1453 * For the moment, return nothing in oh 1454 * (already zero'ed above). 1455 */ 1456 } 1457 result->stat.nlm4_testrply_u.holder.l_offset = fl.l_start; 1458 result->stat.nlm4_testrply_u.holder.l_len = fl.l_len; 1459 } 1460 1461out: 1462 nlm_release_vfs_state(&vs); 1463 return (host); 1464} 1465 1466struct nlm_host * 1467nlm_do_lock(nlm4_lockargs *argp, nlm4_res *result, struct svc_req *rqstp, 1468 bool_t monitor) 1469{ 1470 fhandle_t fh; 1471 struct vfs_state vs; 1472 struct nlm_host *host; 1473 int error, sysid; 1474 struct flock fl; 1475 1476 memset(result, 0, sizeof(*result)); 1477 1478 host = nlm_find_host_by_name(argp->alock.caller_name, rqstp); 1479 if (!host) { 1480 result->stat.stat = nlm4_denied_nolocks; 1481 return (NULL); 1482 } 1483 1484 if (nlm_debug_level >= 3) 1485 printf("nlm_do_lock(): caller_name = %s (sysid = %d)\n", 1486 host->nh_caller_name, host->nh_sysid); 1487 1488 if (monitor && host->nh_state && argp->state 1489 && host->nh_state != argp->state) { 1490 /* 1491 * The host rebooted without telling us. Trash its 1492 * locks. 1493 */ 1494 nlm_host_notify(host, argp->state, FALSE); 1495 } 1496 1497 nlm_free_finished_locks(host); 1498 sysid = host->nh_sysid; 1499 1500 nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1501 nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1502 1503 if (time_uptime < nlm_grace_threshold && !argp->reclaim) { 1504 result->stat.stat = nlm4_denied_grace_period; 1505 return (host); 1506 } 1507 1508 error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 1509 if (error) { 1510 result->stat.stat = nlm_convert_error(error); 1511 goto out; 1512 } 1513 1514 fl.l_start = argp->alock.l_offset; 1515 fl.l_len = argp->alock.l_len; 1516 fl.l_pid = argp->alock.svid; 1517 fl.l_sysid = sysid; 1518 fl.l_whence = SEEK_SET; 1519 if (argp->exclusive) 1520 fl.l_type = F_WRLCK; 1521 else 1522 fl.l_type = F_RDLCK; 1523 if (argp->block) { 1524 struct nlm_async_lock *af; 1525 1526 /* 1527 * First, make sure we can contact the host's NLM. 1528 */ 1529 if (!nlm_host_get_rpc(host)) { 1530 result->stat.stat = nlm4_failed; 1531 goto out; 1532 } 1533 1534 /* 1535 * First we need to check and see if there is an 1536 * existing blocked lock that matches. This could be a 1537 * badly behaved client or an RPC re-send. If we find 1538 * one, just return nlm4_blocked. 1539 */ 1540 mtx_lock(&host->nh_lock); 1541 TAILQ_FOREACH(af, &host->nh_pending, af_link) { 1542 if (af->af_fl.l_start == fl.l_start 1543 && af->af_fl.l_len == fl.l_len 1544 && af->af_fl.l_pid == fl.l_pid 1545 && af->af_fl.l_type == fl.l_type) { 1546 break; 1547 } 1548 } 1549 mtx_unlock(&host->nh_lock); 1550 if (af) { 1551 result->stat.stat = nlm4_blocked; 1552 goto out; 1553 } 1554 1555 af = malloc(sizeof(struct nlm_async_lock), M_NLM, 1556 M_WAITOK|M_ZERO); 1557 TASK_INIT(&af->af_task, 0, nlm_lock_callback, af); 1558 af->af_vp = vs.vs_vp; 1559 af->af_fl = fl; 1560 af->af_host = host; 1561 /* 1562 * We use M_RPC here so that we can xdr_free the thing 1563 * later. 1564 */ 1565 af->af_granted.exclusive = argp->exclusive; 1566 af->af_granted.alock.caller_name = 1567 strdup(argp->alock.caller_name, M_RPC); 1568 nlm_copy_netobj(&af->af_granted.alock.fh, 1569 &argp->alock.fh, M_RPC); 1570 nlm_copy_netobj(&af->af_granted.alock.oh, 1571 &argp->alock.oh, M_RPC); 1572 af->af_granted.alock.svid = argp->alock.svid; 1573 af->af_granted.alock.l_offset = argp->alock.l_offset; 1574 af->af_granted.alock.l_len = argp->alock.l_len; 1575 1576 /* 1577 * Put the entry on the pending list before calling 1578 * VOP_ADVLOCKASYNC. We do this in case the lock 1579 * request was blocked (returning EINPROGRESS) but 1580 * then granted before we manage to run again. The 1581 * client may receive the granted message before we 1582 * send our blocked reply but thats their problem. 1583 */ 1584 mtx_lock(&host->nh_lock); 1585 TAILQ_INSERT_TAIL(&host->nh_pending, af, af_link); 1586 mtx_unlock(&host->nh_lock); 1587 1588 error = VOP_ADVLOCKASYNC(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE, 1589 &af->af_task, &af->af_cookie); 1590 1591 /* 1592 * If the lock completed synchronously, just free the 1593 * tracking structure now. 1594 */ 1595 if (error != EINPROGRESS) { 1596 mtx_lock(&host->nh_lock); 1597 TAILQ_REMOVE(&host->nh_pending, af, af_link); 1598 mtx_unlock(&host->nh_lock); 1599 xdr_free((xdrproc_t) xdr_nlm4_testargs, 1600 &af->af_granted); 1601 free(af, M_NLM); 1602 } else { 1603 if (nlm_debug_level >= 2) 1604 printf("NLM: pending async lock %p for %s " 1605 "(sysid %d)\n", 1606 af, host->nh_caller_name, sysid); 1607 /* 1608 * Don't vrele the vnode just yet - this must 1609 * wait until either the async callback 1610 * happens or the lock is cancelled. 1611 */ 1612 vs.vs_vp = NULL; 1613 } 1614 } else { 1615 error = VOP_ADVLOCK(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE); 1616 } 1617 1618 if (error) { 1619 if (error == EINPROGRESS) { 1620 result->stat.stat = nlm4_blocked; 1621 } else if (error == EDEADLK) { 1622 result->stat.stat = nlm4_deadlck; 1623 } else if (error == EAGAIN) { 1624 result->stat.stat = nlm4_denied; 1625 } else { 1626 result->stat.stat = nlm4_failed; 1627 } 1628 } else { 1629 if (monitor) 1630 nlm_host_monitor(host, argp->state); 1631 result->stat.stat = nlm4_granted; 1632 } 1633 1634out: 1635 nlm_release_vfs_state(&vs); 1636 1637 return (host); 1638} 1639 1640struct nlm_host * 1641nlm_do_cancel(nlm4_cancargs *argp, nlm4_res *result, struct svc_req *rqstp) 1642{ 1643 fhandle_t fh; 1644 struct vfs_state vs; 1645 struct nlm_host *host; 1646 int error, sysid; 1647 struct flock fl; 1648 struct nlm_async_lock *af; 1649 1650 memset(result, 0, sizeof(*result)); 1651 1652 host = nlm_find_host_by_name(argp->alock.caller_name, rqstp); 1653 if (!host) { 1654 result->stat.stat = nlm4_denied_nolocks; 1655 return (NULL); 1656 } 1657 1658 if (nlm_debug_level >= 3) 1659 printf("nlm_do_cancel(): caller_name = %s (sysid = %d)\n", 1660 host->nh_caller_name, host->nh_sysid); 1661 1662 nlm_free_finished_locks(host); 1663 sysid = host->nh_sysid; 1664 1665 nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1666 nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1667 1668 if (time_uptime < nlm_grace_threshold) { 1669 result->stat.stat = nlm4_denied_grace_period; 1670 return (host); 1671 } 1672 1673 error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 1674 if (error) { 1675 result->stat.stat = nlm_convert_error(error); 1676 goto out; 1677 } 1678 1679 fl.l_start = argp->alock.l_offset; 1680 fl.l_len = argp->alock.l_len; 1681 fl.l_pid = argp->alock.svid; 1682 fl.l_sysid = sysid; 1683 fl.l_whence = SEEK_SET; 1684 if (argp->exclusive) 1685 fl.l_type = F_WRLCK; 1686 else 1687 fl.l_type = F_RDLCK; 1688 1689 /* 1690 * First we need to try and find the async lock request - if 1691 * there isn't one, we give up and return nlm4_denied. 1692 */ 1693 mtx_lock(&host->nh_lock); 1694 1695 TAILQ_FOREACH(af, &host->nh_pending, af_link) { 1696 if (af->af_fl.l_start == fl.l_start 1697 && af->af_fl.l_len == fl.l_len 1698 && af->af_fl.l_pid == fl.l_pid 1699 && af->af_fl.l_type == fl.l_type) { 1700 break; 1701 } 1702 } 1703 1704 if (!af) { 1705 mtx_unlock(&host->nh_lock); 1706 result->stat.stat = nlm4_denied; 1707 goto out; 1708 } 1709 1710 error = nlm_cancel_async_lock(af); 1711 1712 if (error) { 1713 result->stat.stat = nlm4_denied; 1714 } else { 1715 result->stat.stat = nlm4_granted; 1716 } 1717 1718 mtx_unlock(&host->nh_lock); 1719 1720out: 1721 nlm_release_vfs_state(&vs); 1722 1723 return (host); 1724} 1725 1726struct nlm_host * 1727nlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *result, struct svc_req *rqstp) 1728{ 1729 fhandle_t fh; 1730 struct vfs_state vs; 1731 struct nlm_host *host; 1732 int error, sysid; 1733 struct flock fl; 1734 1735 memset(result, 0, sizeof(*result)); 1736 1737 host = nlm_find_host_by_name(argp->alock.caller_name, rqstp); 1738 if (!host) { 1739 result->stat.stat = nlm4_denied_nolocks; 1740 return (NULL); 1741 } 1742 1743 if (nlm_debug_level >= 3) 1744 printf("nlm_do_unlock(): caller_name = %s (sysid = %d)\n", 1745 host->nh_caller_name, host->nh_sysid); 1746 1747 nlm_free_finished_locks(host); 1748 sysid = host->nh_sysid; 1749 1750 nlm_convert_to_fhandle_t(&fh, &argp->alock.fh); 1751 nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC); 1752 1753 if (time_uptime < nlm_grace_threshold) { 1754 result->stat.stat = nlm4_denied_grace_period; 1755 return (host); 1756 } 1757 1758 error = nlm_get_vfs_state(host, rqstp, &fh, &vs); 1759 if (error) { 1760 result->stat.stat = nlm_convert_error(error); 1761 goto out; 1762 } 1763 1764 fl.l_start = argp->alock.l_offset; 1765 fl.l_len = argp->alock.l_len; 1766 fl.l_pid = argp->alock.svid; 1767 fl.l_sysid = sysid; 1768 fl.l_whence = SEEK_SET; 1769 fl.l_type = F_UNLCK; 1770 error = VOP_ADVLOCK(vs.vs_vp, NULL, F_UNLCK, &fl, F_REMOTE); 1771 1772 /* 1773 * Ignore the error - there is no result code for failure, 1774 * only for grace period. 1775 */ 1776 result->stat.stat = nlm4_granted; 1777 1778out: 1779 nlm_release_vfs_state(&vs); 1780 1781 return (host); 1782} 1783 1784void 1785nlm_do_free_all(nlm4_notify *argp) 1786{ 1787 struct nlm_host *host, *thost; 1788 1789 TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, thost) { 1790 if (!strcmp(host->nh_caller_name, argp->name)) 1791 nlm_host_notify(host, argp->state, FALSE); 1792 } 1793} 1794 1795#define _PATH_RPCLOCKDSOCK "/var/run/rpclockd.sock" 1796 1797/* 1798 * Make a connection to the userland lockd - we push anything we can't 1799 * handle out to userland. 1800 */ 1801CLIENT * 1802nlm_user_lockd(void) 1803{ 1804 struct sockaddr_un sun; 1805 struct netconfig *nconf; 1806 struct timeval zero; 1807 1808 if (nlm_lockd) 1809 return (nlm_lockd); 1810 1811 sun.sun_family = AF_LOCAL; 1812 strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK); 1813 sun.sun_len = SUN_LEN(&sun); 1814 1815 nconf = getnetconfigent("local"); 1816 nlm_lockd = clnt_reconnect_create(nconf, (struct sockaddr *) &sun, 1817 NLM_PROG, NLM_VERS4, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 1818 1819 /* 1820 * Set the send timeout to zero - we only use this rpc handle 1821 * for sending async replies which have no return value. 1822 */ 1823 zero.tv_sec = 0; 1824 zero.tv_usec = 0; 1825 CLNT_CONTROL(nlm_lockd, CLSET_TIMEOUT, &zero); 1826 1827 return (nlm_lockd); 1828} 1829 1830/* 1831 * Kernel module glue 1832 */ 1833static int 1834nfslockd_modevent(module_t mod, int type, void *data) 1835{ 1836 1837 return (0); 1838} 1839static moduledata_t nfslockd_mod = { 1840 "nfslockd", 1841 nfslockd_modevent, 1842 NULL, 1843}; 1844DECLARE_MODULE(nfslockd, nfslockd_mod, SI_SUB_VFS, SI_ORDER_ANY); 1845 1846/* So that loader and kldload(2) can find us, wherever we are.. */ 1847MODULE_DEPEND(nfslockd, krpc, 1, 1, 1); 1848MODULE_VERSION(nfslockd, 1); 1849