nlm_prot_impl.c revision 1.4 1 1.4 pgoyette /* $NetBSD: nlm_prot_impl.c,v 1.4 2016/12/13 21:58:17 pgoyette Exp $ */
2 1.1 dholland /*-
3 1.1 dholland * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
4 1.1 dholland * Authors: Doug Rabson <dfr (at) rabson.org>
5 1.1 dholland * Developed with Red Inc: Alfred Perlstein <alfred (at) freebsd.org>
6 1.1 dholland *
7 1.1 dholland * Redistribution and use in source and binary forms, with or without
8 1.1 dholland * modification, are permitted provided that the following conditions
9 1.1 dholland * are met:
10 1.1 dholland * 1. Redistributions of source code must retain the above copyright
11 1.1 dholland * notice, this list of conditions and the following disclaimer.
12 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 dholland * notice, this list of conditions and the following disclaimer in the
14 1.1 dholland * documentation and/or other materials provided with the distribution.
15 1.1 dholland *
16 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 dholland * SUCH DAMAGE.
27 1.1 dholland */
28 1.1 dholland
29 1.4 pgoyette #ifdef _KERNEL_OPT
30 1.1 dholland #include "opt_inet6.h"
31 1.4 pgoyette #endif
32 1.1 dholland
33 1.1 dholland #include <sys/cdefs.h>
34 1.3 pgoyette /* __FBSDID("FreeBSD: head/sys/nlm/nlm_prot_impl.c 302216 2016-06-26 20:08:42Z kib "); */
35 1.4 pgoyette __RCSID("$NetBSD: nlm_prot_impl.c,v 1.4 2016/12/13 21:58:17 pgoyette Exp $");
36 1.1 dholland
37 1.1 dholland #include <sys/param.h>
38 1.1 dholland #include <sys/fail.h>
39 1.1 dholland #include <sys/fcntl.h>
40 1.1 dholland #include <sys/kernel.h>
41 1.1 dholland #include <sys/kthread.h>
42 1.1 dholland #include <sys/lockf.h>
43 1.1 dholland #include <sys/malloc.h>
44 1.1 dholland #include <sys/mount.h>
45 1.1 dholland #include <sys/proc.h>
46 1.1 dholland #include <sys/socket.h>
47 1.1 dholland #include <sys/socketvar.h>
48 1.1 dholland #include <sys/syscall.h>
49 1.1 dholland #include <sys/sysctl.h>
50 1.1 dholland #include <sys/sysent.h>
51 1.1 dholland #include <sys/syslog.h>
52 1.1 dholland #include <sys/sysproto.h>
53 1.1 dholland #include <sys/systm.h>
54 1.1 dholland #include <sys/taskqueue.h>
55 1.1 dholland #include <sys/unistd.h>
56 1.1 dholland #include <sys/vnode.h>
57 1.1 dholland
58 1.4 pgoyette #if 0
59 1.4 pgoyette #if __FreeBSD_version >= 700000
60 1.4 pgoyette #include <sys/priv.h>
61 1.4 pgoyette #endif
62 1.4 pgoyette #endif
63 1.4 pgoyette
64 1.4 pgoyette #include <fs/nfs/common/nfsproto.h>
65 1.4 pgoyette #include <fs/nfs/common/nfs_lock.h>
66 1.4 pgoyette
67 1.4 pgoyette #include <fs/nfs/nlm/nlm_prot.h>
68 1.4 pgoyette #include <fs/nfs/nlm/sm_inter.h>
69 1.4 pgoyette #include <fs/nfs/nlm/nlm.h>
70 1.1 dholland
71 1.1 dholland #include <rpc/rpc_com.h>
72 1.1 dholland #include <rpc/rpcb_prot.h>
73 1.1 dholland
74 1.1 dholland MALLOC_DEFINE(M_NLM, "NLM", "Network Lock Manager");
75 1.1 dholland
76 1.1 dholland /*
77 1.1 dholland * If a host is inactive (and holds no locks) for this amount of
78 1.1 dholland * seconds, we consider it idle and stop tracking it.
79 1.1 dholland */
80 1.1 dholland #define NLM_IDLE_TIMEOUT 30
81 1.1 dholland
82 1.1 dholland /*
83 1.1 dholland * We check the host list for idle every few seconds.
84 1.1 dholland */
85 1.1 dholland #define NLM_IDLE_PERIOD 5
86 1.1 dholland
87 1.1 dholland /*
88 1.1 dholland * We only look for GRANTED_RES messages for a little while.
89 1.1 dholland */
90 1.1 dholland #define NLM_EXPIRE_TIMEOUT 10
91 1.1 dholland
92 1.1 dholland /*
93 1.1 dholland * Support for sysctl vfs.nlm.sysid
94 1.1 dholland */
95 1.1 dholland static SYSCTL_NODE(_vfs, OID_AUTO, nlm, CTLFLAG_RW, NULL,
96 1.1 dholland "Network Lock Manager");
97 1.1 dholland static SYSCTL_NODE(_vfs_nlm, OID_AUTO, sysid, CTLFLAG_RW, NULL, "");
98 1.1 dholland
99 1.1 dholland /*
100 1.1 dholland * Syscall hooks
101 1.1 dholland */
102 1.1 dholland static int nlm_syscall_offset = SYS_nlm_syscall;
103 1.1 dholland static struct sysent nlm_syscall_prev_sysent;
104 1.1 dholland #if __FreeBSD_version < 700000
105 1.1 dholland static struct sysent nlm_syscall_sysent = {
106 1.1 dholland (sizeof(struct nlm_syscall_args) / sizeof(register_t)) | SYF_MPSAFE,
107 1.1 dholland (sy_call_t *) nlm_syscall
108 1.1 dholland };
109 1.1 dholland #else
110 1.1 dholland MAKE_SYSENT(nlm_syscall);
111 1.1 dholland #endif
112 1.1 dholland static bool_t nlm_syscall_registered = FALSE;
113 1.1 dholland
114 1.1 dholland /*
115 1.1 dholland * Debug level passed in from userland. We also support a sysctl hook
116 1.1 dholland * so that it can be changed on a live system.
117 1.1 dholland */
118 1.1 dholland static int nlm_debug_level;
119 1.1 dholland SYSCTL_INT(_debug, OID_AUTO, nlm_debug, CTLFLAG_RW, &nlm_debug_level, 0, "");
120 1.1 dholland
121 1.1 dholland #define NLM_DEBUG(_level, args...) \
122 1.1 dholland do { \
123 1.1 dholland if (nlm_debug_level >= (_level)) \
124 1.1 dholland log(LOG_DEBUG, args); \
125 1.1 dholland } while(0)
126 1.1 dholland #define NLM_ERR(args...) \
127 1.1 dholland do { \
128 1.1 dholland log(LOG_ERR, args); \
129 1.1 dholland } while(0)
130 1.1 dholland
131 1.1 dholland /*
132 1.1 dholland * Grace period handling. The value of nlm_grace_threshold is the
133 1.1 dholland * value of time_uptime after which we are serving requests normally.
134 1.1 dholland */
135 1.1 dholland static time_t nlm_grace_threshold;
136 1.1 dholland
137 1.1 dholland /*
138 1.1 dholland * We check for idle hosts if time_uptime is greater than
139 1.1 dholland * nlm_next_idle_check,
140 1.1 dholland */
141 1.1 dholland static time_t nlm_next_idle_check;
142 1.1 dholland
143 1.1 dholland /*
144 1.1 dholland * A flag to indicate the server is already running.
145 1.1 dholland */
146 1.1 dholland static int nlm_is_running;
147 1.1 dholland
148 1.1 dholland /*
149 1.1 dholland * A socket to use for RPC - shared by all IPv4 RPC clients.
150 1.1 dholland */
151 1.1 dholland static struct socket *nlm_socket;
152 1.1 dholland
153 1.1 dholland #ifdef INET6
154 1.1 dholland
155 1.1 dholland /*
156 1.1 dholland * A socket to use for RPC - shared by all IPv6 RPC clients.
157 1.1 dholland */
158 1.1 dholland static struct socket *nlm_socket6;
159 1.1 dholland
160 1.1 dholland #endif
161 1.1 dholland
162 1.1 dholland /*
163 1.1 dholland * An RPC client handle that can be used to communicate with the local
164 1.1 dholland * NSM.
165 1.1 dholland */
166 1.1 dholland static CLIENT *nlm_nsm;
167 1.1 dholland
168 1.1 dholland /*
169 1.1 dholland * An AUTH handle for the server's creds.
170 1.1 dholland */
171 1.1 dholland static AUTH *nlm_auth;
172 1.1 dholland
173 1.1 dholland /*
174 1.1 dholland * A zero timeval for sending async RPC messages.
175 1.1 dholland */
176 1.1 dholland struct timeval nlm_zero_tv = { 0, 0 };
177 1.1 dholland
178 1.1 dholland /*
179 1.1 dholland * The local NSM state number
180 1.1 dholland */
181 1.1 dholland int nlm_nsm_state;
182 1.1 dholland
183 1.1 dholland
184 1.1 dholland /*
185 1.1 dholland * A lock to protect the host list and waiting lock list.
186 1.1 dholland */
187 1.1 dholland static struct mtx nlm_global_lock;
188 1.1 dholland
189 1.1 dholland /*
190 1.1 dholland * Locks:
191 1.1 dholland * (l) locked by nh_lock
192 1.1 dholland * (s) only accessed via server RPC which is single threaded
193 1.1 dholland * (g) locked by nlm_global_lock
194 1.1 dholland * (c) const until freeing
195 1.1 dholland * (a) modified using atomic ops
196 1.1 dholland */
197 1.1 dholland
198 1.1 dholland /*
199 1.1 dholland * A pending client-side lock request, stored on the nlm_waiting_locks
200 1.1 dholland * list.
201 1.1 dholland */
202 1.1 dholland struct nlm_waiting_lock {
203 1.1 dholland TAILQ_ENTRY(nlm_waiting_lock) nw_link; /* (g) */
204 1.1 dholland bool_t nw_waiting; /* (g) */
205 1.1 dholland nlm4_lock nw_lock; /* (c) */
206 1.1 dholland union nfsfh nw_fh; /* (c) */
207 1.1 dholland struct vnode *nw_vp; /* (c) */
208 1.1 dholland };
209 1.1 dholland TAILQ_HEAD(nlm_waiting_lock_list, nlm_waiting_lock);
210 1.1 dholland
211 1.1 dholland struct nlm_waiting_lock_list nlm_waiting_locks; /* (g) */
212 1.1 dholland
213 1.1 dholland /*
214 1.1 dholland * A pending server-side asynchronous lock request, stored on the
215 1.1 dholland * nh_pending list of the NLM host.
216 1.1 dholland */
217 1.1 dholland struct nlm_async_lock {
218 1.1 dholland TAILQ_ENTRY(nlm_async_lock) af_link; /* (l) host's list of locks */
219 1.1 dholland struct task af_task; /* (c) async callback details */
220 1.1 dholland void *af_cookie; /* (l) lock manager cancel token */
221 1.1 dholland struct vnode *af_vp; /* (l) vnode to lock */
222 1.1 dholland struct flock af_fl; /* (c) lock details */
223 1.1 dholland struct nlm_host *af_host; /* (c) host which is locking */
224 1.1 dholland CLIENT *af_rpc; /* (c) rpc client to send message */
225 1.1 dholland nlm4_testargs af_granted; /* (c) notification details */
226 1.1 dholland time_t af_expiretime; /* (c) notification time */
227 1.1 dholland };
228 1.1 dholland TAILQ_HEAD(nlm_async_lock_list, nlm_async_lock);
229 1.1 dholland
230 1.1 dholland /*
231 1.1 dholland * NLM host.
232 1.1 dholland */
233 1.1 dholland enum nlm_host_state {
234 1.1 dholland NLM_UNMONITORED,
235 1.1 dholland NLM_MONITORED,
236 1.1 dholland NLM_MONITOR_FAILED,
237 1.1 dholland NLM_RECOVERING
238 1.1 dholland };
239 1.1 dholland
240 1.1 dholland struct nlm_rpc {
241 1.1 dholland CLIENT *nr_client; /* (l) RPC client handle */
242 1.1 dholland time_t nr_create_time; /* (l) when client was created */
243 1.1 dholland };
244 1.1 dholland
245 1.1 dholland struct nlm_host {
246 1.1 dholland struct mtx nh_lock;
247 1.1 dholland volatile u_int nh_refs; /* (a) reference count */
248 1.1 dholland TAILQ_ENTRY(nlm_host) nh_link; /* (g) global list of hosts */
249 1.1 dholland char nh_caller_name[MAXNAMELEN]; /* (c) printable name of host */
250 1.1 dholland uint32_t nh_sysid; /* (c) our allocaed system ID */
251 1.1 dholland char nh_sysid_string[10]; /* (c) string rep. of sysid */
252 1.1 dholland struct sockaddr_storage nh_addr; /* (s) remote address of host */
253 1.1 dholland struct nlm_rpc nh_srvrpc; /* (l) RPC for server replies */
254 1.1 dholland struct nlm_rpc nh_clntrpc; /* (l) RPC for client requests */
255 1.1 dholland rpcvers_t nh_vers; /* (s) NLM version of host */
256 1.1 dholland int nh_state; /* (s) last seen NSM state of host */
257 1.1 dholland enum nlm_host_state nh_monstate; /* (l) local NSM monitoring state */
258 1.1 dholland time_t nh_idle_timeout; /* (s) Time at which host is idle */
259 1.1 dholland struct sysctl_ctx_list nh_sysctl; /* (c) vfs.nlm.sysid nodes */
260 1.1 dholland uint32_t nh_grantcookie; /* (l) grant cookie counter */
261 1.1 dholland struct nlm_async_lock_list nh_pending; /* (l) pending async locks */
262 1.1 dholland struct nlm_async_lock_list nh_granted; /* (l) granted locks */
263 1.1 dholland struct nlm_async_lock_list nh_finished; /* (l) finished async locks */
264 1.1 dholland };
265 1.1 dholland TAILQ_HEAD(nlm_host_list, nlm_host);
266 1.1 dholland
267 1.1 dholland static struct nlm_host_list nlm_hosts; /* (g) */
268 1.1 dholland static uint32_t nlm_next_sysid = 1; /* (g) */
269 1.1 dholland
270 1.1 dholland static void nlm_host_unmonitor(struct nlm_host *);
271 1.1 dholland
272 1.1 dholland struct nlm_grantcookie {
273 1.1 dholland uint32_t ng_sysid;
274 1.1 dholland uint32_t ng_cookie;
275 1.1 dholland };
276 1.1 dholland
277 1.1 dholland static inline uint32_t
278 1.1 dholland ng_sysid(struct netobj *src)
279 1.1 dholland {
280 1.1 dholland
281 1.1 dholland return ((struct nlm_grantcookie *)src->n_bytes)->ng_sysid;
282 1.1 dholland }
283 1.1 dholland
284 1.1 dholland static inline uint32_t
285 1.1 dholland ng_cookie(struct netobj *src)
286 1.1 dholland {
287 1.1 dholland
288 1.1 dholland return ((struct nlm_grantcookie *)src->n_bytes)->ng_cookie;
289 1.1 dholland }
290 1.1 dholland
291 1.1 dholland /**********************************************************************/
292 1.1 dholland
293 1.1 dholland /*
294 1.1 dholland * Initialise NLM globals.
295 1.1 dholland */
296 1.1 dholland static void
297 1.1 dholland nlm_init(void *dummy)
298 1.1 dholland {
299 1.1 dholland int error;
300 1.1 dholland
301 1.1 dholland mtx_init(&nlm_global_lock, "nlm_global_lock", NULL, MTX_DEF);
302 1.1 dholland TAILQ_INIT(&nlm_waiting_locks);
303 1.1 dholland TAILQ_INIT(&nlm_hosts);
304 1.1 dholland
305 1.1 dholland error = syscall_register(&nlm_syscall_offset, &nlm_syscall_sysent,
306 1.3 pgoyette &nlm_syscall_prev_sysent, SY_THR_STATIC_KLD);
307 1.1 dholland if (error)
308 1.1 dholland NLM_ERR("Can't register NLM syscall\n");
309 1.1 dholland else
310 1.1 dholland nlm_syscall_registered = TRUE;
311 1.1 dholland }
312 1.1 dholland SYSINIT(nlm_init, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_init, NULL);
313 1.1 dholland
314 1.1 dholland static void
315 1.1 dholland nlm_uninit(void *dummy)
316 1.1 dholland {
317 1.1 dholland
318 1.1 dholland if (nlm_syscall_registered)
319 1.1 dholland syscall_deregister(&nlm_syscall_offset,
320 1.1 dholland &nlm_syscall_prev_sysent);
321 1.1 dholland }
322 1.1 dholland SYSUNINIT(nlm_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_uninit, NULL);
323 1.1 dholland
324 1.1 dholland /*
325 1.1 dholland * Create a netobj from an arbitrary source.
326 1.1 dholland */
327 1.1 dholland void
328 1.1 dholland nlm_make_netobj(struct netobj *dst, caddr_t src, size_t srcsize,
329 1.1 dholland struct malloc_type *type)
330 1.1 dholland {
331 1.1 dholland
332 1.1 dholland dst->n_len = srcsize;
333 1.1 dholland dst->n_bytes = malloc(srcsize, type, M_WAITOK);
334 1.1 dholland memcpy(dst->n_bytes, src, srcsize);
335 1.1 dholland }
336 1.1 dholland
337 1.1 dholland /*
338 1.1 dholland * Copy a struct netobj.
339 1.1 dholland */
340 1.1 dholland void
341 1.1 dholland nlm_copy_netobj(struct netobj *dst, struct netobj *src,
342 1.1 dholland struct malloc_type *type)
343 1.1 dholland {
344 1.1 dholland
345 1.1 dholland nlm_make_netobj(dst, src->n_bytes, src->n_len, type);
346 1.1 dholland }
347 1.1 dholland
348 1.1 dholland
349 1.1 dholland /*
350 1.1 dholland * Create an RPC client handle for the given (address,prog,vers)
351 1.1 dholland * triple using UDP.
352 1.1 dholland */
353 1.1 dholland static CLIENT *
354 1.1 dholland nlm_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers)
355 1.1 dholland {
356 1.1 dholland char *wchan = "nlmrcv";
357 1.1 dholland const char* protofmly;
358 1.1 dholland struct sockaddr_storage ss;
359 1.1 dholland struct socket *so;
360 1.1 dholland CLIENT *rpcb;
361 1.1 dholland struct timeval timo;
362 1.1 dholland RPCB parms;
363 1.1 dholland char *uaddr;
364 1.1 dholland enum clnt_stat stat = RPC_SUCCESS;
365 1.1 dholland int rpcvers = RPCBVERS4;
366 1.1 dholland bool_t do_tcp = FALSE;
367 1.1 dholland bool_t tryagain = FALSE;
368 1.1 dholland struct portmap mapping;
369 1.1 dholland u_short port = 0;
370 1.1 dholland
371 1.1 dholland /*
372 1.1 dholland * First we need to contact the remote RPCBIND service to find
373 1.1 dholland * the right port.
374 1.1 dholland */
375 1.1 dholland memcpy(&ss, sa, sa->sa_len);
376 1.1 dholland switch (ss.ss_family) {
377 1.1 dholland case AF_INET:
378 1.1 dholland ((struct sockaddr_in *)&ss)->sin_port = htons(111);
379 1.1 dholland protofmly = "inet";
380 1.1 dholland so = nlm_socket;
381 1.1 dholland break;
382 1.1 dholland
383 1.1 dholland #ifdef INET6
384 1.1 dholland case AF_INET6:
385 1.1 dholland ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111);
386 1.1 dholland protofmly = "inet6";
387 1.1 dholland so = nlm_socket6;
388 1.1 dholland break;
389 1.1 dholland #endif
390 1.1 dholland
391 1.1 dholland default:
392 1.1 dholland /*
393 1.1 dholland * Unsupported address family - fail.
394 1.1 dholland */
395 1.1 dholland return (NULL);
396 1.1 dholland }
397 1.1 dholland
398 1.1 dholland rpcb = clnt_dg_create(so, (struct sockaddr *)&ss,
399 1.1 dholland RPCBPROG, rpcvers, 0, 0);
400 1.1 dholland if (!rpcb)
401 1.1 dholland return (NULL);
402 1.1 dholland
403 1.1 dholland try_tcp:
404 1.1 dholland parms.r_prog = prog;
405 1.1 dholland parms.r_vers = vers;
406 1.1 dholland if (do_tcp)
407 1.1 dholland parms.r_netid = "tcp";
408 1.1 dholland else
409 1.1 dholland parms.r_netid = "udp";
410 1.1 dholland parms.r_addr = "";
411 1.1 dholland parms.r_owner = "";
412 1.1 dholland
413 1.1 dholland /*
414 1.1 dholland * Use the default timeout.
415 1.1 dholland */
416 1.1 dholland timo.tv_sec = 25;
417 1.1 dholland timo.tv_usec = 0;
418 1.1 dholland again:
419 1.1 dholland switch (rpcvers) {
420 1.1 dholland case RPCBVERS4:
421 1.1 dholland case RPCBVERS:
422 1.1 dholland /*
423 1.1 dholland * Try RPCBIND 4 then 3.
424 1.1 dholland */
425 1.1 dholland uaddr = NULL;
426 1.1 dholland stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR,
427 1.1 dholland (xdrproc_t) xdr_rpcb, &parms,
428 1.1 dholland (xdrproc_t) xdr_wrapstring, &uaddr, timo);
429 1.1 dholland if (stat == RPC_SUCCESS) {
430 1.1 dholland /*
431 1.1 dholland * We have a reply from the remote RPCBIND - turn it
432 1.1 dholland * into an appropriate address and make a new client
433 1.1 dholland * that can talk to the remote NLM.
434 1.1 dholland *
435 1.1 dholland * XXX fixup IPv6 scope ID.
436 1.1 dholland */
437 1.1 dholland struct netbuf *a;
438 1.1 dholland a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr);
439 1.1 dholland if (!a) {
440 1.1 dholland tryagain = TRUE;
441 1.1 dholland } else {
442 1.1 dholland tryagain = FALSE;
443 1.1 dholland memcpy(&ss, a->buf, a->len);
444 1.1 dholland free(a->buf, M_RPC);
445 1.1 dholland free(a, M_RPC);
446 1.1 dholland xdr_free((xdrproc_t) xdr_wrapstring, &uaddr);
447 1.1 dholland }
448 1.1 dholland }
449 1.1 dholland if (tryagain || stat == RPC_PROGVERSMISMATCH) {
450 1.1 dholland if (rpcvers == RPCBVERS4)
451 1.1 dholland rpcvers = RPCBVERS;
452 1.1 dholland else if (rpcvers == RPCBVERS)
453 1.1 dholland rpcvers = PMAPVERS;
454 1.1 dholland CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers);
455 1.1 dholland goto again;
456 1.1 dholland }
457 1.1 dholland break;
458 1.1 dholland case PMAPVERS:
459 1.1 dholland /*
460 1.1 dholland * Try portmap.
461 1.1 dholland */
462 1.1 dholland mapping.pm_prog = parms.r_prog;
463 1.1 dholland mapping.pm_vers = parms.r_vers;
464 1.1 dholland mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP;
465 1.1 dholland mapping.pm_port = 0;
466 1.1 dholland
467 1.1 dholland stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT,
468 1.1 dholland (xdrproc_t) xdr_portmap, &mapping,
469 1.1 dholland (xdrproc_t) xdr_u_short, &port, timo);
470 1.1 dholland
471 1.1 dholland if (stat == RPC_SUCCESS) {
472 1.1 dholland switch (ss.ss_family) {
473 1.1 dholland case AF_INET:
474 1.1 dholland ((struct sockaddr_in *)&ss)->sin_port =
475 1.1 dholland htons(port);
476 1.1 dholland break;
477 1.1 dholland
478 1.1 dholland #ifdef INET6
479 1.1 dholland case AF_INET6:
480 1.1 dholland ((struct sockaddr_in6 *)&ss)->sin6_port =
481 1.1 dholland htons(port);
482 1.1 dholland break;
483 1.1 dholland #endif
484 1.1 dholland }
485 1.1 dholland }
486 1.1 dholland break;
487 1.1 dholland default:
488 1.1 dholland panic("invalid rpcvers %d", rpcvers);
489 1.1 dholland }
490 1.1 dholland /*
491 1.1 dholland * We may have a positive response from the portmapper, but the NLM
492 1.1 dholland * service was not found. Make sure we received a valid port.
493 1.1 dholland */
494 1.1 dholland switch (ss.ss_family) {
495 1.1 dholland case AF_INET:
496 1.1 dholland port = ((struct sockaddr_in *)&ss)->sin_port;
497 1.1 dholland break;
498 1.1 dholland #ifdef INET6
499 1.1 dholland case AF_INET6:
500 1.1 dholland port = ((struct sockaddr_in6 *)&ss)->sin6_port;
501 1.1 dholland break;
502 1.1 dholland #endif
503 1.1 dholland }
504 1.1 dholland if (stat != RPC_SUCCESS || !port) {
505 1.1 dholland /*
506 1.1 dholland * If we were able to talk to rpcbind or portmap, but the udp
507 1.1 dholland * variant wasn't available, ask about tcp.
508 1.1 dholland *
509 1.1 dholland * XXX - We could also check for a TCP portmapper, but
510 1.1 dholland * if the host is running a portmapper at all, we should be able
511 1.1 dholland * to hail it over UDP.
512 1.1 dholland */
513 1.1 dholland if (stat == RPC_SUCCESS && !do_tcp) {
514 1.1 dholland do_tcp = TRUE;
515 1.1 dholland goto try_tcp;
516 1.1 dholland }
517 1.1 dholland
518 1.1 dholland /* Otherwise, bad news. */
519 1.1 dholland NLM_ERR("NLM: failed to contact remote rpcbind, "
520 1.1 dholland "stat = %d, port = %d\n", (int) stat, port);
521 1.1 dholland CLNT_DESTROY(rpcb);
522 1.1 dholland return (NULL);
523 1.1 dholland }
524 1.1 dholland
525 1.1 dholland if (do_tcp) {
526 1.1 dholland /*
527 1.1 dholland * Destroy the UDP client we used to speak to rpcbind and
528 1.1 dholland * recreate as a TCP client.
529 1.1 dholland */
530 1.1 dholland struct netconfig *nconf = NULL;
531 1.1 dholland
532 1.1 dholland CLNT_DESTROY(rpcb);
533 1.1 dholland
534 1.1 dholland switch (ss.ss_family) {
535 1.1 dholland case AF_INET:
536 1.1 dholland nconf = getnetconfigent("tcp");
537 1.1 dholland break;
538 1.1 dholland #ifdef INET6
539 1.1 dholland case AF_INET6:
540 1.1 dholland nconf = getnetconfigent("tcp6");
541 1.1 dholland break;
542 1.1 dholland #endif
543 1.1 dholland }
544 1.1 dholland
545 1.1 dholland rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss,
546 1.1 dholland prog, vers, 0, 0);
547 1.1 dholland CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan);
548 1.1 dholland rpcb->cl_auth = nlm_auth;
549 1.1 dholland
550 1.1 dholland } else {
551 1.1 dholland /*
552 1.1 dholland * Re-use the client we used to speak to rpcbind.
553 1.1 dholland */
554 1.1 dholland CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss);
555 1.1 dholland CLNT_CONTROL(rpcb, CLSET_PROG, &prog);
556 1.1 dholland CLNT_CONTROL(rpcb, CLSET_VERS, &vers);
557 1.1 dholland CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan);
558 1.1 dholland rpcb->cl_auth = nlm_auth;
559 1.1 dholland }
560 1.1 dholland
561 1.1 dholland return (rpcb);
562 1.1 dholland }
563 1.1 dholland
564 1.1 dholland /*
565 1.1 dholland * This async callback after when an async lock request has been
566 1.1 dholland * granted. We notify the host which initiated the request.
567 1.1 dholland */
568 1.1 dholland static void
569 1.1 dholland nlm_lock_callback(void *arg, int pending)
570 1.1 dholland {
571 1.1 dholland struct nlm_async_lock *af = (struct nlm_async_lock *) arg;
572 1.1 dholland struct rpc_callextra ext;
573 1.1 dholland
574 1.1 dholland NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) granted,"
575 1.1 dholland " cookie %d:%d\n", af, af->af_host->nh_caller_name,
576 1.1 dholland af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie),
577 1.1 dholland ng_cookie(&af->af_granted.cookie));
578 1.1 dholland
579 1.1 dholland /*
580 1.1 dholland * Send the results back to the host.
581 1.1 dholland *
582 1.1 dholland * Note: there is a possible race here with nlm_host_notify
583 1.1 dholland * destroying the RPC client. To avoid problems, the first
584 1.1 dholland * thing nlm_host_notify does is to cancel pending async lock
585 1.1 dholland * requests.
586 1.1 dholland */
587 1.1 dholland memset(&ext, 0, sizeof(ext));
588 1.1 dholland ext.rc_auth = nlm_auth;
589 1.1 dholland if (af->af_host->nh_vers == NLM_VERS4) {
590 1.1 dholland nlm4_granted_msg_4(&af->af_granted,
591 1.1 dholland NULL, af->af_rpc, &ext, nlm_zero_tv);
592 1.1 dholland } else {
593 1.1 dholland /*
594 1.1 dholland * Back-convert to legacy protocol
595 1.1 dholland */
596 1.1 dholland nlm_testargs granted;
597 1.1 dholland granted.cookie = af->af_granted.cookie;
598 1.1 dholland granted.exclusive = af->af_granted.exclusive;
599 1.1 dholland granted.alock.caller_name =
600 1.1 dholland af->af_granted.alock.caller_name;
601 1.1 dholland granted.alock.fh = af->af_granted.alock.fh;
602 1.1 dholland granted.alock.oh = af->af_granted.alock.oh;
603 1.1 dholland granted.alock.svid = af->af_granted.alock.svid;
604 1.1 dholland granted.alock.l_offset =
605 1.1 dholland af->af_granted.alock.l_offset;
606 1.1 dholland granted.alock.l_len =
607 1.1 dholland af->af_granted.alock.l_len;
608 1.1 dholland
609 1.1 dholland nlm_granted_msg_1(&granted,
610 1.1 dholland NULL, af->af_rpc, &ext, nlm_zero_tv);
611 1.1 dholland }
612 1.1 dholland
613 1.1 dholland /*
614 1.1 dholland * Move this entry to the nh_granted list.
615 1.1 dholland */
616 1.1 dholland af->af_expiretime = time_uptime + NLM_EXPIRE_TIMEOUT;
617 1.1 dholland mtx_lock(&af->af_host->nh_lock);
618 1.1 dholland TAILQ_REMOVE(&af->af_host->nh_pending, af, af_link);
619 1.1 dholland TAILQ_INSERT_TAIL(&af->af_host->nh_granted, af, af_link);
620 1.1 dholland mtx_unlock(&af->af_host->nh_lock);
621 1.1 dholland }
622 1.1 dholland
623 1.1 dholland /*
624 1.1 dholland * Free an async lock request. The request must have been removed from
625 1.1 dholland * any list.
626 1.1 dholland */
627 1.1 dholland static void
628 1.1 dholland nlm_free_async_lock(struct nlm_async_lock *af)
629 1.1 dholland {
630 1.1 dholland /*
631 1.1 dholland * Free an async lock.
632 1.1 dholland */
633 1.1 dholland if (af->af_rpc)
634 1.1 dholland CLNT_RELEASE(af->af_rpc);
635 1.1 dholland xdr_free((xdrproc_t) xdr_nlm4_testargs, &af->af_granted);
636 1.1 dholland if (af->af_vp)
637 1.1 dholland vrele(af->af_vp);
638 1.1 dholland free(af, M_NLM);
639 1.1 dholland }
640 1.1 dholland
641 1.1 dholland /*
642 1.1 dholland * Cancel our async request - this must be called with
643 1.1 dholland * af->nh_host->nh_lock held. This is slightly complicated by a
644 1.1 dholland * potential race with our own callback. If we fail to cancel the
645 1.1 dholland * lock, it must already have been granted - we make sure our async
646 1.1 dholland * task has completed by calling taskqueue_drain in this case.
647 1.1 dholland */
648 1.1 dholland static int
649 1.1 dholland nlm_cancel_async_lock(struct nlm_async_lock *af)
650 1.1 dholland {
651 1.1 dholland struct nlm_host *host = af->af_host;
652 1.1 dholland int error;
653 1.1 dholland
654 1.1 dholland mtx_assert(&host->nh_lock, MA_OWNED);
655 1.1 dholland
656 1.1 dholland mtx_unlock(&host->nh_lock);
657 1.1 dholland
658 1.1 dholland error = VOP_ADVLOCKASYNC(af->af_vp, NULL, F_CANCEL, &af->af_fl,
659 1.1 dholland F_REMOTE, NULL, &af->af_cookie);
660 1.1 dholland
661 1.1 dholland if (error) {
662 1.1 dholland /*
663 1.1 dholland * We failed to cancel - make sure our callback has
664 1.1 dholland * completed before we continue.
665 1.1 dholland */
666 1.1 dholland taskqueue_drain(taskqueue_thread, &af->af_task);
667 1.1 dholland }
668 1.1 dholland
669 1.1 dholland mtx_lock(&host->nh_lock);
670 1.1 dholland
671 1.1 dholland if (!error) {
672 1.1 dholland NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) "
673 1.1 dholland "cancelled\n", af, host->nh_caller_name, host->nh_sysid);
674 1.1 dholland
675 1.1 dholland /*
676 1.1 dholland * Remove from the nh_pending list and free now that
677 1.1 dholland * we are safe from the callback.
678 1.1 dholland */
679 1.1 dholland TAILQ_REMOVE(&host->nh_pending, af, af_link);
680 1.1 dholland mtx_unlock(&host->nh_lock);
681 1.1 dholland nlm_free_async_lock(af);
682 1.1 dholland mtx_lock(&host->nh_lock);
683 1.1 dholland }
684 1.1 dholland
685 1.1 dholland return (error);
686 1.1 dholland }
687 1.1 dholland
688 1.1 dholland static void
689 1.1 dholland nlm_check_expired_locks(struct nlm_host *host)
690 1.1 dholland {
691 1.1 dholland struct nlm_async_lock *af;
692 1.1 dholland time_t uptime = time_uptime;
693 1.1 dholland
694 1.1 dholland mtx_lock(&host->nh_lock);
695 1.1 dholland while ((af = TAILQ_FIRST(&host->nh_granted)) != NULL
696 1.1 dholland && uptime >= af->af_expiretime) {
697 1.1 dholland NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) expired,"
698 1.1 dholland " cookie %d:%d\n", af, af->af_host->nh_caller_name,
699 1.1 dholland af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie),
700 1.1 dholland ng_cookie(&af->af_granted.cookie));
701 1.1 dholland TAILQ_REMOVE(&host->nh_granted, af, af_link);
702 1.1 dholland mtx_unlock(&host->nh_lock);
703 1.1 dholland nlm_free_async_lock(af);
704 1.1 dholland mtx_lock(&host->nh_lock);
705 1.1 dholland }
706 1.1 dholland while ((af = TAILQ_FIRST(&host->nh_finished)) != NULL) {
707 1.1 dholland TAILQ_REMOVE(&host->nh_finished, af, af_link);
708 1.1 dholland mtx_unlock(&host->nh_lock);
709 1.1 dholland nlm_free_async_lock(af);
710 1.1 dholland mtx_lock(&host->nh_lock);
711 1.1 dholland }
712 1.1 dholland mtx_unlock(&host->nh_lock);
713 1.1 dholland }
714 1.1 dholland
715 1.1 dholland /*
716 1.1 dholland * Free resources used by a host. This is called after the reference
717 1.1 dholland * count has reached zero so it doesn't need to worry about locks.
718 1.1 dholland */
719 1.1 dholland static void
720 1.1 dholland nlm_host_destroy(struct nlm_host *host)
721 1.1 dholland {
722 1.1 dholland
723 1.1 dholland mtx_lock(&nlm_global_lock);
724 1.1 dholland TAILQ_REMOVE(&nlm_hosts, host, nh_link);
725 1.1 dholland mtx_unlock(&nlm_global_lock);
726 1.1 dholland
727 1.1 dholland if (host->nh_srvrpc.nr_client)
728 1.1 dholland CLNT_RELEASE(host->nh_srvrpc.nr_client);
729 1.1 dholland if (host->nh_clntrpc.nr_client)
730 1.1 dholland CLNT_RELEASE(host->nh_clntrpc.nr_client);
731 1.1 dholland mtx_destroy(&host->nh_lock);
732 1.1 dholland sysctl_ctx_free(&host->nh_sysctl);
733 1.1 dholland free(host, M_NLM);
734 1.1 dholland }
735 1.1 dholland
736 1.1 dholland /*
737 1.1 dholland * Thread start callback for client lock recovery
738 1.1 dholland */
739 1.1 dholland static void
740 1.1 dholland nlm_client_recovery_start(void *arg)
741 1.1 dholland {
742 1.1 dholland struct nlm_host *host = (struct nlm_host *) arg;
743 1.1 dholland
744 1.1 dholland NLM_DEBUG(1, "NLM: client lock recovery for %s started\n",
745 1.1 dholland host->nh_caller_name);
746 1.1 dholland
747 1.1 dholland nlm_client_recovery(host);
748 1.1 dholland
749 1.1 dholland NLM_DEBUG(1, "NLM: client lock recovery for %s completed\n",
750 1.1 dholland host->nh_caller_name);
751 1.1 dholland
752 1.1 dholland host->nh_monstate = NLM_MONITORED;
753 1.1 dholland nlm_host_release(host);
754 1.1 dholland
755 1.1 dholland kthread_exit();
756 1.1 dholland }
757 1.1 dholland
758 1.1 dholland /*
759 1.1 dholland * This is called when we receive a host state change notification. We
760 1.1 dholland * unlock any active locks owned by the host. When rpc.lockd is
761 1.1 dholland * shutting down, this function is called with newstate set to zero
762 1.1 dholland * which allows us to cancel any pending async locks and clear the
763 1.1 dholland * locking state.
764 1.1 dholland */
765 1.1 dholland static void
766 1.1 dholland nlm_host_notify(struct nlm_host *host, int newstate)
767 1.1 dholland {
768 1.1 dholland struct nlm_async_lock *af;
769 1.1 dholland
770 1.1 dholland if (newstate) {
771 1.1 dholland NLM_DEBUG(1, "NLM: host %s (sysid %d) rebooted, new "
772 1.1 dholland "state is %d\n", host->nh_caller_name,
773 1.1 dholland host->nh_sysid, newstate);
774 1.1 dholland }
775 1.1 dholland
776 1.1 dholland /*
777 1.1 dholland * Cancel any pending async locks for this host.
778 1.1 dholland */
779 1.1 dholland mtx_lock(&host->nh_lock);
780 1.1 dholland while ((af = TAILQ_FIRST(&host->nh_pending)) != NULL) {
781 1.1 dholland /*
782 1.1 dholland * nlm_cancel_async_lock will remove the entry from
783 1.1 dholland * nh_pending and free it.
784 1.1 dholland */
785 1.1 dholland nlm_cancel_async_lock(af);
786 1.1 dholland }
787 1.1 dholland mtx_unlock(&host->nh_lock);
788 1.1 dholland nlm_check_expired_locks(host);
789 1.1 dholland
790 1.1 dholland /*
791 1.1 dholland * The host just rebooted - trash its locks.
792 1.1 dholland */
793 1.1 dholland lf_clearremotesys(host->nh_sysid);
794 1.1 dholland host->nh_state = newstate;
795 1.1 dholland
796 1.1 dholland /*
797 1.1 dholland * If we have any remote locks for this host (i.e. it
798 1.1 dholland * represents a remote NFS server that our local NFS client
799 1.1 dholland * has locks for), start a recovery thread.
800 1.1 dholland */
801 1.1 dholland if (newstate != 0
802 1.1 dholland && host->nh_monstate != NLM_RECOVERING
803 1.1 dholland && lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid) > 0) {
804 1.1 dholland struct thread *td;
805 1.1 dholland host->nh_monstate = NLM_RECOVERING;
806 1.1 dholland refcount_acquire(&host->nh_refs);
807 1.1 dholland kthread_add(nlm_client_recovery_start, host, curproc, &td, 0, 0,
808 1.1 dholland "NFS lock recovery for %s", host->nh_caller_name);
809 1.1 dholland }
810 1.1 dholland }
811 1.1 dholland
812 1.1 dholland /*
813 1.1 dholland * Sysctl handler to count the number of locks for a sysid.
814 1.1 dholland */
815 1.1 dholland static int
816 1.1 dholland nlm_host_lock_count_sysctl(SYSCTL_HANDLER_ARGS)
817 1.1 dholland {
818 1.1 dholland struct nlm_host *host;
819 1.1 dholland int count;
820 1.1 dholland
821 1.1 dholland host = oidp->oid_arg1;
822 1.1 dholland count = lf_countlocks(host->nh_sysid);
823 1.1 dholland return sysctl_handle_int(oidp, &count, 0, req);
824 1.1 dholland }
825 1.1 dholland
826 1.1 dholland /*
827 1.1 dholland * Sysctl handler to count the number of client locks for a sysid.
828 1.1 dholland */
829 1.1 dholland static int
830 1.1 dholland nlm_host_client_lock_count_sysctl(SYSCTL_HANDLER_ARGS)
831 1.1 dholland {
832 1.1 dholland struct nlm_host *host;
833 1.1 dholland int count;
834 1.1 dholland
835 1.1 dholland host = oidp->oid_arg1;
836 1.1 dholland count = lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid);
837 1.1 dholland return sysctl_handle_int(oidp, &count, 0, req);
838 1.1 dholland }
839 1.1 dholland
840 1.1 dholland /*
841 1.1 dholland * Create a new NLM host.
842 1.1 dholland */
843 1.1 dholland static struct nlm_host *
844 1.1 dholland nlm_create_host(const char* caller_name)
845 1.1 dholland {
846 1.1 dholland struct nlm_host *host;
847 1.1 dholland struct sysctl_oid *oid;
848 1.1 dholland
849 1.1 dholland mtx_assert(&nlm_global_lock, MA_OWNED);
850 1.1 dholland
851 1.1 dholland NLM_DEBUG(1, "NLM: new host %s (sysid %d)\n",
852 1.1 dholland caller_name, nlm_next_sysid);
853 1.1 dholland host = malloc(sizeof(struct nlm_host), M_NLM, M_NOWAIT|M_ZERO);
854 1.1 dholland if (!host)
855 1.1 dholland return (NULL);
856 1.1 dholland mtx_init(&host->nh_lock, "nh_lock", NULL, MTX_DEF);
857 1.1 dholland host->nh_refs = 1;
858 1.1 dholland strlcpy(host->nh_caller_name, caller_name, MAXNAMELEN);
859 1.1 dholland host->nh_sysid = nlm_next_sysid++;
860 1.1 dholland snprintf(host->nh_sysid_string, sizeof(host->nh_sysid_string),
861 1.1 dholland "%d", host->nh_sysid);
862 1.1 dholland host->nh_vers = 0;
863 1.1 dholland host->nh_state = 0;
864 1.1 dholland host->nh_monstate = NLM_UNMONITORED;
865 1.1 dholland host->nh_grantcookie = 1;
866 1.1 dholland TAILQ_INIT(&host->nh_pending);
867 1.1 dholland TAILQ_INIT(&host->nh_granted);
868 1.1 dholland TAILQ_INIT(&host->nh_finished);
869 1.1 dholland TAILQ_INSERT_TAIL(&nlm_hosts, host, nh_link);
870 1.1 dholland
871 1.1 dholland mtx_unlock(&nlm_global_lock);
872 1.1 dholland
873 1.1 dholland sysctl_ctx_init(&host->nh_sysctl);
874 1.1 dholland oid = SYSCTL_ADD_NODE(&host->nh_sysctl,
875 1.1 dholland SYSCTL_STATIC_CHILDREN(_vfs_nlm_sysid),
876 1.1 dholland OID_AUTO, host->nh_sysid_string, CTLFLAG_RD, NULL, "");
877 1.1 dholland SYSCTL_ADD_STRING(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
878 1.1 dholland "hostname", CTLFLAG_RD, host->nh_caller_name, 0, "");
879 1.1 dholland SYSCTL_ADD_UINT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
880 1.1 dholland "version", CTLFLAG_RD, &host->nh_vers, 0, "");
881 1.1 dholland SYSCTL_ADD_UINT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
882 1.1 dholland "monitored", CTLFLAG_RD, &host->nh_monstate, 0, "");
883 1.1 dholland SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
884 1.1 dholland "lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0,
885 1.1 dholland nlm_host_lock_count_sysctl, "I", "");
886 1.1 dholland SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
887 1.1 dholland "client_lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0,
888 1.1 dholland nlm_host_client_lock_count_sysctl, "I", "");
889 1.1 dholland
890 1.1 dholland mtx_lock(&nlm_global_lock);
891 1.1 dholland
892 1.1 dholland return (host);
893 1.1 dholland }
894 1.1 dholland
895 1.1 dholland /*
896 1.1 dholland * Acquire the next sysid for remote locks not handled by the NLM.
897 1.1 dholland */
898 1.1 dholland uint32_t
899 1.1 dholland nlm_acquire_next_sysid(void)
900 1.1 dholland {
901 1.1 dholland uint32_t next_sysid;
902 1.1 dholland
903 1.1 dholland mtx_lock(&nlm_global_lock);
904 1.1 dholland next_sysid = nlm_next_sysid++;
905 1.1 dholland mtx_unlock(&nlm_global_lock);
906 1.1 dholland return (next_sysid);
907 1.1 dholland }
908 1.1 dholland
909 1.1 dholland /*
910 1.1 dholland * Return non-zero if the address parts of the two sockaddrs are the
911 1.1 dholland * same.
912 1.1 dholland */
913 1.1 dholland static int
914 1.1 dholland nlm_compare_addr(const struct sockaddr *a, const struct sockaddr *b)
915 1.1 dholland {
916 1.1 dholland const struct sockaddr_in *a4, *b4;
917 1.1 dholland #ifdef INET6
918 1.1 dholland const struct sockaddr_in6 *a6, *b6;
919 1.1 dholland #endif
920 1.1 dholland
921 1.1 dholland if (a->sa_family != b->sa_family)
922 1.1 dholland return (FALSE);
923 1.1 dholland
924 1.1 dholland switch (a->sa_family) {
925 1.1 dholland case AF_INET:
926 1.1 dholland a4 = (const struct sockaddr_in *) a;
927 1.1 dholland b4 = (const struct sockaddr_in *) b;
928 1.1 dholland return !memcmp(&a4->sin_addr, &b4->sin_addr,
929 1.1 dholland sizeof(a4->sin_addr));
930 1.1 dholland #ifdef INET6
931 1.1 dholland case AF_INET6:
932 1.1 dholland a6 = (const struct sockaddr_in6 *) a;
933 1.1 dholland b6 = (const struct sockaddr_in6 *) b;
934 1.1 dholland return !memcmp(&a6->sin6_addr, &b6->sin6_addr,
935 1.1 dholland sizeof(a6->sin6_addr));
936 1.1 dholland #endif
937 1.1 dholland }
938 1.1 dholland
939 1.1 dholland return (0);
940 1.1 dholland }
941 1.1 dholland
942 1.1 dholland /*
943 1.1 dholland * Check for idle hosts and stop monitoring them. We could also free
944 1.1 dholland * the host structure here, possibly after a larger timeout but that
945 1.1 dholland * would require some care to avoid races with
946 1.1 dholland * e.g. nlm_host_lock_count_sysctl.
947 1.1 dholland */
948 1.1 dholland static void
949 1.1 dholland nlm_check_idle(void)
950 1.1 dholland {
951 1.1 dholland struct nlm_host *host;
952 1.1 dholland
953 1.1 dholland mtx_assert(&nlm_global_lock, MA_OWNED);
954 1.1 dholland
955 1.1 dholland if (time_uptime <= nlm_next_idle_check)
956 1.1 dholland return;
957 1.1 dholland
958 1.1 dholland nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD;
959 1.1 dholland
960 1.1 dholland TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
961 1.1 dholland if (host->nh_monstate == NLM_MONITORED
962 1.1 dholland && time_uptime > host->nh_idle_timeout) {
963 1.1 dholland mtx_unlock(&nlm_global_lock);
964 1.1 dholland if (lf_countlocks(host->nh_sysid) > 0
965 1.1 dholland || lf_countlocks(NLM_SYSID_CLIENT
966 1.1 dholland + host->nh_sysid)) {
967 1.1 dholland host->nh_idle_timeout =
968 1.1 dholland time_uptime + NLM_IDLE_TIMEOUT;
969 1.1 dholland mtx_lock(&nlm_global_lock);
970 1.1 dholland continue;
971 1.1 dholland }
972 1.1 dholland nlm_host_unmonitor(host);
973 1.1 dholland mtx_lock(&nlm_global_lock);
974 1.1 dholland }
975 1.1 dholland }
976 1.1 dholland }
977 1.1 dholland
978 1.1 dholland /*
979 1.1 dholland * Search for an existing NLM host that matches the given name
980 1.1 dholland * (typically the caller_name element of an nlm4_lock). If none is
981 1.1 dholland * found, create a new host. If 'addr' is non-NULL, record the remote
982 1.1 dholland * address of the host so that we can call it back for async
983 1.1 dholland * responses. If 'vers' is greater than zero then record the NLM
984 1.1 dholland * program version to use to communicate with this client.
985 1.1 dholland */
986 1.1 dholland struct nlm_host *
987 1.1 dholland nlm_find_host_by_name(const char *name, const struct sockaddr *addr,
988 1.1 dholland rpcvers_t vers)
989 1.1 dholland {
990 1.1 dholland struct nlm_host *host;
991 1.1 dholland
992 1.1 dholland mtx_lock(&nlm_global_lock);
993 1.1 dholland
994 1.1 dholland /*
995 1.1 dholland * The remote host is determined by caller_name.
996 1.1 dholland */
997 1.1 dholland TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
998 1.1 dholland if (!strcmp(host->nh_caller_name, name))
999 1.1 dholland break;
1000 1.1 dholland }
1001 1.1 dholland
1002 1.1 dholland if (!host) {
1003 1.1 dholland host = nlm_create_host(name);
1004 1.1 dholland if (!host) {
1005 1.1 dholland mtx_unlock(&nlm_global_lock);
1006 1.1 dholland return (NULL);
1007 1.1 dholland }
1008 1.1 dholland }
1009 1.1 dholland refcount_acquire(&host->nh_refs);
1010 1.1 dholland
1011 1.1 dholland host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT;
1012 1.1 dholland
1013 1.1 dholland /*
1014 1.1 dholland * If we have an address for the host, record it so that we
1015 1.1 dholland * can send async replies etc.
1016 1.1 dholland */
1017 1.1 dholland if (addr) {
1018 1.1 dholland
1019 1.1 dholland KASSERT(addr->sa_len < sizeof(struct sockaddr_storage),
1020 1.1 dholland ("Strange remote transport address length"));
1021 1.1 dholland
1022 1.1 dholland /*
1023 1.1 dholland * If we have seen an address before and we currently
1024 1.1 dholland * have an RPC client handle, make sure the address is
1025 1.1 dholland * the same, otherwise discard the client handle.
1026 1.1 dholland */
1027 1.1 dholland if (host->nh_addr.ss_len && host->nh_srvrpc.nr_client) {
1028 1.1 dholland if (!nlm_compare_addr(
1029 1.1 dholland (struct sockaddr *) &host->nh_addr,
1030 1.1 dholland addr)
1031 1.1 dholland || host->nh_vers != vers) {
1032 1.1 dholland CLIENT *client;
1033 1.1 dholland mtx_lock(&host->nh_lock);
1034 1.1 dholland client = host->nh_srvrpc.nr_client;
1035 1.1 dholland host->nh_srvrpc.nr_client = NULL;
1036 1.1 dholland mtx_unlock(&host->nh_lock);
1037 1.1 dholland if (client) {
1038 1.1 dholland CLNT_RELEASE(client);
1039 1.1 dholland }
1040 1.1 dholland }
1041 1.1 dholland }
1042 1.1 dholland memcpy(&host->nh_addr, addr, addr->sa_len);
1043 1.1 dholland host->nh_vers = vers;
1044 1.1 dholland }
1045 1.1 dholland
1046 1.1 dholland nlm_check_idle();
1047 1.1 dholland
1048 1.1 dholland mtx_unlock(&nlm_global_lock);
1049 1.1 dholland
1050 1.1 dholland return (host);
1051 1.1 dholland }
1052 1.1 dholland
1053 1.1 dholland /*
1054 1.1 dholland * Search for an existing NLM host that matches the given remote
1055 1.1 dholland * address. If none is found, create a new host with the requested
1056 1.1 dholland * address and remember 'vers' as the NLM protocol version to use for
1057 1.1 dholland * that host.
1058 1.1 dholland */
1059 1.1 dholland struct nlm_host *
1060 1.1 dholland nlm_find_host_by_addr(const struct sockaddr *addr, int vers)
1061 1.1 dholland {
1062 1.1 dholland /*
1063 1.1 dholland * Fake up a name using inet_ntop. This buffer is
1064 1.1 dholland * large enough for an IPv6 address.
1065 1.1 dholland */
1066 1.1 dholland char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
1067 1.1 dholland struct nlm_host *host;
1068 1.1 dholland
1069 1.1 dholland switch (addr->sa_family) {
1070 1.1 dholland case AF_INET:
1071 1.1 dholland inet_ntop(AF_INET,
1072 1.1 dholland &((const struct sockaddr_in *) addr)->sin_addr,
1073 1.1 dholland tmp, sizeof tmp);
1074 1.1 dholland break;
1075 1.1 dholland #ifdef INET6
1076 1.1 dholland case AF_INET6:
1077 1.1 dholland inet_ntop(AF_INET6,
1078 1.1 dholland &((const struct sockaddr_in6 *) addr)->sin6_addr,
1079 1.1 dholland tmp, sizeof tmp);
1080 1.1 dholland break;
1081 1.1 dholland #endif
1082 1.1 dholland default:
1083 1.3 pgoyette strlcpy(tmp, "<unknown>", sizeof(tmp));
1084 1.1 dholland }
1085 1.1 dholland
1086 1.1 dholland
1087 1.1 dholland mtx_lock(&nlm_global_lock);
1088 1.1 dholland
1089 1.1 dholland /*
1090 1.1 dholland * The remote host is determined by caller_name.
1091 1.1 dholland */
1092 1.1 dholland TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
1093 1.1 dholland if (nlm_compare_addr(addr,
1094 1.1 dholland (const struct sockaddr *) &host->nh_addr))
1095 1.1 dholland break;
1096 1.1 dholland }
1097 1.1 dholland
1098 1.1 dholland if (!host) {
1099 1.1 dholland host = nlm_create_host(tmp);
1100 1.1 dholland if (!host) {
1101 1.1 dholland mtx_unlock(&nlm_global_lock);
1102 1.1 dholland return (NULL);
1103 1.1 dholland }
1104 1.1 dholland memcpy(&host->nh_addr, addr, addr->sa_len);
1105 1.1 dholland host->nh_vers = vers;
1106 1.1 dholland }
1107 1.1 dholland refcount_acquire(&host->nh_refs);
1108 1.1 dholland
1109 1.1 dholland host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT;
1110 1.1 dholland
1111 1.1 dholland nlm_check_idle();
1112 1.1 dholland
1113 1.1 dholland mtx_unlock(&nlm_global_lock);
1114 1.1 dholland
1115 1.1 dholland return (host);
1116 1.1 dholland }
1117 1.1 dholland
1118 1.1 dholland /*
1119 1.1 dholland * Find the NLM host that matches the value of 'sysid'. If none
1120 1.1 dholland * exists, return NULL.
1121 1.1 dholland */
1122 1.1 dholland static struct nlm_host *
1123 1.1 dholland nlm_find_host_by_sysid(int sysid)
1124 1.1 dholland {
1125 1.1 dholland struct nlm_host *host;
1126 1.1 dholland
1127 1.1 dholland TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
1128 1.1 dholland if (host->nh_sysid == sysid) {
1129 1.1 dholland refcount_acquire(&host->nh_refs);
1130 1.1 dholland return (host);
1131 1.1 dholland }
1132 1.1 dholland }
1133 1.1 dholland
1134 1.1 dholland return (NULL);
1135 1.1 dholland }
1136 1.1 dholland
1137 1.1 dholland void nlm_host_release(struct nlm_host *host)
1138 1.1 dholland {
1139 1.1 dholland if (refcount_release(&host->nh_refs)) {
1140 1.1 dholland /*
1141 1.1 dholland * Free the host
1142 1.1 dholland */
1143 1.1 dholland nlm_host_destroy(host);
1144 1.1 dholland }
1145 1.1 dholland }
1146 1.1 dholland
1147 1.1 dholland /*
1148 1.1 dholland * Unregister this NLM host with the local NSM due to idleness.
1149 1.1 dholland */
1150 1.1 dholland static void
1151 1.1 dholland nlm_host_unmonitor(struct nlm_host *host)
1152 1.1 dholland {
1153 1.1 dholland mon_id smmonid;
1154 1.1 dholland sm_stat_res smstat;
1155 1.1 dholland struct timeval timo;
1156 1.1 dholland enum clnt_stat stat;
1157 1.1 dholland
1158 1.1 dholland NLM_DEBUG(1, "NLM: unmonitoring %s (sysid %d)\n",
1159 1.1 dholland host->nh_caller_name, host->nh_sysid);
1160 1.1 dholland
1161 1.1 dholland /*
1162 1.1 dholland * We put our assigned system ID value in the priv field to
1163 1.1 dholland * make it simpler to find the host if we are notified of a
1164 1.1 dholland * host restart.
1165 1.1 dholland */
1166 1.1 dholland smmonid.mon_name = host->nh_caller_name;
1167 1.1 dholland smmonid.my_id.my_name = "localhost";
1168 1.1 dholland smmonid.my_id.my_prog = NLM_PROG;
1169 1.1 dholland smmonid.my_id.my_vers = NLM_SM;
1170 1.1 dholland smmonid.my_id.my_proc = NLM_SM_NOTIFY;
1171 1.1 dholland
1172 1.1 dholland timo.tv_sec = 25;
1173 1.1 dholland timo.tv_usec = 0;
1174 1.1 dholland stat = CLNT_CALL(nlm_nsm, SM_UNMON,
1175 1.1 dholland (xdrproc_t) xdr_mon, &smmonid,
1176 1.1 dholland (xdrproc_t) xdr_sm_stat, &smstat, timo);
1177 1.1 dholland
1178 1.1 dholland if (stat != RPC_SUCCESS) {
1179 1.1 dholland NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat);
1180 1.1 dholland return;
1181 1.1 dholland }
1182 1.1 dholland if (smstat.res_stat == stat_fail) {
1183 1.1 dholland NLM_ERR("Local NSM refuses to unmonitor %s\n",
1184 1.1 dholland host->nh_caller_name);
1185 1.1 dholland return;
1186 1.1 dholland }
1187 1.1 dholland
1188 1.1 dholland host->nh_monstate = NLM_UNMONITORED;
1189 1.1 dholland }
1190 1.1 dholland
1191 1.1 dholland /*
1192 1.1 dholland * Register this NLM host with the local NSM so that we can be
1193 1.1 dholland * notified if it reboots.
1194 1.1 dholland */
1195 1.1 dholland void
1196 1.1 dholland nlm_host_monitor(struct nlm_host *host, int state)
1197 1.1 dholland {
1198 1.1 dholland mon smmon;
1199 1.1 dholland sm_stat_res smstat;
1200 1.1 dholland struct timeval timo;
1201 1.1 dholland enum clnt_stat stat;
1202 1.1 dholland
1203 1.1 dholland if (state && !host->nh_state) {
1204 1.1 dholland /*
1205 1.1 dholland * This is the first time we have seen an NSM state
1206 1.1 dholland * value for this host. We record it here to help
1207 1.1 dholland * detect host reboots.
1208 1.1 dholland */
1209 1.1 dholland host->nh_state = state;
1210 1.1 dholland NLM_DEBUG(1, "NLM: host %s (sysid %d) has NSM state %d\n",
1211 1.1 dholland host->nh_caller_name, host->nh_sysid, state);
1212 1.1 dholland }
1213 1.1 dholland
1214 1.1 dholland mtx_lock(&host->nh_lock);
1215 1.1 dholland if (host->nh_monstate != NLM_UNMONITORED) {
1216 1.1 dholland mtx_unlock(&host->nh_lock);
1217 1.1 dholland return;
1218 1.1 dholland }
1219 1.1 dholland host->nh_monstate = NLM_MONITORED;
1220 1.1 dholland mtx_unlock(&host->nh_lock);
1221 1.1 dholland
1222 1.1 dholland NLM_DEBUG(1, "NLM: monitoring %s (sysid %d)\n",
1223 1.1 dholland host->nh_caller_name, host->nh_sysid);
1224 1.1 dholland
1225 1.1 dholland /*
1226 1.1 dholland * We put our assigned system ID value in the priv field to
1227 1.1 dholland * make it simpler to find the host if we are notified of a
1228 1.1 dholland * host restart.
1229 1.1 dholland */
1230 1.1 dholland smmon.mon_id.mon_name = host->nh_caller_name;
1231 1.1 dholland smmon.mon_id.my_id.my_name = "localhost";
1232 1.1 dholland smmon.mon_id.my_id.my_prog = NLM_PROG;
1233 1.1 dholland smmon.mon_id.my_id.my_vers = NLM_SM;
1234 1.1 dholland smmon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
1235 1.1 dholland memcpy(smmon.priv, &host->nh_sysid, sizeof(host->nh_sysid));
1236 1.1 dholland
1237 1.1 dholland timo.tv_sec = 25;
1238 1.1 dholland timo.tv_usec = 0;
1239 1.1 dholland stat = CLNT_CALL(nlm_nsm, SM_MON,
1240 1.1 dholland (xdrproc_t) xdr_mon, &smmon,
1241 1.1 dholland (xdrproc_t) xdr_sm_stat, &smstat, timo);
1242 1.1 dholland
1243 1.1 dholland if (stat != RPC_SUCCESS) {
1244 1.1 dholland NLM_ERR("Failed to contact local NSM - rpc error %d\n", stat);
1245 1.1 dholland return;
1246 1.1 dholland }
1247 1.1 dholland if (smstat.res_stat == stat_fail) {
1248 1.1 dholland NLM_ERR("Local NSM refuses to monitor %s\n",
1249 1.1 dholland host->nh_caller_name);
1250 1.1 dholland mtx_lock(&host->nh_lock);
1251 1.1 dholland host->nh_monstate = NLM_MONITOR_FAILED;
1252 1.1 dholland mtx_unlock(&host->nh_lock);
1253 1.1 dholland return;
1254 1.1 dholland }
1255 1.1 dholland
1256 1.1 dholland host->nh_monstate = NLM_MONITORED;
1257 1.1 dholland }
1258 1.1 dholland
1259 1.1 dholland /*
1260 1.1 dholland * Return an RPC client handle that can be used to talk to the NLM
1261 1.1 dholland * running on the given host.
1262 1.1 dholland */
1263 1.1 dholland CLIENT *
1264 1.1 dholland nlm_host_get_rpc(struct nlm_host *host, bool_t isserver)
1265 1.1 dholland {
1266 1.1 dholland struct nlm_rpc *rpc;
1267 1.1 dholland CLIENT *client;
1268 1.1 dholland
1269 1.1 dholland mtx_lock(&host->nh_lock);
1270 1.1 dholland
1271 1.1 dholland if (isserver)
1272 1.1 dholland rpc = &host->nh_srvrpc;
1273 1.1 dholland else
1274 1.1 dholland rpc = &host->nh_clntrpc;
1275 1.1 dholland
1276 1.1 dholland /*
1277 1.1 dholland * We can't hold onto RPC handles for too long - the async
1278 1.1 dholland * call/reply protocol used by some NLM clients makes it hard
1279 1.1 dholland * to tell when they change port numbers (e.g. after a
1280 1.1 dholland * reboot). Note that if a client reboots while it isn't
1281 1.1 dholland * holding any locks, it won't bother to notify us. We
1282 1.1 dholland * expire the RPC handles after two minutes.
1283 1.1 dholland */
1284 1.1 dholland if (rpc->nr_client && time_uptime > rpc->nr_create_time + 2*60) {
1285 1.1 dholland client = rpc->nr_client;
1286 1.1 dholland rpc->nr_client = NULL;
1287 1.1 dholland mtx_unlock(&host->nh_lock);
1288 1.1 dholland CLNT_RELEASE(client);
1289 1.1 dholland mtx_lock(&host->nh_lock);
1290 1.1 dholland }
1291 1.1 dholland
1292 1.1 dholland if (!rpc->nr_client) {
1293 1.1 dholland mtx_unlock(&host->nh_lock);
1294 1.1 dholland client = nlm_get_rpc((struct sockaddr *)&host->nh_addr,
1295 1.1 dholland NLM_PROG, host->nh_vers);
1296 1.1 dholland mtx_lock(&host->nh_lock);
1297 1.1 dholland
1298 1.1 dholland if (client) {
1299 1.1 dholland if (rpc->nr_client) {
1300 1.1 dholland mtx_unlock(&host->nh_lock);
1301 1.1 dholland CLNT_DESTROY(client);
1302 1.1 dholland mtx_lock(&host->nh_lock);
1303 1.1 dholland } else {
1304 1.1 dholland rpc->nr_client = client;
1305 1.1 dholland rpc->nr_create_time = time_uptime;
1306 1.1 dholland }
1307 1.1 dholland }
1308 1.1 dholland }
1309 1.1 dholland
1310 1.1 dholland client = rpc->nr_client;
1311 1.1 dholland if (client)
1312 1.1 dholland CLNT_ACQUIRE(client);
1313 1.1 dholland mtx_unlock(&host->nh_lock);
1314 1.1 dholland
1315 1.1 dholland return (client);
1316 1.1 dholland
1317 1.1 dholland }
1318 1.1 dholland
1319 1.1 dholland int nlm_host_get_sysid(struct nlm_host *host)
1320 1.1 dholland {
1321 1.1 dholland
1322 1.1 dholland return (host->nh_sysid);
1323 1.1 dholland }
1324 1.1 dholland
1325 1.1 dholland int
1326 1.1 dholland nlm_host_get_state(struct nlm_host *host)
1327 1.1 dholland {
1328 1.1 dholland
1329 1.1 dholland return (host->nh_state);
1330 1.1 dholland }
1331 1.1 dholland
1332 1.1 dholland void *
1333 1.1 dholland nlm_register_wait_lock(struct nlm4_lock *lock, struct vnode *vp)
1334 1.1 dholland {
1335 1.1 dholland struct nlm_waiting_lock *nw;
1336 1.1 dholland
1337 1.1 dholland nw = malloc(sizeof(struct nlm_waiting_lock), M_NLM, M_WAITOK);
1338 1.1 dholland nw->nw_lock = *lock;
1339 1.1 dholland memcpy(&nw->nw_fh.fh_bytes, nw->nw_lock.fh.n_bytes,
1340 1.1 dholland nw->nw_lock.fh.n_len);
1341 1.1 dholland nw->nw_lock.fh.n_bytes = nw->nw_fh.fh_bytes;
1342 1.1 dholland nw->nw_waiting = TRUE;
1343 1.1 dholland nw->nw_vp = vp;
1344 1.1 dholland mtx_lock(&nlm_global_lock);
1345 1.1 dholland TAILQ_INSERT_TAIL(&nlm_waiting_locks, nw, nw_link);
1346 1.1 dholland mtx_unlock(&nlm_global_lock);
1347 1.1 dholland
1348 1.1 dholland return nw;
1349 1.1 dholland }
1350 1.1 dholland
1351 1.1 dholland void
1352 1.1 dholland nlm_deregister_wait_lock(void *handle)
1353 1.1 dholland {
1354 1.1 dholland struct nlm_waiting_lock *nw = handle;
1355 1.1 dholland
1356 1.1 dholland mtx_lock(&nlm_global_lock);
1357 1.1 dholland TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link);
1358 1.1 dholland mtx_unlock(&nlm_global_lock);
1359 1.1 dholland
1360 1.1 dholland free(nw, M_NLM);
1361 1.1 dholland }
1362 1.1 dholland
1363 1.1 dholland int
1364 1.1 dholland nlm_wait_lock(void *handle, int timo)
1365 1.1 dholland {
1366 1.1 dholland struct nlm_waiting_lock *nw = handle;
1367 1.3 pgoyette int error, stops_deferred;
1368 1.1 dholland
1369 1.1 dholland /*
1370 1.1 dholland * If the granted message arrived before we got here,
1371 1.1 dholland * nw->nw_waiting will be FALSE - in that case, don't sleep.
1372 1.1 dholland */
1373 1.1 dholland mtx_lock(&nlm_global_lock);
1374 1.1 dholland error = 0;
1375 1.3 pgoyette if (nw->nw_waiting) {
1376 1.3 pgoyette stops_deferred = sigdeferstop(SIGDEFERSTOP_ERESTART);
1377 1.1 dholland error = msleep(nw, &nlm_global_lock, PCATCH, "nlmlock", timo);
1378 1.3 pgoyette sigallowstop(stops_deferred);
1379 1.3 pgoyette }
1380 1.1 dholland TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link);
1381 1.1 dholland if (error) {
1382 1.1 dholland /*
1383 1.1 dholland * The granted message may arrive after the
1384 1.1 dholland * interrupt/timeout but before we manage to lock the
1385 1.1 dholland * mutex. Detect this by examining nw_lock.
1386 1.1 dholland */
1387 1.1 dholland if (!nw->nw_waiting)
1388 1.1 dholland error = 0;
1389 1.1 dholland } else {
1390 1.1 dholland /*
1391 1.1 dholland * If nlm_cancel_wait is called, then error will be
1392 1.1 dholland * zero but nw_waiting will still be TRUE. We
1393 1.1 dholland * translate this into EINTR.
1394 1.1 dholland */
1395 1.1 dholland if (nw->nw_waiting)
1396 1.1 dholland error = EINTR;
1397 1.1 dholland }
1398 1.1 dholland mtx_unlock(&nlm_global_lock);
1399 1.1 dholland
1400 1.1 dholland free(nw, M_NLM);
1401 1.1 dholland
1402 1.1 dholland return (error);
1403 1.1 dholland }
1404 1.1 dholland
1405 1.1 dholland void
1406 1.1 dholland nlm_cancel_wait(struct vnode *vp)
1407 1.1 dholland {
1408 1.1 dholland struct nlm_waiting_lock *nw;
1409 1.1 dholland
1410 1.1 dholland mtx_lock(&nlm_global_lock);
1411 1.1 dholland TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
1412 1.1 dholland if (nw->nw_vp == vp) {
1413 1.1 dholland wakeup(nw);
1414 1.1 dholland }
1415 1.1 dholland }
1416 1.1 dholland mtx_unlock(&nlm_global_lock);
1417 1.1 dholland }
1418 1.1 dholland
1419 1.1 dholland
1420 1.1 dholland /**********************************************************************/
1421 1.1 dholland
1422 1.1 dholland /*
1423 1.1 dholland * Syscall interface with userland.
1424 1.1 dholland */
1425 1.1 dholland
1426 1.1 dholland extern void nlm_prog_0(struct svc_req *rqstp, SVCXPRT *transp);
1427 1.1 dholland extern void nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp);
1428 1.1 dholland extern void nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp);
1429 1.1 dholland extern void nlm_prog_4(struct svc_req *rqstp, SVCXPRT *transp);
1430 1.1 dholland
1431 1.1 dholland static int
1432 1.1 dholland nlm_register_services(SVCPOOL *pool, int addr_count, char **addrs)
1433 1.1 dholland {
1434 1.1 dholland static rpcvers_t versions[] = {
1435 1.1 dholland NLM_SM, NLM_VERS, NLM_VERSX, NLM_VERS4
1436 1.1 dholland };
1437 1.1 dholland static void (*dispatchers[])(struct svc_req *, SVCXPRT *) = {
1438 1.1 dholland nlm_prog_0, nlm_prog_1, nlm_prog_3, nlm_prog_4
1439 1.1 dholland };
1440 1.1 dholland
1441 1.1 dholland SVCXPRT **xprts;
1442 1.1 dholland char netid[16];
1443 1.1 dholland char uaddr[128];
1444 1.1 dholland struct netconfig *nconf;
1445 1.1 dholland int i, j, error;
1446 1.1 dholland
1447 1.1 dholland if (!addr_count) {
1448 1.1 dholland NLM_ERR("NLM: no service addresses given - can't start server");
1449 1.1 dholland return (EINVAL);
1450 1.1 dholland }
1451 1.1 dholland
1452 1.3 pgoyette if (addr_count < 0 || addr_count > 256 ) {
1453 1.3 pgoyette NLM_ERR("NLM: too many service addresses (%d) given, "
1454 1.3 pgoyette "max 256 - can't start server\n", addr_count);
1455 1.3 pgoyette return (EINVAL);
1456 1.3 pgoyette }
1457 1.3 pgoyette
1458 1.1 dholland xprts = malloc(addr_count * sizeof(SVCXPRT *), M_NLM, M_WAITOK|M_ZERO);
1459 1.3 pgoyette for (i = 0; i < nitems(versions); i++) {
1460 1.1 dholland for (j = 0; j < addr_count; j++) {
1461 1.1 dholland /*
1462 1.1 dholland * Create transports for the first version and
1463 1.1 dholland * then just register everything else to the
1464 1.1 dholland * same transports.
1465 1.1 dholland */
1466 1.1 dholland if (i == 0) {
1467 1.1 dholland char *up;
1468 1.1 dholland
1469 1.1 dholland error = copyin(&addrs[2*j], &up,
1470 1.1 dholland sizeof(char*));
1471 1.1 dholland if (error)
1472 1.1 dholland goto out;
1473 1.1 dholland error = copyinstr(up, netid, sizeof(netid),
1474 1.1 dholland NULL);
1475 1.1 dholland if (error)
1476 1.1 dholland goto out;
1477 1.1 dholland error = copyin(&addrs[2*j+1], &up,
1478 1.1 dholland sizeof(char*));
1479 1.1 dholland if (error)
1480 1.1 dholland goto out;
1481 1.1 dholland error = copyinstr(up, uaddr, sizeof(uaddr),
1482 1.1 dholland NULL);
1483 1.1 dholland if (error)
1484 1.1 dholland goto out;
1485 1.1 dholland nconf = getnetconfigent(netid);
1486 1.1 dholland if (!nconf) {
1487 1.1 dholland NLM_ERR("Can't lookup netid %s\n",
1488 1.1 dholland netid);
1489 1.1 dholland error = EINVAL;
1490 1.1 dholland goto out;
1491 1.1 dholland }
1492 1.1 dholland xprts[j] = svc_tp_create(pool, dispatchers[i],
1493 1.1 dholland NLM_PROG, versions[i], uaddr, nconf);
1494 1.1 dholland if (!xprts[j]) {
1495 1.1 dholland NLM_ERR("NLM: unable to create "
1496 1.1 dholland "(NLM_PROG, %d).\n", versions[i]);
1497 1.1 dholland error = EINVAL;
1498 1.1 dholland goto out;
1499 1.1 dholland }
1500 1.1 dholland freenetconfigent(nconf);
1501 1.1 dholland } else {
1502 1.1 dholland nconf = getnetconfigent(xprts[j]->xp_netid);
1503 1.1 dholland rpcb_unset(NLM_PROG, versions[i], nconf);
1504 1.1 dholland if (!svc_reg(xprts[j], NLM_PROG, versions[i],
1505 1.1 dholland dispatchers[i], nconf)) {
1506 1.1 dholland NLM_ERR("NLM: can't register "
1507 1.1 dholland "(NLM_PROG, %d)\n", versions[i]);
1508 1.1 dholland error = EINVAL;
1509 1.1 dholland goto out;
1510 1.1 dholland }
1511 1.1 dholland }
1512 1.1 dholland }
1513 1.1 dholland }
1514 1.1 dholland error = 0;
1515 1.1 dholland out:
1516 1.1 dholland for (j = 0; j < addr_count; j++) {
1517 1.1 dholland if (xprts[j])
1518 1.1 dholland SVC_RELEASE(xprts[j]);
1519 1.1 dholland }
1520 1.1 dholland free(xprts, M_NLM);
1521 1.1 dholland return (error);
1522 1.1 dholland }
1523 1.1 dholland
1524 1.1 dholland /*
1525 1.1 dholland * Main server entry point. Contacts the local NSM to get its current
1526 1.1 dholland * state and send SM_UNMON_ALL. Registers the NLM services and then
1527 1.1 dholland * services requests. Does not return until the server is interrupted
1528 1.1 dholland * by a signal.
1529 1.1 dholland */
1530 1.1 dholland static int
1531 1.1 dholland nlm_server_main(int addr_count, char **addrs)
1532 1.1 dholland {
1533 1.1 dholland struct thread *td = curthread;
1534 1.1 dholland int error;
1535 1.1 dholland SVCPOOL *pool = NULL;
1536 1.1 dholland struct sockopt opt;
1537 1.1 dholland int portlow;
1538 1.1 dholland #ifdef INET6
1539 1.1 dholland struct sockaddr_in6 sin6;
1540 1.1 dholland #endif
1541 1.1 dholland struct sockaddr_in sin;
1542 1.1 dholland my_id id;
1543 1.1 dholland sm_stat smstat;
1544 1.1 dholland struct timeval timo;
1545 1.1 dholland enum clnt_stat stat;
1546 1.1 dholland struct nlm_host *host, *nhost;
1547 1.1 dholland struct nlm_waiting_lock *nw;
1548 1.1 dholland vop_advlock_t *old_nfs_advlock;
1549 1.1 dholland vop_reclaim_t *old_nfs_reclaim;
1550 1.1 dholland
1551 1.1 dholland if (nlm_is_running != 0) {
1552 1.1 dholland NLM_ERR("NLM: can't start server - "
1553 1.1 dholland "it appears to be running already\n");
1554 1.1 dholland return (EPERM);
1555 1.1 dholland }
1556 1.1 dholland
1557 1.1 dholland if (nlm_socket == NULL) {
1558 1.1 dholland memset(&opt, 0, sizeof(opt));
1559 1.1 dholland
1560 1.1 dholland error = socreate(AF_INET, &nlm_socket, SOCK_DGRAM, 0,
1561 1.1 dholland td->td_ucred, td);
1562 1.1 dholland if (error) {
1563 1.1 dholland NLM_ERR("NLM: can't create IPv4 socket - error %d\n",
1564 1.1 dholland error);
1565 1.1 dholland return (error);
1566 1.1 dholland }
1567 1.1 dholland opt.sopt_dir = SOPT_SET;
1568 1.1 dholland opt.sopt_level = IPPROTO_IP;
1569 1.1 dholland opt.sopt_name = IP_PORTRANGE;
1570 1.1 dholland portlow = IP_PORTRANGE_LOW;
1571 1.1 dholland opt.sopt_val = &portlow;
1572 1.1 dholland opt.sopt_valsize = sizeof(portlow);
1573 1.1 dholland sosetopt(nlm_socket, &opt);
1574 1.1 dholland
1575 1.1 dholland #ifdef INET6
1576 1.1 dholland nlm_socket6 = NULL;
1577 1.1 dholland error = socreate(AF_INET6, &nlm_socket6, SOCK_DGRAM, 0,
1578 1.1 dholland td->td_ucred, td);
1579 1.1 dholland if (error) {
1580 1.1 dholland NLM_ERR("NLM: can't create IPv6 socket - error %d\n",
1581 1.1 dholland error);
1582 1.1 dholland soclose(nlm_socket);
1583 1.1 dholland nlm_socket = NULL;
1584 1.1 dholland return (error);
1585 1.1 dholland }
1586 1.1 dholland opt.sopt_dir = SOPT_SET;
1587 1.1 dholland opt.sopt_level = IPPROTO_IPV6;
1588 1.1 dholland opt.sopt_name = IPV6_PORTRANGE;
1589 1.1 dholland portlow = IPV6_PORTRANGE_LOW;
1590 1.1 dholland opt.sopt_val = &portlow;
1591 1.1 dholland opt.sopt_valsize = sizeof(portlow);
1592 1.1 dholland sosetopt(nlm_socket6, &opt);
1593 1.1 dholland #endif
1594 1.1 dholland }
1595 1.1 dholland
1596 1.1 dholland nlm_auth = authunix_create(curthread->td_ucred);
1597 1.1 dholland
1598 1.1 dholland #ifdef INET6
1599 1.1 dholland memset(&sin6, 0, sizeof(sin6));
1600 1.1 dholland sin6.sin6_len = sizeof(sin6);
1601 1.1 dholland sin6.sin6_family = AF_INET6;
1602 1.1 dholland sin6.sin6_addr = in6addr_loopback;
1603 1.1 dholland nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin6, SM_PROG, SM_VERS);
1604 1.1 dholland if (!nlm_nsm) {
1605 1.1 dholland #endif
1606 1.1 dholland memset(&sin, 0, sizeof(sin));
1607 1.1 dholland sin.sin_len = sizeof(sin);
1608 1.1 dholland sin.sin_family = AF_INET;
1609 1.1 dholland sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1610 1.1 dholland nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin, SM_PROG,
1611 1.1 dholland SM_VERS);
1612 1.1 dholland #ifdef INET6
1613 1.1 dholland }
1614 1.1 dholland #endif
1615 1.1 dholland
1616 1.1 dholland if (!nlm_nsm) {
1617 1.1 dholland NLM_ERR("Can't start NLM - unable to contact NSM\n");
1618 1.1 dholland error = EINVAL;
1619 1.1 dholland goto out;
1620 1.1 dholland }
1621 1.1 dholland
1622 1.1 dholland pool = svcpool_create("NLM", NULL);
1623 1.1 dholland
1624 1.1 dholland error = nlm_register_services(pool, addr_count, addrs);
1625 1.1 dholland if (error)
1626 1.1 dholland goto out;
1627 1.1 dholland
1628 1.1 dholland memset(&id, 0, sizeof(id));
1629 1.1 dholland id.my_name = "NFS NLM";
1630 1.1 dholland
1631 1.1 dholland timo.tv_sec = 25;
1632 1.1 dholland timo.tv_usec = 0;
1633 1.1 dholland stat = CLNT_CALL(nlm_nsm, SM_UNMON_ALL,
1634 1.1 dholland (xdrproc_t) xdr_my_id, &id,
1635 1.1 dholland (xdrproc_t) xdr_sm_stat, &smstat, timo);
1636 1.1 dholland
1637 1.1 dholland if (stat != RPC_SUCCESS) {
1638 1.1 dholland struct rpc_err err;
1639 1.1 dholland
1640 1.1 dholland CLNT_GETERR(nlm_nsm, &err);
1641 1.1 dholland NLM_ERR("NLM: unexpected error contacting NSM, "
1642 1.1 dholland "stat=%d, errno=%d\n", stat, err.re_errno);
1643 1.1 dholland error = EINVAL;
1644 1.1 dholland goto out;
1645 1.1 dholland }
1646 1.1 dholland nlm_is_running = 1;
1647 1.1 dholland
1648 1.1 dholland NLM_DEBUG(1, "NLM: local NSM state is %d\n", smstat.state);
1649 1.1 dholland nlm_nsm_state = smstat.state;
1650 1.1 dholland
1651 1.1 dholland old_nfs_advlock = nfs_advlock_p;
1652 1.1 dholland nfs_advlock_p = nlm_advlock;
1653 1.1 dholland old_nfs_reclaim = nfs_reclaim_p;
1654 1.1 dholland nfs_reclaim_p = nlm_reclaim;
1655 1.1 dholland
1656 1.1 dholland svc_run(pool);
1657 1.1 dholland error = 0;
1658 1.1 dholland
1659 1.1 dholland nfs_advlock_p = old_nfs_advlock;
1660 1.1 dholland nfs_reclaim_p = old_nfs_reclaim;
1661 1.1 dholland
1662 1.1 dholland out:
1663 1.1 dholland nlm_is_running = 0;
1664 1.1 dholland if (pool)
1665 1.1 dholland svcpool_destroy(pool);
1666 1.1 dholland
1667 1.1 dholland /*
1668 1.1 dholland * We are finished communicating with the NSM.
1669 1.1 dholland */
1670 1.1 dholland if (nlm_nsm) {
1671 1.1 dholland CLNT_RELEASE(nlm_nsm);
1672 1.1 dholland nlm_nsm = NULL;
1673 1.1 dholland }
1674 1.1 dholland
1675 1.1 dholland /*
1676 1.1 dholland * Trash all the existing state so that if the server
1677 1.1 dholland * restarts, it gets a clean slate. This is complicated by the
1678 1.1 dholland * possibility that there may be other threads trying to make
1679 1.1 dholland * client locking requests.
1680 1.1 dholland *
1681 1.1 dholland * First we fake a client reboot notification which will
1682 1.1 dholland * cancel any pending async locks and purge remote lock state
1683 1.1 dholland * from the local lock manager. We release the reference from
1684 1.1 dholland * nlm_hosts to the host (which may remove it from the list
1685 1.1 dholland * and free it). After this phase, the only entries in the
1686 1.1 dholland * nlm_host list should be from other threads performing
1687 1.1 dholland * client lock requests.
1688 1.1 dholland */
1689 1.1 dholland mtx_lock(&nlm_global_lock);
1690 1.1 dholland TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
1691 1.1 dholland wakeup(nw);
1692 1.1 dholland }
1693 1.1 dholland TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, nhost) {
1694 1.1 dholland mtx_unlock(&nlm_global_lock);
1695 1.1 dholland nlm_host_notify(host, 0);
1696 1.1 dholland nlm_host_release(host);
1697 1.1 dholland mtx_lock(&nlm_global_lock);
1698 1.1 dholland }
1699 1.1 dholland mtx_unlock(&nlm_global_lock);
1700 1.1 dholland
1701 1.1 dholland AUTH_DESTROY(nlm_auth);
1702 1.1 dholland
1703 1.1 dholland return (error);
1704 1.1 dholland }
1705 1.1 dholland
1706 1.1 dholland int
1707 1.1 dholland sys_nlm_syscall(struct thread *td, struct nlm_syscall_args *uap)
1708 1.1 dholland {
1709 1.1 dholland int error;
1710 1.1 dholland
1711 1.1 dholland #if __FreeBSD_version >= 700000
1712 1.1 dholland error = priv_check(td, PRIV_NFS_LOCKD);
1713 1.1 dholland #else
1714 1.1 dholland error = suser(td);
1715 1.1 dholland #endif
1716 1.1 dholland if (error)
1717 1.1 dholland return (error);
1718 1.1 dholland
1719 1.1 dholland nlm_debug_level = uap->debug_level;
1720 1.1 dholland nlm_grace_threshold = time_uptime + uap->grace_period;
1721 1.1 dholland nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD;
1722 1.1 dholland
1723 1.1 dholland return nlm_server_main(uap->addr_count, uap->addrs);
1724 1.1 dholland }
1725 1.1 dholland
1726 1.1 dholland /**********************************************************************/
1727 1.1 dholland
1728 1.1 dholland /*
1729 1.1 dholland * NLM implementation details, called from the RPC stubs.
1730 1.1 dholland */
1731 1.1 dholland
1732 1.1 dholland
1733 1.1 dholland void
1734 1.1 dholland nlm_sm_notify(struct nlm_sm_status *argp)
1735 1.1 dholland {
1736 1.1 dholland uint32_t sysid;
1737 1.1 dholland struct nlm_host *host;
1738 1.1 dholland
1739 1.1 dholland NLM_DEBUG(3, "nlm_sm_notify(): mon_name = %s\n", argp->mon_name);
1740 1.1 dholland memcpy(&sysid, &argp->priv, sizeof(sysid));
1741 1.1 dholland host = nlm_find_host_by_sysid(sysid);
1742 1.1 dholland if (host) {
1743 1.1 dholland nlm_host_notify(host, argp->state);
1744 1.1 dholland nlm_host_release(host);
1745 1.1 dholland }
1746 1.1 dholland }
1747 1.1 dholland
1748 1.1 dholland static void
1749 1.1 dholland nlm_convert_to_fhandle_t(fhandle_t *fhp, struct netobj *p)
1750 1.1 dholland {
1751 1.1 dholland memcpy(fhp, p->n_bytes, sizeof(fhandle_t));
1752 1.1 dholland }
1753 1.1 dholland
1754 1.1 dholland struct vfs_state {
1755 1.1 dholland struct mount *vs_mp;
1756 1.1 dholland struct vnode *vs_vp;
1757 1.1 dholland int vs_vnlocked;
1758 1.1 dholland };
1759 1.1 dholland
1760 1.1 dholland static int
1761 1.1 dholland nlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp,
1762 1.1 dholland fhandle_t *fhp, struct vfs_state *vs, accmode_t accmode)
1763 1.1 dholland {
1764 1.1 dholland int error, exflags;
1765 1.1 dholland struct ucred *cred = NULL, *credanon = NULL;
1766 1.1 dholland
1767 1.1 dholland memset(vs, 0, sizeof(*vs));
1768 1.1 dholland
1769 1.1 dholland vs->vs_mp = vfs_getvfs(&fhp->fh_fsid);
1770 1.1 dholland if (!vs->vs_mp) {
1771 1.1 dholland return (ESTALE);
1772 1.1 dholland }
1773 1.1 dholland
1774 1.1 dholland /* accmode == 0 means don't check, since it is an unlock. */
1775 1.1 dholland if (accmode != 0) {
1776 1.1 dholland error = VFS_CHECKEXP(vs->vs_mp,
1777 1.1 dholland (struct sockaddr *)&host->nh_addr, &exflags, &credanon,
1778 1.1 dholland NULL, NULL);
1779 1.1 dholland if (error)
1780 1.1 dholland goto out;
1781 1.1 dholland
1782 1.1 dholland if (exflags & MNT_EXRDONLY ||
1783 1.1 dholland (vs->vs_mp->mnt_flag & MNT_RDONLY)) {
1784 1.1 dholland error = EROFS;
1785 1.1 dholland goto out;
1786 1.1 dholland }
1787 1.1 dholland }
1788 1.1 dholland
1789 1.1 dholland error = VFS_FHTOVP(vs->vs_mp, &fhp->fh_fid, LK_EXCLUSIVE, &vs->vs_vp);
1790 1.1 dholland if (error)
1791 1.1 dholland goto out;
1792 1.1 dholland vs->vs_vnlocked = TRUE;
1793 1.1 dholland
1794 1.1 dholland if (accmode != 0) {
1795 1.1 dholland if (!svc_getcred(rqstp, &cred, NULL)) {
1796 1.1 dholland error = EINVAL;
1797 1.1 dholland goto out;
1798 1.1 dholland }
1799 1.1 dholland if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1800 1.1 dholland crfree(cred);
1801 1.1 dholland cred = credanon;
1802 1.1 dholland credanon = NULL;
1803 1.1 dholland }
1804 1.1 dholland
1805 1.1 dholland /*
1806 1.1 dholland * Check cred.
1807 1.1 dholland */
1808 1.1 dholland error = VOP_ACCESS(vs->vs_vp, accmode, cred, curthread);
1809 1.1 dholland /*
1810 1.1 dholland * If this failed and accmode != VWRITE, try again with
1811 1.1 dholland * VWRITE to maintain backwards compatibility with the
1812 1.1 dholland * old code that always used VWRITE.
1813 1.1 dholland */
1814 1.1 dholland if (error != 0 && accmode != VWRITE)
1815 1.1 dholland error = VOP_ACCESS(vs->vs_vp, VWRITE, cred, curthread);
1816 1.1 dholland if (error)
1817 1.1 dholland goto out;
1818 1.1 dholland }
1819 1.1 dholland
1820 1.1 dholland #if __FreeBSD_version < 800011
1821 1.1 dholland VOP_UNLOCK(vs->vs_vp, 0, curthread);
1822 1.1 dholland #else
1823 1.1 dholland VOP_UNLOCK(vs->vs_vp, 0);
1824 1.1 dholland #endif
1825 1.1 dholland vs->vs_vnlocked = FALSE;
1826 1.1 dholland
1827 1.1 dholland out:
1828 1.1 dholland if (cred)
1829 1.1 dholland crfree(cred);
1830 1.1 dholland if (credanon)
1831 1.1 dholland crfree(credanon);
1832 1.1 dholland
1833 1.1 dholland return (error);
1834 1.1 dholland }
1835 1.1 dholland
1836 1.1 dholland static void
1837 1.1 dholland nlm_release_vfs_state(struct vfs_state *vs)
1838 1.1 dholland {
1839 1.1 dholland
1840 1.1 dholland if (vs->vs_vp) {
1841 1.1 dholland if (vs->vs_vnlocked)
1842 1.1 dholland vput(vs->vs_vp);
1843 1.1 dholland else
1844 1.1 dholland vrele(vs->vs_vp);
1845 1.1 dholland }
1846 1.1 dholland if (vs->vs_mp)
1847 1.1 dholland vfs_rel(vs->vs_mp);
1848 1.1 dholland }
1849 1.1 dholland
1850 1.1 dholland static nlm4_stats
1851 1.1 dholland nlm_convert_error(int error)
1852 1.1 dholland {
1853 1.1 dholland
1854 1.1 dholland if (error == ESTALE)
1855 1.1 dholland return nlm4_stale_fh;
1856 1.1 dholland else if (error == EROFS)
1857 1.1 dholland return nlm4_rofs;
1858 1.1 dholland else
1859 1.1 dholland return nlm4_failed;
1860 1.1 dholland }
1861 1.1 dholland
1862 1.1 dholland int
1863 1.1 dholland nlm_do_test(nlm4_testargs *argp, nlm4_testres *result, struct svc_req *rqstp,
1864 1.1 dholland CLIENT **rpcp)
1865 1.1 dholland {
1866 1.1 dholland fhandle_t fh;
1867 1.1 dholland struct vfs_state vs;
1868 1.1 dholland struct nlm_host *host, *bhost;
1869 1.1 dholland int error, sysid;
1870 1.1 dholland struct flock fl;
1871 1.1 dholland accmode_t accmode;
1872 1.1 dholland
1873 1.1 dholland memset(result, 0, sizeof(*result));
1874 1.1 dholland memset(&vs, 0, sizeof(vs));
1875 1.1 dholland
1876 1.1 dholland host = nlm_find_host_by_name(argp->alock.caller_name,
1877 1.1 dholland svc_getrpccaller(rqstp), rqstp->rq_vers);
1878 1.1 dholland if (!host) {
1879 1.1 dholland result->stat.stat = nlm4_denied_nolocks;
1880 1.1 dholland return (ENOMEM);
1881 1.1 dholland }
1882 1.1 dholland
1883 1.1 dholland NLM_DEBUG(3, "nlm_do_test(): caller_name = %s (sysid = %d)\n",
1884 1.1 dholland host->nh_caller_name, host->nh_sysid);
1885 1.1 dholland
1886 1.1 dholland nlm_check_expired_locks(host);
1887 1.1 dholland sysid = host->nh_sysid;
1888 1.1 dholland
1889 1.1 dholland nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
1890 1.1 dholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
1891 1.1 dholland
1892 1.1 dholland if (time_uptime < nlm_grace_threshold) {
1893 1.1 dholland result->stat.stat = nlm4_denied_grace_period;
1894 1.1 dholland goto out;
1895 1.1 dholland }
1896 1.1 dholland
1897 1.1 dholland accmode = argp->exclusive ? VWRITE : VREAD;
1898 1.1 dholland error = nlm_get_vfs_state(host, rqstp, &fh, &vs, accmode);
1899 1.1 dholland if (error) {
1900 1.1 dholland result->stat.stat = nlm_convert_error(error);
1901 1.1 dholland goto out;
1902 1.1 dholland }
1903 1.1 dholland
1904 1.1 dholland fl.l_start = argp->alock.l_offset;
1905 1.1 dholland fl.l_len = argp->alock.l_len;
1906 1.1 dholland fl.l_pid = argp->alock.svid;
1907 1.1 dholland fl.l_sysid = sysid;
1908 1.1 dholland fl.l_whence = SEEK_SET;
1909 1.1 dholland if (argp->exclusive)
1910 1.1 dholland fl.l_type = F_WRLCK;
1911 1.1 dholland else
1912 1.1 dholland fl.l_type = F_RDLCK;
1913 1.1 dholland error = VOP_ADVLOCK(vs.vs_vp, NULL, F_GETLK, &fl, F_REMOTE);
1914 1.1 dholland if (error) {
1915 1.1 dholland result->stat.stat = nlm4_failed;
1916 1.1 dholland goto out;
1917 1.1 dholland }
1918 1.1 dholland
1919 1.1 dholland if (fl.l_type == F_UNLCK) {
1920 1.1 dholland result->stat.stat = nlm4_granted;
1921 1.1 dholland } else {
1922 1.1 dholland result->stat.stat = nlm4_denied;
1923 1.1 dholland result->stat.nlm4_testrply_u.holder.exclusive =
1924 1.1 dholland (fl.l_type == F_WRLCK);
1925 1.1 dholland result->stat.nlm4_testrply_u.holder.svid = fl.l_pid;
1926 1.1 dholland bhost = nlm_find_host_by_sysid(fl.l_sysid);
1927 1.1 dholland if (bhost) {
1928 1.1 dholland /*
1929 1.1 dholland * We don't have any useful way of recording
1930 1.1 dholland * the value of oh used in the original lock
1931 1.1 dholland * request. Ideally, the test reply would have
1932 1.1 dholland * a space for the owning host's name allowing
1933 1.1 dholland * our caller's NLM to keep track.
1934 1.1 dholland *
1935 1.1 dholland * As far as I can see, Solaris uses an eight
1936 1.1 dholland * byte structure for oh which contains a four
1937 1.1 dholland * byte pid encoded in local byte order and
1938 1.1 dholland * the first four bytes of the host
1939 1.1 dholland * name. Linux uses a variable length string
1940 1.1 dholland * 'pid@hostname' in ascii but doesn't even
1941 1.1 dholland * return that in test replies.
1942 1.1 dholland *
1943 1.1 dholland * For the moment, return nothing in oh
1944 1.1 dholland * (already zero'ed above).
1945 1.1 dholland */
1946 1.1 dholland nlm_host_release(bhost);
1947 1.1 dholland }
1948 1.1 dholland result->stat.nlm4_testrply_u.holder.l_offset = fl.l_start;
1949 1.1 dholland result->stat.nlm4_testrply_u.holder.l_len = fl.l_len;
1950 1.1 dholland }
1951 1.1 dholland
1952 1.1 dholland out:
1953 1.1 dholland nlm_release_vfs_state(&vs);
1954 1.1 dholland if (rpcp)
1955 1.1 dholland *rpcp = nlm_host_get_rpc(host, TRUE);
1956 1.1 dholland nlm_host_release(host);
1957 1.1 dholland return (0);
1958 1.1 dholland }
1959 1.1 dholland
1960 1.1 dholland int
1961 1.1 dholland nlm_do_lock(nlm4_lockargs *argp, nlm4_res *result, struct svc_req *rqstp,
1962 1.1 dholland bool_t monitor, CLIENT **rpcp)
1963 1.1 dholland {
1964 1.1 dholland fhandle_t fh;
1965 1.1 dholland struct vfs_state vs;
1966 1.1 dholland struct nlm_host *host;
1967 1.1 dholland int error, sysid;
1968 1.1 dholland struct flock fl;
1969 1.1 dholland accmode_t accmode;
1970 1.1 dholland
1971 1.1 dholland memset(result, 0, sizeof(*result));
1972 1.1 dholland memset(&vs, 0, sizeof(vs));
1973 1.1 dholland
1974 1.1 dholland host = nlm_find_host_by_name(argp->alock.caller_name,
1975 1.1 dholland svc_getrpccaller(rqstp), rqstp->rq_vers);
1976 1.1 dholland if (!host) {
1977 1.1 dholland result->stat.stat = nlm4_denied_nolocks;
1978 1.1 dholland return (ENOMEM);
1979 1.1 dholland }
1980 1.1 dholland
1981 1.1 dholland NLM_DEBUG(3, "nlm_do_lock(): caller_name = %s (sysid = %d)\n",
1982 1.1 dholland host->nh_caller_name, host->nh_sysid);
1983 1.1 dholland
1984 1.1 dholland if (monitor && host->nh_state && argp->state
1985 1.1 dholland && host->nh_state != argp->state) {
1986 1.1 dholland /*
1987 1.1 dholland * The host rebooted without telling us. Trash its
1988 1.1 dholland * locks.
1989 1.1 dholland */
1990 1.1 dholland nlm_host_notify(host, argp->state);
1991 1.1 dholland }
1992 1.1 dholland
1993 1.1 dholland nlm_check_expired_locks(host);
1994 1.1 dholland sysid = host->nh_sysid;
1995 1.1 dholland
1996 1.1 dholland nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
1997 1.1 dholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
1998 1.1 dholland
1999 1.1 dholland if (time_uptime < nlm_grace_threshold && !argp->reclaim) {
2000 1.1 dholland result->stat.stat = nlm4_denied_grace_period;
2001 1.1 dholland goto out;
2002 1.1 dholland }
2003 1.1 dholland
2004 1.1 dholland accmode = argp->exclusive ? VWRITE : VREAD;
2005 1.1 dholland error = nlm_get_vfs_state(host, rqstp, &fh, &vs, accmode);
2006 1.1 dholland if (error) {
2007 1.1 dholland result->stat.stat = nlm_convert_error(error);
2008 1.1 dholland goto out;
2009 1.1 dholland }
2010 1.1 dholland
2011 1.1 dholland fl.l_start = argp->alock.l_offset;
2012 1.1 dholland fl.l_len = argp->alock.l_len;
2013 1.1 dholland fl.l_pid = argp->alock.svid;
2014 1.1 dholland fl.l_sysid = sysid;
2015 1.1 dholland fl.l_whence = SEEK_SET;
2016 1.1 dholland if (argp->exclusive)
2017 1.1 dholland fl.l_type = F_WRLCK;
2018 1.1 dholland else
2019 1.1 dholland fl.l_type = F_RDLCK;
2020 1.1 dholland if (argp->block) {
2021 1.1 dholland struct nlm_async_lock *af;
2022 1.1 dholland CLIENT *client;
2023 1.1 dholland struct nlm_grantcookie cookie;
2024 1.1 dholland
2025 1.1 dholland /*
2026 1.1 dholland * First, make sure we can contact the host's NLM.
2027 1.1 dholland */
2028 1.1 dholland client = nlm_host_get_rpc(host, TRUE);
2029 1.1 dholland if (!client) {
2030 1.1 dholland result->stat.stat = nlm4_failed;
2031 1.1 dholland goto out;
2032 1.1 dholland }
2033 1.1 dholland
2034 1.1 dholland /*
2035 1.1 dholland * First we need to check and see if there is an
2036 1.1 dholland * existing blocked lock that matches. This could be a
2037 1.1 dholland * badly behaved client or an RPC re-send. If we find
2038 1.1 dholland * one, just return nlm4_blocked.
2039 1.1 dholland */
2040 1.1 dholland mtx_lock(&host->nh_lock);
2041 1.1 dholland TAILQ_FOREACH(af, &host->nh_pending, af_link) {
2042 1.1 dholland if (af->af_fl.l_start == fl.l_start
2043 1.1 dholland && af->af_fl.l_len == fl.l_len
2044 1.1 dholland && af->af_fl.l_pid == fl.l_pid
2045 1.1 dholland && af->af_fl.l_type == fl.l_type) {
2046 1.1 dholland break;
2047 1.1 dholland }
2048 1.1 dholland }
2049 1.1 dholland if (!af) {
2050 1.1 dholland cookie.ng_sysid = host->nh_sysid;
2051 1.1 dholland cookie.ng_cookie = host->nh_grantcookie++;
2052 1.1 dholland }
2053 1.1 dholland mtx_unlock(&host->nh_lock);
2054 1.1 dholland if (af) {
2055 1.1 dholland CLNT_RELEASE(client);
2056 1.1 dholland result->stat.stat = nlm4_blocked;
2057 1.1 dholland goto out;
2058 1.1 dholland }
2059 1.1 dholland
2060 1.1 dholland af = malloc(sizeof(struct nlm_async_lock), M_NLM,
2061 1.1 dholland M_WAITOK|M_ZERO);
2062 1.1 dholland TASK_INIT(&af->af_task, 0, nlm_lock_callback, af);
2063 1.1 dholland af->af_vp = vs.vs_vp;
2064 1.1 dholland af->af_fl = fl;
2065 1.1 dholland af->af_host = host;
2066 1.1 dholland af->af_rpc = client;
2067 1.1 dholland /*
2068 1.1 dholland * We use M_RPC here so that we can xdr_free the thing
2069 1.1 dholland * later.
2070 1.1 dholland */
2071 1.1 dholland nlm_make_netobj(&af->af_granted.cookie,
2072 1.1 dholland (caddr_t)&cookie, sizeof(cookie), M_RPC);
2073 1.1 dholland af->af_granted.exclusive = argp->exclusive;
2074 1.1 dholland af->af_granted.alock.caller_name =
2075 1.1 dholland strdup(argp->alock.caller_name, M_RPC);
2076 1.1 dholland nlm_copy_netobj(&af->af_granted.alock.fh,
2077 1.1 dholland &argp->alock.fh, M_RPC);
2078 1.1 dholland nlm_copy_netobj(&af->af_granted.alock.oh,
2079 1.1 dholland &argp->alock.oh, M_RPC);
2080 1.1 dholland af->af_granted.alock.svid = argp->alock.svid;
2081 1.1 dholland af->af_granted.alock.l_offset = argp->alock.l_offset;
2082 1.1 dholland af->af_granted.alock.l_len = argp->alock.l_len;
2083 1.1 dholland
2084 1.1 dholland /*
2085 1.1 dholland * Put the entry on the pending list before calling
2086 1.1 dholland * VOP_ADVLOCKASYNC. We do this in case the lock
2087 1.1 dholland * request was blocked (returning EINPROGRESS) but
2088 1.1 dholland * then granted before we manage to run again. The
2089 1.1 dholland * client may receive the granted message before we
2090 1.1 dholland * send our blocked reply but thats their problem.
2091 1.1 dholland */
2092 1.1 dholland mtx_lock(&host->nh_lock);
2093 1.1 dholland TAILQ_INSERT_TAIL(&host->nh_pending, af, af_link);
2094 1.1 dholland mtx_unlock(&host->nh_lock);
2095 1.1 dholland
2096 1.1 dholland error = VOP_ADVLOCKASYNC(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE,
2097 1.1 dholland &af->af_task, &af->af_cookie);
2098 1.1 dholland
2099 1.1 dholland /*
2100 1.1 dholland * If the lock completed synchronously, just free the
2101 1.1 dholland * tracking structure now.
2102 1.1 dholland */
2103 1.1 dholland if (error != EINPROGRESS) {
2104 1.1 dholland CLNT_RELEASE(af->af_rpc);
2105 1.1 dholland mtx_lock(&host->nh_lock);
2106 1.1 dholland TAILQ_REMOVE(&host->nh_pending, af, af_link);
2107 1.1 dholland mtx_unlock(&host->nh_lock);
2108 1.1 dholland xdr_free((xdrproc_t) xdr_nlm4_testargs,
2109 1.1 dholland &af->af_granted);
2110 1.1 dholland free(af, M_NLM);
2111 1.1 dholland } else {
2112 1.1 dholland NLM_DEBUG(2, "NLM: pending async lock %p for %s "
2113 1.1 dholland "(sysid %d)\n", af, host->nh_caller_name, sysid);
2114 1.1 dholland /*
2115 1.1 dholland * Don't vrele the vnode just yet - this must
2116 1.1 dholland * wait until either the async callback
2117 1.1 dholland * happens or the lock is cancelled.
2118 1.1 dholland */
2119 1.1 dholland vs.vs_vp = NULL;
2120 1.1 dholland }
2121 1.1 dholland } else {
2122 1.1 dholland error = VOP_ADVLOCK(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE);
2123 1.1 dholland }
2124 1.1 dholland
2125 1.1 dholland if (error) {
2126 1.1 dholland if (error == EINPROGRESS) {
2127 1.1 dholland result->stat.stat = nlm4_blocked;
2128 1.1 dholland } else if (error == EDEADLK) {
2129 1.1 dholland result->stat.stat = nlm4_deadlck;
2130 1.1 dholland } else if (error == EAGAIN) {
2131 1.1 dholland result->stat.stat = nlm4_denied;
2132 1.1 dholland } else {
2133 1.1 dholland result->stat.stat = nlm4_failed;
2134 1.1 dholland }
2135 1.1 dholland } else {
2136 1.1 dholland if (monitor)
2137 1.1 dholland nlm_host_monitor(host, argp->state);
2138 1.1 dholland result->stat.stat = nlm4_granted;
2139 1.1 dholland }
2140 1.1 dholland
2141 1.1 dholland out:
2142 1.1 dholland nlm_release_vfs_state(&vs);
2143 1.1 dholland if (rpcp)
2144 1.1 dholland *rpcp = nlm_host_get_rpc(host, TRUE);
2145 1.1 dholland nlm_host_release(host);
2146 1.1 dholland return (0);
2147 1.1 dholland }
2148 1.1 dholland
2149 1.1 dholland int
2150 1.1 dholland nlm_do_cancel(nlm4_cancargs *argp, nlm4_res *result, struct svc_req *rqstp,
2151 1.1 dholland CLIENT **rpcp)
2152 1.1 dholland {
2153 1.1 dholland fhandle_t fh;
2154 1.1 dholland struct vfs_state vs;
2155 1.1 dholland struct nlm_host *host;
2156 1.1 dholland int error, sysid;
2157 1.1 dholland struct flock fl;
2158 1.1 dholland struct nlm_async_lock *af;
2159 1.1 dholland
2160 1.1 dholland memset(result, 0, sizeof(*result));
2161 1.1 dholland memset(&vs, 0, sizeof(vs));
2162 1.1 dholland
2163 1.1 dholland host = nlm_find_host_by_name(argp->alock.caller_name,
2164 1.1 dholland svc_getrpccaller(rqstp), rqstp->rq_vers);
2165 1.1 dholland if (!host) {
2166 1.1 dholland result->stat.stat = nlm4_denied_nolocks;
2167 1.1 dholland return (ENOMEM);
2168 1.1 dholland }
2169 1.1 dholland
2170 1.1 dholland NLM_DEBUG(3, "nlm_do_cancel(): caller_name = %s (sysid = %d)\n",
2171 1.1 dholland host->nh_caller_name, host->nh_sysid);
2172 1.1 dholland
2173 1.1 dholland nlm_check_expired_locks(host);
2174 1.1 dholland sysid = host->nh_sysid;
2175 1.1 dholland
2176 1.1 dholland nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
2177 1.1 dholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
2178 1.1 dholland
2179 1.1 dholland if (time_uptime < nlm_grace_threshold) {
2180 1.1 dholland result->stat.stat = nlm4_denied_grace_period;
2181 1.1 dholland goto out;
2182 1.1 dholland }
2183 1.1 dholland
2184 1.1 dholland error = nlm_get_vfs_state(host, rqstp, &fh, &vs, (accmode_t)0);
2185 1.1 dholland if (error) {
2186 1.1 dholland result->stat.stat = nlm_convert_error(error);
2187 1.1 dholland goto out;
2188 1.1 dholland }
2189 1.1 dholland
2190 1.1 dholland fl.l_start = argp->alock.l_offset;
2191 1.1 dholland fl.l_len = argp->alock.l_len;
2192 1.1 dholland fl.l_pid = argp->alock.svid;
2193 1.1 dholland fl.l_sysid = sysid;
2194 1.1 dholland fl.l_whence = SEEK_SET;
2195 1.1 dholland if (argp->exclusive)
2196 1.1 dholland fl.l_type = F_WRLCK;
2197 1.1 dholland else
2198 1.1 dholland fl.l_type = F_RDLCK;
2199 1.1 dholland
2200 1.1 dholland /*
2201 1.1 dholland * First we need to try and find the async lock request - if
2202 1.1 dholland * there isn't one, we give up and return nlm4_denied.
2203 1.1 dholland */
2204 1.1 dholland mtx_lock(&host->nh_lock);
2205 1.1 dholland
2206 1.1 dholland TAILQ_FOREACH(af, &host->nh_pending, af_link) {
2207 1.1 dholland if (af->af_fl.l_start == fl.l_start
2208 1.1 dholland && af->af_fl.l_len == fl.l_len
2209 1.1 dholland && af->af_fl.l_pid == fl.l_pid
2210 1.1 dholland && af->af_fl.l_type == fl.l_type) {
2211 1.1 dholland break;
2212 1.1 dholland }
2213 1.1 dholland }
2214 1.1 dholland
2215 1.1 dholland if (!af) {
2216 1.1 dholland mtx_unlock(&host->nh_lock);
2217 1.1 dholland result->stat.stat = nlm4_denied;
2218 1.1 dholland goto out;
2219 1.1 dholland }
2220 1.1 dholland
2221 1.1 dholland error = nlm_cancel_async_lock(af);
2222 1.1 dholland
2223 1.1 dholland if (error) {
2224 1.1 dholland result->stat.stat = nlm4_denied;
2225 1.1 dholland } else {
2226 1.1 dholland result->stat.stat = nlm4_granted;
2227 1.1 dholland }
2228 1.1 dholland
2229 1.1 dholland mtx_unlock(&host->nh_lock);
2230 1.1 dholland
2231 1.1 dholland out:
2232 1.1 dholland nlm_release_vfs_state(&vs);
2233 1.1 dholland if (rpcp)
2234 1.1 dholland *rpcp = nlm_host_get_rpc(host, TRUE);
2235 1.1 dholland nlm_host_release(host);
2236 1.1 dholland return (0);
2237 1.1 dholland }
2238 1.1 dholland
2239 1.1 dholland int
2240 1.1 dholland nlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *result, struct svc_req *rqstp,
2241 1.1 dholland CLIENT **rpcp)
2242 1.1 dholland {
2243 1.1 dholland fhandle_t fh;
2244 1.1 dholland struct vfs_state vs;
2245 1.1 dholland struct nlm_host *host;
2246 1.1 dholland int error, sysid;
2247 1.1 dholland struct flock fl;
2248 1.1 dholland
2249 1.1 dholland memset(result, 0, sizeof(*result));
2250 1.1 dholland memset(&vs, 0, sizeof(vs));
2251 1.1 dholland
2252 1.1 dholland host = nlm_find_host_by_name(argp->alock.caller_name,
2253 1.1 dholland svc_getrpccaller(rqstp), rqstp->rq_vers);
2254 1.1 dholland if (!host) {
2255 1.1 dholland result->stat.stat = nlm4_denied_nolocks;
2256 1.1 dholland return (ENOMEM);
2257 1.1 dholland }
2258 1.1 dholland
2259 1.1 dholland NLM_DEBUG(3, "nlm_do_unlock(): caller_name = %s (sysid = %d)\n",
2260 1.1 dholland host->nh_caller_name, host->nh_sysid);
2261 1.1 dholland
2262 1.1 dholland nlm_check_expired_locks(host);
2263 1.1 dholland sysid = host->nh_sysid;
2264 1.1 dholland
2265 1.1 dholland nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
2266 1.1 dholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
2267 1.1 dholland
2268 1.1 dholland if (time_uptime < nlm_grace_threshold) {
2269 1.1 dholland result->stat.stat = nlm4_denied_grace_period;
2270 1.1 dholland goto out;
2271 1.1 dholland }
2272 1.1 dholland
2273 1.1 dholland error = nlm_get_vfs_state(host, rqstp, &fh, &vs, (accmode_t)0);
2274 1.1 dholland if (error) {
2275 1.1 dholland result->stat.stat = nlm_convert_error(error);
2276 1.1 dholland goto out;
2277 1.1 dholland }
2278 1.1 dholland
2279 1.1 dholland fl.l_start = argp->alock.l_offset;
2280 1.1 dholland fl.l_len = argp->alock.l_len;
2281 1.1 dholland fl.l_pid = argp->alock.svid;
2282 1.1 dholland fl.l_sysid = sysid;
2283 1.1 dholland fl.l_whence = SEEK_SET;
2284 1.1 dholland fl.l_type = F_UNLCK;
2285 1.1 dholland error = VOP_ADVLOCK(vs.vs_vp, NULL, F_UNLCK, &fl, F_REMOTE);
2286 1.1 dholland
2287 1.1 dholland /*
2288 1.1 dholland * Ignore the error - there is no result code for failure,
2289 1.1 dholland * only for grace period.
2290 1.1 dholland */
2291 1.1 dholland result->stat.stat = nlm4_granted;
2292 1.1 dholland
2293 1.1 dholland out:
2294 1.1 dholland nlm_release_vfs_state(&vs);
2295 1.1 dholland if (rpcp)
2296 1.1 dholland *rpcp = nlm_host_get_rpc(host, TRUE);
2297 1.1 dholland nlm_host_release(host);
2298 1.1 dholland return (0);
2299 1.1 dholland }
2300 1.1 dholland
2301 1.1 dholland int
2302 1.1 dholland nlm_do_granted(nlm4_testargs *argp, nlm4_res *result, struct svc_req *rqstp,
2303 1.1 dholland
2304 1.1 dholland CLIENT **rpcp)
2305 1.1 dholland {
2306 1.1 dholland struct nlm_host *host;
2307 1.1 dholland struct nlm_waiting_lock *nw;
2308 1.1 dholland
2309 1.1 dholland memset(result, 0, sizeof(*result));
2310 1.1 dholland
2311 1.1 dholland host = nlm_find_host_by_addr(svc_getrpccaller(rqstp), rqstp->rq_vers);
2312 1.1 dholland if (!host) {
2313 1.1 dholland result->stat.stat = nlm4_denied_nolocks;
2314 1.1 dholland return (ENOMEM);
2315 1.1 dholland }
2316 1.1 dholland
2317 1.1 dholland nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
2318 1.1 dholland result->stat.stat = nlm4_denied;
2319 1.1 dholland KFAIL_POINT_CODE(DEBUG_FP, nlm_deny_grant, goto out);
2320 1.1 dholland
2321 1.1 dholland mtx_lock(&nlm_global_lock);
2322 1.1 dholland TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
2323 1.1 dholland if (!nw->nw_waiting)
2324 1.1 dholland continue;
2325 1.1 dholland if (argp->alock.svid == nw->nw_lock.svid
2326 1.1 dholland && argp->alock.l_offset == nw->nw_lock.l_offset
2327 1.1 dholland && argp->alock.l_len == nw->nw_lock.l_len
2328 1.1 dholland && argp->alock.fh.n_len == nw->nw_lock.fh.n_len
2329 1.1 dholland && !memcmp(argp->alock.fh.n_bytes, nw->nw_lock.fh.n_bytes,
2330 1.1 dholland nw->nw_lock.fh.n_len)) {
2331 1.1 dholland nw->nw_waiting = FALSE;
2332 1.1 dholland wakeup(nw);
2333 1.1 dholland result->stat.stat = nlm4_granted;
2334 1.1 dholland break;
2335 1.1 dholland }
2336 1.1 dholland }
2337 1.1 dholland mtx_unlock(&nlm_global_lock);
2338 1.1 dholland
2339 1.1 dholland out:
2340 1.1 dholland if (rpcp)
2341 1.1 dholland *rpcp = nlm_host_get_rpc(host, TRUE);
2342 1.1 dholland nlm_host_release(host);
2343 1.1 dholland return (0);
2344 1.1 dholland }
2345 1.1 dholland
2346 1.1 dholland void
2347 1.1 dholland nlm_do_granted_res(nlm4_res *argp, struct svc_req *rqstp)
2348 1.1 dholland {
2349 1.1 dholland struct nlm_host *host = NULL;
2350 1.1 dholland struct nlm_async_lock *af = NULL;
2351 1.1 dholland int error;
2352 1.1 dholland
2353 1.1 dholland if (argp->cookie.n_len != sizeof(struct nlm_grantcookie)) {
2354 1.1 dholland NLM_DEBUG(1, "NLM: bogus grant cookie");
2355 1.1 dholland goto out;
2356 1.1 dholland }
2357 1.1 dholland
2358 1.1 dholland host = nlm_find_host_by_sysid(ng_sysid(&argp->cookie));
2359 1.1 dholland if (!host) {
2360 1.1 dholland NLM_DEBUG(1, "NLM: Unknown host rejected our grant");
2361 1.1 dholland goto out;
2362 1.1 dholland }
2363 1.1 dholland
2364 1.1 dholland mtx_lock(&host->nh_lock);
2365 1.1 dholland TAILQ_FOREACH(af, &host->nh_granted, af_link)
2366 1.1 dholland if (ng_cookie(&argp->cookie) ==
2367 1.1 dholland ng_cookie(&af->af_granted.cookie))
2368 1.1 dholland break;
2369 1.1 dholland if (af)
2370 1.1 dholland TAILQ_REMOVE(&host->nh_granted, af, af_link);
2371 1.1 dholland mtx_unlock(&host->nh_lock);
2372 1.1 dholland
2373 1.1 dholland if (!af) {
2374 1.1 dholland NLM_DEBUG(1, "NLM: host %s (sysid %d) replied to our grant "
2375 1.1 dholland "with unrecognized cookie %d:%d", host->nh_caller_name,
2376 1.1 dholland host->nh_sysid, ng_sysid(&argp->cookie),
2377 1.1 dholland ng_cookie(&argp->cookie));
2378 1.1 dholland goto out;
2379 1.1 dholland }
2380 1.1 dholland
2381 1.1 dholland if (argp->stat.stat != nlm4_granted) {
2382 1.1 dholland af->af_fl.l_type = F_UNLCK;
2383 1.1 dholland error = VOP_ADVLOCK(af->af_vp, NULL, F_UNLCK, &af->af_fl, F_REMOTE);
2384 1.1 dholland if (error) {
2385 1.1 dholland NLM_DEBUG(1, "NLM: host %s (sysid %d) rejected our grant "
2386 1.1 dholland "and we failed to unlock (%d)", host->nh_caller_name,
2387 1.1 dholland host->nh_sysid, error);
2388 1.1 dholland goto out;
2389 1.1 dholland }
2390 1.1 dholland
2391 1.1 dholland NLM_DEBUG(5, "NLM: async lock %p rejected by host %s (sysid %d)",
2392 1.1 dholland af, host->nh_caller_name, host->nh_sysid);
2393 1.1 dholland } else {
2394 1.1 dholland NLM_DEBUG(5, "NLM: async lock %p accepted by host %s (sysid %d)",
2395 1.1 dholland af, host->nh_caller_name, host->nh_sysid);
2396 1.1 dholland }
2397 1.1 dholland
2398 1.1 dholland out:
2399 1.1 dholland if (af)
2400 1.1 dholland nlm_free_async_lock(af);
2401 1.1 dholland if (host)
2402 1.1 dholland nlm_host_release(host);
2403 1.1 dholland }
2404 1.1 dholland
2405 1.1 dholland void
2406 1.1 dholland nlm_do_free_all(nlm4_notify *argp)
2407 1.1 dholland {
2408 1.1 dholland struct nlm_host *host, *thost;
2409 1.1 dholland
2410 1.1 dholland TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, thost) {
2411 1.1 dholland if (!strcmp(host->nh_caller_name, argp->name))
2412 1.1 dholland nlm_host_notify(host, argp->state);
2413 1.1 dholland }
2414 1.1 dholland }
2415 1.1 dholland
2416 1.1 dholland /*
2417 1.1 dholland * Kernel module glue
2418 1.1 dholland */
2419 1.1 dholland static int
2420 1.1 dholland nfslockd_modevent(module_t mod, int type, void *data)
2421 1.1 dholland {
2422 1.1 dholland
2423 1.1 dholland switch (type) {
2424 1.1 dholland case MOD_LOAD:
2425 1.1 dholland return (0);
2426 1.1 dholland case MOD_UNLOAD:
2427 1.1 dholland /* The NLM module cannot be safely unloaded. */
2428 1.1 dholland /* FALLTHROUGH */
2429 1.1 dholland default:
2430 1.1 dholland return (EOPNOTSUPP);
2431 1.1 dholland }
2432 1.1 dholland }
2433 1.1 dholland static moduledata_t nfslockd_mod = {
2434 1.1 dholland "nfslockd",
2435 1.1 dholland nfslockd_modevent,
2436 1.1 dholland NULL,
2437 1.1 dholland };
2438 1.1 dholland DECLARE_MODULE(nfslockd, nfslockd_mod, SI_SUB_VFS, SI_ORDER_ANY);
2439 1.1 dholland
2440 1.1 dholland /* So that loader and kldload(2) can find us, wherever we are.. */
2441 1.1 dholland MODULE_DEPEND(nfslockd, krpc, 1, 1, 1);
2442 1.1 dholland MODULE_DEPEND(nfslockd, nfslock, 1, 1, 1);
2443 1.1 dholland MODULE_VERSION(nfslockd, 1);
2444