xref: /netbsd-src/sys/fs/nfs/nlm/nlm_prot_impl.c (revision a002c830eb91285acca39715ad623b8a2e676b81)
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