1*a002c830Sandvar /* $NetBSD: nlm_prot_impl.c,v 1.5 2023/04/28 22:31:38 andvar Exp $ */
26ca35587Sdholland /*-
36ca35587Sdholland * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
46ca35587Sdholland * Authors: Doug Rabson <dfr@rabson.org>
56ca35587Sdholland * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
66ca35587Sdholland *
76ca35587Sdholland * Redistribution and use in source and binary forms, with or without
86ca35587Sdholland * modification, are permitted provided that the following conditions
96ca35587Sdholland * are met:
106ca35587Sdholland * 1. Redistributions of source code must retain the above copyright
116ca35587Sdholland * notice, this list of conditions and the following disclaimer.
126ca35587Sdholland * 2. Redistributions in binary form must reproduce the above copyright
136ca35587Sdholland * notice, this list of conditions and the following disclaimer in the
146ca35587Sdholland * documentation and/or other materials provided with the distribution.
156ca35587Sdholland *
166ca35587Sdholland * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
176ca35587Sdholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
186ca35587Sdholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
196ca35587Sdholland * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
206ca35587Sdholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
216ca35587Sdholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
226ca35587Sdholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
236ca35587Sdholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
246ca35587Sdholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
256ca35587Sdholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
266ca35587Sdholland * SUCH DAMAGE.
276ca35587Sdholland */
286ca35587Sdholland
29d687e96aSpgoyette #ifdef _KERNEL_OPT
306ca35587Sdholland #include "opt_inet6.h"
31d687e96aSpgoyette #endif
326ca35587Sdholland
336ca35587Sdholland #include <sys/cdefs.h>
342d39560cSpgoyette /* __FBSDID("FreeBSD: head/sys/nlm/nlm_prot_impl.c 302216 2016-06-26 20:08:42Z kib "); */
35*a002c830Sandvar __RCSID("$NetBSD: nlm_prot_impl.c,v 1.5 2023/04/28 22:31:38 andvar Exp $");
366ca35587Sdholland
376ca35587Sdholland #include <sys/param.h>
386ca35587Sdholland #include <sys/fail.h>
396ca35587Sdholland #include <sys/fcntl.h>
406ca35587Sdholland #include <sys/kernel.h>
416ca35587Sdholland #include <sys/kthread.h>
426ca35587Sdholland #include <sys/lockf.h>
436ca35587Sdholland #include <sys/malloc.h>
446ca35587Sdholland #include <sys/mount.h>
456ca35587Sdholland #include <sys/proc.h>
466ca35587Sdholland #include <sys/socket.h>
476ca35587Sdholland #include <sys/socketvar.h>
486ca35587Sdholland #include <sys/syscall.h>
496ca35587Sdholland #include <sys/sysctl.h>
506ca35587Sdholland #include <sys/sysent.h>
516ca35587Sdholland #include <sys/syslog.h>
526ca35587Sdholland #include <sys/sysproto.h>
536ca35587Sdholland #include <sys/systm.h>
546ca35587Sdholland #include <sys/taskqueue.h>
556ca35587Sdholland #include <sys/unistd.h>
566ca35587Sdholland #include <sys/vnode.h>
576ca35587Sdholland
58d687e96aSpgoyette #if 0
59d687e96aSpgoyette #if __FreeBSD_version >= 700000
60d687e96aSpgoyette #include <sys/priv.h>
61d687e96aSpgoyette #endif
62d687e96aSpgoyette #endif
636ca35587Sdholland
64d687e96aSpgoyette #include <fs/nfs/common/nfsproto.h>
65d687e96aSpgoyette #include <fs/nfs/common/nfs_lock.h>
66d687e96aSpgoyette
67d687e96aSpgoyette #include <fs/nfs/nlm/nlm_prot.h>
68d687e96aSpgoyette #include <fs/nfs/nlm/sm_inter.h>
69d687e96aSpgoyette #include <fs/nfs/nlm/nlm.h>
70d687e96aSpgoyette
716ca35587Sdholland #include <rpc/rpc_com.h>
726ca35587Sdholland #include <rpc/rpcb_prot.h>
736ca35587Sdholland
746ca35587Sdholland MALLOC_DEFINE(M_NLM, "NLM", "Network Lock Manager");
756ca35587Sdholland
766ca35587Sdholland /*
776ca35587Sdholland * If a host is inactive (and holds no locks) for this amount of
786ca35587Sdholland * seconds, we consider it idle and stop tracking it.
796ca35587Sdholland */
806ca35587Sdholland #define NLM_IDLE_TIMEOUT 30
816ca35587Sdholland
826ca35587Sdholland /*
836ca35587Sdholland * We check the host list for idle every few seconds.
846ca35587Sdholland */
856ca35587Sdholland #define NLM_IDLE_PERIOD 5
866ca35587Sdholland
876ca35587Sdholland /*
886ca35587Sdholland * We only look for GRANTED_RES messages for a little while.
896ca35587Sdholland */
906ca35587Sdholland #define NLM_EXPIRE_TIMEOUT 10
916ca35587Sdholland
926ca35587Sdholland /*
936ca35587Sdholland * Support for sysctl vfs.nlm.sysid
946ca35587Sdholland */
956ca35587Sdholland static SYSCTL_NODE(_vfs, OID_AUTO, nlm, CTLFLAG_RW, NULL,
966ca35587Sdholland "Network Lock Manager");
976ca35587Sdholland static SYSCTL_NODE(_vfs_nlm, OID_AUTO, sysid, CTLFLAG_RW, NULL, "");
986ca35587Sdholland
996ca35587Sdholland /*
1006ca35587Sdholland * Syscall hooks
1016ca35587Sdholland */
1026ca35587Sdholland static int nlm_syscall_offset = SYS_nlm_syscall;
1036ca35587Sdholland static struct sysent nlm_syscall_prev_sysent;
1046ca35587Sdholland #if __FreeBSD_version < 700000
1056ca35587Sdholland static struct sysent nlm_syscall_sysent = {
1066ca35587Sdholland (sizeof(struct nlm_syscall_args) / sizeof(register_t)) | SYF_MPSAFE,
1076ca35587Sdholland (sy_call_t *) nlm_syscall
1086ca35587Sdholland };
1096ca35587Sdholland #else
1106ca35587Sdholland MAKE_SYSENT(nlm_syscall);
1116ca35587Sdholland #endif
1126ca35587Sdholland static bool_t nlm_syscall_registered = FALSE;
1136ca35587Sdholland
1146ca35587Sdholland /*
1156ca35587Sdholland * Debug level passed in from userland. We also support a sysctl hook
1166ca35587Sdholland * so that it can be changed on a live system.
1176ca35587Sdholland */
1186ca35587Sdholland static int nlm_debug_level;
1196ca35587Sdholland SYSCTL_INT(_debug, OID_AUTO, nlm_debug, CTLFLAG_RW, &nlm_debug_level, 0, "");
1206ca35587Sdholland
1216ca35587Sdholland #define NLM_DEBUG(_level, args...) \
1226ca35587Sdholland do { \
1236ca35587Sdholland if (nlm_debug_level >= (_level)) \
1246ca35587Sdholland log(LOG_DEBUG, args); \
1256ca35587Sdholland } while(0)
1266ca35587Sdholland #define NLM_ERR(args...) \
1276ca35587Sdholland do { \
1286ca35587Sdholland log(LOG_ERR, args); \
1296ca35587Sdholland } while(0)
1306ca35587Sdholland
1316ca35587Sdholland /*
1326ca35587Sdholland * Grace period handling. The value of nlm_grace_threshold is the
1336ca35587Sdholland * value of time_uptime after which we are serving requests normally.
1346ca35587Sdholland */
1356ca35587Sdholland static time_t nlm_grace_threshold;
1366ca35587Sdholland
1376ca35587Sdholland /*
1386ca35587Sdholland * We check for idle hosts if time_uptime is greater than
1396ca35587Sdholland * nlm_next_idle_check,
1406ca35587Sdholland */
1416ca35587Sdholland static time_t nlm_next_idle_check;
1426ca35587Sdholland
1436ca35587Sdholland /*
1446ca35587Sdholland * A flag to indicate the server is already running.
1456ca35587Sdholland */
1466ca35587Sdholland static int nlm_is_running;
1476ca35587Sdholland
1486ca35587Sdholland /*
1496ca35587Sdholland * A socket to use for RPC - shared by all IPv4 RPC clients.
1506ca35587Sdholland */
1516ca35587Sdholland static struct socket *nlm_socket;
1526ca35587Sdholland
1536ca35587Sdholland #ifdef INET6
1546ca35587Sdholland
1556ca35587Sdholland /*
1566ca35587Sdholland * A socket to use for RPC - shared by all IPv6 RPC clients.
1576ca35587Sdholland */
1586ca35587Sdholland static struct socket *nlm_socket6;
1596ca35587Sdholland
1606ca35587Sdholland #endif
1616ca35587Sdholland
1626ca35587Sdholland /*
1636ca35587Sdholland * An RPC client handle that can be used to communicate with the local
1646ca35587Sdholland * NSM.
1656ca35587Sdholland */
1666ca35587Sdholland static CLIENT *nlm_nsm;
1676ca35587Sdholland
1686ca35587Sdholland /*
1696ca35587Sdholland * An AUTH handle for the server's creds.
1706ca35587Sdholland */
1716ca35587Sdholland static AUTH *nlm_auth;
1726ca35587Sdholland
1736ca35587Sdholland /*
1746ca35587Sdholland * A zero timeval for sending async RPC messages.
1756ca35587Sdholland */
1766ca35587Sdholland struct timeval nlm_zero_tv = { 0, 0 };
1776ca35587Sdholland
1786ca35587Sdholland /*
1796ca35587Sdholland * The local NSM state number
1806ca35587Sdholland */
1816ca35587Sdholland int nlm_nsm_state;
1826ca35587Sdholland
1836ca35587Sdholland
1846ca35587Sdholland /*
1856ca35587Sdholland * A lock to protect the host list and waiting lock list.
1866ca35587Sdholland */
1876ca35587Sdholland static struct mtx nlm_global_lock;
1886ca35587Sdholland
1896ca35587Sdholland /*
1906ca35587Sdholland * Locks:
1916ca35587Sdholland * (l) locked by nh_lock
1926ca35587Sdholland * (s) only accessed via server RPC which is single threaded
1936ca35587Sdholland * (g) locked by nlm_global_lock
1946ca35587Sdholland * (c) const until freeing
1956ca35587Sdholland * (a) modified using atomic ops
1966ca35587Sdholland */
1976ca35587Sdholland
1986ca35587Sdholland /*
1996ca35587Sdholland * A pending client-side lock request, stored on the nlm_waiting_locks
2006ca35587Sdholland * list.
2016ca35587Sdholland */
2026ca35587Sdholland struct nlm_waiting_lock {
2036ca35587Sdholland TAILQ_ENTRY(nlm_waiting_lock) nw_link; /* (g) */
2046ca35587Sdholland bool_t nw_waiting; /* (g) */
2056ca35587Sdholland nlm4_lock nw_lock; /* (c) */
2066ca35587Sdholland union nfsfh nw_fh; /* (c) */
2076ca35587Sdholland struct vnode *nw_vp; /* (c) */
2086ca35587Sdholland };
2096ca35587Sdholland TAILQ_HEAD(nlm_waiting_lock_list, nlm_waiting_lock);
2106ca35587Sdholland
2116ca35587Sdholland struct nlm_waiting_lock_list nlm_waiting_locks; /* (g) */
2126ca35587Sdholland
2136ca35587Sdholland /*
2146ca35587Sdholland * A pending server-side asynchronous lock request, stored on the
2156ca35587Sdholland * nh_pending list of the NLM host.
2166ca35587Sdholland */
2176ca35587Sdholland struct nlm_async_lock {
2186ca35587Sdholland TAILQ_ENTRY(nlm_async_lock) af_link; /* (l) host's list of locks */
2196ca35587Sdholland struct task af_task; /* (c) async callback details */
2206ca35587Sdholland void *af_cookie; /* (l) lock manager cancel token */
2216ca35587Sdholland struct vnode *af_vp; /* (l) vnode to lock */
2226ca35587Sdholland struct flock af_fl; /* (c) lock details */
2236ca35587Sdholland struct nlm_host *af_host; /* (c) host which is locking */
2246ca35587Sdholland CLIENT *af_rpc; /* (c) rpc client to send message */
2256ca35587Sdholland nlm4_testargs af_granted; /* (c) notification details */
2266ca35587Sdholland time_t af_expiretime; /* (c) notification time */
2276ca35587Sdholland };
2286ca35587Sdholland TAILQ_HEAD(nlm_async_lock_list, nlm_async_lock);
2296ca35587Sdholland
2306ca35587Sdholland /*
2316ca35587Sdholland * NLM host.
2326ca35587Sdholland */
2336ca35587Sdholland enum nlm_host_state {
2346ca35587Sdholland NLM_UNMONITORED,
2356ca35587Sdholland NLM_MONITORED,
2366ca35587Sdholland NLM_MONITOR_FAILED,
2376ca35587Sdholland NLM_RECOVERING
2386ca35587Sdholland };
2396ca35587Sdholland
2406ca35587Sdholland struct nlm_rpc {
2416ca35587Sdholland CLIENT *nr_client; /* (l) RPC client handle */
2426ca35587Sdholland time_t nr_create_time; /* (l) when client was created */
2436ca35587Sdholland };
2446ca35587Sdholland
2456ca35587Sdholland struct nlm_host {
2466ca35587Sdholland struct mtx nh_lock;
2476ca35587Sdholland volatile u_int nh_refs; /* (a) reference count */
2486ca35587Sdholland TAILQ_ENTRY(nlm_host) nh_link; /* (g) global list of hosts */
2496ca35587Sdholland char nh_caller_name[MAXNAMELEN]; /* (c) printable name of host */
250*a002c830Sandvar uint32_t nh_sysid; /* (c) our allocated system ID */
2516ca35587Sdholland char nh_sysid_string[10]; /* (c) string rep. of sysid */
2526ca35587Sdholland struct sockaddr_storage nh_addr; /* (s) remote address of host */
2536ca35587Sdholland struct nlm_rpc nh_srvrpc; /* (l) RPC for server replies */
2546ca35587Sdholland struct nlm_rpc nh_clntrpc; /* (l) RPC for client requests */
2556ca35587Sdholland rpcvers_t nh_vers; /* (s) NLM version of host */
2566ca35587Sdholland int nh_state; /* (s) last seen NSM state of host */
2576ca35587Sdholland enum nlm_host_state nh_monstate; /* (l) local NSM monitoring state */
2586ca35587Sdholland time_t nh_idle_timeout; /* (s) Time at which host is idle */
2596ca35587Sdholland struct sysctl_ctx_list nh_sysctl; /* (c) vfs.nlm.sysid nodes */
2606ca35587Sdholland uint32_t nh_grantcookie; /* (l) grant cookie counter */
2616ca35587Sdholland struct nlm_async_lock_list nh_pending; /* (l) pending async locks */
2626ca35587Sdholland struct nlm_async_lock_list nh_granted; /* (l) granted locks */
2636ca35587Sdholland struct nlm_async_lock_list nh_finished; /* (l) finished async locks */
2646ca35587Sdholland };
2656ca35587Sdholland TAILQ_HEAD(nlm_host_list, nlm_host);
2666ca35587Sdholland
2676ca35587Sdholland static struct nlm_host_list nlm_hosts; /* (g) */
2686ca35587Sdholland static uint32_t nlm_next_sysid = 1; /* (g) */
2696ca35587Sdholland
2706ca35587Sdholland static void nlm_host_unmonitor(struct nlm_host *);
2716ca35587Sdholland
2726ca35587Sdholland struct nlm_grantcookie {
2736ca35587Sdholland uint32_t ng_sysid;
2746ca35587Sdholland uint32_t ng_cookie;
2756ca35587Sdholland };
2766ca35587Sdholland
2776ca35587Sdholland static inline uint32_t
ng_sysid(struct netobj * src)2786ca35587Sdholland ng_sysid(struct netobj *src)
2796ca35587Sdholland {
2806ca35587Sdholland
2816ca35587Sdholland return ((struct nlm_grantcookie *)src->n_bytes)->ng_sysid;
2826ca35587Sdholland }
2836ca35587Sdholland
2846ca35587Sdholland static inline uint32_t
ng_cookie(struct netobj * src)2856ca35587Sdholland ng_cookie(struct netobj *src)
2866ca35587Sdholland {
2876ca35587Sdholland
2886ca35587Sdholland return ((struct nlm_grantcookie *)src->n_bytes)->ng_cookie;
2896ca35587Sdholland }
2906ca35587Sdholland
2916ca35587Sdholland /**********************************************************************/
2926ca35587Sdholland
2936ca35587Sdholland /*
2946ca35587Sdholland * Initialise NLM globals.
2956ca35587Sdholland */
2966ca35587Sdholland static void
nlm_init(void * dummy)2976ca35587Sdholland nlm_init(void *dummy)
2986ca35587Sdholland {
2996ca35587Sdholland int error;
3006ca35587Sdholland
3016ca35587Sdholland mtx_init(&nlm_global_lock, "nlm_global_lock", NULL, MTX_DEF);
3026ca35587Sdholland TAILQ_INIT(&nlm_waiting_locks);
3036ca35587Sdholland TAILQ_INIT(&nlm_hosts);
3046ca35587Sdholland
3056ca35587Sdholland error = syscall_register(&nlm_syscall_offset, &nlm_syscall_sysent,
3062d39560cSpgoyette &nlm_syscall_prev_sysent, SY_THR_STATIC_KLD);
3076ca35587Sdholland if (error)
3086ca35587Sdholland NLM_ERR("Can't register NLM syscall\n");
3096ca35587Sdholland else
3106ca35587Sdholland nlm_syscall_registered = TRUE;
3116ca35587Sdholland }
3126ca35587Sdholland SYSINIT(nlm_init, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_init, NULL);
3136ca35587Sdholland
3146ca35587Sdholland static void
nlm_uninit(void * dummy)3156ca35587Sdholland nlm_uninit(void *dummy)
3166ca35587Sdholland {
3176ca35587Sdholland
3186ca35587Sdholland if (nlm_syscall_registered)
3196ca35587Sdholland syscall_deregister(&nlm_syscall_offset,
3206ca35587Sdholland &nlm_syscall_prev_sysent);
3216ca35587Sdholland }
3226ca35587Sdholland SYSUNINIT(nlm_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_uninit, NULL);
3236ca35587Sdholland
3246ca35587Sdholland /*
3256ca35587Sdholland * Create a netobj from an arbitrary source.
3266ca35587Sdholland */
3276ca35587Sdholland void
nlm_make_netobj(struct netobj * dst,caddr_t src,size_t srcsize,struct malloc_type * type)3286ca35587Sdholland nlm_make_netobj(struct netobj *dst, caddr_t src, size_t srcsize,
3296ca35587Sdholland struct malloc_type *type)
3306ca35587Sdholland {
3316ca35587Sdholland
3326ca35587Sdholland dst->n_len = srcsize;
3336ca35587Sdholland dst->n_bytes = malloc(srcsize, type, M_WAITOK);
3346ca35587Sdholland memcpy(dst->n_bytes, src, srcsize);
3356ca35587Sdholland }
3366ca35587Sdholland
3376ca35587Sdholland /*
3386ca35587Sdholland * Copy a struct netobj.
3396ca35587Sdholland */
3406ca35587Sdholland void
nlm_copy_netobj(struct netobj * dst,struct netobj * src,struct malloc_type * type)3416ca35587Sdholland nlm_copy_netobj(struct netobj *dst, struct netobj *src,
3426ca35587Sdholland struct malloc_type *type)
3436ca35587Sdholland {
3446ca35587Sdholland
3456ca35587Sdholland nlm_make_netobj(dst, src->n_bytes, src->n_len, type);
3466ca35587Sdholland }
3476ca35587Sdholland
3486ca35587Sdholland
3496ca35587Sdholland /*
3506ca35587Sdholland * Create an RPC client handle for the given (address,prog,vers)
3516ca35587Sdholland * triple using UDP.
3526ca35587Sdholland */
3536ca35587Sdholland static CLIENT *
nlm_get_rpc(struct sockaddr * sa,rpcprog_t prog,rpcvers_t vers)3546ca35587Sdholland nlm_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers)
3556ca35587Sdholland {
3566ca35587Sdholland char *wchan = "nlmrcv";
3576ca35587Sdholland const char* protofmly;
3586ca35587Sdholland struct sockaddr_storage ss;
3596ca35587Sdholland struct socket *so;
3606ca35587Sdholland CLIENT *rpcb;
3616ca35587Sdholland struct timeval timo;
3626ca35587Sdholland RPCB parms;
3636ca35587Sdholland char *uaddr;
3646ca35587Sdholland enum clnt_stat stat = RPC_SUCCESS;
3656ca35587Sdholland int rpcvers = RPCBVERS4;
3666ca35587Sdholland bool_t do_tcp = FALSE;
3676ca35587Sdholland bool_t tryagain = FALSE;
3686ca35587Sdholland struct portmap mapping;
3696ca35587Sdholland u_short port = 0;
3706ca35587Sdholland
3716ca35587Sdholland /*
3726ca35587Sdholland * First we need to contact the remote RPCBIND service to find
3736ca35587Sdholland * the right port.
3746ca35587Sdholland */
3756ca35587Sdholland memcpy(&ss, sa, sa->sa_len);
3766ca35587Sdholland switch (ss.ss_family) {
3776ca35587Sdholland case AF_INET:
3786ca35587Sdholland ((struct sockaddr_in *)&ss)->sin_port = htons(111);
3796ca35587Sdholland protofmly = "inet";
3806ca35587Sdholland so = nlm_socket;
3816ca35587Sdholland break;
3826ca35587Sdholland
3836ca35587Sdholland #ifdef INET6
3846ca35587Sdholland case AF_INET6:
3856ca35587Sdholland ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111);
3866ca35587Sdholland protofmly = "inet6";
3876ca35587Sdholland so = nlm_socket6;
3886ca35587Sdholland break;
3896ca35587Sdholland #endif
3906ca35587Sdholland
3916ca35587Sdholland default:
3926ca35587Sdholland /*
3936ca35587Sdholland * Unsupported address family - fail.
3946ca35587Sdholland */
3956ca35587Sdholland return (NULL);
3966ca35587Sdholland }
3976ca35587Sdholland
3986ca35587Sdholland rpcb = clnt_dg_create(so, (struct sockaddr *)&ss,
3996ca35587Sdholland RPCBPROG, rpcvers, 0, 0);
4006ca35587Sdholland if (!rpcb)
4016ca35587Sdholland return (NULL);
4026ca35587Sdholland
4036ca35587Sdholland try_tcp:
4046ca35587Sdholland parms.r_prog = prog;
4056ca35587Sdholland parms.r_vers = vers;
4066ca35587Sdholland if (do_tcp)
4076ca35587Sdholland parms.r_netid = "tcp";
4086ca35587Sdholland else
4096ca35587Sdholland parms.r_netid = "udp";
4106ca35587Sdholland parms.r_addr = "";
4116ca35587Sdholland parms.r_owner = "";
4126ca35587Sdholland
4136ca35587Sdholland /*
4146ca35587Sdholland * Use the default timeout.
4156ca35587Sdholland */
4166ca35587Sdholland timo.tv_sec = 25;
4176ca35587Sdholland timo.tv_usec = 0;
4186ca35587Sdholland again:
4196ca35587Sdholland switch (rpcvers) {
4206ca35587Sdholland case RPCBVERS4:
4216ca35587Sdholland case RPCBVERS:
4226ca35587Sdholland /*
4236ca35587Sdholland * Try RPCBIND 4 then 3.
4246ca35587Sdholland */
4256ca35587Sdholland uaddr = NULL;
4266ca35587Sdholland stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR,
4276ca35587Sdholland (xdrproc_t) xdr_rpcb, &parms,
4286ca35587Sdholland (xdrproc_t) xdr_wrapstring, &uaddr, timo);
4296ca35587Sdholland if (stat == RPC_SUCCESS) {
4306ca35587Sdholland /*
4316ca35587Sdholland * We have a reply from the remote RPCBIND - turn it
4326ca35587Sdholland * into an appropriate address and make a new client
4336ca35587Sdholland * that can talk to the remote NLM.
4346ca35587Sdholland *
4356ca35587Sdholland * XXX fixup IPv6 scope ID.
4366ca35587Sdholland */
4376ca35587Sdholland struct netbuf *a;
4386ca35587Sdholland a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr);
4396ca35587Sdholland if (!a) {
4406ca35587Sdholland tryagain = TRUE;
4416ca35587Sdholland } else {
4426ca35587Sdholland tryagain = FALSE;
4436ca35587Sdholland memcpy(&ss, a->buf, a->len);
4446ca35587Sdholland free(a->buf, M_RPC);
4456ca35587Sdholland free(a, M_RPC);
4466ca35587Sdholland xdr_free((xdrproc_t) xdr_wrapstring, &uaddr);
4476ca35587Sdholland }
4486ca35587Sdholland }
4496ca35587Sdholland if (tryagain || stat == RPC_PROGVERSMISMATCH) {
4506ca35587Sdholland if (rpcvers == RPCBVERS4)
4516ca35587Sdholland rpcvers = RPCBVERS;
4526ca35587Sdholland else if (rpcvers == RPCBVERS)
4536ca35587Sdholland rpcvers = PMAPVERS;
4546ca35587Sdholland CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers);
4556ca35587Sdholland goto again;
4566ca35587Sdholland }
4576ca35587Sdholland break;
4586ca35587Sdholland case PMAPVERS:
4596ca35587Sdholland /*
4606ca35587Sdholland * Try portmap.
4616ca35587Sdholland */
4626ca35587Sdholland mapping.pm_prog = parms.r_prog;
4636ca35587Sdholland mapping.pm_vers = parms.r_vers;
4646ca35587Sdholland mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP;
4656ca35587Sdholland mapping.pm_port = 0;
4666ca35587Sdholland
4676ca35587Sdholland stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT,
4686ca35587Sdholland (xdrproc_t) xdr_portmap, &mapping,
4696ca35587Sdholland (xdrproc_t) xdr_u_short, &port, timo);
4706ca35587Sdholland
4716ca35587Sdholland if (stat == RPC_SUCCESS) {
4726ca35587Sdholland switch (ss.ss_family) {
4736ca35587Sdholland case AF_INET:
4746ca35587Sdholland ((struct sockaddr_in *)&ss)->sin_port =
4756ca35587Sdholland htons(port);
4766ca35587Sdholland break;
4776ca35587Sdholland
4786ca35587Sdholland #ifdef INET6
4796ca35587Sdholland case AF_INET6:
4806ca35587Sdholland ((struct sockaddr_in6 *)&ss)->sin6_port =
4816ca35587Sdholland htons(port);
4826ca35587Sdholland break;
4836ca35587Sdholland #endif
4846ca35587Sdholland }
4856ca35587Sdholland }
4866ca35587Sdholland break;
4876ca35587Sdholland default:
4886ca35587Sdholland panic("invalid rpcvers %d", rpcvers);
4896ca35587Sdholland }
4906ca35587Sdholland /*
4916ca35587Sdholland * We may have a positive response from the portmapper, but the NLM
4926ca35587Sdholland * service was not found. Make sure we received a valid port.
4936ca35587Sdholland */
4946ca35587Sdholland switch (ss.ss_family) {
4956ca35587Sdholland case AF_INET:
4966ca35587Sdholland port = ((struct sockaddr_in *)&ss)->sin_port;
4976ca35587Sdholland break;
4986ca35587Sdholland #ifdef INET6
4996ca35587Sdholland case AF_INET6:
5006ca35587Sdholland port = ((struct sockaddr_in6 *)&ss)->sin6_port;
5016ca35587Sdholland break;
5026ca35587Sdholland #endif
5036ca35587Sdholland }
5046ca35587Sdholland if (stat != RPC_SUCCESS || !port) {
5056ca35587Sdholland /*
5066ca35587Sdholland * If we were able to talk to rpcbind or portmap, but the udp
5076ca35587Sdholland * variant wasn't available, ask about tcp.
5086ca35587Sdholland *
5096ca35587Sdholland * XXX - We could also check for a TCP portmapper, but
5106ca35587Sdholland * if the host is running a portmapper at all, we should be able
5116ca35587Sdholland * to hail it over UDP.
5126ca35587Sdholland */
5136ca35587Sdholland if (stat == RPC_SUCCESS && !do_tcp) {
5146ca35587Sdholland do_tcp = TRUE;
5156ca35587Sdholland goto try_tcp;
5166ca35587Sdholland }
5176ca35587Sdholland
5186ca35587Sdholland /* Otherwise, bad news. */
5196ca35587Sdholland NLM_ERR("NLM: failed to contact remote rpcbind, "
5206ca35587Sdholland "stat = %d, port = %d\n", (int) stat, port);
5216ca35587Sdholland CLNT_DESTROY(rpcb);
5226ca35587Sdholland return (NULL);
5236ca35587Sdholland }
5246ca35587Sdholland
5256ca35587Sdholland if (do_tcp) {
5266ca35587Sdholland /*
5276ca35587Sdholland * Destroy the UDP client we used to speak to rpcbind and
5286ca35587Sdholland * recreate as a TCP client.
5296ca35587Sdholland */
5306ca35587Sdholland struct netconfig *nconf = NULL;
5316ca35587Sdholland
5326ca35587Sdholland CLNT_DESTROY(rpcb);
5336ca35587Sdholland
5346ca35587Sdholland switch (ss.ss_family) {
5356ca35587Sdholland case AF_INET:
5366ca35587Sdholland nconf = getnetconfigent("tcp");
5376ca35587Sdholland break;
5386ca35587Sdholland #ifdef INET6
5396ca35587Sdholland case AF_INET6:
5406ca35587Sdholland nconf = getnetconfigent("tcp6");
5416ca35587Sdholland break;
5426ca35587Sdholland #endif
5436ca35587Sdholland }
5446ca35587Sdholland
5456ca35587Sdholland rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss,
5466ca35587Sdholland prog, vers, 0, 0);
5476ca35587Sdholland CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan);
5486ca35587Sdholland rpcb->cl_auth = nlm_auth;
5496ca35587Sdholland
5506ca35587Sdholland } else {
5516ca35587Sdholland /*
5526ca35587Sdholland * Re-use the client we used to speak to rpcbind.
5536ca35587Sdholland */
5546ca35587Sdholland CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss);
5556ca35587Sdholland CLNT_CONTROL(rpcb, CLSET_PROG, &prog);
5566ca35587Sdholland CLNT_CONTROL(rpcb, CLSET_VERS, &vers);
5576ca35587Sdholland CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan);
5586ca35587Sdholland rpcb->cl_auth = nlm_auth;
5596ca35587Sdholland }
5606ca35587Sdholland
5616ca35587Sdholland return (rpcb);
5626ca35587Sdholland }
5636ca35587Sdholland
5646ca35587Sdholland /*
5656ca35587Sdholland * This async callback after when an async lock request has been
5666ca35587Sdholland * granted. We notify the host which initiated the request.
5676ca35587Sdholland */
5686ca35587Sdholland static void
nlm_lock_callback(void * arg,int pending)5696ca35587Sdholland nlm_lock_callback(void *arg, int pending)
5706ca35587Sdholland {
5716ca35587Sdholland struct nlm_async_lock *af = (struct nlm_async_lock *) arg;
5726ca35587Sdholland struct rpc_callextra ext;
5736ca35587Sdholland
5746ca35587Sdholland NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) granted,"
5756ca35587Sdholland " cookie %d:%d\n", af, af->af_host->nh_caller_name,
5766ca35587Sdholland af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie),
5776ca35587Sdholland ng_cookie(&af->af_granted.cookie));
5786ca35587Sdholland
5796ca35587Sdholland /*
5806ca35587Sdholland * Send the results back to the host.
5816ca35587Sdholland *
5826ca35587Sdholland * Note: there is a possible race here with nlm_host_notify
5836ca35587Sdholland * destroying the RPC client. To avoid problems, the first
5846ca35587Sdholland * thing nlm_host_notify does is to cancel pending async lock
5856ca35587Sdholland * requests.
5866ca35587Sdholland */
5876ca35587Sdholland memset(&ext, 0, sizeof(ext));
5886ca35587Sdholland ext.rc_auth = nlm_auth;
5896ca35587Sdholland if (af->af_host->nh_vers == NLM_VERS4) {
5906ca35587Sdholland nlm4_granted_msg_4(&af->af_granted,
5916ca35587Sdholland NULL, af->af_rpc, &ext, nlm_zero_tv);
5926ca35587Sdholland } else {
5936ca35587Sdholland /*
5946ca35587Sdholland * Back-convert to legacy protocol
5956ca35587Sdholland */
5966ca35587Sdholland nlm_testargs granted;
5976ca35587Sdholland granted.cookie = af->af_granted.cookie;
5986ca35587Sdholland granted.exclusive = af->af_granted.exclusive;
5996ca35587Sdholland granted.alock.caller_name =
6006ca35587Sdholland af->af_granted.alock.caller_name;
6016ca35587Sdholland granted.alock.fh = af->af_granted.alock.fh;
6026ca35587Sdholland granted.alock.oh = af->af_granted.alock.oh;
6036ca35587Sdholland granted.alock.svid = af->af_granted.alock.svid;
6046ca35587Sdholland granted.alock.l_offset =
6056ca35587Sdholland af->af_granted.alock.l_offset;
6066ca35587Sdholland granted.alock.l_len =
6076ca35587Sdholland af->af_granted.alock.l_len;
6086ca35587Sdholland
6096ca35587Sdholland nlm_granted_msg_1(&granted,
6106ca35587Sdholland NULL, af->af_rpc, &ext, nlm_zero_tv);
6116ca35587Sdholland }
6126ca35587Sdholland
6136ca35587Sdholland /*
6146ca35587Sdholland * Move this entry to the nh_granted list.
6156ca35587Sdholland */
6166ca35587Sdholland af->af_expiretime = time_uptime + NLM_EXPIRE_TIMEOUT;
6176ca35587Sdholland mtx_lock(&af->af_host->nh_lock);
6186ca35587Sdholland TAILQ_REMOVE(&af->af_host->nh_pending, af, af_link);
6196ca35587Sdholland TAILQ_INSERT_TAIL(&af->af_host->nh_granted, af, af_link);
6206ca35587Sdholland mtx_unlock(&af->af_host->nh_lock);
6216ca35587Sdholland }
6226ca35587Sdholland
6236ca35587Sdholland /*
6246ca35587Sdholland * Free an async lock request. The request must have been removed from
6256ca35587Sdholland * any list.
6266ca35587Sdholland */
6276ca35587Sdholland static void
nlm_free_async_lock(struct nlm_async_lock * af)6286ca35587Sdholland nlm_free_async_lock(struct nlm_async_lock *af)
6296ca35587Sdholland {
6306ca35587Sdholland /*
6316ca35587Sdholland * Free an async lock.
6326ca35587Sdholland */
6336ca35587Sdholland if (af->af_rpc)
6346ca35587Sdholland CLNT_RELEASE(af->af_rpc);
6356ca35587Sdholland xdr_free((xdrproc_t) xdr_nlm4_testargs, &af->af_granted);
6366ca35587Sdholland if (af->af_vp)
6376ca35587Sdholland vrele(af->af_vp);
6386ca35587Sdholland free(af, M_NLM);
6396ca35587Sdholland }
6406ca35587Sdholland
6416ca35587Sdholland /*
6426ca35587Sdholland * Cancel our async request - this must be called with
6436ca35587Sdholland * af->nh_host->nh_lock held. This is slightly complicated by a
6446ca35587Sdholland * potential race with our own callback. If we fail to cancel the
6456ca35587Sdholland * lock, it must already have been granted - we make sure our async
6466ca35587Sdholland * task has completed by calling taskqueue_drain in this case.
6476ca35587Sdholland */
6486ca35587Sdholland static int
nlm_cancel_async_lock(struct nlm_async_lock * af)6496ca35587Sdholland nlm_cancel_async_lock(struct nlm_async_lock *af)
6506ca35587Sdholland {
6516ca35587Sdholland struct nlm_host *host = af->af_host;
6526ca35587Sdholland int error;
6536ca35587Sdholland
6546ca35587Sdholland mtx_assert(&host->nh_lock, MA_OWNED);
6556ca35587Sdholland
6566ca35587Sdholland mtx_unlock(&host->nh_lock);
6576ca35587Sdholland
6586ca35587Sdholland error = VOP_ADVLOCKASYNC(af->af_vp, NULL, F_CANCEL, &af->af_fl,
6596ca35587Sdholland F_REMOTE, NULL, &af->af_cookie);
6606ca35587Sdholland
6616ca35587Sdholland if (error) {
6626ca35587Sdholland /*
6636ca35587Sdholland * We failed to cancel - make sure our callback has
6646ca35587Sdholland * completed before we continue.
6656ca35587Sdholland */
6666ca35587Sdholland taskqueue_drain(taskqueue_thread, &af->af_task);
6676ca35587Sdholland }
6686ca35587Sdholland
6696ca35587Sdholland mtx_lock(&host->nh_lock);
6706ca35587Sdholland
6716ca35587Sdholland if (!error) {
6726ca35587Sdholland NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) "
6736ca35587Sdholland "cancelled\n", af, host->nh_caller_name, host->nh_sysid);
6746ca35587Sdholland
6756ca35587Sdholland /*
6766ca35587Sdholland * Remove from the nh_pending list and free now that
6776ca35587Sdholland * we are safe from the callback.
6786ca35587Sdholland */
6796ca35587Sdholland TAILQ_REMOVE(&host->nh_pending, af, af_link);
6806ca35587Sdholland mtx_unlock(&host->nh_lock);
6816ca35587Sdholland nlm_free_async_lock(af);
6826ca35587Sdholland mtx_lock(&host->nh_lock);
6836ca35587Sdholland }
6846ca35587Sdholland
6856ca35587Sdholland return (error);
6866ca35587Sdholland }
6876ca35587Sdholland
6886ca35587Sdholland static void
nlm_check_expired_locks(struct nlm_host * host)6896ca35587Sdholland nlm_check_expired_locks(struct nlm_host *host)
6906ca35587Sdholland {
6916ca35587Sdholland struct nlm_async_lock *af;
6926ca35587Sdholland time_t uptime = time_uptime;
6936ca35587Sdholland
6946ca35587Sdholland mtx_lock(&host->nh_lock);
6956ca35587Sdholland while ((af = TAILQ_FIRST(&host->nh_granted)) != NULL
6966ca35587Sdholland && uptime >= af->af_expiretime) {
6976ca35587Sdholland NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) expired,"
6986ca35587Sdholland " cookie %d:%d\n", af, af->af_host->nh_caller_name,
6996ca35587Sdholland af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie),
7006ca35587Sdholland ng_cookie(&af->af_granted.cookie));
7016ca35587Sdholland TAILQ_REMOVE(&host->nh_granted, af, af_link);
7026ca35587Sdholland mtx_unlock(&host->nh_lock);
7036ca35587Sdholland nlm_free_async_lock(af);
7046ca35587Sdholland mtx_lock(&host->nh_lock);
7056ca35587Sdholland }
7066ca35587Sdholland while ((af = TAILQ_FIRST(&host->nh_finished)) != NULL) {
7076ca35587Sdholland TAILQ_REMOVE(&host->nh_finished, af, af_link);
7086ca35587Sdholland mtx_unlock(&host->nh_lock);
7096ca35587Sdholland nlm_free_async_lock(af);
7106ca35587Sdholland mtx_lock(&host->nh_lock);
7116ca35587Sdholland }
7126ca35587Sdholland mtx_unlock(&host->nh_lock);
7136ca35587Sdholland }
7146ca35587Sdholland
7156ca35587Sdholland /*
7166ca35587Sdholland * Free resources used by a host. This is called after the reference
7176ca35587Sdholland * count has reached zero so it doesn't need to worry about locks.
7186ca35587Sdholland */
7196ca35587Sdholland static void
nlm_host_destroy(struct nlm_host * host)7206ca35587Sdholland nlm_host_destroy(struct nlm_host *host)
7216ca35587Sdholland {
7226ca35587Sdholland
7236ca35587Sdholland mtx_lock(&nlm_global_lock);
7246ca35587Sdholland TAILQ_REMOVE(&nlm_hosts, host, nh_link);
7256ca35587Sdholland mtx_unlock(&nlm_global_lock);
7266ca35587Sdholland
7276ca35587Sdholland if (host->nh_srvrpc.nr_client)
7286ca35587Sdholland CLNT_RELEASE(host->nh_srvrpc.nr_client);
7296ca35587Sdholland if (host->nh_clntrpc.nr_client)
7306ca35587Sdholland CLNT_RELEASE(host->nh_clntrpc.nr_client);
7316ca35587Sdholland mtx_destroy(&host->nh_lock);
7326ca35587Sdholland sysctl_ctx_free(&host->nh_sysctl);
7336ca35587Sdholland free(host, M_NLM);
7346ca35587Sdholland }
7356ca35587Sdholland
7366ca35587Sdholland /*
7376ca35587Sdholland * Thread start callback for client lock recovery
7386ca35587Sdholland */
7396ca35587Sdholland static void
nlm_client_recovery_start(void * arg)7406ca35587Sdholland nlm_client_recovery_start(void *arg)
7416ca35587Sdholland {
7426ca35587Sdholland struct nlm_host *host = (struct nlm_host *) arg;
7436ca35587Sdholland
7446ca35587Sdholland NLM_DEBUG(1, "NLM: client lock recovery for %s started\n",
7456ca35587Sdholland host->nh_caller_name);
7466ca35587Sdholland
7476ca35587Sdholland nlm_client_recovery(host);
7486ca35587Sdholland
7496ca35587Sdholland NLM_DEBUG(1, "NLM: client lock recovery for %s completed\n",
7506ca35587Sdholland host->nh_caller_name);
7516ca35587Sdholland
7526ca35587Sdholland host->nh_monstate = NLM_MONITORED;
7536ca35587Sdholland nlm_host_release(host);
7546ca35587Sdholland
7556ca35587Sdholland kthread_exit();
7566ca35587Sdholland }
7576ca35587Sdholland
7586ca35587Sdholland /*
7596ca35587Sdholland * This is called when we receive a host state change notification. We
7606ca35587Sdholland * unlock any active locks owned by the host. When rpc.lockd is
7616ca35587Sdholland * shutting down, this function is called with newstate set to zero
7626ca35587Sdholland * which allows us to cancel any pending async locks and clear the
7636ca35587Sdholland * locking state.
7646ca35587Sdholland */
7656ca35587Sdholland static void
nlm_host_notify(struct nlm_host * host,int newstate)7666ca35587Sdholland nlm_host_notify(struct nlm_host *host, int newstate)
7676ca35587Sdholland {
7686ca35587Sdholland struct nlm_async_lock *af;
7696ca35587Sdholland
7706ca35587Sdholland if (newstate) {
7716ca35587Sdholland NLM_DEBUG(1, "NLM: host %s (sysid %d) rebooted, new "
7726ca35587Sdholland "state is %d\n", host->nh_caller_name,
7736ca35587Sdholland host->nh_sysid, newstate);
7746ca35587Sdholland }
7756ca35587Sdholland
7766ca35587Sdholland /*
7776ca35587Sdholland * Cancel any pending async locks for this host.
7786ca35587Sdholland */
7796ca35587Sdholland mtx_lock(&host->nh_lock);
7806ca35587Sdholland while ((af = TAILQ_FIRST(&host->nh_pending)) != NULL) {
7816ca35587Sdholland /*
7826ca35587Sdholland * nlm_cancel_async_lock will remove the entry from
7836ca35587Sdholland * nh_pending and free it.
7846ca35587Sdholland */
7856ca35587Sdholland nlm_cancel_async_lock(af);
7866ca35587Sdholland }
7876ca35587Sdholland mtx_unlock(&host->nh_lock);
7886ca35587Sdholland nlm_check_expired_locks(host);
7896ca35587Sdholland
7906ca35587Sdholland /*
7916ca35587Sdholland * The host just rebooted - trash its locks.
7926ca35587Sdholland */
7936ca35587Sdholland lf_clearremotesys(host->nh_sysid);
7946ca35587Sdholland host->nh_state = newstate;
7956ca35587Sdholland
7966ca35587Sdholland /*
7976ca35587Sdholland * If we have any remote locks for this host (i.e. it
7986ca35587Sdholland * represents a remote NFS server that our local NFS client
7996ca35587Sdholland * has locks for), start a recovery thread.
8006ca35587Sdholland */
8016ca35587Sdholland if (newstate != 0
8026ca35587Sdholland && host->nh_monstate != NLM_RECOVERING
8036ca35587Sdholland && lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid) > 0) {
8046ca35587Sdholland struct thread *td;
8056ca35587Sdholland host->nh_monstate = NLM_RECOVERING;
8066ca35587Sdholland refcount_acquire(&host->nh_refs);
8076ca35587Sdholland kthread_add(nlm_client_recovery_start, host, curproc, &td, 0, 0,
8086ca35587Sdholland "NFS lock recovery for %s", host->nh_caller_name);
8096ca35587Sdholland }
8106ca35587Sdholland }
8116ca35587Sdholland
8126ca35587Sdholland /*
8136ca35587Sdholland * Sysctl handler to count the number of locks for a sysid.
8146ca35587Sdholland */
8156ca35587Sdholland static int
nlm_host_lock_count_sysctl(SYSCTL_HANDLER_ARGS)8166ca35587Sdholland nlm_host_lock_count_sysctl(SYSCTL_HANDLER_ARGS)
8176ca35587Sdholland {
8186ca35587Sdholland struct nlm_host *host;
8196ca35587Sdholland int count;
8206ca35587Sdholland
8216ca35587Sdholland host = oidp->oid_arg1;
8226ca35587Sdholland count = lf_countlocks(host->nh_sysid);
8236ca35587Sdholland return sysctl_handle_int(oidp, &count, 0, req);
8246ca35587Sdholland }
8256ca35587Sdholland
8266ca35587Sdholland /*
8276ca35587Sdholland * Sysctl handler to count the number of client locks for a sysid.
8286ca35587Sdholland */
8296ca35587Sdholland static int
nlm_host_client_lock_count_sysctl(SYSCTL_HANDLER_ARGS)8306ca35587Sdholland nlm_host_client_lock_count_sysctl(SYSCTL_HANDLER_ARGS)
8316ca35587Sdholland {
8326ca35587Sdholland struct nlm_host *host;
8336ca35587Sdholland int count;
8346ca35587Sdholland
8356ca35587Sdholland host = oidp->oid_arg1;
8366ca35587Sdholland count = lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid);
8376ca35587Sdholland return sysctl_handle_int(oidp, &count, 0, req);
8386ca35587Sdholland }
8396ca35587Sdholland
8406ca35587Sdholland /*
8416ca35587Sdholland * Create a new NLM host.
8426ca35587Sdholland */
8436ca35587Sdholland static struct nlm_host *
nlm_create_host(const char * caller_name)8446ca35587Sdholland nlm_create_host(const char* caller_name)
8456ca35587Sdholland {
8466ca35587Sdholland struct nlm_host *host;
8476ca35587Sdholland struct sysctl_oid *oid;
8486ca35587Sdholland
8496ca35587Sdholland mtx_assert(&nlm_global_lock, MA_OWNED);
8506ca35587Sdholland
8516ca35587Sdholland NLM_DEBUG(1, "NLM: new host %s (sysid %d)\n",
8526ca35587Sdholland caller_name, nlm_next_sysid);
8536ca35587Sdholland host = malloc(sizeof(struct nlm_host), M_NLM, M_NOWAIT|M_ZERO);
8546ca35587Sdholland if (!host)
8556ca35587Sdholland return (NULL);
8566ca35587Sdholland mtx_init(&host->nh_lock, "nh_lock", NULL, MTX_DEF);
8576ca35587Sdholland host->nh_refs = 1;
8586ca35587Sdholland strlcpy(host->nh_caller_name, caller_name, MAXNAMELEN);
8596ca35587Sdholland host->nh_sysid = nlm_next_sysid++;
8606ca35587Sdholland snprintf(host->nh_sysid_string, sizeof(host->nh_sysid_string),
8616ca35587Sdholland "%d", host->nh_sysid);
8626ca35587Sdholland host->nh_vers = 0;
8636ca35587Sdholland host->nh_state = 0;
8646ca35587Sdholland host->nh_monstate = NLM_UNMONITORED;
8656ca35587Sdholland host->nh_grantcookie = 1;
8666ca35587Sdholland TAILQ_INIT(&host->nh_pending);
8676ca35587Sdholland TAILQ_INIT(&host->nh_granted);
8686ca35587Sdholland TAILQ_INIT(&host->nh_finished);
8696ca35587Sdholland TAILQ_INSERT_TAIL(&nlm_hosts, host, nh_link);
8706ca35587Sdholland
8716ca35587Sdholland mtx_unlock(&nlm_global_lock);
8726ca35587Sdholland
8736ca35587Sdholland sysctl_ctx_init(&host->nh_sysctl);
8746ca35587Sdholland oid = SYSCTL_ADD_NODE(&host->nh_sysctl,
8756ca35587Sdholland SYSCTL_STATIC_CHILDREN(_vfs_nlm_sysid),
8766ca35587Sdholland OID_AUTO, host->nh_sysid_string, CTLFLAG_RD, NULL, "");
8776ca35587Sdholland SYSCTL_ADD_STRING(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
8786ca35587Sdholland "hostname", CTLFLAG_RD, host->nh_caller_name, 0, "");
8796ca35587Sdholland SYSCTL_ADD_UINT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
8806ca35587Sdholland "version", CTLFLAG_RD, &host->nh_vers, 0, "");
8816ca35587Sdholland SYSCTL_ADD_UINT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
8826ca35587Sdholland "monitored", CTLFLAG_RD, &host->nh_monstate, 0, "");
8836ca35587Sdholland SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
8846ca35587Sdholland "lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0,
8856ca35587Sdholland nlm_host_lock_count_sysctl, "I", "");
8866ca35587Sdholland SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
8876ca35587Sdholland "client_lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0,
8886ca35587Sdholland nlm_host_client_lock_count_sysctl, "I", "");
8896ca35587Sdholland
8906ca35587Sdholland mtx_lock(&nlm_global_lock);
8916ca35587Sdholland
8926ca35587Sdholland return (host);
8936ca35587Sdholland }
8946ca35587Sdholland
8956ca35587Sdholland /*
8966ca35587Sdholland * Acquire the next sysid for remote locks not handled by the NLM.
8976ca35587Sdholland */
8986ca35587Sdholland uint32_t
nlm_acquire_next_sysid(void)8996ca35587Sdholland nlm_acquire_next_sysid(void)
9006ca35587Sdholland {
9016ca35587Sdholland uint32_t next_sysid;
9026ca35587Sdholland
9036ca35587Sdholland mtx_lock(&nlm_global_lock);
9046ca35587Sdholland next_sysid = nlm_next_sysid++;
9056ca35587Sdholland mtx_unlock(&nlm_global_lock);
9066ca35587Sdholland return (next_sysid);
9076ca35587Sdholland }
9086ca35587Sdholland
9096ca35587Sdholland /*
9106ca35587Sdholland * Return non-zero if the address parts of the two sockaddrs are the
9116ca35587Sdholland * same.
9126ca35587Sdholland */
9136ca35587Sdholland static int
nlm_compare_addr(const struct sockaddr * a,const struct sockaddr * b)9146ca35587Sdholland nlm_compare_addr(const struct sockaddr *a, const struct sockaddr *b)
9156ca35587Sdholland {
9166ca35587Sdholland const struct sockaddr_in *a4, *b4;
9176ca35587Sdholland #ifdef INET6
9186ca35587Sdholland const struct sockaddr_in6 *a6, *b6;
9196ca35587Sdholland #endif
9206ca35587Sdholland
9216ca35587Sdholland if (a->sa_family != b->sa_family)
9226ca35587Sdholland return (FALSE);
9236ca35587Sdholland
9246ca35587Sdholland switch (a->sa_family) {
9256ca35587Sdholland case AF_INET:
9266ca35587Sdholland a4 = (const struct sockaddr_in *) a;
9276ca35587Sdholland b4 = (const struct sockaddr_in *) b;
9286ca35587Sdholland return !memcmp(&a4->sin_addr, &b4->sin_addr,
9296ca35587Sdholland sizeof(a4->sin_addr));
9306ca35587Sdholland #ifdef INET6
9316ca35587Sdholland case AF_INET6:
9326ca35587Sdholland a6 = (const struct sockaddr_in6 *) a;
9336ca35587Sdholland b6 = (const struct sockaddr_in6 *) b;
9346ca35587Sdholland return !memcmp(&a6->sin6_addr, &b6->sin6_addr,
9356ca35587Sdholland sizeof(a6->sin6_addr));
9366ca35587Sdholland #endif
9376ca35587Sdholland }
9386ca35587Sdholland
9396ca35587Sdholland return (0);
9406ca35587Sdholland }
9416ca35587Sdholland
9426ca35587Sdholland /*
9436ca35587Sdholland * Check for idle hosts and stop monitoring them. We could also free
9446ca35587Sdholland * the host structure here, possibly after a larger timeout but that
9456ca35587Sdholland * would require some care to avoid races with
9466ca35587Sdholland * e.g. nlm_host_lock_count_sysctl.
9476ca35587Sdholland */
9486ca35587Sdholland static void
nlm_check_idle(void)9496ca35587Sdholland nlm_check_idle(void)
9506ca35587Sdholland {
9516ca35587Sdholland struct nlm_host *host;
9526ca35587Sdholland
9536ca35587Sdholland mtx_assert(&nlm_global_lock, MA_OWNED);
9546ca35587Sdholland
9556ca35587Sdholland if (time_uptime <= nlm_next_idle_check)
9566ca35587Sdholland return;
9576ca35587Sdholland
9586ca35587Sdholland nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD;
9596ca35587Sdholland
9606ca35587Sdholland TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
9616ca35587Sdholland if (host->nh_monstate == NLM_MONITORED
9626ca35587Sdholland && time_uptime > host->nh_idle_timeout) {
9636ca35587Sdholland mtx_unlock(&nlm_global_lock);
9646ca35587Sdholland if (lf_countlocks(host->nh_sysid) > 0
9656ca35587Sdholland || lf_countlocks(NLM_SYSID_CLIENT
9666ca35587Sdholland + host->nh_sysid)) {
9676ca35587Sdholland host->nh_idle_timeout =
9686ca35587Sdholland time_uptime + NLM_IDLE_TIMEOUT;
9696ca35587Sdholland mtx_lock(&nlm_global_lock);
9706ca35587Sdholland continue;
9716ca35587Sdholland }
9726ca35587Sdholland nlm_host_unmonitor(host);
9736ca35587Sdholland mtx_lock(&nlm_global_lock);
9746ca35587Sdholland }
9756ca35587Sdholland }
9766ca35587Sdholland }
9776ca35587Sdholland
9786ca35587Sdholland /*
9796ca35587Sdholland * Search for an existing NLM host that matches the given name
9806ca35587Sdholland * (typically the caller_name element of an nlm4_lock). If none is
9816ca35587Sdholland * found, create a new host. If 'addr' is non-NULL, record the remote
9826ca35587Sdholland * address of the host so that we can call it back for async
9836ca35587Sdholland * responses. If 'vers' is greater than zero then record the NLM
9846ca35587Sdholland * program version to use to communicate with this client.
9856ca35587Sdholland */
9866ca35587Sdholland struct nlm_host *
nlm_find_host_by_name(const char * name,const struct sockaddr * addr,rpcvers_t vers)9876ca35587Sdholland nlm_find_host_by_name(const char *name, const struct sockaddr *addr,
9886ca35587Sdholland rpcvers_t vers)
9896ca35587Sdholland {
9906ca35587Sdholland struct nlm_host *host;
9916ca35587Sdholland
9926ca35587Sdholland mtx_lock(&nlm_global_lock);
9936ca35587Sdholland
9946ca35587Sdholland /*
9956ca35587Sdholland * The remote host is determined by caller_name.
9966ca35587Sdholland */
9976ca35587Sdholland TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
9986ca35587Sdholland if (!strcmp(host->nh_caller_name, name))
9996ca35587Sdholland break;
10006ca35587Sdholland }
10016ca35587Sdholland
10026ca35587Sdholland if (!host) {
10036ca35587Sdholland host = nlm_create_host(name);
10046ca35587Sdholland if (!host) {
10056ca35587Sdholland mtx_unlock(&nlm_global_lock);
10066ca35587Sdholland return (NULL);
10076ca35587Sdholland }
10086ca35587Sdholland }
10096ca35587Sdholland refcount_acquire(&host->nh_refs);
10106ca35587Sdholland
10116ca35587Sdholland host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT;
10126ca35587Sdholland
10136ca35587Sdholland /*
10146ca35587Sdholland * If we have an address for the host, record it so that we
10156ca35587Sdholland * can send async replies etc.
10166ca35587Sdholland */
10176ca35587Sdholland if (addr) {
10186ca35587Sdholland
10196ca35587Sdholland KASSERT(addr->sa_len < sizeof(struct sockaddr_storage),
10206ca35587Sdholland ("Strange remote transport address length"));
10216ca35587Sdholland
10226ca35587Sdholland /*
10236ca35587Sdholland * If we have seen an address before and we currently
10246ca35587Sdholland * have an RPC client handle, make sure the address is
10256ca35587Sdholland * the same, otherwise discard the client handle.
10266ca35587Sdholland */
10276ca35587Sdholland if (host->nh_addr.ss_len && host->nh_srvrpc.nr_client) {
10286ca35587Sdholland if (!nlm_compare_addr(
10296ca35587Sdholland (struct sockaddr *) &host->nh_addr,
10306ca35587Sdholland addr)
10316ca35587Sdholland || host->nh_vers != vers) {
10326ca35587Sdholland CLIENT *client;
10336ca35587Sdholland mtx_lock(&host->nh_lock);
10346ca35587Sdholland client = host->nh_srvrpc.nr_client;
10356ca35587Sdholland host->nh_srvrpc.nr_client = NULL;
10366ca35587Sdholland mtx_unlock(&host->nh_lock);
10376ca35587Sdholland if (client) {
10386ca35587Sdholland CLNT_RELEASE(client);
10396ca35587Sdholland }
10406ca35587Sdholland }
10416ca35587Sdholland }
10426ca35587Sdholland memcpy(&host->nh_addr, addr, addr->sa_len);
10436ca35587Sdholland host->nh_vers = vers;
10446ca35587Sdholland }
10456ca35587Sdholland
10466ca35587Sdholland nlm_check_idle();
10476ca35587Sdholland
10486ca35587Sdholland mtx_unlock(&nlm_global_lock);
10496ca35587Sdholland
10506ca35587Sdholland return (host);
10516ca35587Sdholland }
10526ca35587Sdholland
10536ca35587Sdholland /*
10546ca35587Sdholland * Search for an existing NLM host that matches the given remote
10556ca35587Sdholland * address. If none is found, create a new host with the requested
10566ca35587Sdholland * address and remember 'vers' as the NLM protocol version to use for
10576ca35587Sdholland * that host.
10586ca35587Sdholland */
10596ca35587Sdholland struct nlm_host *
nlm_find_host_by_addr(const struct sockaddr * addr,int vers)10606ca35587Sdholland nlm_find_host_by_addr(const struct sockaddr *addr, int vers)
10616ca35587Sdholland {
10626ca35587Sdholland /*
10636ca35587Sdholland * Fake up a name using inet_ntop. This buffer is
10646ca35587Sdholland * large enough for an IPv6 address.
10656ca35587Sdholland */
10666ca35587Sdholland char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
10676ca35587Sdholland struct nlm_host *host;
10686ca35587Sdholland
10696ca35587Sdholland switch (addr->sa_family) {
10706ca35587Sdholland case AF_INET:
10716ca35587Sdholland inet_ntop(AF_INET,
10726ca35587Sdholland &((const struct sockaddr_in *) addr)->sin_addr,
10736ca35587Sdholland tmp, sizeof tmp);
10746ca35587Sdholland break;
10756ca35587Sdholland #ifdef INET6
10766ca35587Sdholland case AF_INET6:
10776ca35587Sdholland inet_ntop(AF_INET6,
10786ca35587Sdholland &((const struct sockaddr_in6 *) addr)->sin6_addr,
10796ca35587Sdholland tmp, sizeof tmp);
10806ca35587Sdholland break;
10816ca35587Sdholland #endif
10826ca35587Sdholland default:
10832d39560cSpgoyette strlcpy(tmp, "<unknown>", sizeof(tmp));
10846ca35587Sdholland }
10856ca35587Sdholland
10866ca35587Sdholland
10876ca35587Sdholland mtx_lock(&nlm_global_lock);
10886ca35587Sdholland
10896ca35587Sdholland /*
10906ca35587Sdholland * The remote host is determined by caller_name.
10916ca35587Sdholland */
10926ca35587Sdholland TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
10936ca35587Sdholland if (nlm_compare_addr(addr,
10946ca35587Sdholland (const struct sockaddr *) &host->nh_addr))
10956ca35587Sdholland break;
10966ca35587Sdholland }
10976ca35587Sdholland
10986ca35587Sdholland if (!host) {
10996ca35587Sdholland host = nlm_create_host(tmp);
11006ca35587Sdholland if (!host) {
11016ca35587Sdholland mtx_unlock(&nlm_global_lock);
11026ca35587Sdholland return (NULL);
11036ca35587Sdholland }
11046ca35587Sdholland memcpy(&host->nh_addr, addr, addr->sa_len);
11056ca35587Sdholland host->nh_vers = vers;
11066ca35587Sdholland }
11076ca35587Sdholland refcount_acquire(&host->nh_refs);
11086ca35587Sdholland
11096ca35587Sdholland host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT;
11106ca35587Sdholland
11116ca35587Sdholland nlm_check_idle();
11126ca35587Sdholland
11136ca35587Sdholland mtx_unlock(&nlm_global_lock);
11146ca35587Sdholland
11156ca35587Sdholland return (host);
11166ca35587Sdholland }
11176ca35587Sdholland
11186ca35587Sdholland /*
11196ca35587Sdholland * Find the NLM host that matches the value of 'sysid'. If none
11206ca35587Sdholland * exists, return NULL.
11216ca35587Sdholland */
11226ca35587Sdholland static struct nlm_host *
nlm_find_host_by_sysid(int sysid)11236ca35587Sdholland nlm_find_host_by_sysid(int sysid)
11246ca35587Sdholland {
11256ca35587Sdholland struct nlm_host *host;
11266ca35587Sdholland
11276ca35587Sdholland TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
11286ca35587Sdholland if (host->nh_sysid == sysid) {
11296ca35587Sdholland refcount_acquire(&host->nh_refs);
11306ca35587Sdholland return (host);
11316ca35587Sdholland }
11326ca35587Sdholland }
11336ca35587Sdholland
11346ca35587Sdholland return (NULL);
11356ca35587Sdholland }
11366ca35587Sdholland
nlm_host_release(struct nlm_host * host)11376ca35587Sdholland void nlm_host_release(struct nlm_host *host)
11386ca35587Sdholland {
11396ca35587Sdholland if (refcount_release(&host->nh_refs)) {
11406ca35587Sdholland /*
11416ca35587Sdholland * Free the host
11426ca35587Sdholland */
11436ca35587Sdholland nlm_host_destroy(host);
11446ca35587Sdholland }
11456ca35587Sdholland }
11466ca35587Sdholland
11476ca35587Sdholland /*
11486ca35587Sdholland * Unregister this NLM host with the local NSM due to idleness.
11496ca35587Sdholland */
11506ca35587Sdholland static void
nlm_host_unmonitor(struct nlm_host * host)11516ca35587Sdholland nlm_host_unmonitor(struct nlm_host *host)
11526ca35587Sdholland {
11536ca35587Sdholland mon_id smmonid;
11546ca35587Sdholland sm_stat_res smstat;
11556ca35587Sdholland struct timeval timo;
11566ca35587Sdholland enum clnt_stat stat;
11576ca35587Sdholland
11586ca35587Sdholland NLM_DEBUG(1, "NLM: unmonitoring %s (sysid %d)\n",
11596ca35587Sdholland host->nh_caller_name, host->nh_sysid);
11606ca35587Sdholland
11616ca35587Sdholland /*
11626ca35587Sdholland * We put our assigned system ID value in the priv field to
11636ca35587Sdholland * make it simpler to find the host if we are notified of a
11646ca35587Sdholland * host restart.
11656ca35587Sdholland */
11666ca35587Sdholland smmonid.mon_name = host->nh_caller_name;
11676ca35587Sdholland smmonid.my_id.my_name = "localhost";
11686ca35587Sdholland smmonid.my_id.my_prog = NLM_PROG;
11696ca35587Sdholland smmonid.my_id.my_vers = NLM_SM;
11706ca35587Sdholland smmonid.my_id.my_proc = NLM_SM_NOTIFY;
11716ca35587Sdholland
11726ca35587Sdholland timo.tv_sec = 25;
11736ca35587Sdholland timo.tv_usec = 0;
11746ca35587Sdholland stat = CLNT_CALL(nlm_nsm, SM_UNMON,
11756ca35587Sdholland (xdrproc_t) xdr_mon, &smmonid,
11766ca35587Sdholland (xdrproc_t) xdr_sm_stat, &smstat, timo);
11776ca35587Sdholland
11786ca35587Sdholland if (stat != RPC_SUCCESS) {
11796ca35587Sdholland NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat);
11806ca35587Sdholland return;
11816ca35587Sdholland }
11826ca35587Sdholland if (smstat.res_stat == stat_fail) {
11836ca35587Sdholland NLM_ERR("Local NSM refuses to unmonitor %s\n",
11846ca35587Sdholland host->nh_caller_name);
11856ca35587Sdholland return;
11866ca35587Sdholland }
11876ca35587Sdholland
11886ca35587Sdholland host->nh_monstate = NLM_UNMONITORED;
11896ca35587Sdholland }
11906ca35587Sdholland
11916ca35587Sdholland /*
11926ca35587Sdholland * Register this NLM host with the local NSM so that we can be
11936ca35587Sdholland * notified if it reboots.
11946ca35587Sdholland */
11956ca35587Sdholland void
nlm_host_monitor(struct nlm_host * host,int state)11966ca35587Sdholland nlm_host_monitor(struct nlm_host *host, int state)
11976ca35587Sdholland {
11986ca35587Sdholland mon smmon;
11996ca35587Sdholland sm_stat_res smstat;
12006ca35587Sdholland struct timeval timo;
12016ca35587Sdholland enum clnt_stat stat;
12026ca35587Sdholland
12036ca35587Sdholland if (state && !host->nh_state) {
12046ca35587Sdholland /*
12056ca35587Sdholland * This is the first time we have seen an NSM state
12066ca35587Sdholland * value for this host. We record it here to help
12076ca35587Sdholland * detect host reboots.
12086ca35587Sdholland */
12096ca35587Sdholland host->nh_state = state;
12106ca35587Sdholland NLM_DEBUG(1, "NLM: host %s (sysid %d) has NSM state %d\n",
12116ca35587Sdholland host->nh_caller_name, host->nh_sysid, state);
12126ca35587Sdholland }
12136ca35587Sdholland
12146ca35587Sdholland mtx_lock(&host->nh_lock);
12156ca35587Sdholland if (host->nh_monstate != NLM_UNMONITORED) {
12166ca35587Sdholland mtx_unlock(&host->nh_lock);
12176ca35587Sdholland return;
12186ca35587Sdholland }
12196ca35587Sdholland host->nh_monstate = NLM_MONITORED;
12206ca35587Sdholland mtx_unlock(&host->nh_lock);
12216ca35587Sdholland
12226ca35587Sdholland NLM_DEBUG(1, "NLM: monitoring %s (sysid %d)\n",
12236ca35587Sdholland host->nh_caller_name, host->nh_sysid);
12246ca35587Sdholland
12256ca35587Sdholland /*
12266ca35587Sdholland * We put our assigned system ID value in the priv field to
12276ca35587Sdholland * make it simpler to find the host if we are notified of a
12286ca35587Sdholland * host restart.
12296ca35587Sdholland */
12306ca35587Sdholland smmon.mon_id.mon_name = host->nh_caller_name;
12316ca35587Sdholland smmon.mon_id.my_id.my_name = "localhost";
12326ca35587Sdholland smmon.mon_id.my_id.my_prog = NLM_PROG;
12336ca35587Sdholland smmon.mon_id.my_id.my_vers = NLM_SM;
12346ca35587Sdholland smmon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
12356ca35587Sdholland memcpy(smmon.priv, &host->nh_sysid, sizeof(host->nh_sysid));
12366ca35587Sdholland
12376ca35587Sdholland timo.tv_sec = 25;
12386ca35587Sdholland timo.tv_usec = 0;
12396ca35587Sdholland stat = CLNT_CALL(nlm_nsm, SM_MON,
12406ca35587Sdholland (xdrproc_t) xdr_mon, &smmon,
12416ca35587Sdholland (xdrproc_t) xdr_sm_stat, &smstat, timo);
12426ca35587Sdholland
12436ca35587Sdholland if (stat != RPC_SUCCESS) {
12446ca35587Sdholland NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat);
12456ca35587Sdholland return;
12466ca35587Sdholland }
12476ca35587Sdholland if (smstat.res_stat == stat_fail) {
12486ca35587Sdholland NLM_ERR("Local NSM refuses to monitor %s\n",
12496ca35587Sdholland host->nh_caller_name);
12506ca35587Sdholland mtx_lock(&host->nh_lock);
12516ca35587Sdholland host->nh_monstate = NLM_MONITOR_FAILED;
12526ca35587Sdholland mtx_unlock(&host->nh_lock);
12536ca35587Sdholland return;
12546ca35587Sdholland }
12556ca35587Sdholland
12566ca35587Sdholland host->nh_monstate = NLM_MONITORED;
12576ca35587Sdholland }
12586ca35587Sdholland
12596ca35587Sdholland /*
12606ca35587Sdholland * Return an RPC client handle that can be used to talk to the NLM
12616ca35587Sdholland * running on the given host.
12626ca35587Sdholland */
12636ca35587Sdholland CLIENT *
nlm_host_get_rpc(struct nlm_host * host,bool_t isserver)12646ca35587Sdholland nlm_host_get_rpc(struct nlm_host *host, bool_t isserver)
12656ca35587Sdholland {
12666ca35587Sdholland struct nlm_rpc *rpc;
12676ca35587Sdholland CLIENT *client;
12686ca35587Sdholland
12696ca35587Sdholland mtx_lock(&host->nh_lock);
12706ca35587Sdholland
12716ca35587Sdholland if (isserver)
12726ca35587Sdholland rpc = &host->nh_srvrpc;
12736ca35587Sdholland else
12746ca35587Sdholland rpc = &host->nh_clntrpc;
12756ca35587Sdholland
12766ca35587Sdholland /*
12776ca35587Sdholland * We can't hold onto RPC handles for too long - the async
12786ca35587Sdholland * call/reply protocol used by some NLM clients makes it hard
12796ca35587Sdholland * to tell when they change port numbers (e.g. after a
12806ca35587Sdholland * reboot). Note that if a client reboots while it isn't
12816ca35587Sdholland * holding any locks, it won't bother to notify us. We
12826ca35587Sdholland * expire the RPC handles after two minutes.
12836ca35587Sdholland */
12846ca35587Sdholland if (rpc->nr_client && time_uptime > rpc->nr_create_time + 2*60) {
12856ca35587Sdholland client = rpc->nr_client;
12866ca35587Sdholland rpc->nr_client = NULL;
12876ca35587Sdholland mtx_unlock(&host->nh_lock);
12886ca35587Sdholland CLNT_RELEASE(client);
12896ca35587Sdholland mtx_lock(&host->nh_lock);
12906ca35587Sdholland }
12916ca35587Sdholland
12926ca35587Sdholland if (!rpc->nr_client) {
12936ca35587Sdholland mtx_unlock(&host->nh_lock);
12946ca35587Sdholland client = nlm_get_rpc((struct sockaddr *)&host->nh_addr,
12956ca35587Sdholland NLM_PROG, host->nh_vers);
12966ca35587Sdholland mtx_lock(&host->nh_lock);
12976ca35587Sdholland
12986ca35587Sdholland if (client) {
12996ca35587Sdholland if (rpc->nr_client) {
13006ca35587Sdholland mtx_unlock(&host->nh_lock);
13016ca35587Sdholland CLNT_DESTROY(client);
13026ca35587Sdholland mtx_lock(&host->nh_lock);
13036ca35587Sdholland } else {
13046ca35587Sdholland rpc->nr_client = client;
13056ca35587Sdholland rpc->nr_create_time = time_uptime;
13066ca35587Sdholland }
13076ca35587Sdholland }
13086ca35587Sdholland }
13096ca35587Sdholland
13106ca35587Sdholland client = rpc->nr_client;
13116ca35587Sdholland if (client)
13126ca35587Sdholland CLNT_ACQUIRE(client);
13136ca35587Sdholland mtx_unlock(&host->nh_lock);
13146ca35587Sdholland
13156ca35587Sdholland return (client);
13166ca35587Sdholland
13176ca35587Sdholland }
13186ca35587Sdholland
nlm_host_get_sysid(struct nlm_host * host)13196ca35587Sdholland int nlm_host_get_sysid(struct nlm_host *host)
13206ca35587Sdholland {
13216ca35587Sdholland
13226ca35587Sdholland return (host->nh_sysid);
13236ca35587Sdholland }
13246ca35587Sdholland
13256ca35587Sdholland int
nlm_host_get_state(struct nlm_host * host)13266ca35587Sdholland nlm_host_get_state(struct nlm_host *host)
13276ca35587Sdholland {
13286ca35587Sdholland
13296ca35587Sdholland return (host->nh_state);
13306ca35587Sdholland }
13316ca35587Sdholland
13326ca35587Sdholland void *
nlm_register_wait_lock(struct nlm4_lock * lock,struct vnode * vp)13336ca35587Sdholland nlm_register_wait_lock(struct nlm4_lock *lock, struct vnode *vp)
13346ca35587Sdholland {
13356ca35587Sdholland struct nlm_waiting_lock *nw;
13366ca35587Sdholland
13376ca35587Sdholland nw = malloc(sizeof(struct nlm_waiting_lock), M_NLM, M_WAITOK);
13386ca35587Sdholland nw->nw_lock = *lock;
13396ca35587Sdholland memcpy(&nw->nw_fh.fh_bytes, nw->nw_lock.fh.n_bytes,
13406ca35587Sdholland nw->nw_lock.fh.n_len);
13416ca35587Sdholland nw->nw_lock.fh.n_bytes = nw->nw_fh.fh_bytes;
13426ca35587Sdholland nw->nw_waiting = TRUE;
13436ca35587Sdholland nw->nw_vp = vp;
13446ca35587Sdholland mtx_lock(&nlm_global_lock);
13456ca35587Sdholland TAILQ_INSERT_TAIL(&nlm_waiting_locks, nw, nw_link);
13466ca35587Sdholland mtx_unlock(&nlm_global_lock);
13476ca35587Sdholland
13486ca35587Sdholland return nw;
13496ca35587Sdholland }
13506ca35587Sdholland
13516ca35587Sdholland void
nlm_deregister_wait_lock(void * handle)13526ca35587Sdholland nlm_deregister_wait_lock(void *handle)
13536ca35587Sdholland {
13546ca35587Sdholland struct nlm_waiting_lock *nw = handle;
13556ca35587Sdholland
13566ca35587Sdholland mtx_lock(&nlm_global_lock);
13576ca35587Sdholland TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link);
13586ca35587Sdholland mtx_unlock(&nlm_global_lock);
13596ca35587Sdholland
13606ca35587Sdholland free(nw, M_NLM);
13616ca35587Sdholland }
13626ca35587Sdholland
13636ca35587Sdholland int
nlm_wait_lock(void * handle,int timo)13646ca35587Sdholland nlm_wait_lock(void *handle, int timo)
13656ca35587Sdholland {
13666ca35587Sdholland struct nlm_waiting_lock *nw = handle;
13672d39560cSpgoyette int error, stops_deferred;
13686ca35587Sdholland
13696ca35587Sdholland /*
13706ca35587Sdholland * If the granted message arrived before we got here,
13716ca35587Sdholland * nw->nw_waiting will be FALSE - in that case, don't sleep.
13726ca35587Sdholland */
13736ca35587Sdholland mtx_lock(&nlm_global_lock);
13746ca35587Sdholland error = 0;
13752d39560cSpgoyette if (nw->nw_waiting) {
13762d39560cSpgoyette stops_deferred = sigdeferstop(SIGDEFERSTOP_ERESTART);
13776ca35587Sdholland error = msleep(nw, &nlm_global_lock, PCATCH, "nlmlock", timo);
13782d39560cSpgoyette sigallowstop(stops_deferred);
13792d39560cSpgoyette }
13806ca35587Sdholland TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link);
13816ca35587Sdholland if (error) {
13826ca35587Sdholland /*
13836ca35587Sdholland * The granted message may arrive after the
13846ca35587Sdholland * interrupt/timeout but before we manage to lock the
13856ca35587Sdholland * mutex. Detect this by examining nw_lock.
13866ca35587Sdholland */
13876ca35587Sdholland if (!nw->nw_waiting)
13886ca35587Sdholland error = 0;
13896ca35587Sdholland } else {
13906ca35587Sdholland /*
13916ca35587Sdholland * If nlm_cancel_wait is called, then error will be
13926ca35587Sdholland * zero but nw_waiting will still be TRUE. We
13936ca35587Sdholland * translate this into EINTR.
13946ca35587Sdholland */
13956ca35587Sdholland if (nw->nw_waiting)
13966ca35587Sdholland error = EINTR;
13976ca35587Sdholland }
13986ca35587Sdholland mtx_unlock(&nlm_global_lock);
13996ca35587Sdholland
14006ca35587Sdholland free(nw, M_NLM);
14016ca35587Sdholland
14026ca35587Sdholland return (error);
14036ca35587Sdholland }
14046ca35587Sdholland
14056ca35587Sdholland void
nlm_cancel_wait(struct vnode * vp)14066ca35587Sdholland nlm_cancel_wait(struct vnode *vp)
14076ca35587Sdholland {
14086ca35587Sdholland struct nlm_waiting_lock *nw;
14096ca35587Sdholland
14106ca35587Sdholland mtx_lock(&nlm_global_lock);
14116ca35587Sdholland TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
14126ca35587Sdholland if (nw->nw_vp == vp) {
14136ca35587Sdholland wakeup(nw);
14146ca35587Sdholland }
14156ca35587Sdholland }
14166ca35587Sdholland mtx_unlock(&nlm_global_lock);
14176ca35587Sdholland }
14186ca35587Sdholland
14196ca35587Sdholland
14206ca35587Sdholland /**********************************************************************/
14216ca35587Sdholland
14226ca35587Sdholland /*
14236ca35587Sdholland * Syscall interface with userland.
14246ca35587Sdholland */
14256ca35587Sdholland
14266ca35587Sdholland extern void nlm_prog_0(struct svc_req *rqstp, SVCXPRT *transp);
14276ca35587Sdholland extern void nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp);
14286ca35587Sdholland extern void nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp);
14296ca35587Sdholland extern void nlm_prog_4(struct svc_req *rqstp, SVCXPRT *transp);
14306ca35587Sdholland
14316ca35587Sdholland static int
nlm_register_services(SVCPOOL * pool,int addr_count,char ** addrs)14326ca35587Sdholland nlm_register_services(SVCPOOL *pool, int addr_count, char **addrs)
14336ca35587Sdholland {
14346ca35587Sdholland static rpcvers_t versions[] = {
14356ca35587Sdholland NLM_SM, NLM_VERS, NLM_VERSX, NLM_VERS4
14366ca35587Sdholland };
14376ca35587Sdholland static void (*dispatchers[])(struct svc_req *, SVCXPRT *) = {
14386ca35587Sdholland nlm_prog_0, nlm_prog_1, nlm_prog_3, nlm_prog_4
14396ca35587Sdholland };
14406ca35587Sdholland
14416ca35587Sdholland SVCXPRT **xprts;
14426ca35587Sdholland char netid[16];
14436ca35587Sdholland char uaddr[128];
14446ca35587Sdholland struct netconfig *nconf;
14456ca35587Sdholland int i, j, error;
14466ca35587Sdholland
14476ca35587Sdholland if (!addr_count) {
14486ca35587Sdholland NLM_ERR("NLM: no service addresses given - can't start server");
14496ca35587Sdholland return (EINVAL);
14506ca35587Sdholland }
14516ca35587Sdholland
14522d39560cSpgoyette if (addr_count < 0 || addr_count > 256 ) {
14532d39560cSpgoyette NLM_ERR("NLM: too many service addresses (%d) given, "
14542d39560cSpgoyette "max 256 - can't start server\n", addr_count);
14552d39560cSpgoyette return (EINVAL);
14562d39560cSpgoyette }
14572d39560cSpgoyette
14586ca35587Sdholland xprts = malloc(addr_count * sizeof(SVCXPRT *), M_NLM, M_WAITOK|M_ZERO);
14592d39560cSpgoyette for (i = 0; i < nitems(versions); i++) {
14606ca35587Sdholland for (j = 0; j < addr_count; j++) {
14616ca35587Sdholland /*
14626ca35587Sdholland * Create transports for the first version and
14636ca35587Sdholland * then just register everything else to the
14646ca35587Sdholland * same transports.
14656ca35587Sdholland */
14666ca35587Sdholland if (i == 0) {
14676ca35587Sdholland char *up;
14686ca35587Sdholland
14696ca35587Sdholland error = copyin(&addrs[2*j], &up,
14706ca35587Sdholland sizeof(char*));
14716ca35587Sdholland if (error)
14726ca35587Sdholland goto out;
14736ca35587Sdholland error = copyinstr(up, netid, sizeof(netid),
14746ca35587Sdholland NULL);
14756ca35587Sdholland if (error)
14766ca35587Sdholland goto out;
14776ca35587Sdholland error = copyin(&addrs[2*j+1], &up,
14786ca35587Sdholland sizeof(char*));
14796ca35587Sdholland if (error)
14806ca35587Sdholland goto out;
14816ca35587Sdholland error = copyinstr(up, uaddr, sizeof(uaddr),
14826ca35587Sdholland NULL);
14836ca35587Sdholland if (error)
14846ca35587Sdholland goto out;
14856ca35587Sdholland nconf = getnetconfigent(netid);
14866ca35587Sdholland if (!nconf) {
14876ca35587Sdholland NLM_ERR("Can't lookup netid %s\n",
14886ca35587Sdholland netid);
14896ca35587Sdholland error = EINVAL;
14906ca35587Sdholland goto out;
14916ca35587Sdholland }
14926ca35587Sdholland xprts[j] = svc_tp_create(pool, dispatchers[i],
14936ca35587Sdholland NLM_PROG, versions[i], uaddr, nconf);
14946ca35587Sdholland if (!xprts[j]) {
14956ca35587Sdholland NLM_ERR("NLM: unable to create "
14966ca35587Sdholland "(NLM_PROG, %d).\n", versions[i]);
14976ca35587Sdholland error = EINVAL;
14986ca35587Sdholland goto out;
14996ca35587Sdholland }
15006ca35587Sdholland freenetconfigent(nconf);
15016ca35587Sdholland } else {
15026ca35587Sdholland nconf = getnetconfigent(xprts[j]->xp_netid);
15036ca35587Sdholland rpcb_unset(NLM_PROG, versions[i], nconf);
15046ca35587Sdholland if (!svc_reg(xprts[j], NLM_PROG, versions[i],
15056ca35587Sdholland dispatchers[i], nconf)) {
15066ca35587Sdholland NLM_ERR("NLM: can't register "
15076ca35587Sdholland "(NLM_PROG, %d)\n", versions[i]);
15086ca35587Sdholland error = EINVAL;
15096ca35587Sdholland goto out;
15106ca35587Sdholland }
15116ca35587Sdholland }
15126ca35587Sdholland }
15136ca35587Sdholland }
15146ca35587Sdholland error = 0;
15156ca35587Sdholland out:
15166ca35587Sdholland for (j = 0; j < addr_count; j++) {
15176ca35587Sdholland if (xprts[j])
15186ca35587Sdholland SVC_RELEASE(xprts[j]);
15196ca35587Sdholland }
15206ca35587Sdholland free(xprts, M_NLM);
15216ca35587Sdholland return (error);
15226ca35587Sdholland }
15236ca35587Sdholland
15246ca35587Sdholland /*
15256ca35587Sdholland * Main server entry point. Contacts the local NSM to get its current
15266ca35587Sdholland * state and send SM_UNMON_ALL. Registers the NLM services and then
15276ca35587Sdholland * services requests. Does not return until the server is interrupted
15286ca35587Sdholland * by a signal.
15296ca35587Sdholland */
15306ca35587Sdholland static int
nlm_server_main(int addr_count,char ** addrs)15316ca35587Sdholland nlm_server_main(int addr_count, char **addrs)
15326ca35587Sdholland {
15336ca35587Sdholland struct thread *td = curthread;
15346ca35587Sdholland int error;
15356ca35587Sdholland SVCPOOL *pool = NULL;
15366ca35587Sdholland struct sockopt opt;
15376ca35587Sdholland int portlow;
15386ca35587Sdholland #ifdef INET6
15396ca35587Sdholland struct sockaddr_in6 sin6;
15406ca35587Sdholland #endif
15416ca35587Sdholland struct sockaddr_in sin;
15426ca35587Sdholland my_id id;
15436ca35587Sdholland sm_stat smstat;
15446ca35587Sdholland struct timeval timo;
15456ca35587Sdholland enum clnt_stat stat;
15466ca35587Sdholland struct nlm_host *host, *nhost;
15476ca35587Sdholland struct nlm_waiting_lock *nw;
15486ca35587Sdholland vop_advlock_t *old_nfs_advlock;
15496ca35587Sdholland vop_reclaim_t *old_nfs_reclaim;
15506ca35587Sdholland
15516ca35587Sdholland if (nlm_is_running != 0) {
15526ca35587Sdholland NLM_ERR("NLM: can't start server - "
15536ca35587Sdholland "it appears to be running already\n");
15546ca35587Sdholland return (EPERM);
15556ca35587Sdholland }
15566ca35587Sdholland
15576ca35587Sdholland if (nlm_socket == NULL) {
15586ca35587Sdholland memset(&opt, 0, sizeof(opt));
15596ca35587Sdholland
15606ca35587Sdholland error = socreate(AF_INET, &nlm_socket, SOCK_DGRAM, 0,
15616ca35587Sdholland td->td_ucred, td);
15626ca35587Sdholland if (error) {
15636ca35587Sdholland NLM_ERR("NLM: can't create IPv4 socket - error %d\n",
15646ca35587Sdholland error);
15656ca35587Sdholland return (error);
15666ca35587Sdholland }
15676ca35587Sdholland opt.sopt_dir = SOPT_SET;
15686ca35587Sdholland opt.sopt_level = IPPROTO_IP;
15696ca35587Sdholland opt.sopt_name = IP_PORTRANGE;
15706ca35587Sdholland portlow = IP_PORTRANGE_LOW;
15716ca35587Sdholland opt.sopt_val = &portlow;
15726ca35587Sdholland opt.sopt_valsize = sizeof(portlow);
15736ca35587Sdholland sosetopt(nlm_socket, &opt);
15746ca35587Sdholland
15756ca35587Sdholland #ifdef INET6
15766ca35587Sdholland nlm_socket6 = NULL;
15776ca35587Sdholland error = socreate(AF_INET6, &nlm_socket6, SOCK_DGRAM, 0,
15786ca35587Sdholland td->td_ucred, td);
15796ca35587Sdholland if (error) {
15806ca35587Sdholland NLM_ERR("NLM: can't create IPv6 socket - error %d\n",
15816ca35587Sdholland error);
15826ca35587Sdholland soclose(nlm_socket);
15836ca35587Sdholland nlm_socket = NULL;
15846ca35587Sdholland return (error);
15856ca35587Sdholland }
15866ca35587Sdholland opt.sopt_dir = SOPT_SET;
15876ca35587Sdholland opt.sopt_level = IPPROTO_IPV6;
15886ca35587Sdholland opt.sopt_name = IPV6_PORTRANGE;
15896ca35587Sdholland portlow = IPV6_PORTRANGE_LOW;
15906ca35587Sdholland opt.sopt_val = &portlow;
15916ca35587Sdholland opt.sopt_valsize = sizeof(portlow);
15926ca35587Sdholland sosetopt(nlm_socket6, &opt);
15936ca35587Sdholland #endif
15946ca35587Sdholland }
15956ca35587Sdholland
15966ca35587Sdholland nlm_auth = authunix_create(curthread->td_ucred);
15976ca35587Sdholland
15986ca35587Sdholland #ifdef INET6
15996ca35587Sdholland memset(&sin6, 0, sizeof(sin6));
16006ca35587Sdholland sin6.sin6_len = sizeof(sin6);
16016ca35587Sdholland sin6.sin6_family = AF_INET6;
16026ca35587Sdholland sin6.sin6_addr = in6addr_loopback;
16036ca35587Sdholland nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin6, SM_PROG, SM_VERS);
16046ca35587Sdholland if (!nlm_nsm) {
16056ca35587Sdholland #endif
16066ca35587Sdholland memset(&sin, 0, sizeof(sin));
16076ca35587Sdholland sin.sin_len = sizeof(sin);
16086ca35587Sdholland sin.sin_family = AF_INET;
16096ca35587Sdholland sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
16106ca35587Sdholland nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin, SM_PROG,
16116ca35587Sdholland SM_VERS);
16126ca35587Sdholland #ifdef INET6
16136ca35587Sdholland }
16146ca35587Sdholland #endif
16156ca35587Sdholland
16166ca35587Sdholland if (!nlm_nsm) {
16176ca35587Sdholland NLM_ERR("Can't start NLM - unable to contact NSM\n");
16186ca35587Sdholland error = EINVAL;
16196ca35587Sdholland goto out;
16206ca35587Sdholland }
16216ca35587Sdholland
16226ca35587Sdholland pool = svcpool_create("NLM", NULL);
16236ca35587Sdholland
16246ca35587Sdholland error = nlm_register_services(pool, addr_count, addrs);
16256ca35587Sdholland if (error)
16266ca35587Sdholland goto out;
16276ca35587Sdholland
16286ca35587Sdholland memset(&id, 0, sizeof(id));
16296ca35587Sdholland id.my_name = "NFS NLM";
16306ca35587Sdholland
16316ca35587Sdholland timo.tv_sec = 25;
16326ca35587Sdholland timo.tv_usec = 0;
16336ca35587Sdholland stat = CLNT_CALL(nlm_nsm, SM_UNMON_ALL,
16346ca35587Sdholland (xdrproc_t) xdr_my_id, &id,
16356ca35587Sdholland (xdrproc_t) xdr_sm_stat, &smstat, timo);
16366ca35587Sdholland
16376ca35587Sdholland if (stat != RPC_SUCCESS) {
16386ca35587Sdholland struct rpc_err err;
16396ca35587Sdholland
16406ca35587Sdholland CLNT_GETERR(nlm_nsm, &err);
16416ca35587Sdholland NLM_ERR("NLM: unexpected error contacting NSM, "
16426ca35587Sdholland "stat=%d, errno=%d\n", stat, err.re_errno);
16436ca35587Sdholland error = EINVAL;
16446ca35587Sdholland goto out;
16456ca35587Sdholland }
16466ca35587Sdholland nlm_is_running = 1;
16476ca35587Sdholland
16486ca35587Sdholland NLM_DEBUG(1, "NLM: local NSM state is %d\n", smstat.state);
16496ca35587Sdholland nlm_nsm_state = smstat.state;
16506ca35587Sdholland
16516ca35587Sdholland old_nfs_advlock = nfs_advlock_p;
16526ca35587Sdholland nfs_advlock_p = nlm_advlock;
16536ca35587Sdholland old_nfs_reclaim = nfs_reclaim_p;
16546ca35587Sdholland nfs_reclaim_p = nlm_reclaim;
16556ca35587Sdholland
16566ca35587Sdholland svc_run(pool);
16576ca35587Sdholland error = 0;
16586ca35587Sdholland
16596ca35587Sdholland nfs_advlock_p = old_nfs_advlock;
16606ca35587Sdholland nfs_reclaim_p = old_nfs_reclaim;
16616ca35587Sdholland
16626ca35587Sdholland out:
16636ca35587Sdholland nlm_is_running = 0;
16646ca35587Sdholland if (pool)
16656ca35587Sdholland svcpool_destroy(pool);
16666ca35587Sdholland
16676ca35587Sdholland /*
16686ca35587Sdholland * We are finished communicating with the NSM.
16696ca35587Sdholland */
16706ca35587Sdholland if (nlm_nsm) {
16716ca35587Sdholland CLNT_RELEASE(nlm_nsm);
16726ca35587Sdholland nlm_nsm = NULL;
16736ca35587Sdholland }
16746ca35587Sdholland
16756ca35587Sdholland /*
16766ca35587Sdholland * Trash all the existing state so that if the server
16776ca35587Sdholland * restarts, it gets a clean slate. This is complicated by the
16786ca35587Sdholland * possibility that there may be other threads trying to make
16796ca35587Sdholland * client locking requests.
16806ca35587Sdholland *
16816ca35587Sdholland * First we fake a client reboot notification which will
16826ca35587Sdholland * cancel any pending async locks and purge remote lock state
16836ca35587Sdholland * from the local lock manager. We release the reference from
16846ca35587Sdholland * nlm_hosts to the host (which may remove it from the list
16856ca35587Sdholland * and free it). After this phase, the only entries in the
16866ca35587Sdholland * nlm_host list should be from other threads performing
16876ca35587Sdholland * client lock requests.
16886ca35587Sdholland */
16896ca35587Sdholland mtx_lock(&nlm_global_lock);
16906ca35587Sdholland TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
16916ca35587Sdholland wakeup(nw);
16926ca35587Sdholland }
16936ca35587Sdholland TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, nhost) {
16946ca35587Sdholland mtx_unlock(&nlm_global_lock);
16956ca35587Sdholland nlm_host_notify(host, 0);
16966ca35587Sdholland nlm_host_release(host);
16976ca35587Sdholland mtx_lock(&nlm_global_lock);
16986ca35587Sdholland }
16996ca35587Sdholland mtx_unlock(&nlm_global_lock);
17006ca35587Sdholland
17016ca35587Sdholland AUTH_DESTROY(nlm_auth);
17026ca35587Sdholland
17036ca35587Sdholland return (error);
17046ca35587Sdholland }
17056ca35587Sdholland
17066ca35587Sdholland int
sys_nlm_syscall(struct thread * td,struct nlm_syscall_args * uap)17076ca35587Sdholland sys_nlm_syscall(struct thread *td, struct nlm_syscall_args *uap)
17086ca35587Sdholland {
17096ca35587Sdholland int error;
17106ca35587Sdholland
17116ca35587Sdholland #if __FreeBSD_version >= 700000
17126ca35587Sdholland error = priv_check(td, PRIV_NFS_LOCKD);
17136ca35587Sdholland #else
17146ca35587Sdholland error = suser(td);
17156ca35587Sdholland #endif
17166ca35587Sdholland if (error)
17176ca35587Sdholland return (error);
17186ca35587Sdholland
17196ca35587Sdholland nlm_debug_level = uap->debug_level;
17206ca35587Sdholland nlm_grace_threshold = time_uptime + uap->grace_period;
17216ca35587Sdholland nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD;
17226ca35587Sdholland
17236ca35587Sdholland return nlm_server_main(uap->addr_count, uap->addrs);
17246ca35587Sdholland }
17256ca35587Sdholland
17266ca35587Sdholland /**********************************************************************/
17276ca35587Sdholland
17286ca35587Sdholland /*
17296ca35587Sdholland * NLM implementation details, called from the RPC stubs.
17306ca35587Sdholland */
17316ca35587Sdholland
17326ca35587Sdholland
17336ca35587Sdholland void
nlm_sm_notify(struct nlm_sm_status * argp)17346ca35587Sdholland nlm_sm_notify(struct nlm_sm_status *argp)
17356ca35587Sdholland {
17366ca35587Sdholland uint32_t sysid;
17376ca35587Sdholland struct nlm_host *host;
17386ca35587Sdholland
17396ca35587Sdholland NLM_DEBUG(3, "nlm_sm_notify(): mon_name = %s\n", argp->mon_name);
17406ca35587Sdholland memcpy(&sysid, &argp->priv, sizeof(sysid));
17416ca35587Sdholland host = nlm_find_host_by_sysid(sysid);
17426ca35587Sdholland if (host) {
17436ca35587Sdholland nlm_host_notify(host, argp->state);
17446ca35587Sdholland nlm_host_release(host);
17456ca35587Sdholland }
17466ca35587Sdholland }
17476ca35587Sdholland
17486ca35587Sdholland static void
nlm_convert_to_fhandle_t(fhandle_t * fhp,struct netobj * p)17496ca35587Sdholland nlm_convert_to_fhandle_t(fhandle_t *fhp, struct netobj *p)
17506ca35587Sdholland {
17516ca35587Sdholland memcpy(fhp, p->n_bytes, sizeof(fhandle_t));
17526ca35587Sdholland }
17536ca35587Sdholland
17546ca35587Sdholland struct vfs_state {
17556ca35587Sdholland struct mount *vs_mp;
17566ca35587Sdholland struct vnode *vs_vp;
17576ca35587Sdholland int vs_vnlocked;
17586ca35587Sdholland };
17596ca35587Sdholland
17606ca35587Sdholland static int
nlm_get_vfs_state(struct nlm_host * host,struct svc_req * rqstp,fhandle_t * fhp,struct vfs_state * vs,accmode_t accmode)17616ca35587Sdholland nlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp,
17626ca35587Sdholland fhandle_t *fhp, struct vfs_state *vs, accmode_t accmode)
17636ca35587Sdholland {
17646ca35587Sdholland int error, exflags;
17656ca35587Sdholland struct ucred *cred = NULL, *credanon = NULL;
17666ca35587Sdholland
17676ca35587Sdholland memset(vs, 0, sizeof(*vs));
17686ca35587Sdholland
17696ca35587Sdholland vs->vs_mp = vfs_getvfs(&fhp->fh_fsid);
17706ca35587Sdholland if (!vs->vs_mp) {
17716ca35587Sdholland return (ESTALE);
17726ca35587Sdholland }
17736ca35587Sdholland
17746ca35587Sdholland /* accmode == 0 means don't check, since it is an unlock. */
17756ca35587Sdholland if (accmode != 0) {
17766ca35587Sdholland error = VFS_CHECKEXP(vs->vs_mp,
17776ca35587Sdholland (struct sockaddr *)&host->nh_addr, &exflags, &credanon,
17786ca35587Sdholland NULL, NULL);
17796ca35587Sdholland if (error)
17806ca35587Sdholland goto out;
17816ca35587Sdholland
17826ca35587Sdholland if (exflags & MNT_EXRDONLY ||
17836ca35587Sdholland (vs->vs_mp->mnt_flag & MNT_RDONLY)) {
17846ca35587Sdholland error = EROFS;
17856ca35587Sdholland goto out;
17866ca35587Sdholland }
17876ca35587Sdholland }
17886ca35587Sdholland
17896ca35587Sdholland error = VFS_FHTOVP(vs->vs_mp, &fhp->fh_fid, LK_EXCLUSIVE, &vs->vs_vp);
17906ca35587Sdholland if (error)
17916ca35587Sdholland goto out;
17926ca35587Sdholland vs->vs_vnlocked = TRUE;
17936ca35587Sdholland
17946ca35587Sdholland if (accmode != 0) {
17956ca35587Sdholland if (!svc_getcred(rqstp, &cred, NULL)) {
17966ca35587Sdholland error = EINVAL;
17976ca35587Sdholland goto out;
17986ca35587Sdholland }
17996ca35587Sdholland if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
18006ca35587Sdholland crfree(cred);
18016ca35587Sdholland cred = credanon;
18026ca35587Sdholland credanon = NULL;
18036ca35587Sdholland }
18046ca35587Sdholland
18056ca35587Sdholland /*
18066ca35587Sdholland * Check cred.
18076ca35587Sdholland */
18086ca35587Sdholland error = VOP_ACCESS(vs->vs_vp, accmode, cred, curthread);
18096ca35587Sdholland /*
18106ca35587Sdholland * If this failed and accmode != VWRITE, try again with
18116ca35587Sdholland * VWRITE to maintain backwards compatibility with the
18126ca35587Sdholland * old code that always used VWRITE.
18136ca35587Sdholland */
18146ca35587Sdholland if (error != 0 && accmode != VWRITE)
18156ca35587Sdholland error = VOP_ACCESS(vs->vs_vp, VWRITE, cred, curthread);
18166ca35587Sdholland if (error)
18176ca35587Sdholland goto out;
18186ca35587Sdholland }
18196ca35587Sdholland
18206ca35587Sdholland #if __FreeBSD_version < 800011
18216ca35587Sdholland VOP_UNLOCK(vs->vs_vp, 0, curthread);
18226ca35587Sdholland #else
18236ca35587Sdholland VOP_UNLOCK(vs->vs_vp, 0);
18246ca35587Sdholland #endif
18256ca35587Sdholland vs->vs_vnlocked = FALSE;
18266ca35587Sdholland
18276ca35587Sdholland out:
18286ca35587Sdholland if (cred)
18296ca35587Sdholland crfree(cred);
18306ca35587Sdholland if (credanon)
18316ca35587Sdholland crfree(credanon);
18326ca35587Sdholland
18336ca35587Sdholland return (error);
18346ca35587Sdholland }
18356ca35587Sdholland
18366ca35587Sdholland static void
nlm_release_vfs_state(struct vfs_state * vs)18376ca35587Sdholland nlm_release_vfs_state(struct vfs_state *vs)
18386ca35587Sdholland {
18396ca35587Sdholland
18406ca35587Sdholland if (vs->vs_vp) {
18416ca35587Sdholland if (vs->vs_vnlocked)
18426ca35587Sdholland vput(vs->vs_vp);
18436ca35587Sdholland else
18446ca35587Sdholland vrele(vs->vs_vp);
18456ca35587Sdholland }
18466ca35587Sdholland if (vs->vs_mp)
18476ca35587Sdholland vfs_rel(vs->vs_mp);
18486ca35587Sdholland }
18496ca35587Sdholland
18506ca35587Sdholland static nlm4_stats
nlm_convert_error(int error)18516ca35587Sdholland nlm_convert_error(int error)
18526ca35587Sdholland {
18536ca35587Sdholland
18546ca35587Sdholland if (error == ESTALE)
18556ca35587Sdholland return nlm4_stale_fh;
18566ca35587Sdholland else if (error == EROFS)
18576ca35587Sdholland return nlm4_rofs;
18586ca35587Sdholland else
18596ca35587Sdholland return nlm4_failed;
18606ca35587Sdholland }
18616ca35587Sdholland
18626ca35587Sdholland int
nlm_do_test(nlm4_testargs * argp,nlm4_testres * result,struct svc_req * rqstp,CLIENT ** rpcp)18636ca35587Sdholland nlm_do_test(nlm4_testargs *argp, nlm4_testres *result, struct svc_req *rqstp,
18646ca35587Sdholland CLIENT **rpcp)
18656ca35587Sdholland {
18666ca35587Sdholland fhandle_t fh;
18676ca35587Sdholland struct vfs_state vs;
18686ca35587Sdholland struct nlm_host *host, *bhost;
18696ca35587Sdholland int error, sysid;
18706ca35587Sdholland struct flock fl;
18716ca35587Sdholland accmode_t accmode;
18726ca35587Sdholland
18736ca35587Sdholland memset(result, 0, sizeof(*result));
18746ca35587Sdholland memset(&vs, 0, sizeof(vs));
18756ca35587Sdholland
18766ca35587Sdholland host = nlm_find_host_by_name(argp->alock.caller_name,
18776ca35587Sdholland svc_getrpccaller(rqstp), rqstp->rq_vers);
18786ca35587Sdholland if (!host) {
18796ca35587Sdholland result->stat.stat = nlm4_denied_nolocks;
18806ca35587Sdholland return (ENOMEM);
18816ca35587Sdholland }
18826ca35587Sdholland
18836ca35587Sdholland NLM_DEBUG(3, "nlm_do_test(): caller_name = %s (sysid = %d)\n",
18846ca35587Sdholland host->nh_caller_name, host->nh_sysid);
18856ca35587Sdholland
18866ca35587Sdholland nlm_check_expired_locks(host);
18876ca35587Sdholland sysid = host->nh_sysid;
18886ca35587Sdholland
18896ca35587Sdholland nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
18906ca35587Sdholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
18916ca35587Sdholland
18926ca35587Sdholland if (time_uptime < nlm_grace_threshold) {
18936ca35587Sdholland result->stat.stat = nlm4_denied_grace_period;
18946ca35587Sdholland goto out;
18956ca35587Sdholland }
18966ca35587Sdholland
18976ca35587Sdholland accmode = argp->exclusive ? VWRITE : VREAD;
18986ca35587Sdholland error = nlm_get_vfs_state(host, rqstp, &fh, &vs, accmode);
18996ca35587Sdholland if (error) {
19006ca35587Sdholland result->stat.stat = nlm_convert_error(error);
19016ca35587Sdholland goto out;
19026ca35587Sdholland }
19036ca35587Sdholland
19046ca35587Sdholland fl.l_start = argp->alock.l_offset;
19056ca35587Sdholland fl.l_len = argp->alock.l_len;
19066ca35587Sdholland fl.l_pid = argp->alock.svid;
19076ca35587Sdholland fl.l_sysid = sysid;
19086ca35587Sdholland fl.l_whence = SEEK_SET;
19096ca35587Sdholland if (argp->exclusive)
19106ca35587Sdholland fl.l_type = F_WRLCK;
19116ca35587Sdholland else
19126ca35587Sdholland fl.l_type = F_RDLCK;
19136ca35587Sdholland error = VOP_ADVLOCK(vs.vs_vp, NULL, F_GETLK, &fl, F_REMOTE);
19146ca35587Sdholland if (error) {
19156ca35587Sdholland result->stat.stat = nlm4_failed;
19166ca35587Sdholland goto out;
19176ca35587Sdholland }
19186ca35587Sdholland
19196ca35587Sdholland if (fl.l_type == F_UNLCK) {
19206ca35587Sdholland result->stat.stat = nlm4_granted;
19216ca35587Sdholland } else {
19226ca35587Sdholland result->stat.stat = nlm4_denied;
19236ca35587Sdholland result->stat.nlm4_testrply_u.holder.exclusive =
19246ca35587Sdholland (fl.l_type == F_WRLCK);
19256ca35587Sdholland result->stat.nlm4_testrply_u.holder.svid = fl.l_pid;
19266ca35587Sdholland bhost = nlm_find_host_by_sysid(fl.l_sysid);
19276ca35587Sdholland if (bhost) {
19286ca35587Sdholland /*
19296ca35587Sdholland * We don't have any useful way of recording
19306ca35587Sdholland * the value of oh used in the original lock
19316ca35587Sdholland * request. Ideally, the test reply would have
19326ca35587Sdholland * a space for the owning host's name allowing
19336ca35587Sdholland * our caller's NLM to keep track.
19346ca35587Sdholland *
19356ca35587Sdholland * As far as I can see, Solaris uses an eight
19366ca35587Sdholland * byte structure for oh which contains a four
19376ca35587Sdholland * byte pid encoded in local byte order and
19386ca35587Sdholland * the first four bytes of the host
19396ca35587Sdholland * name. Linux uses a variable length string
19406ca35587Sdholland * 'pid@hostname' in ascii but doesn't even
19416ca35587Sdholland * return that in test replies.
19426ca35587Sdholland *
19436ca35587Sdholland * For the moment, return nothing in oh
19446ca35587Sdholland * (already zero'ed above).
19456ca35587Sdholland */
19466ca35587Sdholland nlm_host_release(bhost);
19476ca35587Sdholland }
19486ca35587Sdholland result->stat.nlm4_testrply_u.holder.l_offset = fl.l_start;
19496ca35587Sdholland result->stat.nlm4_testrply_u.holder.l_len = fl.l_len;
19506ca35587Sdholland }
19516ca35587Sdholland
19526ca35587Sdholland out:
19536ca35587Sdholland nlm_release_vfs_state(&vs);
19546ca35587Sdholland if (rpcp)
19556ca35587Sdholland *rpcp = nlm_host_get_rpc(host, TRUE);
19566ca35587Sdholland nlm_host_release(host);
19576ca35587Sdholland return (0);
19586ca35587Sdholland }
19596ca35587Sdholland
19606ca35587Sdholland int
nlm_do_lock(nlm4_lockargs * argp,nlm4_res * result,struct svc_req * rqstp,bool_t monitor,CLIENT ** rpcp)19616ca35587Sdholland nlm_do_lock(nlm4_lockargs *argp, nlm4_res *result, struct svc_req *rqstp,
19626ca35587Sdholland bool_t monitor, CLIENT **rpcp)
19636ca35587Sdholland {
19646ca35587Sdholland fhandle_t fh;
19656ca35587Sdholland struct vfs_state vs;
19666ca35587Sdholland struct nlm_host *host;
19676ca35587Sdholland int error, sysid;
19686ca35587Sdholland struct flock fl;
19696ca35587Sdholland accmode_t accmode;
19706ca35587Sdholland
19716ca35587Sdholland memset(result, 0, sizeof(*result));
19726ca35587Sdholland memset(&vs, 0, sizeof(vs));
19736ca35587Sdholland
19746ca35587Sdholland host = nlm_find_host_by_name(argp->alock.caller_name,
19756ca35587Sdholland svc_getrpccaller(rqstp), rqstp->rq_vers);
19766ca35587Sdholland if (!host) {
19776ca35587Sdholland result->stat.stat = nlm4_denied_nolocks;
19786ca35587Sdholland return (ENOMEM);
19796ca35587Sdholland }
19806ca35587Sdholland
19816ca35587Sdholland NLM_DEBUG(3, "nlm_do_lock(): caller_name = %s (sysid = %d)\n",
19826ca35587Sdholland host->nh_caller_name, host->nh_sysid);
19836ca35587Sdholland
19846ca35587Sdholland if (monitor && host->nh_state && argp->state
19856ca35587Sdholland && host->nh_state != argp->state) {
19866ca35587Sdholland /*
19876ca35587Sdholland * The host rebooted without telling us. Trash its
19886ca35587Sdholland * locks.
19896ca35587Sdholland */
19906ca35587Sdholland nlm_host_notify(host, argp->state);
19916ca35587Sdholland }
19926ca35587Sdholland
19936ca35587Sdholland nlm_check_expired_locks(host);
19946ca35587Sdholland sysid = host->nh_sysid;
19956ca35587Sdholland
19966ca35587Sdholland nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
19976ca35587Sdholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
19986ca35587Sdholland
19996ca35587Sdholland if (time_uptime < nlm_grace_threshold && !argp->reclaim) {
20006ca35587Sdholland result->stat.stat = nlm4_denied_grace_period;
20016ca35587Sdholland goto out;
20026ca35587Sdholland }
20036ca35587Sdholland
20046ca35587Sdholland accmode = argp->exclusive ? VWRITE : VREAD;
20056ca35587Sdholland error = nlm_get_vfs_state(host, rqstp, &fh, &vs, accmode);
20066ca35587Sdholland if (error) {
20076ca35587Sdholland result->stat.stat = nlm_convert_error(error);
20086ca35587Sdholland goto out;
20096ca35587Sdholland }
20106ca35587Sdholland
20116ca35587Sdholland fl.l_start = argp->alock.l_offset;
20126ca35587Sdholland fl.l_len = argp->alock.l_len;
20136ca35587Sdholland fl.l_pid = argp->alock.svid;
20146ca35587Sdholland fl.l_sysid = sysid;
20156ca35587Sdholland fl.l_whence = SEEK_SET;
20166ca35587Sdholland if (argp->exclusive)
20176ca35587Sdholland fl.l_type = F_WRLCK;
20186ca35587Sdholland else
20196ca35587Sdholland fl.l_type = F_RDLCK;
20206ca35587Sdholland if (argp->block) {
20216ca35587Sdholland struct nlm_async_lock *af;
20226ca35587Sdholland CLIENT *client;
20236ca35587Sdholland struct nlm_grantcookie cookie;
20246ca35587Sdholland
20256ca35587Sdholland /*
20266ca35587Sdholland * First, make sure we can contact the host's NLM.
20276ca35587Sdholland */
20286ca35587Sdholland client = nlm_host_get_rpc(host, TRUE);
20296ca35587Sdholland if (!client) {
20306ca35587Sdholland result->stat.stat = nlm4_failed;
20316ca35587Sdholland goto out;
20326ca35587Sdholland }
20336ca35587Sdholland
20346ca35587Sdholland /*
20356ca35587Sdholland * First we need to check and see if there is an
20366ca35587Sdholland * existing blocked lock that matches. This could be a
20376ca35587Sdholland * badly behaved client or an RPC re-send. If we find
20386ca35587Sdholland * one, just return nlm4_blocked.
20396ca35587Sdholland */
20406ca35587Sdholland mtx_lock(&host->nh_lock);
20416ca35587Sdholland TAILQ_FOREACH(af, &host->nh_pending, af_link) {
20426ca35587Sdholland if (af->af_fl.l_start == fl.l_start
20436ca35587Sdholland && af->af_fl.l_len == fl.l_len
20446ca35587Sdholland && af->af_fl.l_pid == fl.l_pid
20456ca35587Sdholland && af->af_fl.l_type == fl.l_type) {
20466ca35587Sdholland break;
20476ca35587Sdholland }
20486ca35587Sdholland }
20496ca35587Sdholland if (!af) {
20506ca35587Sdholland cookie.ng_sysid = host->nh_sysid;
20516ca35587Sdholland cookie.ng_cookie = host->nh_grantcookie++;
20526ca35587Sdholland }
20536ca35587Sdholland mtx_unlock(&host->nh_lock);
20546ca35587Sdholland if (af) {
20556ca35587Sdholland CLNT_RELEASE(client);
20566ca35587Sdholland result->stat.stat = nlm4_blocked;
20576ca35587Sdholland goto out;
20586ca35587Sdholland }
20596ca35587Sdholland
20606ca35587Sdholland af = malloc(sizeof(struct nlm_async_lock), M_NLM,
20616ca35587Sdholland M_WAITOK|M_ZERO);
20626ca35587Sdholland TASK_INIT(&af->af_task, 0, nlm_lock_callback, af);
20636ca35587Sdholland af->af_vp = vs.vs_vp;
20646ca35587Sdholland af->af_fl = fl;
20656ca35587Sdholland af->af_host = host;
20666ca35587Sdholland af->af_rpc = client;
20676ca35587Sdholland /*
20686ca35587Sdholland * We use M_RPC here so that we can xdr_free the thing
20696ca35587Sdholland * later.
20706ca35587Sdholland */
20716ca35587Sdholland nlm_make_netobj(&af->af_granted.cookie,
20726ca35587Sdholland (caddr_t)&cookie, sizeof(cookie), M_RPC);
20736ca35587Sdholland af->af_granted.exclusive = argp->exclusive;
20746ca35587Sdholland af->af_granted.alock.caller_name =
20756ca35587Sdholland strdup(argp->alock.caller_name, M_RPC);
20766ca35587Sdholland nlm_copy_netobj(&af->af_granted.alock.fh,
20776ca35587Sdholland &argp->alock.fh, M_RPC);
20786ca35587Sdholland nlm_copy_netobj(&af->af_granted.alock.oh,
20796ca35587Sdholland &argp->alock.oh, M_RPC);
20806ca35587Sdholland af->af_granted.alock.svid = argp->alock.svid;
20816ca35587Sdholland af->af_granted.alock.l_offset = argp->alock.l_offset;
20826ca35587Sdholland af->af_granted.alock.l_len = argp->alock.l_len;
20836ca35587Sdholland
20846ca35587Sdholland /*
20856ca35587Sdholland * Put the entry on the pending list before calling
20866ca35587Sdholland * VOP_ADVLOCKASYNC. We do this in case the lock
20876ca35587Sdholland * request was blocked (returning EINPROGRESS) but
20886ca35587Sdholland * then granted before we manage to run again. The
20896ca35587Sdholland * client may receive the granted message before we
20906ca35587Sdholland * send our blocked reply but thats their problem.
20916ca35587Sdholland */
20926ca35587Sdholland mtx_lock(&host->nh_lock);
20936ca35587Sdholland TAILQ_INSERT_TAIL(&host->nh_pending, af, af_link);
20946ca35587Sdholland mtx_unlock(&host->nh_lock);
20956ca35587Sdholland
20966ca35587Sdholland error = VOP_ADVLOCKASYNC(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE,
20976ca35587Sdholland &af->af_task, &af->af_cookie);
20986ca35587Sdholland
20996ca35587Sdholland /*
21006ca35587Sdholland * If the lock completed synchronously, just free the
21016ca35587Sdholland * tracking structure now.
21026ca35587Sdholland */
21036ca35587Sdholland if (error != EINPROGRESS) {
21046ca35587Sdholland CLNT_RELEASE(af->af_rpc);
21056ca35587Sdholland mtx_lock(&host->nh_lock);
21066ca35587Sdholland TAILQ_REMOVE(&host->nh_pending, af, af_link);
21076ca35587Sdholland mtx_unlock(&host->nh_lock);
21086ca35587Sdholland xdr_free((xdrproc_t) xdr_nlm4_testargs,
21096ca35587Sdholland &af->af_granted);
21106ca35587Sdholland free(af, M_NLM);
21116ca35587Sdholland } else {
21126ca35587Sdholland NLM_DEBUG(2, "NLM: pending async lock %p for %s "
21136ca35587Sdholland "(sysid %d)\n", af, host->nh_caller_name, sysid);
21146ca35587Sdholland /*
21156ca35587Sdholland * Don't vrele the vnode just yet - this must
21166ca35587Sdholland * wait until either the async callback
21176ca35587Sdholland * happens or the lock is cancelled.
21186ca35587Sdholland */
21196ca35587Sdholland vs.vs_vp = NULL;
21206ca35587Sdholland }
21216ca35587Sdholland } else {
21226ca35587Sdholland error = VOP_ADVLOCK(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE);
21236ca35587Sdholland }
21246ca35587Sdholland
21256ca35587Sdholland if (error) {
21266ca35587Sdholland if (error == EINPROGRESS) {
21276ca35587Sdholland result->stat.stat = nlm4_blocked;
21286ca35587Sdholland } else if (error == EDEADLK) {
21296ca35587Sdholland result->stat.stat = nlm4_deadlck;
21306ca35587Sdholland } else if (error == EAGAIN) {
21316ca35587Sdholland result->stat.stat = nlm4_denied;
21326ca35587Sdholland } else {
21336ca35587Sdholland result->stat.stat = nlm4_failed;
21346ca35587Sdholland }
21356ca35587Sdholland } else {
21366ca35587Sdholland if (monitor)
21376ca35587Sdholland nlm_host_monitor(host, argp->state);
21386ca35587Sdholland result->stat.stat = nlm4_granted;
21396ca35587Sdholland }
21406ca35587Sdholland
21416ca35587Sdholland out:
21426ca35587Sdholland nlm_release_vfs_state(&vs);
21436ca35587Sdholland if (rpcp)
21446ca35587Sdholland *rpcp = nlm_host_get_rpc(host, TRUE);
21456ca35587Sdholland nlm_host_release(host);
21466ca35587Sdholland return (0);
21476ca35587Sdholland }
21486ca35587Sdholland
21496ca35587Sdholland int
nlm_do_cancel(nlm4_cancargs * argp,nlm4_res * result,struct svc_req * rqstp,CLIENT ** rpcp)21506ca35587Sdholland nlm_do_cancel(nlm4_cancargs *argp, nlm4_res *result, struct svc_req *rqstp,
21516ca35587Sdholland CLIENT **rpcp)
21526ca35587Sdholland {
21536ca35587Sdholland fhandle_t fh;
21546ca35587Sdholland struct vfs_state vs;
21556ca35587Sdholland struct nlm_host *host;
21566ca35587Sdholland int error, sysid;
21576ca35587Sdholland struct flock fl;
21586ca35587Sdholland struct nlm_async_lock *af;
21596ca35587Sdholland
21606ca35587Sdholland memset(result, 0, sizeof(*result));
21616ca35587Sdholland memset(&vs, 0, sizeof(vs));
21626ca35587Sdholland
21636ca35587Sdholland host = nlm_find_host_by_name(argp->alock.caller_name,
21646ca35587Sdholland svc_getrpccaller(rqstp), rqstp->rq_vers);
21656ca35587Sdholland if (!host) {
21666ca35587Sdholland result->stat.stat = nlm4_denied_nolocks;
21676ca35587Sdholland return (ENOMEM);
21686ca35587Sdholland }
21696ca35587Sdholland
21706ca35587Sdholland NLM_DEBUG(3, "nlm_do_cancel(): caller_name = %s (sysid = %d)\n",
21716ca35587Sdholland host->nh_caller_name, host->nh_sysid);
21726ca35587Sdholland
21736ca35587Sdholland nlm_check_expired_locks(host);
21746ca35587Sdholland sysid = host->nh_sysid;
21756ca35587Sdholland
21766ca35587Sdholland nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
21776ca35587Sdholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
21786ca35587Sdholland
21796ca35587Sdholland if (time_uptime < nlm_grace_threshold) {
21806ca35587Sdholland result->stat.stat = nlm4_denied_grace_period;
21816ca35587Sdholland goto out;
21826ca35587Sdholland }
21836ca35587Sdholland
21846ca35587Sdholland error = nlm_get_vfs_state(host, rqstp, &fh, &vs, (accmode_t)0);
21856ca35587Sdholland if (error) {
21866ca35587Sdholland result->stat.stat = nlm_convert_error(error);
21876ca35587Sdholland goto out;
21886ca35587Sdholland }
21896ca35587Sdholland
21906ca35587Sdholland fl.l_start = argp->alock.l_offset;
21916ca35587Sdholland fl.l_len = argp->alock.l_len;
21926ca35587Sdholland fl.l_pid = argp->alock.svid;
21936ca35587Sdholland fl.l_sysid = sysid;
21946ca35587Sdholland fl.l_whence = SEEK_SET;
21956ca35587Sdholland if (argp->exclusive)
21966ca35587Sdholland fl.l_type = F_WRLCK;
21976ca35587Sdholland else
21986ca35587Sdholland fl.l_type = F_RDLCK;
21996ca35587Sdholland
22006ca35587Sdholland /*
22016ca35587Sdholland * First we need to try and find the async lock request - if
22026ca35587Sdholland * there isn't one, we give up and return nlm4_denied.
22036ca35587Sdholland */
22046ca35587Sdholland mtx_lock(&host->nh_lock);
22056ca35587Sdholland
22066ca35587Sdholland TAILQ_FOREACH(af, &host->nh_pending, af_link) {
22076ca35587Sdholland if (af->af_fl.l_start == fl.l_start
22086ca35587Sdholland && af->af_fl.l_len == fl.l_len
22096ca35587Sdholland && af->af_fl.l_pid == fl.l_pid
22106ca35587Sdholland && af->af_fl.l_type == fl.l_type) {
22116ca35587Sdholland break;
22126ca35587Sdholland }
22136ca35587Sdholland }
22146ca35587Sdholland
22156ca35587Sdholland if (!af) {
22166ca35587Sdholland mtx_unlock(&host->nh_lock);
22176ca35587Sdholland result->stat.stat = nlm4_denied;
22186ca35587Sdholland goto out;
22196ca35587Sdholland }
22206ca35587Sdholland
22216ca35587Sdholland error = nlm_cancel_async_lock(af);
22226ca35587Sdholland
22236ca35587Sdholland if (error) {
22246ca35587Sdholland result->stat.stat = nlm4_denied;
22256ca35587Sdholland } else {
22266ca35587Sdholland result->stat.stat = nlm4_granted;
22276ca35587Sdholland }
22286ca35587Sdholland
22296ca35587Sdholland mtx_unlock(&host->nh_lock);
22306ca35587Sdholland
22316ca35587Sdholland out:
22326ca35587Sdholland nlm_release_vfs_state(&vs);
22336ca35587Sdholland if (rpcp)
22346ca35587Sdholland *rpcp = nlm_host_get_rpc(host, TRUE);
22356ca35587Sdholland nlm_host_release(host);
22366ca35587Sdholland return (0);
22376ca35587Sdholland }
22386ca35587Sdholland
22396ca35587Sdholland int
nlm_do_unlock(nlm4_unlockargs * argp,nlm4_res * result,struct svc_req * rqstp,CLIENT ** rpcp)22406ca35587Sdholland nlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *result, struct svc_req *rqstp,
22416ca35587Sdholland CLIENT **rpcp)
22426ca35587Sdholland {
22436ca35587Sdholland fhandle_t fh;
22446ca35587Sdholland struct vfs_state vs;
22456ca35587Sdholland struct nlm_host *host;
22466ca35587Sdholland int error, sysid;
22476ca35587Sdholland struct flock fl;
22486ca35587Sdholland
22496ca35587Sdholland memset(result, 0, sizeof(*result));
22506ca35587Sdholland memset(&vs, 0, sizeof(vs));
22516ca35587Sdholland
22526ca35587Sdholland host = nlm_find_host_by_name(argp->alock.caller_name,
22536ca35587Sdholland svc_getrpccaller(rqstp), rqstp->rq_vers);
22546ca35587Sdholland if (!host) {
22556ca35587Sdholland result->stat.stat = nlm4_denied_nolocks;
22566ca35587Sdholland return (ENOMEM);
22576ca35587Sdholland }
22586ca35587Sdholland
22596ca35587Sdholland NLM_DEBUG(3, "nlm_do_unlock(): caller_name = %s (sysid = %d)\n",
22606ca35587Sdholland host->nh_caller_name, host->nh_sysid);
22616ca35587Sdholland
22626ca35587Sdholland nlm_check_expired_locks(host);
22636ca35587Sdholland sysid = host->nh_sysid;
22646ca35587Sdholland
22656ca35587Sdholland nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
22666ca35587Sdholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
22676ca35587Sdholland
22686ca35587Sdholland if (time_uptime < nlm_grace_threshold) {
22696ca35587Sdholland result->stat.stat = nlm4_denied_grace_period;
22706ca35587Sdholland goto out;
22716ca35587Sdholland }
22726ca35587Sdholland
22736ca35587Sdholland error = nlm_get_vfs_state(host, rqstp, &fh, &vs, (accmode_t)0);
22746ca35587Sdholland if (error) {
22756ca35587Sdholland result->stat.stat = nlm_convert_error(error);
22766ca35587Sdholland goto out;
22776ca35587Sdholland }
22786ca35587Sdholland
22796ca35587Sdholland fl.l_start = argp->alock.l_offset;
22806ca35587Sdholland fl.l_len = argp->alock.l_len;
22816ca35587Sdholland fl.l_pid = argp->alock.svid;
22826ca35587Sdholland fl.l_sysid = sysid;
22836ca35587Sdholland fl.l_whence = SEEK_SET;
22846ca35587Sdholland fl.l_type = F_UNLCK;
22856ca35587Sdholland error = VOP_ADVLOCK(vs.vs_vp, NULL, F_UNLCK, &fl, F_REMOTE);
22866ca35587Sdholland
22876ca35587Sdholland /*
22886ca35587Sdholland * Ignore the error - there is no result code for failure,
22896ca35587Sdholland * only for grace period.
22906ca35587Sdholland */
22916ca35587Sdholland result->stat.stat = nlm4_granted;
22926ca35587Sdholland
22936ca35587Sdholland out:
22946ca35587Sdholland nlm_release_vfs_state(&vs);
22956ca35587Sdholland if (rpcp)
22966ca35587Sdholland *rpcp = nlm_host_get_rpc(host, TRUE);
22976ca35587Sdholland nlm_host_release(host);
22986ca35587Sdholland return (0);
22996ca35587Sdholland }
23006ca35587Sdholland
23016ca35587Sdholland int
nlm_do_granted(nlm4_testargs * argp,nlm4_res * result,struct svc_req * rqstp,CLIENT ** rpcp)23026ca35587Sdholland nlm_do_granted(nlm4_testargs *argp, nlm4_res *result, struct svc_req *rqstp,
23036ca35587Sdholland
23046ca35587Sdholland CLIENT **rpcp)
23056ca35587Sdholland {
23066ca35587Sdholland struct nlm_host *host;
23076ca35587Sdholland struct nlm_waiting_lock *nw;
23086ca35587Sdholland
23096ca35587Sdholland memset(result, 0, sizeof(*result));
23106ca35587Sdholland
23116ca35587Sdholland host = nlm_find_host_by_addr(svc_getrpccaller(rqstp), rqstp->rq_vers);
23126ca35587Sdholland if (!host) {
23136ca35587Sdholland result->stat.stat = nlm4_denied_nolocks;
23146ca35587Sdholland return (ENOMEM);
23156ca35587Sdholland }
23166ca35587Sdholland
23176ca35587Sdholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
23186ca35587Sdholland result->stat.stat = nlm4_denied;
23196ca35587Sdholland KFAIL_POINT_CODE(DEBUG_FP, nlm_deny_grant, goto out);
23206ca35587Sdholland
23216ca35587Sdholland mtx_lock(&nlm_global_lock);
23226ca35587Sdholland TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
23236ca35587Sdholland if (!nw->nw_waiting)
23246ca35587Sdholland continue;
23256ca35587Sdholland if (argp->alock.svid == nw->nw_lock.svid
23266ca35587Sdholland && argp->alock.l_offset == nw->nw_lock.l_offset
23276ca35587Sdholland && argp->alock.l_len == nw->nw_lock.l_len
23286ca35587Sdholland && argp->alock.fh.n_len == nw->nw_lock.fh.n_len
23296ca35587Sdholland && !memcmp(argp->alock.fh.n_bytes, nw->nw_lock.fh.n_bytes,
23306ca35587Sdholland nw->nw_lock.fh.n_len)) {
23316ca35587Sdholland nw->nw_waiting = FALSE;
23326ca35587Sdholland wakeup(nw);
23336ca35587Sdholland result->stat.stat = nlm4_granted;
23346ca35587Sdholland break;
23356ca35587Sdholland }
23366ca35587Sdholland }
23376ca35587Sdholland mtx_unlock(&nlm_global_lock);
23386ca35587Sdholland
23396ca35587Sdholland out:
23406ca35587Sdholland if (rpcp)
23416ca35587Sdholland *rpcp = nlm_host_get_rpc(host, TRUE);
23426ca35587Sdholland nlm_host_release(host);
23436ca35587Sdholland return (0);
23446ca35587Sdholland }
23456ca35587Sdholland
23466ca35587Sdholland void
nlm_do_granted_res(nlm4_res * argp,struct svc_req * rqstp)23476ca35587Sdholland nlm_do_granted_res(nlm4_res *argp, struct svc_req *rqstp)
23486ca35587Sdholland {
23496ca35587Sdholland struct nlm_host *host = NULL;
23506ca35587Sdholland struct nlm_async_lock *af = NULL;
23516ca35587Sdholland int error;
23526ca35587Sdholland
23536ca35587Sdholland if (argp->cookie.n_len != sizeof(struct nlm_grantcookie)) {
23546ca35587Sdholland NLM_DEBUG(1, "NLM: bogus grant cookie");
23556ca35587Sdholland goto out;
23566ca35587Sdholland }
23576ca35587Sdholland
23586ca35587Sdholland host = nlm_find_host_by_sysid(ng_sysid(&argp->cookie));
23596ca35587Sdholland if (!host) {
23606ca35587Sdholland NLM_DEBUG(1, "NLM: Unknown host rejected our grant");
23616ca35587Sdholland goto out;
23626ca35587Sdholland }
23636ca35587Sdholland
23646ca35587Sdholland mtx_lock(&host->nh_lock);
23656ca35587Sdholland TAILQ_FOREACH(af, &host->nh_granted, af_link)
23666ca35587Sdholland if (ng_cookie(&argp->cookie) ==
23676ca35587Sdholland ng_cookie(&af->af_granted.cookie))
23686ca35587Sdholland break;
23696ca35587Sdholland if (af)
23706ca35587Sdholland TAILQ_REMOVE(&host->nh_granted, af, af_link);
23716ca35587Sdholland mtx_unlock(&host->nh_lock);
23726ca35587Sdholland
23736ca35587Sdholland if (!af) {
23746ca35587Sdholland NLM_DEBUG(1, "NLM: host %s (sysid %d) replied to our grant "
23756ca35587Sdholland "with unrecognized cookie %d:%d", host->nh_caller_name,
23766ca35587Sdholland host->nh_sysid, ng_sysid(&argp->cookie),
23776ca35587Sdholland ng_cookie(&argp->cookie));
23786ca35587Sdholland goto out;
23796ca35587Sdholland }
23806ca35587Sdholland
23816ca35587Sdholland if (argp->stat.stat != nlm4_granted) {
23826ca35587Sdholland af->af_fl.l_type = F_UNLCK;
23836ca35587Sdholland error = VOP_ADVLOCK(af->af_vp, NULL, F_UNLCK, &af->af_fl, F_REMOTE);
23846ca35587Sdholland if (error) {
23856ca35587Sdholland NLM_DEBUG(1, "NLM: host %s (sysid %d) rejected our grant "
23866ca35587Sdholland "and we failed to unlock (%d)", host->nh_caller_name,
23876ca35587Sdholland host->nh_sysid, error);
23886ca35587Sdholland goto out;
23896ca35587Sdholland }
23906ca35587Sdholland
23916ca35587Sdholland NLM_DEBUG(5, "NLM: async lock %p rejected by host %s (sysid %d)",
23926ca35587Sdholland af, host->nh_caller_name, host->nh_sysid);
23936ca35587Sdholland } else {
23946ca35587Sdholland NLM_DEBUG(5, "NLM: async lock %p accepted by host %s (sysid %d)",
23956ca35587Sdholland af, host->nh_caller_name, host->nh_sysid);
23966ca35587Sdholland }
23976ca35587Sdholland
23986ca35587Sdholland out:
23996ca35587Sdholland if (af)
24006ca35587Sdholland nlm_free_async_lock(af);
24016ca35587Sdholland if (host)
24026ca35587Sdholland nlm_host_release(host);
24036ca35587Sdholland }
24046ca35587Sdholland
24056ca35587Sdholland void
nlm_do_free_all(nlm4_notify * argp)24066ca35587Sdholland nlm_do_free_all(nlm4_notify *argp)
24076ca35587Sdholland {
24086ca35587Sdholland struct nlm_host *host, *thost;
24096ca35587Sdholland
24106ca35587Sdholland TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, thost) {
24116ca35587Sdholland if (!strcmp(host->nh_caller_name, argp->name))
24126ca35587Sdholland nlm_host_notify(host, argp->state);
24136ca35587Sdholland }
24146ca35587Sdholland }
24156ca35587Sdholland
24166ca35587Sdholland /*
24176ca35587Sdholland * Kernel module glue
24186ca35587Sdholland */
24196ca35587Sdholland static int
nfslockd_modevent(module_t mod,int type,void * data)24206ca35587Sdholland nfslockd_modevent(module_t mod, int type, void *data)
24216ca35587Sdholland {
24226ca35587Sdholland
24236ca35587Sdholland switch (type) {
24246ca35587Sdholland case MOD_LOAD:
24256ca35587Sdholland return (0);
24266ca35587Sdholland case MOD_UNLOAD:
24276ca35587Sdholland /* The NLM module cannot be safely unloaded. */
24286ca35587Sdholland /* FALLTHROUGH */
24296ca35587Sdholland default:
24306ca35587Sdholland return (EOPNOTSUPP);
24316ca35587Sdholland }
24326ca35587Sdholland }
24336ca35587Sdholland static moduledata_t nfslockd_mod = {
24346ca35587Sdholland "nfslockd",
24356ca35587Sdholland nfslockd_modevent,
24366ca35587Sdholland NULL,
24376ca35587Sdholland };
24386ca35587Sdholland DECLARE_MODULE(nfslockd, nfslockd_mod, SI_SUB_VFS, SI_ORDER_ANY);
24396ca35587Sdholland
24406ca35587Sdholland /* So that loader and kldload(2) can find us, wherever we are.. */
24416ca35587Sdholland MODULE_DEPEND(nfslockd, krpc, 1, 1, 1);
24426ca35587Sdholland MODULE_DEPEND(nfslockd, nfslock, 1, 1, 1);
24436ca35587Sdholland MODULE_VERSION(nfslockd, 1);
2444