Deleted Added
sdiff udiff text old ( 197730 ) new ( 197840 )
full compact
1/*-
2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3 * Authors: Doug Rabson <dfr@rabson.org>
4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 14 unchanged lines hidden (view full) ---

23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include "opt_inet6.h"
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/nlm/nlm_prot_impl.c 197840 2009-10-07 19:50:14Z zml $");
32
33#include <sys/param.h>
34#include <sys/fail.h>
35#include <sys/fcntl.h>
36#include <sys/kernel.h>
37#include <sys/kthread.h>
38#include <sys/lockf.h>
39#include <sys/malloc.h>
40#include <sys/mount.h>
41#if __FreeBSD_version >= 700000
42#include <sys/priv.h>

--- 30 unchanged lines hidden (view full) ---

73#define NLM_IDLE_TIMEOUT 30
74
75/*
76 * We check the host list for idle every few seconds.
77 */
78#define NLM_IDLE_PERIOD 5
79
80/*
81 * We only look for GRANTED_RES messages for a little while.
82 */
83#define NLM_EXPIRE_TIMEOUT 10
84
85/*
86 * Support for sysctl vfs.nlm.sysid
87 */
88SYSCTL_NODE(_vfs, OID_AUTO, nlm, CTLFLAG_RW, NULL, "Network Lock Manager");
89SYSCTL_NODE(_vfs_nlm, OID_AUTO, sysid, CTLFLAG_RW, NULL, "");
90
91/*
92 * Syscall hooks
93 */

--- 111 unchanged lines hidden (view full) ---

205 TAILQ_ENTRY(nlm_async_lock) af_link; /* (l) host's list of locks */
206 struct task af_task; /* (c) async callback details */
207 void *af_cookie; /* (l) lock manager cancel token */
208 struct vnode *af_vp; /* (l) vnode to lock */
209 struct flock af_fl; /* (c) lock details */
210 struct nlm_host *af_host; /* (c) host which is locking */
211 CLIENT *af_rpc; /* (c) rpc client to send message */
212 nlm4_testargs af_granted; /* (c) notification details */
213 time_t af_expiretime; /* (c) notification time */
214};
215TAILQ_HEAD(nlm_async_lock_list, nlm_async_lock);
216
217/*
218 * NLM host.
219 */
220enum nlm_host_state {
221 NLM_UNMONITORED,

--- 17 unchanged lines hidden (view full) ---

239 struct sockaddr_storage nh_addr; /* (s) remote address of host */
240 struct nlm_rpc nh_srvrpc; /* (l) RPC for server replies */
241 struct nlm_rpc nh_clntrpc; /* (l) RPC for client requests */
242 rpcvers_t nh_vers; /* (s) NLM version of host */
243 int nh_state; /* (s) last seen NSM state of host */
244 enum nlm_host_state nh_monstate; /* (l) local NSM monitoring state */
245 time_t nh_idle_timeout; /* (s) Time at which host is idle */
246 struct sysctl_ctx_list nh_sysctl; /* (c) vfs.nlm.sysid nodes */
247 uint32_t nh_grantcookie; /* (l) grant cookie counter */
248 struct nlm_async_lock_list nh_pending; /* (l) pending async locks */
249 struct nlm_async_lock_list nh_granted; /* (l) granted locks */
250 struct nlm_async_lock_list nh_finished; /* (l) finished async locks */
251};
252TAILQ_HEAD(nlm_host_list, nlm_host);
253
254static struct nlm_host_list nlm_hosts; /* (g) */
255static uint32_t nlm_next_sysid = 1; /* (g) */
256
257static void nlm_host_unmonitor(struct nlm_host *);
258
259struct nlm_grantcookie {
260 uint32_t ng_sysid;
261 uint32_t ng_cookie;
262};
263
264static inline uint32_t
265ng_sysid(struct netobj *src)
266{
267
268 return ((struct nlm_grantcookie *)src->n_bytes)->ng_sysid;
269}
270
271static inline uint32_t
272ng_cookie(struct netobj *src)
273{
274
275 return ((struct nlm_grantcookie *)src->n_bytes)->ng_cookie;
276}
277
278/**********************************************************************/
279
280/*
281 * Initialise NLM globals.
282 */
283static void
284nlm_init(void *dummy)
285{

--- 18 unchanged lines hidden (view full) ---

304
305 if (nlm_syscall_registered)
306 syscall_deregister(&nlm_syscall_offset,
307 &nlm_syscall_prev_sysent);
308}
309SYSUNINIT(nlm_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_uninit, NULL);
310
311/*
312 * Create a netobj from an arbitrary source.
313 */
314void
315nlm_make_netobj(struct netobj *dst, caddr_t src, size_t srcsize,
316 struct malloc_type *type)
317{
318
319 dst->n_len = srcsize;
320 dst->n_bytes = malloc(srcsize, type, M_WAITOK);
321 memcpy(dst->n_bytes, src, srcsize);
322}
323
324/*
325 * Copy a struct netobj.
326 */
327void
328nlm_copy_netobj(struct netobj *dst, struct netobj *src,
329 struct malloc_type *type)
330{
331
332 nlm_make_netobj(dst, src->n_bytes, src->n_len, type);
333}
334
335
336/*
337 * Create an RPC client handle for the given (address,prog,vers)
338 * triple using UDP.
339 */
340static CLIENT *
341nlm_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers)
342{
343 char *wchan = "nlmrcv";

--- 209 unchanged lines hidden (view full) ---

553 * granted. We notify the host which initiated the request.
554 */
555static void
556nlm_lock_callback(void *arg, int pending)
557{
558 struct nlm_async_lock *af = (struct nlm_async_lock *) arg;
559 struct rpc_callextra ext;
560
561 NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) granted,"
562 " cookie %d:%d\n", af, af->af_host->nh_caller_name,
563 af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie),
564 ng_cookie(&af->af_granted.cookie));
565
566 /*
567 * Send the results back to the host.
568 *
569 * Note: there is a possible race here with nlm_host_notify
570 * destroying the RPC client. To avoid problems, the first
571 * thing nlm_host_notify does is to cancel pending async lock
572 * requests.

--- 20 unchanged lines hidden (view full) ---

593 granted.alock.l_len =
594 af->af_granted.alock.l_len;
595
596 nlm_granted_msg_1(&granted,
597 NULL, af->af_rpc, &ext, nlm_zero_tv);
598 }
599
600 /*
601 * Move this entry to the nh_granted list.
602 */
603 af->af_expiretime = time_uptime + NLM_EXPIRE_TIMEOUT;
604 mtx_lock(&af->af_host->nh_lock);
605 TAILQ_REMOVE(&af->af_host->nh_pending, af, af_link);
606 TAILQ_INSERT_TAIL(&af->af_host->nh_granted, af, af_link);
607 mtx_unlock(&af->af_host->nh_lock);
608}
609
610/*
611 * Free an async lock request. The request must have been removed from
612 * any list.
613 */
614static void

--- 53 unchanged lines hidden (view full) ---

668 nlm_free_async_lock(af);
669 mtx_lock(&host->nh_lock);
670 }
671
672 return (error);
673}
674
675static void
676nlm_check_expired_locks(struct nlm_host *host)
677{
678 struct nlm_async_lock *af;
679 time_t uptime = time_uptime;
680
681 mtx_lock(&host->nh_lock);
682 while ((af = TAILQ_FIRST(&host->nh_granted)) != NULL
683 && uptime >= af->af_expiretime) {
684 NLM_DEBUG(2, "NLM: async lock %p for %s (sysid %d) expired,"
685 " cookie %d:%d\n", af, af->af_host->nh_caller_name,
686 af->af_host->nh_sysid, ng_sysid(&af->af_granted.cookie),
687 ng_cookie(&af->af_granted.cookie));
688 TAILQ_REMOVE(&host->nh_granted, af, af_link);
689 mtx_unlock(&host->nh_lock);
690 nlm_free_async_lock(af);
691 mtx_lock(&host->nh_lock);
692 }
693 while ((af = TAILQ_FIRST(&host->nh_finished)) != NULL) {
694 TAILQ_REMOVE(&host->nh_finished, af, af_link);
695 mtx_unlock(&host->nh_lock);
696 nlm_free_async_lock(af);
697 mtx_lock(&host->nh_lock);
698 }
699 mtx_unlock(&host->nh_lock);
700}

--- 66 unchanged lines hidden (view full) ---

767 while ((af = TAILQ_FIRST(&host->nh_pending)) != NULL) {
768 /*
769 * nlm_cancel_async_lock will remove the entry from
770 * nh_pending and free it.
771 */
772 nlm_cancel_async_lock(af);
773 }
774 mtx_unlock(&host->nh_lock);
775 nlm_check_expired_locks(host);
776
777 /*
778 * The host just rebooted - trash its locks.
779 */
780 lf_clearremotesys(host->nh_sysid);
781 host->nh_state = newstate;
782
783 /*

--- 60 unchanged lines hidden (view full) ---

844 host->nh_refs = 1;
845 strlcpy(host->nh_caller_name, caller_name, MAXNAMELEN);
846 host->nh_sysid = nlm_next_sysid++;
847 snprintf(host->nh_sysid_string, sizeof(host->nh_sysid_string),
848 "%d", host->nh_sysid);
849 host->nh_vers = 0;
850 host->nh_state = 0;
851 host->nh_monstate = NLM_UNMONITORED;
852 host->nh_grantcookie = 1;
853 TAILQ_INIT(&host->nh_pending);
854 TAILQ_INIT(&host->nh_granted);
855 TAILQ_INIT(&host->nh_finished);
856 TAILQ_INSERT_TAIL(&nlm_hosts, host, nh_link);
857
858 mtx_unlock(&nlm_global_lock);
859
860 sysctl_ctx_init(&host->nh_sysctl);
861 oid = SYSCTL_ADD_NODE(&host->nh_sysctl,
862 SYSCTL_STATIC_CHILDREN(_vfs_nlm_sysid),

--- 1018 unchanged lines hidden (view full) ---

1881 if (!host) {
1882 result->stat.stat = nlm4_denied_nolocks;
1883 return (ENOMEM);
1884 }
1885
1886 NLM_DEBUG(3, "nlm_do_test(): caller_name = %s (sysid = %d)\n",
1887 host->nh_caller_name, host->nh_sysid);
1888
1889 nlm_check_expired_locks(host);
1890 sysid = host->nh_sysid;
1891
1892 nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
1893 nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
1894
1895 if (time_uptime < nlm_grace_threshold) {
1896 result->stat.stat = nlm4_denied_grace_period;
1897 goto out;

--- 88 unchanged lines hidden (view full) ---

1986 && host->nh_state != argp->state) {
1987 /*
1988 * The host rebooted without telling us. Trash its
1989 * locks.
1990 */
1991 nlm_host_notify(host, argp->state);
1992 }
1993
1994 nlm_check_expired_locks(host);
1995 sysid = host->nh_sysid;
1996
1997 nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
1998 nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
1999
2000 if (time_uptime < nlm_grace_threshold && !argp->reclaim) {
2001 result->stat.stat = nlm4_denied_grace_period;
2002 goto out;

--- 12 unchanged lines hidden (view full) ---

2015 fl.l_whence = SEEK_SET;
2016 if (argp->exclusive)
2017 fl.l_type = F_WRLCK;
2018 else
2019 fl.l_type = F_RDLCK;
2020 if (argp->block) {
2021 struct nlm_async_lock *af;
2022 CLIENT *client;
2023 struct nlm_grantcookie cookie;
2024
2025 /*
2026 * First, make sure we can contact the host's NLM.
2027 */
2028 client = nlm_host_get_rpc(host, TRUE);
2029 if (!client) {
2030 result->stat.stat = nlm4_failed;
2031 goto out;

--- 9 unchanged lines hidden (view full) ---

2041 TAILQ_FOREACH(af, &host->nh_pending, af_link) {
2042 if (af->af_fl.l_start == fl.l_start
2043 && af->af_fl.l_len == fl.l_len
2044 && af->af_fl.l_pid == fl.l_pid
2045 && af->af_fl.l_type == fl.l_type) {
2046 break;
2047 }
2048 }
2049 if (!af) {
2050 cookie.ng_sysid = host->nh_sysid;
2051 cookie.ng_cookie = host->nh_grantcookie++;
2052 }
2053 mtx_unlock(&host->nh_lock);
2054 if (af) {
2055 CLNT_RELEASE(client);
2056 result->stat.stat = nlm4_blocked;
2057 goto out;
2058 }
2059
2060 af = malloc(sizeof(struct nlm_async_lock), M_NLM,
2061 M_WAITOK|M_ZERO);
2062 TASK_INIT(&af->af_task, 0, nlm_lock_callback, af);
2063 af->af_vp = vs.vs_vp;
2064 af->af_fl = fl;
2065 af->af_host = host;
2066 af->af_rpc = client;
2067 /*
2068 * We use M_RPC here so that we can xdr_free the thing
2069 * later.
2070 */
2071 nlm_make_netobj(&af->af_granted.cookie,
2072 (caddr_t)&cookie, sizeof(cookie), M_RPC);
2073 af->af_granted.exclusive = argp->exclusive;
2074 af->af_granted.alock.caller_name =
2075 strdup(argp->alock.caller_name, M_RPC);
2076 nlm_copy_netobj(&af->af_granted.alock.fh,
2077 &argp->alock.fh, M_RPC);
2078 nlm_copy_netobj(&af->af_granted.alock.oh,
2079 &argp->alock.oh, M_RPC);
2080 af->af_granted.alock.svid = argp->alock.svid;

--- 84 unchanged lines hidden (view full) ---

2165 if (!host) {
2166 result->stat.stat = nlm4_denied_nolocks;
2167 return (ENOMEM);
2168 }
2169
2170 NLM_DEBUG(3, "nlm_do_cancel(): caller_name = %s (sysid = %d)\n",
2171 host->nh_caller_name, host->nh_sysid);
2172
2173 nlm_check_expired_locks(host);
2174 sysid = host->nh_sysid;
2175
2176 nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
2177 nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
2178
2179 if (time_uptime < nlm_grace_threshold) {
2180 result->stat.stat = nlm4_denied_grace_period;
2181 goto out;

--- 72 unchanged lines hidden (view full) ---

2254 if (!host) {
2255 result->stat.stat = nlm4_denied_nolocks;
2256 return (ENOMEM);
2257 }
2258
2259 NLM_DEBUG(3, "nlm_do_unlock(): caller_name = %s (sysid = %d)\n",
2260 host->nh_caller_name, host->nh_sysid);
2261
2262 nlm_check_expired_locks(host);
2263 sysid = host->nh_sysid;
2264
2265 nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
2266 nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
2267
2268 if (time_uptime < nlm_grace_threshold) {
2269 result->stat.stat = nlm4_denied_grace_period;
2270 goto out;

--- 40 unchanged lines hidden (view full) ---

2311 host = nlm_find_host_by_addr(svc_getrpccaller(rqstp), rqstp->rq_vers);
2312 if (!host) {
2313 result->stat.stat = nlm4_denied_nolocks;
2314 return (ENOMEM);
2315 }
2316
2317 nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
2318 result->stat.stat = nlm4_denied;
2319 KFAIL_POINT_CODE(DEBUG_FP, nlm_deny_grant, goto out);
2320
2321 mtx_lock(&nlm_global_lock);
2322 TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
2323 if (!nw->nw_waiting)
2324 continue;
2325 if (argp->alock.svid == nw->nw_lock.svid
2326 && argp->alock.l_offset == nw->nw_lock.l_offset
2327 && argp->alock.l_len == nw->nw_lock.l_len
2328 && argp->alock.fh.n_len == nw->nw_lock.fh.n_len
2329 && !memcmp(argp->alock.fh.n_bytes, nw->nw_lock.fh.n_bytes,
2330 nw->nw_lock.fh.n_len)) {
2331 nw->nw_waiting = FALSE;
2332 wakeup(nw);
2333 result->stat.stat = nlm4_granted;
2334 break;
2335 }
2336 }
2337 mtx_unlock(&nlm_global_lock);
2338
2339out:
2340 if (rpcp)
2341 *rpcp = nlm_host_get_rpc(host, TRUE);
2342 nlm_host_release(host);
2343 return (0);
2344}
2345
2346void
2347nlm_do_granted_res(nlm4_res *argp, struct svc_req *rqstp)
2348{
2349 struct nlm_host *host = NULL;
2350 struct nlm_async_lock *af = NULL;
2351 int error;
2352
2353 if (argp->cookie.n_len != sizeof(struct nlm_grantcookie)) {
2354 NLM_DEBUG(1, "NLM: bogus grant cookie");
2355 goto out;
2356 }
2357
2358 host = nlm_find_host_by_sysid(ng_sysid(&argp->cookie));
2359 if (!host) {
2360 NLM_DEBUG(1, "NLM: Unknown host rejected our grant");
2361 goto out;
2362 }
2363
2364 mtx_lock(&host->nh_lock);
2365 TAILQ_FOREACH(af, &host->nh_granted, af_link)
2366 if (ng_cookie(&argp->cookie) ==
2367 ng_cookie(&af->af_granted.cookie))
2368 break;
2369 if (af)
2370 TAILQ_REMOVE(&host->nh_granted, af, af_link);
2371 mtx_unlock(&host->nh_lock);
2372
2373 if (!af) {
2374 NLM_DEBUG(1, "NLM: host %s (sysid %d) replied to our grant "
2375 "with unrecognized cookie %d:%d", host->nh_caller_name,
2376 host->nh_sysid, ng_sysid(&argp->cookie),
2377 ng_cookie(&argp->cookie));
2378 goto out;
2379 }
2380
2381 if (argp->stat.stat != nlm4_granted) {
2382 af->af_fl.l_type = F_UNLCK;
2383 error = VOP_ADVLOCK(af->af_vp, NULL, F_UNLCK, &af->af_fl, F_REMOTE);
2384 if (error) {
2385 NLM_DEBUG(1, "NLM: host %s (sysid %d) rejected our grant "
2386 "and we failed to unlock (%d)", host->nh_caller_name,
2387 host->nh_sysid, error);
2388 goto out;
2389 }
2390
2391 NLM_DEBUG(5, "NLM: async lock %p rejected by host %s (sysid %d)",
2392 af, host->nh_caller_name, host->nh_sysid);
2393 } else {
2394 NLM_DEBUG(5, "NLM: async lock %p accepted by host %s (sysid %d)",
2395 af, host->nh_caller_name, host->nh_sysid);
2396 }
2397
2398 out:
2399 if (af)
2400 nlm_free_async_lock(af);
2401 if (host)
2402 nlm_host_release(host);
2403}
2404
2405void
2406nlm_do_free_all(nlm4_notify *argp)
2407{
2408 struct nlm_host *host, *thost;
2409
2410 TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, thost) {
2411 if (!strcmp(host->nh_caller_name, argp->name))
2412 nlm_host_notify(host, argp->state);
2413 }

--- 22 unchanged lines hidden ---