2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy is of the CDDL is also available via the Internet
9 * at http://www.illumos.org/license/CDDL.
13 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
14 * Copyright (c) 2012 by Delphix. All rights reserved.
18 * NFS Lock Manager, server-side and common.
20 * This file contains all the external entry points of klmmod.
21 * Basically, this is the "glue" to the BSD nlm code.
24 #include <sys/types.h>
25 #include <sys/errno.h>
26 #include <sys/modctl.h>
27 #include <sys/flock.h>
30 #include <nfs/nfssys.h>
32 #include <rpcsvc/nlm_prot.h>
35 static struct modlmisc modlmisc
= {
36 &mod_miscops
, "lock mgr common module"
39 static struct modlinkage modlinkage
= {
40 MODREV_1
, &modlmisc
, NULL
44 * Cluster node ID. Zero unless we're part of a cluster.
45 * Set by lm_set_nlmid_flk. Pass to lm_set_nlm_status.
46 * We're not yet doing "clustered" NLM stuff.
48 int lm_global_nlmid
= 0;
51 * Call-back hook for clusters: Set lock manager status.
52 * If this hook is set, call this instead of the ususal
53 * flk_set_lockmgr_status(FLK_LOCKMGR_UP / DOWN);
55 void (*lm_set_nlm_status
)(int nlm_id
, flk_nlm_status_t
) = NULL
;
58 * Call-back hook for clusters: Delete all locks held by sysid.
59 * Call from code that drops all client locks (for which we're
60 * the server) i.e. after the SM tells us a client has crashed.
62 void (*lm_remove_file_locks
)(int) = NULL
;
65 zone_key_t nlm_zone_key
;
68 * Init/fini per-zone stuff for klm
72 lm_zone_init(zoneid_t zoneid
)
74 struct nlm_globals
*g
;
76 g
= kmem_zalloc(sizeof (*g
), KM_SLEEP
);
78 avl_create(&g
->nlm_hosts_tree
, nlm_host_cmp
,
79 sizeof (struct nlm_host
),
80 offsetof(struct nlm_host
, nh_by_addr
));
82 g
->nlm_hosts_hash
= mod_hash_create_idhash("nlm_host_by_sysid",
83 64, mod_hash_null_valdtor
);
85 TAILQ_INIT(&g
->nlm_idle_hosts
);
86 TAILQ_INIT(&g
->nlm_slocks
);
88 mutex_init(&g
->lock
, NULL
, MUTEX_DEFAULT
, NULL
);
89 cv_init(&g
->nlm_gc_sched_cv
, NULL
, CV_DEFAULT
, NULL
);
90 cv_init(&g
->nlm_gc_finish_cv
, NULL
, CV_DEFAULT
, NULL
);
91 mutex_init(&g
->clean_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
94 g
->run_status
= NLM_ST_DOWN
;
96 nlm_globals_register(g
);
102 lm_zone_fini(zoneid_t zoneid
, void *data
)
104 struct nlm_globals
*g
= data
;
106 ASSERT(avl_is_empty(&g
->nlm_hosts_tree
));
107 avl_destroy(&g
->nlm_hosts_tree
);
108 mod_hash_destroy_idhash(g
->nlm_hosts_hash
);
110 ASSERT(g
->nlm_gc_thread
== NULL
);
111 mutex_destroy(&g
->lock
);
112 cv_destroy(&g
->nlm_gc_sched_cv
);
113 cv_destroy(&g
->nlm_gc_finish_cv
);
114 mutex_destroy(&g
->clean_lock
);
116 nlm_globals_unregister(g
);
117 kmem_free(g
, sizeof (*g
));
123 * ****************************************************************
124 * module init, fini, info
131 rw_init(&lm_lck
, NULL
, RW_DEFAULT
, NULL
);
134 zone_key_create(&nlm_zone_key
, lm_zone_init
, NULL
, lm_zone_fini
);
135 /* Per-zone lockmgr data. See: os/flock.c */
136 zone_key_create(&flock_zone_key
, flk_zone_init
, NULL
, flk_zone_fini
);
138 retval
= mod_install(&modlinkage
);
143 * mod_install failed! undo above, reverse order
146 (void) zone_key_delete(flock_zone_key
);
147 flock_zone_key
= ZONE_KEY_UNINITIALIZED
;
148 (void) zone_key_delete(nlm_zone_key
);
162 _info(struct modinfo
*modinfop
)
164 return (mod_info(&modlinkage
, modinfop
));
170 * ****************************************************************
171 * Stubs listed in modstubs.s
175 * klm system calls. Start service on some endpoint.
176 * Called by nfssys() LM_SVC, from lockd.
179 lm_svc(struct lm_svc_args
*args
)
181 struct knetconfig knc
;
183 struct nlm_globals
*g
;
184 struct file
*fp
= NULL
;
187 /* Get our "globals" */
188 g
= zone_getspecific(nlm_zone_key
, curzone
);
191 * Check version of lockd calling.
193 if (args
->version
!= LM_SVC_CUR_VERS
) {
194 NLM_ERR("lm_svc: Version mismatch "
195 "(given 0x%x, expected 0x%x)\n",
196 args
->version
, LM_SVC_CUR_VERS
);
201 * Build knetconfig, checking arg values.
202 * Also come up with the "netid" string.
203 * (With some knowledge of /etc/netconfig)
205 bzero(&knc
, sizeof (knc
));
206 switch (args
->n_proto
) {
208 knc
.knc_semantics
= NC_TPI_COTS_ORD
;
209 knc
.knc_proto
= NC_TCP
;
212 knc
.knc_semantics
= NC_TPI_CLTS
;
213 knc
.knc_proto
= NC_UDP
;
216 NLM_ERR("nlm_build_knetconfig: Unknown "
217 "lm_proto=0x%x\n", args
->n_proto
);
221 switch (args
->n_fmly
) {
223 knc
.knc_protofmly
= NC_INET
;
226 knc
.knc_protofmly
= NC_INET6
;
229 knc
.knc_protofmly
= NC_LOOPBACK
;
230 /* Override what we set above. */
231 knc
.knc_proto
= NC_NOPROTO
;
234 NLM_ERR("nlm_build_knetconfig: Unknown "
235 "lm_fmly=0x%x\n", args
->n_fmly
);
239 knc
.knc_rdev
= args
->n_rdev
;
240 netid
= nlm_knc_to_netid(&knc
);
245 * Setup service on the passed transport.
246 * NB: must releasef(fp) after this.
248 if ((fp
= getf(args
->fd
)) == NULL
)
251 mutex_enter(&g
->lock
);
253 * Don't try to start while still shutting down,
254 * or lots of things will fail...
256 if (g
->run_status
== NLM_ST_STOPPING
) {
262 * There is no separate "initialize" sub-call for nfssys,
263 * and we want to do some one-time work when the first
264 * binding comes in from lockd.
266 if (g
->run_status
== NLM_ST_DOWN
) {
267 g
->run_status
= NLM_ST_STARTING
;
268 g
->lockd_pid
= curproc
->p_pid
;
270 /* Save the options. */
271 g
->cn_idle_tmo
= args
->timout
;
272 g
->grace_period
= args
->grace
;
273 g
->retrans_tmo
= args
->retransmittimeout
;
275 /* See nfs_sys.c (not yet per-zone) */
276 if (INGLOBALZONE(curproc
)) {
277 rfs4_grace_period
= args
->grace
;
278 rfs4_lease_time
= args
->grace
;
281 mutex_exit(&g
->lock
);
282 err
= nlm_svc_starting(g
, fp
, netid
, &knc
);
283 mutex_enter(&g
->lock
);
286 * If KLM is not started and the very first endpoint lockd
287 * tries to add is not a loopback device, report an error.
289 if (g
->run_status
!= NLM_ST_UP
) {
293 if (g
->lockd_pid
!= curproc
->p_pid
) {
294 /* Check if caller has the same PID lockd does */
299 err
= nlm_svc_add_ep(fp
, netid
, &knc
);
303 mutex_exit(&g
->lock
);
311 * klm system calls. Kill the lock manager.
312 * Called by nfssys() KILL_LOCKMGR,
313 * liblm:lm_shutdown() <- unused?
318 struct nlm_globals
*g
;
322 /* Get our "globals" */
323 g
= zone_getspecific(nlm_zone_key
, curzone
);
325 mutex_enter(&g
->lock
);
326 if (g
->run_status
!= NLM_ST_UP
) {
327 mutex_exit(&g
->lock
);
331 g
->run_status
= NLM_ST_STOPPING
;
333 mutex_exit(&g
->lock
);
336 mutex_enter(&pidlock
);
341 mutex_exit(&pidlock
);
346 * Cleanup remote locks on FS un-export.
348 * NOTE: called from nfs_export.c:unexport()
349 * right before the share is going to
353 lm_unexport(struct exportinfo
*exi
)
359 * CPR suspend/resume hooks.
360 * See:cpr_suspend, cpr_resume
362 * Before suspend, get current state from "statd" on
363 * all remote systems for which we have locks.
365 * After resume, check with those systems again,
366 * and either reclaim locks, or do SIGLOST.
381 * Add the nlm_id bits to the sysid (by ref).
384 lm_set_nlmid_flk(int *new_sysid
)
386 if (lm_global_nlmid
!= 0)
387 *new_sysid
|= (lm_global_nlmid
<< BITS_IN_SYSID
);
391 * It seems that closed source klmmod used
392 * this function to release knetconfig stored
393 * in mntinfo structure (see mntinfo's mi_klmconfig
395 * We store knetconfigs differently, thus we don't
396 * need this function.
399 lm_free_config(struct knetconfig
*knc
)
401 _NOTE(ARGUNUSED(knc
));
405 * Called by NFS4 delegation code to check if there are any
406 * NFSv2/v3 locks for the file, so it should not delegate.
408 * NOTE: called from NFSv4 code
409 * (see nfs4_srv_deleg.c:rfs4_bgrant_delegation())
412 lm_vp_active(const vnode_t
*vp
)
414 return (nlm_vp_active(vp
));
418 * Find or create a "sysid" for given knc+addr.
419 * name is optional. Sets nc_changed if the
420 * found knc_proto is different from passed.
421 * Increments the reference count.
423 * Called internally, and in nfs4_find_sysid()
426 lm_get_sysid(struct knetconfig
*knc
, struct netbuf
*addr
,
427 char *name
, bool_t
*nc_changed
)
429 struct nlm_globals
*g
;
431 struct nlm_host
*hostp
;
433 _NOTE(ARGUNUSED(nc_changed
));
434 netid
= nlm_knc_to_netid(knc
);
438 g
= zone_getspecific(nlm_zone_key
, curzone
);
440 hostp
= nlm_host_findcreate(g
, name
, netid
, addr
);
444 return ((struct lm_sysid
*)hostp
);
448 * Release a reference on a "sysid".
451 lm_rel_sysid(struct lm_sysid
*sysid
)
453 struct nlm_globals
*g
;
455 g
= zone_getspecific(nlm_zone_key
, curzone
);
456 nlm_host_release(g
, (struct nlm_host
*)sysid
);
460 * Alloc/free a sysid_t (a unique number between
461 * LM_SYSID and LM_SYSID_MAX).
463 * Used by NFSv4 rfs4_op_lockt and smbsrv/smb_fsop_frlock,
464 * both to represent non-local locks outside of klm.
466 * NOTE: called from NFSv4 and SMBFS to allocate unique
470 lm_alloc_sysidt(void)
472 return (nlm_sysid_alloc());
476 lm_free_sysidt(sysid_t sysid
)
478 nlm_sysid_free(sysid
);
481 /* Access private member lms->sysid */
483 lm_sysidt(struct lm_sysid
*lms
)
485 return (((struct nlm_host
*)lms
)->nh_sysid
);
489 * Called by nfs_frlock to check lock constraints.
490 * Return non-zero if the lock request is "safe", i.e.
491 * the range is not mapped, not MANDLOCK, etc.
493 * NOTE: callde from NFSv3/NFSv2 frlock() functions to
494 * determine whether it's safe to add new lock.
497 lm_safelock(vnode_t
*vp
, const struct flock64
*fl
, cred_t
*cr
)
499 return (nlm_safelock(vp
, fl
, cr
));
503 * Called by nfs_lockcompletion to check whether it's "safe"
504 * to map the file (and cache it's data). Walks the list of
505 * file locks looking for any that are not "whole file".
507 * NOTE: called from nfs_client.c:nfs_lockcompletion()
510 lm_safemap(const vnode_t
*vp
)
512 return (nlm_safemap(vp
));
516 * Called by nfs_map() for the MANDLOCK case.
517 * Return non-zero if the file has any locks with a
518 * blocked request (sleep).
520 * NOTE: called from NFSv3/NFSv2 map() functions in
521 * order to determine whether it's safe to add new
525 lm_has_sleep(const vnode_t
*vp
)
527 return (nlm_has_sleep(vp
));
531 * ****************************************************************
532 * Stuff needed by klmops?