1bbaa8b60SDan Kruchinin /*
2bbaa8b60SDan Kruchinin * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3bbaa8b60SDan Kruchinin * Authors: Doug Rabson <dfr@rabson.org>
4bbaa8b60SDan Kruchinin * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5bbaa8b60SDan Kruchinin *
6bbaa8b60SDan Kruchinin * Redistribution and use in source and binary forms, with or without
7bbaa8b60SDan Kruchinin * modification, are permitted provided that the following conditions
8bbaa8b60SDan Kruchinin * are met:
9bbaa8b60SDan Kruchinin * 1. Redistributions of source code must retain the above copyright
10bbaa8b60SDan Kruchinin * notice, this list of conditions and the following disclaimer.
11bbaa8b60SDan Kruchinin * 2. Redistributions in binary form must reproduce the above copyright
12bbaa8b60SDan Kruchinin * notice, this list of conditions and the following disclaimer in the
13bbaa8b60SDan Kruchinin * documentation and/or other materials provided with the distribution.
14bbaa8b60SDan Kruchinin *
15bbaa8b60SDan Kruchinin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16bbaa8b60SDan Kruchinin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17bbaa8b60SDan Kruchinin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18bbaa8b60SDan Kruchinin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19bbaa8b60SDan Kruchinin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20bbaa8b60SDan Kruchinin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21bbaa8b60SDan Kruchinin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22bbaa8b60SDan Kruchinin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23bbaa8b60SDan Kruchinin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24bbaa8b60SDan Kruchinin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25bbaa8b60SDan Kruchinin * SUCH DAMAGE.
26bbaa8b60SDan Kruchinin */
27bbaa8b60SDan Kruchinin
28bbaa8b60SDan Kruchinin /*
2948bbca81SDaniel Hoffman * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
30*54b3584eSGordon Ross * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
31b4ecf764SJerry Jelinek * Copyright 2014 Joyent, Inc. All rights reserved.
32bbaa8b60SDan Kruchinin */
33bbaa8b60SDan Kruchinin
34bbaa8b60SDan Kruchinin /*
35bbaa8b60SDan Kruchinin * NFS Lock Manager service functions (nlm_do_...)
36bbaa8b60SDan Kruchinin * Called from nlm_rpc_svc.c wrappers.
37bbaa8b60SDan Kruchinin *
38bbaa8b60SDan Kruchinin * Source code derived from FreeBSD nlm_prot_impl.c
39bbaa8b60SDan Kruchinin */
40bbaa8b60SDan Kruchinin
41bbaa8b60SDan Kruchinin #include <sys/param.h>
42bbaa8b60SDan Kruchinin #include <sys/systm.h>
43bbaa8b60SDan Kruchinin #include <sys/thread.h>
44bbaa8b60SDan Kruchinin #include <sys/fcntl.h>
45bbaa8b60SDan Kruchinin #include <sys/flock.h>
46bbaa8b60SDan Kruchinin #include <sys/mount.h>
47bbaa8b60SDan Kruchinin #include <sys/priv.h>
48bbaa8b60SDan Kruchinin #include <sys/proc.h>
49bbaa8b60SDan Kruchinin #include <sys/share.h>
50bbaa8b60SDan Kruchinin #include <sys/socket.h>
51bbaa8b60SDan Kruchinin #include <sys/syscall.h>
52bbaa8b60SDan Kruchinin #include <sys/syslog.h>
53bbaa8b60SDan Kruchinin #include <sys/systm.h>
54bbaa8b60SDan Kruchinin #include <sys/taskq.h>
55bbaa8b60SDan Kruchinin #include <sys/unistd.h>
56bbaa8b60SDan Kruchinin #include <sys/vnode.h>
57bbaa8b60SDan Kruchinin #include <sys/vfs.h>
58bbaa8b60SDan Kruchinin #include <sys/queue.h>
59bbaa8b60SDan Kruchinin #include <sys/sdt.h>
60bbaa8b60SDan Kruchinin #include <netinet/in.h>
61bbaa8b60SDan Kruchinin
62bbaa8b60SDan Kruchinin #include <rpc/rpc.h>
63bbaa8b60SDan Kruchinin #include <rpc/xdr.h>
64bbaa8b60SDan Kruchinin #include <rpc/pmap_prot.h>
65bbaa8b60SDan Kruchinin #include <rpc/pmap_clnt.h>
66bbaa8b60SDan Kruchinin #include <rpc/rpcb_prot.h>
67bbaa8b60SDan Kruchinin
68bbaa8b60SDan Kruchinin #include <rpcsvc/nlm_prot.h>
69bbaa8b60SDan Kruchinin #include <rpcsvc/sm_inter.h>
70bbaa8b60SDan Kruchinin
71bbaa8b60SDan Kruchinin #include <nfs/nfs.h>
72bbaa8b60SDan Kruchinin #include <nfs/nfs_clnt.h>
73bbaa8b60SDan Kruchinin #include <nfs/export.h>
74bbaa8b60SDan Kruchinin #include <nfs/rnode.h>
75bbaa8b60SDan Kruchinin
76bbaa8b60SDan Kruchinin #include "nlm_impl.h"
77bbaa8b60SDan Kruchinin
78bbaa8b60SDan Kruchinin #define NLM_IN_GRACE(g) (ddi_get_lbolt() < (g)->grace_threshold)
79bbaa8b60SDan Kruchinin
80bbaa8b60SDan Kruchinin struct nlm_block_cb_data {
81bbaa8b60SDan Kruchinin struct nlm_host *hostp;
82bbaa8b60SDan Kruchinin struct nlm_vhold *nvp;
83bbaa8b60SDan Kruchinin struct flock64 *flp;
84*54b3584eSGordon Ross bool_t registered;
85bbaa8b60SDan Kruchinin };
86bbaa8b60SDan Kruchinin
87bbaa8b60SDan Kruchinin /*
88bbaa8b60SDan Kruchinin * Invoke an asyncronous RPC callbeck
89bbaa8b60SDan Kruchinin * (used when NLM server needs to reply to MSG NLM procedure).
90bbaa8b60SDan Kruchinin */
91bbaa8b60SDan Kruchinin #define NLM_INVOKE_CALLBACK(descr, rpcp, resp, callb) \
92bbaa8b60SDan Kruchinin do { \
93bbaa8b60SDan Kruchinin enum clnt_stat _stat; \
94bbaa8b60SDan Kruchinin \
95bbaa8b60SDan Kruchinin _stat = (*(callb))(resp, NULL, (rpcp)->nr_handle); \
96bbaa8b60SDan Kruchinin if (_stat != RPC_SUCCESS && _stat != RPC_TIMEDOUT) { \
97bbaa8b60SDan Kruchinin struct rpc_err _err; \
98bbaa8b60SDan Kruchinin \
99bbaa8b60SDan Kruchinin CLNT_GETERR((rpcp)->nr_handle, &_err); \
100bbaa8b60SDan Kruchinin NLM_ERR("NLM: %s callback failed: " \
101bbaa8b60SDan Kruchinin "stat %d, err %d\n", descr, _stat, \
102bbaa8b60SDan Kruchinin _err.re_errno); \
103bbaa8b60SDan Kruchinin } \
104bbaa8b60SDan Kruchinin \
105bbaa8b60SDan Kruchinin _NOTE(CONSTCOND) } while (0)
106bbaa8b60SDan Kruchinin
107bbaa8b60SDan Kruchinin static void nlm_block(
108bbaa8b60SDan Kruchinin nlm4_lockargs *lockargs,
109bbaa8b60SDan Kruchinin struct nlm_host *host,
110bbaa8b60SDan Kruchinin struct nlm_vhold *nvp,
111bbaa8b60SDan Kruchinin struct flock64 *fl,
112*54b3584eSGordon Ross nlm_granted_cb grant_cb,
113*54b3584eSGordon Ross rpcvers_t);
114bbaa8b60SDan Kruchinin
115bbaa8b60SDan Kruchinin static vnode_t *nlm_fh_to_vp(struct netobj *);
116bbaa8b60SDan Kruchinin static struct nlm_vhold *nlm_fh_to_vhold(struct nlm_host *, struct netobj *);
117bbaa8b60SDan Kruchinin static void nlm_init_shrlock(struct shrlock *, nlm4_share *, struct nlm_host *);
118bbaa8b60SDan Kruchinin static callb_cpr_t *nlm_block_callback(flk_cb_when_t, void *);
119bbaa8b60SDan Kruchinin static int nlm_vop_frlock(vnode_t *, int, flock64_t *, int, offset_t,
120bbaa8b60SDan Kruchinin struct flk_callback *, cred_t *, caller_context_t *);
121bbaa8b60SDan Kruchinin
122bbaa8b60SDan Kruchinin /*
123bbaa8b60SDan Kruchinin * Convert a lock from network to local form, and
124bbaa8b60SDan Kruchinin * check for valid range (no overflow).
125bbaa8b60SDan Kruchinin */
126bbaa8b60SDan Kruchinin static int
nlm_init_flock(struct flock64 * fl,struct nlm4_lock * nl,struct nlm_host * host,rpcvers_t vers,short type)127bbaa8b60SDan Kruchinin nlm_init_flock(struct flock64 *fl, struct nlm4_lock *nl,
128745caa42SMarcel Telka struct nlm_host *host, rpcvers_t vers, short type)
129bbaa8b60SDan Kruchinin {
130bbaa8b60SDan Kruchinin uint64_t off, len;
131bbaa8b60SDan Kruchinin
132bbaa8b60SDan Kruchinin bzero(fl, sizeof (*fl));
133bbaa8b60SDan Kruchinin off = nl->l_offset;
134bbaa8b60SDan Kruchinin len = nl->l_len;
135bbaa8b60SDan Kruchinin
136bbaa8b60SDan Kruchinin if (vers < NLM4_VERS) {
137bbaa8b60SDan Kruchinin if (off > MAX_UOFF32 || len > MAX_UOFF32)
138bbaa8b60SDan Kruchinin return (EINVAL);
139bbaa8b60SDan Kruchinin if (off + len > MAX_UOFF32 + 1)
140bbaa8b60SDan Kruchinin return (EINVAL);
141bbaa8b60SDan Kruchinin } else {
142bbaa8b60SDan Kruchinin /*
143bbaa8b60SDan Kruchinin * Check range for 64-bit client (no overflow).
144bbaa8b60SDan Kruchinin * Again allow len == ~0 to mean lock to EOF.
145bbaa8b60SDan Kruchinin */
146bbaa8b60SDan Kruchinin if (len == MAX_U_OFFSET_T)
147bbaa8b60SDan Kruchinin len = 0;
148bbaa8b60SDan Kruchinin if (len != 0 && off + (len - 1) < off)
149bbaa8b60SDan Kruchinin return (EINVAL);
150bbaa8b60SDan Kruchinin }
151bbaa8b60SDan Kruchinin
152bbaa8b60SDan Kruchinin fl->l_type = type;
153bbaa8b60SDan Kruchinin fl->l_whence = SEEK_SET;
154bbaa8b60SDan Kruchinin fl->l_start = off;
155bbaa8b60SDan Kruchinin fl->l_len = len;
156bbaa8b60SDan Kruchinin fl->l_sysid = host->nh_sysid;
157bbaa8b60SDan Kruchinin fl->l_pid = nl->svid;
158bbaa8b60SDan Kruchinin /* l_pad */
159bbaa8b60SDan Kruchinin
160bbaa8b60SDan Kruchinin return (0);
161bbaa8b60SDan Kruchinin }
162bbaa8b60SDan Kruchinin
163b4ecf764SJerry Jelinek /*
164b4ecf764SJerry Jelinek * Convert an fhandle into a vnode.
165b4ecf764SJerry Jelinek * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
166b4ecf764SJerry Jelinek * WARNING: users of this routine must do a VN_RELE on the vnode when they
167b4ecf764SJerry Jelinek * are done with it.
168b4ecf764SJerry Jelinek * This is just like nfs_fhtovp() but without the exportinfo argument.
169b4ecf764SJerry Jelinek */
170b4ecf764SJerry Jelinek static vnode_t *
lm_fhtovp(fhandle3_t * fh)171b4ecf764SJerry Jelinek lm_fhtovp(fhandle3_t *fh)
172b4ecf764SJerry Jelinek {
173b4ecf764SJerry Jelinek vfs_t *vfsp;
174b4ecf764SJerry Jelinek vnode_t *vp;
175b4ecf764SJerry Jelinek int error;
176b4ecf764SJerry Jelinek
177b4ecf764SJerry Jelinek vfsp = getvfs(&fh->_fh3_fsid);
178b4ecf764SJerry Jelinek if (vfsp == NULL)
179b4ecf764SJerry Jelinek return (NULL);
180b4ecf764SJerry Jelinek
181b4ecf764SJerry Jelinek /* LINTED E_BAD_PTR_CAST_ALIGN */
182b4ecf764SJerry Jelinek error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->_fh3_len));
183b4ecf764SJerry Jelinek VFS_RELE(vfsp);
184b4ecf764SJerry Jelinek if (error || vp == NULL)
185b4ecf764SJerry Jelinek return (NULL);
186b4ecf764SJerry Jelinek
187b4ecf764SJerry Jelinek return (vp);
188b4ecf764SJerry Jelinek }
189b4ecf764SJerry Jelinek
190bbaa8b60SDan Kruchinin /*
191bbaa8b60SDan Kruchinin * Gets vnode from client's filehandle
192bbaa8b60SDan Kruchinin * NOTE: Holds vnode, it _must_ be explicitly
193bbaa8b60SDan Kruchinin * released by VN_RELE().
194bbaa8b60SDan Kruchinin */
195bbaa8b60SDan Kruchinin static vnode_t *
nlm_fh_to_vp(struct netobj * fh)196bbaa8b60SDan Kruchinin nlm_fh_to_vp(struct netobj *fh)
197bbaa8b60SDan Kruchinin {
198b4ecf764SJerry Jelinek fhandle3_t *fhp;
199bbaa8b60SDan Kruchinin
200bbaa8b60SDan Kruchinin /*
201bbaa8b60SDan Kruchinin * Get a vnode pointer for the given NFS file handle.
202b4ecf764SJerry Jelinek * Note that it could be an NFSv2 or NFSv3 handle,
203bbaa8b60SDan Kruchinin * which means the size might vary. (don't copy)
204bbaa8b60SDan Kruchinin */
205b4ecf764SJerry Jelinek if (fh->n_len < sizeof (fhandle_t))
206bbaa8b60SDan Kruchinin return (NULL);
207bbaa8b60SDan Kruchinin
208bbaa8b60SDan Kruchinin /* We know this is aligned (kmem_alloc) */
209bbaa8b60SDan Kruchinin /* LINTED E_BAD_PTR_CAST_ALIGN */
210b4ecf764SJerry Jelinek fhp = (fhandle3_t *)fh->n_bytes;
211b4ecf764SJerry Jelinek
212b4ecf764SJerry Jelinek /*
213b4ecf764SJerry Jelinek * See the comment for NFS_FH3MAXDATA in uts/common/nfs/nfs.h for
214b4ecf764SJerry Jelinek * converting fhandles. Check the NFSv3 file handle size. The lockmgr
215b4ecf764SJerry Jelinek * is not used for NFS v4.
216b4ecf764SJerry Jelinek */
217b4ecf764SJerry Jelinek if (fhp->_fh3_len > NFS_FH3MAXDATA || fhp->_fh3_len == 0)
218b4ecf764SJerry Jelinek return (NULL);
219b4ecf764SJerry Jelinek
220bbaa8b60SDan Kruchinin return (lm_fhtovp(fhp));
221bbaa8b60SDan Kruchinin }
222bbaa8b60SDan Kruchinin
223bbaa8b60SDan Kruchinin /*
224bbaa8b60SDan Kruchinin * Get vhold from client's filehandle, but in contrast to
225bbaa8b60SDan Kruchinin * The function tries to check some access rights as well.
226bbaa8b60SDan Kruchinin *
227bbaa8b60SDan Kruchinin * NOTE: vhold object _must_ be explicitly released by
228bbaa8b60SDan Kruchinin * nlm_vhold_release().
229bbaa8b60SDan Kruchinin */
230bbaa8b60SDan Kruchinin static struct nlm_vhold *
nlm_fh_to_vhold(struct nlm_host * hostp,struct netobj * fh)231bbaa8b60SDan Kruchinin nlm_fh_to_vhold(struct nlm_host *hostp, struct netobj *fh)
232bbaa8b60SDan Kruchinin {
233bbaa8b60SDan Kruchinin vnode_t *vp;
234bbaa8b60SDan Kruchinin struct nlm_vhold *nvp;
235bbaa8b60SDan Kruchinin
236bbaa8b60SDan Kruchinin vp = nlm_fh_to_vp(fh);
237bbaa8b60SDan Kruchinin if (vp == NULL)
238bbaa8b60SDan Kruchinin return (NULL);
239bbaa8b60SDan Kruchinin
240bbaa8b60SDan Kruchinin
241bbaa8b60SDan Kruchinin nvp = nlm_vhold_get(hostp, vp);
242bbaa8b60SDan Kruchinin
243bbaa8b60SDan Kruchinin /*
244bbaa8b60SDan Kruchinin * Both nlm_fh_to_vp() and nlm_vhold_get()
245bbaa8b60SDan Kruchinin * do VN_HOLD(), so we need to drop one
246bbaa8b60SDan Kruchinin * reference on vnode.
247bbaa8b60SDan Kruchinin */
248bbaa8b60SDan Kruchinin VN_RELE(vp);
249bbaa8b60SDan Kruchinin return (nvp);
250bbaa8b60SDan Kruchinin }
251bbaa8b60SDan Kruchinin
252bbaa8b60SDan Kruchinin /* ******************************************************************* */
253bbaa8b60SDan Kruchinin
254bbaa8b60SDan Kruchinin /*
255bbaa8b60SDan Kruchinin * NLM implementation details, called from the RPC svc code.
256bbaa8b60SDan Kruchinin */
257bbaa8b60SDan Kruchinin
258bbaa8b60SDan Kruchinin /*
259bbaa8b60SDan Kruchinin * Call-back from NFS statd, used to notify that one of our
260bbaa8b60SDan Kruchinin * hosts had a status change. The host can be either an
261bbaa8b60SDan Kruchinin * NFS client, NFS server or both.
262bbaa8b60SDan Kruchinin * According to NSM protocol description, the state is a
263bbaa8b60SDan Kruchinin * number that is increases monotonically each time the
264bbaa8b60SDan Kruchinin * state of host changes. An even number indicates that
265bbaa8b60SDan Kruchinin * the host is down, while an odd number indicates that
266bbaa8b60SDan Kruchinin * the host is up.
267bbaa8b60SDan Kruchinin *
268bbaa8b60SDan Kruchinin * Here we ignore this even/odd difference of status number
269bbaa8b60SDan Kruchinin * reported by the NSM, we launch notification handlers
270bbaa8b60SDan Kruchinin * every time the state is changed. The reason we why do so
271bbaa8b60SDan Kruchinin * is that client and server can talk to each other using
272bbaa8b60SDan Kruchinin * connectionless transport and it's easy to lose packet
273bbaa8b60SDan Kruchinin * containing NSM notification with status number update.
274bbaa8b60SDan Kruchinin *
275bbaa8b60SDan Kruchinin * In nlm_host_monitor(), we put the sysid in the private data
276bbaa8b60SDan Kruchinin * that statd carries in this callback, so we can easliy find
277bbaa8b60SDan Kruchinin * the host this call applies to.
278bbaa8b60SDan Kruchinin */
279bbaa8b60SDan Kruchinin /* ARGSUSED */
280bbaa8b60SDan Kruchinin void
nlm_do_notify1(nlm_sm_status * argp,void * res,struct svc_req * sr)281bbaa8b60SDan Kruchinin nlm_do_notify1(nlm_sm_status *argp, void *res, struct svc_req *sr)
282bbaa8b60SDan Kruchinin {
283bbaa8b60SDan Kruchinin struct nlm_globals *g;
284bbaa8b60SDan Kruchinin struct nlm_host *host;
285bbaa8b60SDan Kruchinin uint16_t sysid;
286bbaa8b60SDan Kruchinin
287bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone);
288bbaa8b60SDan Kruchinin bcopy(&argp->priv, &sysid, sizeof (sysid));
289bbaa8b60SDan Kruchinin
290bbaa8b60SDan Kruchinin DTRACE_PROBE2(nsm__notify, uint16_t, sysid,
291bbaa8b60SDan Kruchinin int, argp->state);
292bbaa8b60SDan Kruchinin
293bbaa8b60SDan Kruchinin host = nlm_host_find_by_sysid(g, (sysid_t)sysid);
294bbaa8b60SDan Kruchinin if (host == NULL)
295bbaa8b60SDan Kruchinin return;
296bbaa8b60SDan Kruchinin
297bbaa8b60SDan Kruchinin nlm_host_notify_server(host, argp->state);
298bbaa8b60SDan Kruchinin nlm_host_notify_client(host, argp->state);
299bbaa8b60SDan Kruchinin nlm_host_release(g, host);
300bbaa8b60SDan Kruchinin }
301bbaa8b60SDan Kruchinin
302bbaa8b60SDan Kruchinin /*
303bbaa8b60SDan Kruchinin * Another available call-back for NFS statd.
304bbaa8b60SDan Kruchinin * Not currently used.
305bbaa8b60SDan Kruchinin */
306bbaa8b60SDan Kruchinin /* ARGSUSED */
307bbaa8b60SDan Kruchinin void
nlm_do_notify2(nlm_sm_status * argp,void * res,struct svc_req * sr)308bbaa8b60SDan Kruchinin nlm_do_notify2(nlm_sm_status *argp, void *res, struct svc_req *sr)
309bbaa8b60SDan Kruchinin {
310bbaa8b60SDan Kruchinin ASSERT(0);
311bbaa8b60SDan Kruchinin }
312bbaa8b60SDan Kruchinin
313bbaa8b60SDan Kruchinin
314bbaa8b60SDan Kruchinin /*
315bbaa8b60SDan Kruchinin * NLM_TEST, NLM_TEST_MSG,
316bbaa8b60SDan Kruchinin * NLM4_TEST, NLM4_TEST_MSG,
317bbaa8b60SDan Kruchinin * Client inquiry about locks, non-blocking.
318*54b3584eSGordon Ross *
319*54b3584eSGordon Ross * Arg cb is NULL for NLM_TEST, NLM4_TEST, and
320*54b3584eSGordon Ross * non-NULL for NLM_TEST_MSG, NLM4_TEST_MSG
321*54b3584eSGordon Ross * The MSG forms use the cb to send the reply,
322*54b3584eSGordon Ross * and don't return a reply for this call.
323bbaa8b60SDan Kruchinin */
324bbaa8b60SDan Kruchinin void
nlm_do_test(nlm4_testargs * argp,nlm4_testres * resp,struct svc_req * sr,nlm_testres_cb cb)325bbaa8b60SDan Kruchinin nlm_do_test(nlm4_testargs *argp, nlm4_testres *resp,
326bbaa8b60SDan Kruchinin struct svc_req *sr, nlm_testres_cb cb)
327bbaa8b60SDan Kruchinin {
328bbaa8b60SDan Kruchinin struct nlm_globals *g;
329bbaa8b60SDan Kruchinin struct nlm_host *host;
330bbaa8b60SDan Kruchinin struct nlm4_holder *lh;
331bbaa8b60SDan Kruchinin struct nlm_owner_handle *oh;
332bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp = NULL;
333bbaa8b60SDan Kruchinin vnode_t *vp = NULL;
334bbaa8b60SDan Kruchinin struct netbuf *addr;
335bbaa8b60SDan Kruchinin char *netid;
336bbaa8b60SDan Kruchinin char *name;
337bbaa8b60SDan Kruchinin int error;
338bbaa8b60SDan Kruchinin struct flock64 fl;
339bbaa8b60SDan Kruchinin
340bbaa8b60SDan Kruchinin nlm_copy_netobj(&resp->cookie, &argp->cookie);
341bbaa8b60SDan Kruchinin
342bbaa8b60SDan Kruchinin name = argp->alock.caller_name;
343bbaa8b60SDan Kruchinin netid = svc_getnetid(sr->rq_xprt);
344bbaa8b60SDan Kruchinin addr = svc_getrpccaller(sr->rq_xprt);
345bbaa8b60SDan Kruchinin
346bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone);
347bbaa8b60SDan Kruchinin host = nlm_host_findcreate(g, name, netid, addr);
348bbaa8b60SDan Kruchinin if (host == NULL) {
349bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied_nolocks;
350bbaa8b60SDan Kruchinin return;
351bbaa8b60SDan Kruchinin }
352bbaa8b60SDan Kruchinin if (cb != NULL) {
353bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
354bbaa8b60SDan Kruchinin if (error != 0) {
355bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied_nolocks;
356bbaa8b60SDan Kruchinin goto out;
357bbaa8b60SDan Kruchinin }
358bbaa8b60SDan Kruchinin }
359bbaa8b60SDan Kruchinin
360bbaa8b60SDan Kruchinin vp = nlm_fh_to_vp(&argp->alock.fh);
361bbaa8b60SDan Kruchinin if (vp == NULL) {
362bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_stale_fh;
363bbaa8b60SDan Kruchinin goto out;
364bbaa8b60SDan Kruchinin }
365bbaa8b60SDan Kruchinin
366bbaa8b60SDan Kruchinin if (NLM_IN_GRACE(g)) {
367bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied_grace_period;
368bbaa8b60SDan Kruchinin goto out;
369bbaa8b60SDan Kruchinin }
370bbaa8b60SDan Kruchinin
371bbaa8b60SDan Kruchinin /* Convert to local form. */
372bbaa8b60SDan Kruchinin error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers,
373bbaa8b60SDan Kruchinin (argp->exclusive) ? F_WRLCK : F_RDLCK);
374bbaa8b60SDan Kruchinin if (error) {
375bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_failed;
376bbaa8b60SDan Kruchinin goto out;
377bbaa8b60SDan Kruchinin }
378bbaa8b60SDan Kruchinin
379bbaa8b60SDan Kruchinin /* BSD: VOP_ADVLOCK(nv->nv_vp, NULL, F_GETLK, &fl, F_REMOTE); */
380bbaa8b60SDan Kruchinin error = nlm_vop_frlock(vp, F_GETLK, &fl,
381bbaa8b60SDan Kruchinin F_REMOTELOCK | FREAD | FWRITE,
382bbaa8b60SDan Kruchinin (u_offset_t)0, NULL, CRED(), NULL);
383bbaa8b60SDan Kruchinin if (error) {
384bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_failed;
385bbaa8b60SDan Kruchinin goto out;
386bbaa8b60SDan Kruchinin }
387bbaa8b60SDan Kruchinin
388bbaa8b60SDan Kruchinin if (fl.l_type == F_UNLCK) {
389bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_granted;
390bbaa8b60SDan Kruchinin goto out;
391bbaa8b60SDan Kruchinin }
392bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied;
393bbaa8b60SDan Kruchinin
394bbaa8b60SDan Kruchinin /*
395bbaa8b60SDan Kruchinin * This lock "test" fails due to a conflicting lock.
396bbaa8b60SDan Kruchinin *
397bbaa8b60SDan Kruchinin * If this is a v1 client, make sure the conflicting
398bbaa8b60SDan Kruchinin * lock range we report can be expressed with 32-bit
399bbaa8b60SDan Kruchinin * offsets. The lock range requested was expressed
400bbaa8b60SDan Kruchinin * as 32-bit offset and length, so at least part of
401bbaa8b60SDan Kruchinin * the conflicting lock should lie below MAX_UOFF32.
402bbaa8b60SDan Kruchinin * If the conflicting lock extends past that, we'll
403bbaa8b60SDan Kruchinin * trim the range to end at MAX_UOFF32 so this lock
404bbaa8b60SDan Kruchinin * can be represented in a 32-bit response. Check
405bbaa8b60SDan Kruchinin * the start also (paranoid, but a low cost check).
406bbaa8b60SDan Kruchinin */
407bbaa8b60SDan Kruchinin if (sr->rq_vers < NLM4_VERS) {
408bbaa8b60SDan Kruchinin uint64 maxlen;
409bbaa8b60SDan Kruchinin if (fl.l_start > MAX_UOFF32)
410bbaa8b60SDan Kruchinin fl.l_start = MAX_UOFF32;
411bbaa8b60SDan Kruchinin maxlen = MAX_UOFF32 + 1 - fl.l_start;
412bbaa8b60SDan Kruchinin if (fl.l_len > maxlen)
413bbaa8b60SDan Kruchinin fl.l_len = maxlen;
414bbaa8b60SDan Kruchinin }
415bbaa8b60SDan Kruchinin
416bbaa8b60SDan Kruchinin /*
417bbaa8b60SDan Kruchinin * Build the nlm4_holder result structure.
418bbaa8b60SDan Kruchinin *
419bbaa8b60SDan Kruchinin * Note that lh->oh is freed via xdr_free,
420bbaa8b60SDan Kruchinin * xdr_nlm4_holder, xdr_netobj, xdr_bytes.
421bbaa8b60SDan Kruchinin */
422bbaa8b60SDan Kruchinin oh = kmem_zalloc(sizeof (*oh), KM_SLEEP);
423bbaa8b60SDan Kruchinin oh->oh_sysid = (sysid_t)fl.l_sysid;
424bbaa8b60SDan Kruchinin lh = &resp->stat.nlm4_testrply_u.holder;
425bbaa8b60SDan Kruchinin lh->exclusive = (fl.l_type == F_WRLCK);
426bbaa8b60SDan Kruchinin lh->svid = fl.l_pid;
427bbaa8b60SDan Kruchinin lh->oh.n_len = sizeof (*oh);
428bbaa8b60SDan Kruchinin lh->oh.n_bytes = (void *)oh;
429bbaa8b60SDan Kruchinin lh->l_offset = fl.l_start;
430bbaa8b60SDan Kruchinin lh->l_len = fl.l_len;
431bbaa8b60SDan Kruchinin
432bbaa8b60SDan Kruchinin out:
433bbaa8b60SDan Kruchinin /*
43495fa5714SMarcel Telka * If we have a callback function, use that to
435bbaa8b60SDan Kruchinin * deliver the response via another RPC call.
436bbaa8b60SDan Kruchinin */
437bbaa8b60SDan Kruchinin if (cb != NULL && rpcp != NULL)
438bbaa8b60SDan Kruchinin NLM_INVOKE_CALLBACK("test", rpcp, resp, cb);
439bbaa8b60SDan Kruchinin
440bbaa8b60SDan Kruchinin if (vp != NULL)
441bbaa8b60SDan Kruchinin VN_RELE(vp);
442bbaa8b60SDan Kruchinin if (rpcp != NULL)
443bbaa8b60SDan Kruchinin nlm_host_rele_rpc(host, rpcp);
444bbaa8b60SDan Kruchinin
445bbaa8b60SDan Kruchinin nlm_host_release(g, host);
446bbaa8b60SDan Kruchinin }
447bbaa8b60SDan Kruchinin
448bbaa8b60SDan Kruchinin /*
449bbaa8b60SDan Kruchinin * NLM_LOCK, NLM_LOCK_MSG, NLM_NM_LOCK
450bbaa8b60SDan Kruchinin * NLM4_LOCK, NLM4_LOCK_MSG, NLM4_NM_LOCK
451bbaa8b60SDan Kruchinin *
452bbaa8b60SDan Kruchinin * Client request to set a lock, possibly blocking.
453bbaa8b60SDan Kruchinin *
454bbaa8b60SDan Kruchinin * If the lock needs to block, we return status blocked to
455bbaa8b60SDan Kruchinin * this RPC call, and then later call back the client with
456bbaa8b60SDan Kruchinin * a "granted" callback. Tricky aspects of this include:
457bbaa8b60SDan Kruchinin * sending a reply before this function returns, and then
458bbaa8b60SDan Kruchinin * borrowing this thread from the RPC service pool for the
459bbaa8b60SDan Kruchinin * wait on the lock and doing the later granted callback.
460bbaa8b60SDan Kruchinin *
461bbaa8b60SDan Kruchinin * We also have to keep a list of locks (pending + granted)
462bbaa8b60SDan Kruchinin * both to handle retransmitted requests, and to keep the
463bbaa8b60SDan Kruchinin * vnodes for those locks active.
464*54b3584eSGordon Ross *
465*54b3584eSGordon Ross * Callback arguments:
466*54b3584eSGordon Ross * reply_cb Used to send a normal RPC reply just as if
467*54b3584eSGordon Ross * we had filled in a response for our caller.
468*54b3584eSGordon Ross * Needed because we do work after the reply.
469*54b3584eSGordon Ross * res_cb Used for the MSG calls, where there's no
470*54b3584eSGordon Ross * regular RPC response.
471*54b3584eSGordon Ross * grant_cb Used to CALL the client informing them of a
472*54b3584eSGordon Ross * granted lock after a "blocked" reply.
473bbaa8b60SDan Kruchinin */
474bbaa8b60SDan Kruchinin void
nlm_do_lock(nlm4_lockargs * argp,nlm4_res * resp,struct svc_req * sr,nlm_reply_cb reply_cb,nlm_res_cb res_cb,nlm_granted_cb grant_cb)475bbaa8b60SDan Kruchinin nlm_do_lock(nlm4_lockargs *argp, nlm4_res *resp, struct svc_req *sr,
476*54b3584eSGordon Ross nlm_reply_cb reply_cb, nlm_res_cb res_cb, nlm_granted_cb grant_cb)
477bbaa8b60SDan Kruchinin {
478bbaa8b60SDan Kruchinin struct nlm_globals *g;
479bbaa8b60SDan Kruchinin struct flock64 fl;
480bbaa8b60SDan Kruchinin struct nlm_host *host = NULL;
481bbaa8b60SDan Kruchinin struct netbuf *addr;
482bbaa8b60SDan Kruchinin struct nlm_vhold *nvp = NULL;
483bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp = NULL;
484bbaa8b60SDan Kruchinin char *netid;
485bbaa8b60SDan Kruchinin char *name;
486bbaa8b60SDan Kruchinin int error, flags;
487bbaa8b60SDan Kruchinin bool_t do_blocking = FALSE;
488bbaa8b60SDan Kruchinin bool_t do_mon_req = FALSE;
489bbaa8b60SDan Kruchinin enum nlm4_stats status;
490bbaa8b60SDan Kruchinin
491bbaa8b60SDan Kruchinin nlm_copy_netobj(&resp->cookie, &argp->cookie);
492bbaa8b60SDan Kruchinin
493bbaa8b60SDan Kruchinin name = argp->alock.caller_name;
494bbaa8b60SDan Kruchinin netid = svc_getnetid(sr->rq_xprt);
495bbaa8b60SDan Kruchinin addr = svc_getrpccaller(sr->rq_xprt);
496bbaa8b60SDan Kruchinin
497bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone);
498bbaa8b60SDan Kruchinin host = nlm_host_findcreate(g, name, netid, addr);
499bbaa8b60SDan Kruchinin if (host == NULL) {
500bbaa8b60SDan Kruchinin DTRACE_PROBE4(no__host, struct nlm_globals *, g,
501bbaa8b60SDan Kruchinin char *, name, char *, netid, struct netbuf *, addr);
502bbaa8b60SDan Kruchinin status = nlm4_denied_nolocks;
503bbaa8b60SDan Kruchinin goto doreply;
504bbaa8b60SDan Kruchinin }
505bbaa8b60SDan Kruchinin
506bbaa8b60SDan Kruchinin DTRACE_PROBE3(start, struct nlm_globals *, g,
507bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_lockargs *, argp);
508bbaa8b60SDan Kruchinin
509bbaa8b60SDan Kruchinin /*
510*54b3584eSGordon Ross * If this is a MSG call (NLM_LOCK_MSG, NLM4_LOCK_MSG)
511*54b3584eSGordon Ross * we'll have res_cb != NULL, and we know we'll need an
512*54b3584eSGordon Ross * RPC client handle _now_ so we can send the response.
513*54b3584eSGordon Ross * If we can't get an rpc handle (rpcp) then we have
514*54b3584eSGordon Ross * no way to respond, and the client will time out.
515bbaa8b60SDan Kruchinin */
516*54b3584eSGordon Ross if (res_cb != NULL) {
517bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
518bbaa8b60SDan Kruchinin if (error != 0) {
519*54b3584eSGordon Ross ASSERT(rpcp == NULL);
520bbaa8b60SDan Kruchinin status = nlm4_denied_nolocks;
521*54b3584eSGordon Ross goto out;
522bbaa8b60SDan Kruchinin }
523bbaa8b60SDan Kruchinin }
524bbaa8b60SDan Kruchinin
525bbaa8b60SDan Kruchinin /*
526bbaa8b60SDan Kruchinin * During the "grace period", only allow reclaim.
527bbaa8b60SDan Kruchinin */
528bbaa8b60SDan Kruchinin if (argp->reclaim == 0 && NLM_IN_GRACE(g)) {
529bbaa8b60SDan Kruchinin status = nlm4_denied_grace_period;
530bbaa8b60SDan Kruchinin goto doreply;
531bbaa8b60SDan Kruchinin }
532bbaa8b60SDan Kruchinin
533bbaa8b60SDan Kruchinin /*
534bbaa8b60SDan Kruchinin * Check whether we missed host shutdown event
535bbaa8b60SDan Kruchinin */
536bbaa8b60SDan Kruchinin if (nlm_host_get_state(host) != argp->state)
537bbaa8b60SDan Kruchinin nlm_host_notify_server(host, argp->state);
538bbaa8b60SDan Kruchinin
539bbaa8b60SDan Kruchinin /*
540bbaa8b60SDan Kruchinin * Get a hold on the vnode for a lock operation.
541bbaa8b60SDan Kruchinin * Only lock() and share() need vhold objects.
542bbaa8b60SDan Kruchinin */
543bbaa8b60SDan Kruchinin nvp = nlm_fh_to_vhold(host, &argp->alock.fh);
544bbaa8b60SDan Kruchinin if (nvp == NULL) {
545bbaa8b60SDan Kruchinin status = nlm4_stale_fh;
546bbaa8b60SDan Kruchinin goto doreply;
547bbaa8b60SDan Kruchinin }
548bbaa8b60SDan Kruchinin
549bbaa8b60SDan Kruchinin /* Convert to local form. */
550bbaa8b60SDan Kruchinin error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers,
551bbaa8b60SDan Kruchinin (argp->exclusive) ? F_WRLCK : F_RDLCK);
552bbaa8b60SDan Kruchinin if (error) {
553bbaa8b60SDan Kruchinin status = nlm4_failed;
554bbaa8b60SDan Kruchinin goto doreply;
555bbaa8b60SDan Kruchinin }
556bbaa8b60SDan Kruchinin
557bbaa8b60SDan Kruchinin /*
558bbaa8b60SDan Kruchinin * Try to lock non-blocking first. If we succeed
559bbaa8b60SDan Kruchinin * getting the lock, we can reply with the granted
560bbaa8b60SDan Kruchinin * status directly and avoid the complications of
561bbaa8b60SDan Kruchinin * making the "granted" RPC callback later.
562bbaa8b60SDan Kruchinin *
563bbaa8b60SDan Kruchinin * This also let's us find out now about some
564bbaa8b60SDan Kruchinin * possible errors like EROFS, etc.
565bbaa8b60SDan Kruchinin */
566bbaa8b60SDan Kruchinin flags = F_REMOTELOCK | FREAD | FWRITE;
567bbaa8b60SDan Kruchinin error = nlm_vop_frlock(nvp->nv_vp, F_SETLK, &fl, flags,
568bbaa8b60SDan Kruchinin (u_offset_t)0, NULL, CRED(), NULL);
569bbaa8b60SDan Kruchinin
570bbaa8b60SDan Kruchinin DTRACE_PROBE3(setlk__res, struct flock64 *, &fl,
571bbaa8b60SDan Kruchinin int, flags, int, error);
572bbaa8b60SDan Kruchinin
573bbaa8b60SDan Kruchinin switch (error) {
574bbaa8b60SDan Kruchinin case 0:
575bbaa8b60SDan Kruchinin /* Got it without waiting! */
576bbaa8b60SDan Kruchinin status = nlm4_granted;
577bbaa8b60SDan Kruchinin do_mon_req = TRUE;
578bbaa8b60SDan Kruchinin break;
579bbaa8b60SDan Kruchinin
580bbaa8b60SDan Kruchinin /* EINPROGRESS too? */
581bbaa8b60SDan Kruchinin case EAGAIN:
582bbaa8b60SDan Kruchinin /* We did not get the lock. Should we block? */
583bbaa8b60SDan Kruchinin if (argp->block == FALSE || grant_cb == NULL) {
584bbaa8b60SDan Kruchinin status = nlm4_denied;
585bbaa8b60SDan Kruchinin break;
586bbaa8b60SDan Kruchinin }
587bbaa8b60SDan Kruchinin /*
588bbaa8b60SDan Kruchinin * Should block. Try to reserve this thread
589bbaa8b60SDan Kruchinin * so we can use it to wait for the lock and
590bbaa8b60SDan Kruchinin * later send the granted message. If this
591bbaa8b60SDan Kruchinin * reservation fails, say "no resources".
592bbaa8b60SDan Kruchinin */
593bbaa8b60SDan Kruchinin if (!svc_reserve_thread(sr->rq_xprt)) {
594bbaa8b60SDan Kruchinin status = nlm4_denied_nolocks;
595bbaa8b60SDan Kruchinin break;
596bbaa8b60SDan Kruchinin }
597bbaa8b60SDan Kruchinin /*
598bbaa8b60SDan Kruchinin * OK, can detach this thread, so this call
599bbaa8b60SDan Kruchinin * will block below (after we reply).
600*54b3584eSGordon Ross * The "blocked" reply tells the client to
601*54b3584eSGordon Ross * expect a "granted" call-back later.
602bbaa8b60SDan Kruchinin */
603bbaa8b60SDan Kruchinin status = nlm4_blocked;
604bbaa8b60SDan Kruchinin do_blocking = TRUE;
605bbaa8b60SDan Kruchinin do_mon_req = TRUE;
606bbaa8b60SDan Kruchinin break;
607bbaa8b60SDan Kruchinin
608bbaa8b60SDan Kruchinin case ENOLCK:
609bbaa8b60SDan Kruchinin /* Failed for lack of resources. */
610bbaa8b60SDan Kruchinin status = nlm4_denied_nolocks;
611bbaa8b60SDan Kruchinin break;
612bbaa8b60SDan Kruchinin
613bbaa8b60SDan Kruchinin case EROFS:
614bbaa8b60SDan Kruchinin /* read-only file system */
615bbaa8b60SDan Kruchinin status = nlm4_rofs;
616bbaa8b60SDan Kruchinin break;
617bbaa8b60SDan Kruchinin
618bbaa8b60SDan Kruchinin case EFBIG:
619bbaa8b60SDan Kruchinin /* file too big */
620bbaa8b60SDan Kruchinin status = nlm4_fbig;
621bbaa8b60SDan Kruchinin break;
622bbaa8b60SDan Kruchinin
623bbaa8b60SDan Kruchinin case EDEADLK:
624bbaa8b60SDan Kruchinin /* dead lock condition */
625bbaa8b60SDan Kruchinin status = nlm4_deadlck;
626bbaa8b60SDan Kruchinin break;
627bbaa8b60SDan Kruchinin
628bbaa8b60SDan Kruchinin default:
629bbaa8b60SDan Kruchinin status = nlm4_denied;
630bbaa8b60SDan Kruchinin break;
631bbaa8b60SDan Kruchinin }
632bbaa8b60SDan Kruchinin
633bbaa8b60SDan Kruchinin doreply:
634bbaa8b60SDan Kruchinin resp->stat.stat = status;
635bbaa8b60SDan Kruchinin
636bbaa8b60SDan Kruchinin /*
637bbaa8b60SDan Kruchinin * We get one of two function pointers; one for a
638bbaa8b60SDan Kruchinin * normal RPC reply, and another for doing an RPC
639bbaa8b60SDan Kruchinin * "callback" _res reply for a _msg function.
640bbaa8b60SDan Kruchinin * Use either of those to send the reply now.
641bbaa8b60SDan Kruchinin *
642bbaa8b60SDan Kruchinin * If sending this reply fails, just leave the
643bbaa8b60SDan Kruchinin * lock in the list for retransmitted requests.
644bbaa8b60SDan Kruchinin * Cleanup is via unlock or host rele (statmon).
645bbaa8b60SDan Kruchinin */
646bbaa8b60SDan Kruchinin if (reply_cb != NULL) {
647bbaa8b60SDan Kruchinin /* i.e. nlm_lock_1_reply */
648bbaa8b60SDan Kruchinin if (!(*reply_cb)(sr->rq_xprt, resp))
649bbaa8b60SDan Kruchinin svcerr_systemerr(sr->rq_xprt);
650bbaa8b60SDan Kruchinin }
651bbaa8b60SDan Kruchinin if (res_cb != NULL && rpcp != NULL)
652bbaa8b60SDan Kruchinin NLM_INVOKE_CALLBACK("lock", rpcp, resp, res_cb);
653bbaa8b60SDan Kruchinin
654bbaa8b60SDan Kruchinin /*
655bbaa8b60SDan Kruchinin * The reply has been sent to the client.
656bbaa8b60SDan Kruchinin * Start monitoring this client (maybe).
657bbaa8b60SDan Kruchinin *
658bbaa8b60SDan Kruchinin * Note that the non-monitored (NM) calls pass grant_cb=NULL
659bbaa8b60SDan Kruchinin * indicating that the client doesn't support RPC callbacks.
660bbaa8b60SDan Kruchinin * No monitoring for these (lame) clients.
661bbaa8b60SDan Kruchinin */
662bbaa8b60SDan Kruchinin if (do_mon_req && grant_cb != NULL)
663bbaa8b60SDan Kruchinin nlm_host_monitor(g, host, argp->state);
664bbaa8b60SDan Kruchinin
665bbaa8b60SDan Kruchinin if (do_blocking) {
666bbaa8b60SDan Kruchinin /*
667bbaa8b60SDan Kruchinin * We need to block on this lock, and when that
668bbaa8b60SDan Kruchinin * completes, do the granted RPC call. Note that
669bbaa8b60SDan Kruchinin * we "reserved" this thread above, so we can now
670bbaa8b60SDan Kruchinin * "detach" it from the RPC SVC pool, allowing it
671bbaa8b60SDan Kruchinin * to block indefinitely if needed.
672bbaa8b60SDan Kruchinin */
673*54b3584eSGordon Ross ASSERT(grant_cb != NULL);
674bbaa8b60SDan Kruchinin (void) svc_detach_thread(sr->rq_xprt);
675*54b3584eSGordon Ross nlm_block(argp, host, nvp, &fl, grant_cb, sr->rq_vers);
676bbaa8b60SDan Kruchinin }
677bbaa8b60SDan Kruchinin
678*54b3584eSGordon Ross out:
679bbaa8b60SDan Kruchinin DTRACE_PROBE3(lock__end, struct nlm_globals *, g,
680bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_res *, resp);
681bbaa8b60SDan Kruchinin
682bbaa8b60SDan Kruchinin if (rpcp != NULL)
683bbaa8b60SDan Kruchinin nlm_host_rele_rpc(host, rpcp);
684bbaa8b60SDan Kruchinin
685bbaa8b60SDan Kruchinin nlm_vhold_release(host, nvp);
686bbaa8b60SDan Kruchinin nlm_host_release(g, host);
687bbaa8b60SDan Kruchinin }
688bbaa8b60SDan Kruchinin
689bbaa8b60SDan Kruchinin /*
690bbaa8b60SDan Kruchinin * Helper for nlm_do_lock(), partly for observability,
691bbaa8b60SDan Kruchinin * (we'll see a call blocked in this function) and
692bbaa8b60SDan Kruchinin * because nlm_do_lock() was getting quite long.
693bbaa8b60SDan Kruchinin */
694bbaa8b60SDan Kruchinin static void
nlm_block(nlm4_lockargs * lockargs,struct nlm_host * host,struct nlm_vhold * nvp,struct flock64 * flp,nlm_granted_cb grant_cb,rpcvers_t vers)695bbaa8b60SDan Kruchinin nlm_block(nlm4_lockargs *lockargs,
696bbaa8b60SDan Kruchinin struct nlm_host *host,
697bbaa8b60SDan Kruchinin struct nlm_vhold *nvp,
698bbaa8b60SDan Kruchinin struct flock64 *flp,
699*54b3584eSGordon Ross nlm_granted_cb grant_cb,
700*54b3584eSGordon Ross rpcvers_t vers)
701bbaa8b60SDan Kruchinin {
702bbaa8b60SDan Kruchinin nlm4_testargs args;
703*54b3584eSGordon Ross nlm4_res res;
704bbaa8b60SDan Kruchinin int error;
705bbaa8b60SDan Kruchinin flk_callback_t flk_cb;
706bbaa8b60SDan Kruchinin struct nlm_block_cb_data cb_data;
707*54b3584eSGordon Ross nlm_rpc_t *rpcp = NULL;
708*54b3584eSGordon Ross enum clnt_stat status;
709bbaa8b60SDan Kruchinin
710bbaa8b60SDan Kruchinin /*
711bbaa8b60SDan Kruchinin * Keep a list of blocked locks on nh_pending, and use it
712bbaa8b60SDan Kruchinin * to cancel these threads in nlm_destroy_client_pending.
713bbaa8b60SDan Kruchinin *
714*54b3584eSGordon Ross * Check to see if this lock is already in the list. If so,
715*54b3584eSGordon Ross * some earlier call is already blocked getting this lock,
716*54b3584eSGordon Ross * so there's nothing more this call needs to do.
717bbaa8b60SDan Kruchinin */
718bbaa8b60SDan Kruchinin error = nlm_slreq_register(host, nvp, flp);
719bbaa8b60SDan Kruchinin if (error != 0) {
720bbaa8b60SDan Kruchinin /*
721bbaa8b60SDan Kruchinin * Sleeping lock request with given fl is already
722bbaa8b60SDan Kruchinin * registered by someone else. This means that
723bbaa8b60SDan Kruchinin * some other thread is handling the request, let
72448bbca81SDaniel Hoffman * it do its work.
725bbaa8b60SDan Kruchinin */
726bbaa8b60SDan Kruchinin ASSERT(error == EEXIST);
727bbaa8b60SDan Kruchinin return;
728bbaa8b60SDan Kruchinin }
729bbaa8b60SDan Kruchinin
730*54b3584eSGordon Ross /*
731*54b3584eSGordon Ross * Make sure we can get an RPC client handle we can use to
732*54b3584eSGordon Ross * deliver the "granted" callback if/when we get the lock.
733*54b3584eSGordon Ross * If we can't, there's no point blocking to get the lock
734*54b3584eSGordon Ross * for them because they'll never find out about it.
735*54b3584eSGordon Ross */
736*54b3584eSGordon Ross error = nlm_host_get_rpc(host, vers, &rpcp);
737*54b3584eSGordon Ross if (error != 0) {
738*54b3584eSGordon Ross (void) nlm_slreq_unregister(host, nvp, flp);
739*54b3584eSGordon Ross return;
740*54b3584eSGordon Ross }
741*54b3584eSGordon Ross
742bbaa8b60SDan Kruchinin cb_data.hostp = host;
743bbaa8b60SDan Kruchinin cb_data.nvp = nvp;
744bbaa8b60SDan Kruchinin cb_data.flp = flp;
745*54b3584eSGordon Ross cb_data.registered = TRUE;
746bbaa8b60SDan Kruchinin flk_init_callback(&flk_cb, nlm_block_callback, &cb_data);
747bbaa8b60SDan Kruchinin
748bbaa8b60SDan Kruchinin /* BSD: VOP_ADVLOCK(vp, NULL, F_SETLK, fl, F_REMOTE); */
749bbaa8b60SDan Kruchinin error = nlm_vop_frlock(nvp->nv_vp, F_SETLKW, flp,
750bbaa8b60SDan Kruchinin F_REMOTELOCK | FREAD | FWRITE,
751bbaa8b60SDan Kruchinin (u_offset_t)0, &flk_cb, CRED(), NULL);
752bbaa8b60SDan Kruchinin
753*54b3584eSGordon Ross /*
754*54b3584eSGordon Ross * If the nlm_block_callback didn't already do it...
755*54b3584eSGordon Ross */
756*54b3584eSGordon Ross if (cb_data.registered)
757*54b3584eSGordon Ross (void) nlm_slreq_unregister(host, nvp, flp);
758*54b3584eSGordon Ross
759bbaa8b60SDan Kruchinin if (error != 0) {
760bbaa8b60SDan Kruchinin /*
761bbaa8b60SDan Kruchinin * We failed getting the lock, but have no way to
762bbaa8b60SDan Kruchinin * tell the client about that. Let 'em time out.
763bbaa8b60SDan Kruchinin */
764bbaa8b60SDan Kruchinin return;
765bbaa8b60SDan Kruchinin }
766bbaa8b60SDan Kruchinin /*
767*54b3584eSGordon Ross * ... else we got the lock on behalf of this client.
768*54b3584eSGordon Ross *
769*54b3584eSGordon Ross * We MUST either tell the client about this lock
770*54b3584eSGordon Ross * (via the "granted" callback RPC) or unlock.
771*54b3584eSGordon Ross *
772bbaa8b60SDan Kruchinin * Do the "granted" call-back to the client.
773bbaa8b60SDan Kruchinin */
774*54b3584eSGordon Ross bzero(&args, sizeof (args));
775bbaa8b60SDan Kruchinin args.cookie = lockargs->cookie;
776bbaa8b60SDan Kruchinin args.exclusive = lockargs->exclusive;
777bbaa8b60SDan Kruchinin args.alock = lockargs->alock;
778*54b3584eSGordon Ross bzero(&res, sizeof (res));
779*54b3584eSGordon Ross
780*54b3584eSGordon Ross /*
781*54b3584eSGordon Ross * Not using the NLM_INVOKE_CALLBACK() macro because
782*54b3584eSGordon Ross * we need to take actions on errors.
783*54b3584eSGordon Ross */
784*54b3584eSGordon Ross status = (*grant_cb)(&args, &res, (rpcp)->nr_handle);
785*54b3584eSGordon Ross if (status != RPC_SUCCESS) {
786*54b3584eSGordon Ross struct rpc_err err;
787*54b3584eSGordon Ross
788*54b3584eSGordon Ross CLNT_GETERR((rpcp)->nr_handle, &err);
789*54b3584eSGordon Ross NLM_ERR("NLM: %s callback failed: "
790*54b3584eSGordon Ross "stat %d, err %d\n", "grant", status,
791*54b3584eSGordon Ross err.re_errno);
792*54b3584eSGordon Ross res.stat.stat = nlm4_failed;
793*54b3584eSGordon Ross }
794*54b3584eSGordon Ross if (res.stat.stat != nlm4_granted) {
795*54b3584eSGordon Ross /*
796*54b3584eSGordon Ross * Failed to deliver the granted callback, so
797*54b3584eSGordon Ross * the client doesn't know about this lock.
798*54b3584eSGordon Ross * Unlock the lock. The client will time out.
799*54b3584eSGordon Ross */
800*54b3584eSGordon Ross (void) nlm_vop_frlock(nvp->nv_vp, F_UNLCK, flp,
801*54b3584eSGordon Ross F_REMOTELOCK | FREAD | FWRITE,
802*54b3584eSGordon Ross (u_offset_t)0, NULL, CRED(), NULL);
803*54b3584eSGordon Ross }
804*54b3584eSGordon Ross xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res);
805bbaa8b60SDan Kruchinin
806*54b3584eSGordon Ross nlm_host_rele_rpc(host, rpcp);
807bbaa8b60SDan Kruchinin }
808bbaa8b60SDan Kruchinin
809bbaa8b60SDan Kruchinin /*
810bbaa8b60SDan Kruchinin * The function that is used as flk callback when NLM server
811bbaa8b60SDan Kruchinin * sets new sleeping lock. The function unregisters NLM
812bbaa8b60SDan Kruchinin * sleeping lock request (nlm_slreq) associated with the
813bbaa8b60SDan Kruchinin * sleeping lock _before_ lock becomes active. It prevents
814bbaa8b60SDan Kruchinin * potential race condition between nlm_block() and
815bbaa8b60SDan Kruchinin * nlm_do_cancel().
816bbaa8b60SDan Kruchinin */
817bbaa8b60SDan Kruchinin static callb_cpr_t *
nlm_block_callback(flk_cb_when_t when,void * data)818bbaa8b60SDan Kruchinin nlm_block_callback(flk_cb_when_t when, void *data)
819bbaa8b60SDan Kruchinin {
820bbaa8b60SDan Kruchinin struct nlm_block_cb_data *cb_data;
821bbaa8b60SDan Kruchinin
822bbaa8b60SDan Kruchinin cb_data = (struct nlm_block_cb_data *)data;
823bbaa8b60SDan Kruchinin if (when == FLK_AFTER_SLEEP) {
824bbaa8b60SDan Kruchinin (void) nlm_slreq_unregister(cb_data->hostp,
825bbaa8b60SDan Kruchinin cb_data->nvp, cb_data->flp);
826*54b3584eSGordon Ross cb_data->registered = FALSE;
827bbaa8b60SDan Kruchinin }
828bbaa8b60SDan Kruchinin
829bbaa8b60SDan Kruchinin return (0);
830bbaa8b60SDan Kruchinin }
831bbaa8b60SDan Kruchinin
832bbaa8b60SDan Kruchinin /*
833bbaa8b60SDan Kruchinin * NLM_CANCEL, NLM_CANCEL_MSG,
834bbaa8b60SDan Kruchinin * NLM4_CANCEL, NLM4_CANCEL_MSG,
835bbaa8b60SDan Kruchinin * Client gives up waiting for a blocking lock.
836bbaa8b60SDan Kruchinin */
837bbaa8b60SDan Kruchinin void
nlm_do_cancel(nlm4_cancargs * argp,nlm4_res * resp,struct svc_req * sr,nlm_res_cb cb)838bbaa8b60SDan Kruchinin nlm_do_cancel(nlm4_cancargs *argp, nlm4_res *resp,
839bbaa8b60SDan Kruchinin struct svc_req *sr, nlm_res_cb cb)
840bbaa8b60SDan Kruchinin {
841bbaa8b60SDan Kruchinin struct nlm_globals *g;
842bbaa8b60SDan Kruchinin struct nlm_host *host;
843bbaa8b60SDan Kruchinin struct netbuf *addr;
844bbaa8b60SDan Kruchinin struct nlm_vhold *nvp = NULL;
845bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp = NULL;
846bbaa8b60SDan Kruchinin char *netid;
847bbaa8b60SDan Kruchinin char *name;
848bbaa8b60SDan Kruchinin int error;
849bbaa8b60SDan Kruchinin struct flock64 fl;
850bbaa8b60SDan Kruchinin
851bbaa8b60SDan Kruchinin nlm_copy_netobj(&resp->cookie, &argp->cookie);
852bbaa8b60SDan Kruchinin netid = svc_getnetid(sr->rq_xprt);
853bbaa8b60SDan Kruchinin addr = svc_getrpccaller(sr->rq_xprt);
854bbaa8b60SDan Kruchinin name = argp->alock.caller_name;
855bbaa8b60SDan Kruchinin
856bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone);
857bbaa8b60SDan Kruchinin host = nlm_host_findcreate(g, name, netid, addr);
858bbaa8b60SDan Kruchinin if (host == NULL) {
859bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied_nolocks;
860bbaa8b60SDan Kruchinin return;
861bbaa8b60SDan Kruchinin }
862bbaa8b60SDan Kruchinin if (cb != NULL) {
863bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
864bbaa8b60SDan Kruchinin if (error != 0) {
865bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied_nolocks;
866745caa42SMarcel Telka goto out;
867bbaa8b60SDan Kruchinin }
868bbaa8b60SDan Kruchinin }
869bbaa8b60SDan Kruchinin
870bbaa8b60SDan Kruchinin DTRACE_PROBE3(start, struct nlm_globals *, g,
871bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_cancargs *, argp);
872bbaa8b60SDan Kruchinin
873bbaa8b60SDan Kruchinin if (NLM_IN_GRACE(g)) {
874bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied_grace_period;
875bbaa8b60SDan Kruchinin goto out;
876bbaa8b60SDan Kruchinin }
877bbaa8b60SDan Kruchinin
878bbaa8b60SDan Kruchinin nvp = nlm_fh_to_vhold(host, &argp->alock.fh);
879bbaa8b60SDan Kruchinin if (nvp == NULL) {
880bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_stale_fh;
881bbaa8b60SDan Kruchinin goto out;
882bbaa8b60SDan Kruchinin }
883bbaa8b60SDan Kruchinin
884bbaa8b60SDan Kruchinin /* Convert to local form. */
885bbaa8b60SDan Kruchinin error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers,
886bbaa8b60SDan Kruchinin (argp->exclusive) ? F_WRLCK : F_RDLCK);
887bbaa8b60SDan Kruchinin if (error) {
888bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_failed;
889bbaa8b60SDan Kruchinin goto out;
890bbaa8b60SDan Kruchinin }
891bbaa8b60SDan Kruchinin
892bbaa8b60SDan Kruchinin error = nlm_slreq_unregister(host, nvp, &fl);
893bbaa8b60SDan Kruchinin if (error != 0) {
894bbaa8b60SDan Kruchinin /*
895bbaa8b60SDan Kruchinin * There's no sleeping lock request corresponding
896bbaa8b60SDan Kruchinin * to the lock. Then requested sleeping lock
897bbaa8b60SDan Kruchinin * doesn't exist.
898bbaa8b60SDan Kruchinin */
899bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied;
900bbaa8b60SDan Kruchinin goto out;
901bbaa8b60SDan Kruchinin }
902bbaa8b60SDan Kruchinin
903bbaa8b60SDan Kruchinin fl.l_type = F_UNLCK;
904bbaa8b60SDan Kruchinin error = nlm_vop_frlock(nvp->nv_vp, F_SETLK, &fl,
905bbaa8b60SDan Kruchinin F_REMOTELOCK | FREAD | FWRITE,
906bbaa8b60SDan Kruchinin (u_offset_t)0, NULL, CRED(), NULL);
907bbaa8b60SDan Kruchinin
908bbaa8b60SDan Kruchinin resp->stat.stat = (error == 0) ?
909bbaa8b60SDan Kruchinin nlm4_granted : nlm4_denied;
910bbaa8b60SDan Kruchinin
911bbaa8b60SDan Kruchinin out:
912bbaa8b60SDan Kruchinin /*
91395fa5714SMarcel Telka * If we have a callback function, use that to
914bbaa8b60SDan Kruchinin * deliver the response via another RPC call.
915bbaa8b60SDan Kruchinin */
916bbaa8b60SDan Kruchinin if (cb != NULL && rpcp != NULL)
917bbaa8b60SDan Kruchinin NLM_INVOKE_CALLBACK("cancel", rpcp, resp, cb);
918bbaa8b60SDan Kruchinin
919bbaa8b60SDan Kruchinin DTRACE_PROBE3(cancel__end, struct nlm_globals *, g,
920bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_res *, resp);
921bbaa8b60SDan Kruchinin
922bbaa8b60SDan Kruchinin if (rpcp != NULL)
923bbaa8b60SDan Kruchinin nlm_host_rele_rpc(host, rpcp);
924bbaa8b60SDan Kruchinin
925bbaa8b60SDan Kruchinin nlm_vhold_release(host, nvp);
926bbaa8b60SDan Kruchinin nlm_host_release(g, host);
927bbaa8b60SDan Kruchinin }
928bbaa8b60SDan Kruchinin
929bbaa8b60SDan Kruchinin /*
930bbaa8b60SDan Kruchinin * NLM_UNLOCK, NLM_UNLOCK_MSG,
931bbaa8b60SDan Kruchinin * NLM4_UNLOCK, NLM4_UNLOCK_MSG,
932bbaa8b60SDan Kruchinin * Client removes one of their locks.
933bbaa8b60SDan Kruchinin */
934bbaa8b60SDan Kruchinin void
nlm_do_unlock(nlm4_unlockargs * argp,nlm4_res * resp,struct svc_req * sr,nlm_res_cb cb)935bbaa8b60SDan Kruchinin nlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *resp,
936bbaa8b60SDan Kruchinin struct svc_req *sr, nlm_res_cb cb)
937bbaa8b60SDan Kruchinin {
938bbaa8b60SDan Kruchinin struct nlm_globals *g;
939bbaa8b60SDan Kruchinin struct nlm_host *host;
940bbaa8b60SDan Kruchinin struct netbuf *addr;
941bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp = NULL;
942bbaa8b60SDan Kruchinin vnode_t *vp = NULL;
943bbaa8b60SDan Kruchinin char *netid;
944bbaa8b60SDan Kruchinin char *name;
945bbaa8b60SDan Kruchinin int error;
946bbaa8b60SDan Kruchinin struct flock64 fl;
947bbaa8b60SDan Kruchinin
948bbaa8b60SDan Kruchinin nlm_copy_netobj(&resp->cookie, &argp->cookie);
949bbaa8b60SDan Kruchinin
950bbaa8b60SDan Kruchinin netid = svc_getnetid(sr->rq_xprt);
951bbaa8b60SDan Kruchinin addr = svc_getrpccaller(sr->rq_xprt);
952bbaa8b60SDan Kruchinin name = argp->alock.caller_name;
953bbaa8b60SDan Kruchinin
954bbaa8b60SDan Kruchinin /*
955bbaa8b60SDan Kruchinin * NLM_UNLOCK operation doesn't have an error code
956bbaa8b60SDan Kruchinin * denoting that operation failed, so we always
957bbaa8b60SDan Kruchinin * return nlm4_granted except when the server is
958bbaa8b60SDan Kruchinin * in a grace period.
959bbaa8b60SDan Kruchinin */
960bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_granted;
961bbaa8b60SDan Kruchinin
962bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone);
963bbaa8b60SDan Kruchinin host = nlm_host_findcreate(g, name, netid, addr);
964bbaa8b60SDan Kruchinin if (host == NULL)
965bbaa8b60SDan Kruchinin return;
966bbaa8b60SDan Kruchinin
967bbaa8b60SDan Kruchinin if (cb != NULL) {
968bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
969bbaa8b60SDan Kruchinin if (error != 0)
970bbaa8b60SDan Kruchinin goto out;
971bbaa8b60SDan Kruchinin }
972bbaa8b60SDan Kruchinin
973bbaa8b60SDan Kruchinin DTRACE_PROBE3(start, struct nlm_globals *, g,
974bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_unlockargs *, argp);
975bbaa8b60SDan Kruchinin
976bbaa8b60SDan Kruchinin if (NLM_IN_GRACE(g)) {
977bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied_grace_period;
978bbaa8b60SDan Kruchinin goto out;
979bbaa8b60SDan Kruchinin }
980bbaa8b60SDan Kruchinin
981bbaa8b60SDan Kruchinin vp = nlm_fh_to_vp(&argp->alock.fh);
982bbaa8b60SDan Kruchinin if (vp == NULL)
983bbaa8b60SDan Kruchinin goto out;
984bbaa8b60SDan Kruchinin
985bbaa8b60SDan Kruchinin /* Convert to local form. */
986bbaa8b60SDan Kruchinin error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers, F_UNLCK);
987bbaa8b60SDan Kruchinin if (error)
988bbaa8b60SDan Kruchinin goto out;
989bbaa8b60SDan Kruchinin
990bbaa8b60SDan Kruchinin /* BSD: VOP_ADVLOCK(nv->nv_vp, NULL, F_UNLCK, &fl, F_REMOTE); */
991bbaa8b60SDan Kruchinin error = nlm_vop_frlock(vp, F_SETLK, &fl,
992bbaa8b60SDan Kruchinin F_REMOTELOCK | FREAD | FWRITE,
993bbaa8b60SDan Kruchinin (u_offset_t)0, NULL, CRED(), NULL);
994bbaa8b60SDan Kruchinin
995bbaa8b60SDan Kruchinin DTRACE_PROBE1(unlock__res, int, error);
996bbaa8b60SDan Kruchinin out:
997bbaa8b60SDan Kruchinin /*
99895fa5714SMarcel Telka * If we have a callback function, use that to
999bbaa8b60SDan Kruchinin * deliver the response via another RPC call.
1000bbaa8b60SDan Kruchinin */
1001bbaa8b60SDan Kruchinin if (cb != NULL && rpcp != NULL)
1002bbaa8b60SDan Kruchinin NLM_INVOKE_CALLBACK("unlock", rpcp, resp, cb);
1003bbaa8b60SDan Kruchinin
1004bbaa8b60SDan Kruchinin DTRACE_PROBE3(unlock__end, struct nlm_globals *, g,
1005bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_res *, resp);
1006bbaa8b60SDan Kruchinin
1007bbaa8b60SDan Kruchinin if (vp != NULL)
1008bbaa8b60SDan Kruchinin VN_RELE(vp);
1009bbaa8b60SDan Kruchinin if (rpcp != NULL)
1010bbaa8b60SDan Kruchinin nlm_host_rele_rpc(host, rpcp);
1011bbaa8b60SDan Kruchinin
1012bbaa8b60SDan Kruchinin nlm_host_release(g, host);
1013bbaa8b60SDan Kruchinin }
1014bbaa8b60SDan Kruchinin
1015bbaa8b60SDan Kruchinin /*
1016bbaa8b60SDan Kruchinin * NLM_GRANTED, NLM_GRANTED_MSG,
1017bbaa8b60SDan Kruchinin * NLM4_GRANTED, NLM4_GRANTED_MSG,
1018bbaa8b60SDan Kruchinin *
1019bbaa8b60SDan Kruchinin * This service routine is special. It's the only one that's
1020bbaa8b60SDan Kruchinin * really part of our NLM _client_ support, used by _servers_
1021bbaa8b60SDan Kruchinin * to "call back" when a blocking lock from this NLM client
1022bbaa8b60SDan Kruchinin * is granted by the server. In this case, we _know_ there is
1023bbaa8b60SDan Kruchinin * already an nlm_host allocated and held by the client code.
1024bbaa8b60SDan Kruchinin * We want to find that nlm_host here.
1025bbaa8b60SDan Kruchinin *
1026bbaa8b60SDan Kruchinin * Over in nlm_call_lock(), the client encoded the sysid for this
1027bbaa8b60SDan Kruchinin * server in the "owner handle" netbuf sent with our lock request.
1028bbaa8b60SDan Kruchinin * We can now use that to find the nlm_host object we used there.
1029bbaa8b60SDan Kruchinin * (NB: The owner handle is opaque to the server.)
1030bbaa8b60SDan Kruchinin */
1031bbaa8b60SDan Kruchinin void
nlm_do_granted(nlm4_testargs * argp,nlm4_res * resp,struct svc_req * sr,nlm_res_cb cb)1032bbaa8b60SDan Kruchinin nlm_do_granted(nlm4_testargs *argp, nlm4_res *resp,
1033bbaa8b60SDan Kruchinin struct svc_req *sr, nlm_res_cb cb)
1034bbaa8b60SDan Kruchinin {
1035bbaa8b60SDan Kruchinin struct nlm_globals *g;
1036bbaa8b60SDan Kruchinin struct nlm_owner_handle *oh;
1037bbaa8b60SDan Kruchinin struct nlm_host *host;
1038bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp = NULL;
1039bbaa8b60SDan Kruchinin int error;
1040bbaa8b60SDan Kruchinin
1041bbaa8b60SDan Kruchinin nlm_copy_netobj(&resp->cookie, &argp->cookie);
1042bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied;
1043bbaa8b60SDan Kruchinin
1044bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone);
1045bbaa8b60SDan Kruchinin oh = (void *) argp->alock.oh.n_bytes;
1046bbaa8b60SDan Kruchinin if (oh == NULL)
1047bbaa8b60SDan Kruchinin return;
1048bbaa8b60SDan Kruchinin
1049bbaa8b60SDan Kruchinin host = nlm_host_find_by_sysid(g, oh->oh_sysid);
1050bbaa8b60SDan Kruchinin if (host == NULL)
1051bbaa8b60SDan Kruchinin return;
1052bbaa8b60SDan Kruchinin
1053bbaa8b60SDan Kruchinin if (cb != NULL) {
1054bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
1055bbaa8b60SDan Kruchinin if (error != 0)
1056bbaa8b60SDan Kruchinin goto out;
1057bbaa8b60SDan Kruchinin }
1058bbaa8b60SDan Kruchinin
1059bbaa8b60SDan Kruchinin if (NLM_IN_GRACE(g)) {
1060bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_denied_grace_period;
1061bbaa8b60SDan Kruchinin goto out;
1062bbaa8b60SDan Kruchinin }
1063bbaa8b60SDan Kruchinin
1064bbaa8b60SDan Kruchinin error = nlm_slock_grant(g, host, &argp->alock);
1065bbaa8b60SDan Kruchinin if (error == 0)
1066bbaa8b60SDan Kruchinin resp->stat.stat = nlm4_granted;
1067bbaa8b60SDan Kruchinin
1068bbaa8b60SDan Kruchinin out:
1069bbaa8b60SDan Kruchinin /*
107095fa5714SMarcel Telka * If we have a callback function, use that to
1071bbaa8b60SDan Kruchinin * deliver the response via another RPC call.
1072bbaa8b60SDan Kruchinin */
1073bbaa8b60SDan Kruchinin if (cb != NULL && rpcp != NULL)
1074bbaa8b60SDan Kruchinin NLM_INVOKE_CALLBACK("do_granted", rpcp, resp, cb);
1075bbaa8b60SDan Kruchinin
1076bbaa8b60SDan Kruchinin if (rpcp != NULL)
1077bbaa8b60SDan Kruchinin nlm_host_rele_rpc(host, rpcp);
1078bbaa8b60SDan Kruchinin
1079bbaa8b60SDan Kruchinin nlm_host_release(g, host);
1080bbaa8b60SDan Kruchinin }
1081bbaa8b60SDan Kruchinin
1082bbaa8b60SDan Kruchinin /*
1083bbaa8b60SDan Kruchinin * NLM_FREE_ALL, NLM4_FREE_ALL
1084bbaa8b60SDan Kruchinin *
1085bbaa8b60SDan Kruchinin * Destroy all lock state for the calling client.
1086bbaa8b60SDan Kruchinin */
1087bbaa8b60SDan Kruchinin void
nlm_do_free_all(nlm4_notify * argp,void * res,struct svc_req * sr)1088bbaa8b60SDan Kruchinin nlm_do_free_all(nlm4_notify *argp, void *res, struct svc_req *sr)
1089bbaa8b60SDan Kruchinin {
1090bbaa8b60SDan Kruchinin struct nlm_globals *g;
1091bbaa8b60SDan Kruchinin struct nlm_host_list host_list;
1092bbaa8b60SDan Kruchinin struct nlm_host *hostp;
1093bbaa8b60SDan Kruchinin
1094bbaa8b60SDan Kruchinin TAILQ_INIT(&host_list);
1095bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone);
1096bbaa8b60SDan Kruchinin
1097bbaa8b60SDan Kruchinin /* Serialize calls to clean locks. */
1098bbaa8b60SDan Kruchinin mutex_enter(&g->clean_lock);
1099bbaa8b60SDan Kruchinin
1100bbaa8b60SDan Kruchinin /*
1101bbaa8b60SDan Kruchinin * Find all hosts that have the given node name and put them on a
1102bbaa8b60SDan Kruchinin * local list.
1103bbaa8b60SDan Kruchinin */
1104bbaa8b60SDan Kruchinin mutex_enter(&g->lock);
1105bbaa8b60SDan Kruchinin for (hostp = avl_first(&g->nlm_hosts_tree); hostp != NULL;
1106bbaa8b60SDan Kruchinin hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp)) {
1107bbaa8b60SDan Kruchinin if (strcasecmp(hostp->nh_name, argp->name) == 0) {
1108bbaa8b60SDan Kruchinin /*
1109bbaa8b60SDan Kruchinin * If needed take the host out of the idle list since
1110bbaa8b60SDan Kruchinin * we are taking a reference.
1111bbaa8b60SDan Kruchinin */
1112bbaa8b60SDan Kruchinin if (hostp->nh_flags & NLM_NH_INIDLE) {
1113bbaa8b60SDan Kruchinin TAILQ_REMOVE(&g->nlm_idle_hosts, hostp,
1114bbaa8b60SDan Kruchinin nh_link);
1115bbaa8b60SDan Kruchinin hostp->nh_flags &= ~NLM_NH_INIDLE;
1116bbaa8b60SDan Kruchinin }
1117bbaa8b60SDan Kruchinin hostp->nh_refs++;
1118bbaa8b60SDan Kruchinin
1119bbaa8b60SDan Kruchinin TAILQ_INSERT_TAIL(&host_list, hostp, nh_link);
1120bbaa8b60SDan Kruchinin }
1121bbaa8b60SDan Kruchinin }
1122bbaa8b60SDan Kruchinin mutex_exit(&g->lock);
1123bbaa8b60SDan Kruchinin
1124bbaa8b60SDan Kruchinin /* Free locks for all hosts on the local list. */
1125bbaa8b60SDan Kruchinin while (!TAILQ_EMPTY(&host_list)) {
1126bbaa8b60SDan Kruchinin hostp = TAILQ_FIRST(&host_list);
1127bbaa8b60SDan Kruchinin TAILQ_REMOVE(&host_list, hostp, nh_link);
1128bbaa8b60SDan Kruchinin
1129bbaa8b60SDan Kruchinin /*
1130bbaa8b60SDan Kruchinin * Note that this does not do client-side cleanup.
1131bbaa8b60SDan Kruchinin * We want to do that ONLY if statd tells us the
1132bbaa8b60SDan Kruchinin * server has restarted.
1133bbaa8b60SDan Kruchinin */
1134bbaa8b60SDan Kruchinin nlm_host_notify_server(hostp, argp->state);
1135bbaa8b60SDan Kruchinin nlm_host_release(g, hostp);
1136bbaa8b60SDan Kruchinin }
1137bbaa8b60SDan Kruchinin
1138bbaa8b60SDan Kruchinin mutex_exit(&g->clean_lock);
1139bbaa8b60SDan Kruchinin
1140bbaa8b60SDan Kruchinin (void) res;
1141bbaa8b60SDan Kruchinin (void) sr;
1142bbaa8b60SDan Kruchinin }
1143bbaa8b60SDan Kruchinin
1144bbaa8b60SDan Kruchinin static void
nlm_init_shrlock(struct shrlock * shr,nlm4_share * nshare,struct nlm_host * host)1145bbaa8b60SDan Kruchinin nlm_init_shrlock(struct shrlock *shr,
1146bbaa8b60SDan Kruchinin nlm4_share *nshare, struct nlm_host *host)
1147bbaa8b60SDan Kruchinin {
1148bbaa8b60SDan Kruchinin
1149bbaa8b60SDan Kruchinin switch (nshare->access) {
1150bbaa8b60SDan Kruchinin default:
1151bbaa8b60SDan Kruchinin case fsa_NONE:
1152bbaa8b60SDan Kruchinin shr->s_access = 0;
1153bbaa8b60SDan Kruchinin break;
1154bbaa8b60SDan Kruchinin case fsa_R:
1155bbaa8b60SDan Kruchinin shr->s_access = F_RDACC;
1156bbaa8b60SDan Kruchinin break;
1157bbaa8b60SDan Kruchinin case fsa_W:
1158bbaa8b60SDan Kruchinin shr->s_access = F_WRACC;
1159bbaa8b60SDan Kruchinin break;
1160bbaa8b60SDan Kruchinin case fsa_RW:
1161bbaa8b60SDan Kruchinin shr->s_access = F_RWACC;
1162bbaa8b60SDan Kruchinin break;
1163bbaa8b60SDan Kruchinin }
1164bbaa8b60SDan Kruchinin
1165bbaa8b60SDan Kruchinin switch (nshare->mode) {
1166bbaa8b60SDan Kruchinin default:
1167bbaa8b60SDan Kruchinin case fsm_DN:
1168bbaa8b60SDan Kruchinin shr->s_deny = F_NODNY;
1169bbaa8b60SDan Kruchinin break;
1170bbaa8b60SDan Kruchinin case fsm_DR:
1171bbaa8b60SDan Kruchinin shr->s_deny = F_RDDNY;
1172bbaa8b60SDan Kruchinin break;
1173bbaa8b60SDan Kruchinin case fsm_DW:
1174bbaa8b60SDan Kruchinin shr->s_deny = F_WRDNY;
1175bbaa8b60SDan Kruchinin break;
1176bbaa8b60SDan Kruchinin case fsm_DRW:
1177bbaa8b60SDan Kruchinin shr->s_deny = F_RWDNY;
1178bbaa8b60SDan Kruchinin break;
1179bbaa8b60SDan Kruchinin }
1180bbaa8b60SDan Kruchinin
1181bbaa8b60SDan Kruchinin shr->s_sysid = host->nh_sysid;
1182bbaa8b60SDan Kruchinin shr->s_pid = 0;
1183bbaa8b60SDan Kruchinin shr->s_own_len = nshare->oh.n_len;
1184bbaa8b60SDan Kruchinin shr->s_owner = nshare->oh.n_bytes;
1185bbaa8b60SDan Kruchinin }
1186bbaa8b60SDan Kruchinin
1187bbaa8b60SDan Kruchinin /*
1188bbaa8b60SDan Kruchinin * NLM_SHARE, NLM4_SHARE
1189bbaa8b60SDan Kruchinin *
1190bbaa8b60SDan Kruchinin * Request a DOS-style share reservation
1191bbaa8b60SDan Kruchinin */
1192bbaa8b60SDan Kruchinin void
nlm_do_share(nlm4_shareargs * argp,nlm4_shareres * resp,struct svc_req * sr)1193bbaa8b60SDan Kruchinin nlm_do_share(nlm4_shareargs *argp, nlm4_shareres *resp, struct svc_req *sr)
1194bbaa8b60SDan Kruchinin {
1195bbaa8b60SDan Kruchinin struct nlm_globals *g;
1196bbaa8b60SDan Kruchinin struct nlm_host *host;
1197bbaa8b60SDan Kruchinin struct netbuf *addr;
1198bbaa8b60SDan Kruchinin struct nlm_vhold *nvp = NULL;
1199bbaa8b60SDan Kruchinin char *netid;
1200bbaa8b60SDan Kruchinin char *name;
1201bbaa8b60SDan Kruchinin int error;
1202bbaa8b60SDan Kruchinin struct shrlock shr;
1203bbaa8b60SDan Kruchinin
1204bbaa8b60SDan Kruchinin nlm_copy_netobj(&resp->cookie, &argp->cookie);
1205bbaa8b60SDan Kruchinin
1206bbaa8b60SDan Kruchinin name = argp->share.caller_name;
1207bbaa8b60SDan Kruchinin netid = svc_getnetid(sr->rq_xprt);
1208bbaa8b60SDan Kruchinin addr = svc_getrpccaller(sr->rq_xprt);
1209bbaa8b60SDan Kruchinin
1210bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone);
1211bbaa8b60SDan Kruchinin host = nlm_host_findcreate(g, name, netid, addr);
1212bbaa8b60SDan Kruchinin if (host == NULL) {
1213bbaa8b60SDan Kruchinin resp->stat = nlm4_denied_nolocks;
1214bbaa8b60SDan Kruchinin return;
1215bbaa8b60SDan Kruchinin }
1216bbaa8b60SDan Kruchinin
1217bbaa8b60SDan Kruchinin DTRACE_PROBE3(share__start, struct nlm_globals *, g,
1218bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_shareargs *, argp);
1219bbaa8b60SDan Kruchinin
1220bbaa8b60SDan Kruchinin if (argp->reclaim == 0 && NLM_IN_GRACE(g)) {
1221bbaa8b60SDan Kruchinin resp->stat = nlm4_denied_grace_period;
1222bbaa8b60SDan Kruchinin goto out;
1223bbaa8b60SDan Kruchinin }
1224bbaa8b60SDan Kruchinin
1225bbaa8b60SDan Kruchinin /*
1226bbaa8b60SDan Kruchinin * Get holded vnode when on lock operation.
1227bbaa8b60SDan Kruchinin * Only lock() and share() need vhold objects.
1228bbaa8b60SDan Kruchinin */
1229bbaa8b60SDan Kruchinin nvp = nlm_fh_to_vhold(host, &argp->share.fh);
1230bbaa8b60SDan Kruchinin if (nvp == NULL) {
1231bbaa8b60SDan Kruchinin resp->stat = nlm4_stale_fh;
1232bbaa8b60SDan Kruchinin goto out;
1233bbaa8b60SDan Kruchinin }
1234bbaa8b60SDan Kruchinin
1235bbaa8b60SDan Kruchinin /* Convert to local form. */
1236bbaa8b60SDan Kruchinin nlm_init_shrlock(&shr, &argp->share, host);
1237bbaa8b60SDan Kruchinin error = VOP_SHRLOCK(nvp->nv_vp, F_SHARE, &shr,
1238bbaa8b60SDan Kruchinin FREAD | FWRITE, CRED(), NULL);
1239bbaa8b60SDan Kruchinin
1240bbaa8b60SDan Kruchinin if (error == 0) {
1241bbaa8b60SDan Kruchinin resp->stat = nlm4_granted;
1242bbaa8b60SDan Kruchinin nlm_host_monitor(g, host, 0);
1243bbaa8b60SDan Kruchinin } else {
1244bbaa8b60SDan Kruchinin resp->stat = nlm4_denied;
1245bbaa8b60SDan Kruchinin }
1246bbaa8b60SDan Kruchinin
1247bbaa8b60SDan Kruchinin out:
1248bbaa8b60SDan Kruchinin DTRACE_PROBE3(share__end, struct nlm_globals *, g,
1249bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_shareres *, resp);
1250bbaa8b60SDan Kruchinin
1251bbaa8b60SDan Kruchinin nlm_vhold_release(host, nvp);
1252bbaa8b60SDan Kruchinin nlm_host_release(g, host);
1253bbaa8b60SDan Kruchinin }
1254bbaa8b60SDan Kruchinin
1255bbaa8b60SDan Kruchinin /*
1256bbaa8b60SDan Kruchinin * NLM_UNSHARE, NLM4_UNSHARE
1257bbaa8b60SDan Kruchinin *
1258bbaa8b60SDan Kruchinin * Release a DOS-style share reservation
1259bbaa8b60SDan Kruchinin */
1260bbaa8b60SDan Kruchinin void
nlm_do_unshare(nlm4_shareargs * argp,nlm4_shareres * resp,struct svc_req * sr)1261bbaa8b60SDan Kruchinin nlm_do_unshare(nlm4_shareargs *argp, nlm4_shareres *resp, struct svc_req *sr)
1262bbaa8b60SDan Kruchinin {
1263bbaa8b60SDan Kruchinin struct nlm_globals *g;
1264bbaa8b60SDan Kruchinin struct nlm_host *host;
1265bbaa8b60SDan Kruchinin struct netbuf *addr;
1266bbaa8b60SDan Kruchinin vnode_t *vp = NULL;
1267bbaa8b60SDan Kruchinin char *netid;
1268bbaa8b60SDan Kruchinin int error;
1269bbaa8b60SDan Kruchinin struct shrlock shr;
1270bbaa8b60SDan Kruchinin
1271bbaa8b60SDan Kruchinin nlm_copy_netobj(&resp->cookie, &argp->cookie);
1272bbaa8b60SDan Kruchinin
1273bbaa8b60SDan Kruchinin netid = svc_getnetid(sr->rq_xprt);
1274bbaa8b60SDan Kruchinin addr = svc_getrpccaller(sr->rq_xprt);
1275bbaa8b60SDan Kruchinin
1276bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone);
1277bbaa8b60SDan Kruchinin host = nlm_host_find(g, netid, addr);
1278bbaa8b60SDan Kruchinin if (host == NULL) {
1279bbaa8b60SDan Kruchinin resp->stat = nlm4_denied_nolocks;
1280bbaa8b60SDan Kruchinin return;
1281bbaa8b60SDan Kruchinin }
1282bbaa8b60SDan Kruchinin
1283bbaa8b60SDan Kruchinin DTRACE_PROBE3(unshare__start, struct nlm_globals *, g,
1284bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_shareargs *, argp);
1285bbaa8b60SDan Kruchinin
1286bbaa8b60SDan Kruchinin if (NLM_IN_GRACE(g)) {
1287bbaa8b60SDan Kruchinin resp->stat = nlm4_denied_grace_period;
1288bbaa8b60SDan Kruchinin goto out;
1289bbaa8b60SDan Kruchinin }
1290bbaa8b60SDan Kruchinin
1291bbaa8b60SDan Kruchinin vp = nlm_fh_to_vp(&argp->share.fh);
1292bbaa8b60SDan Kruchinin if (vp == NULL) {
1293bbaa8b60SDan Kruchinin resp->stat = nlm4_stale_fh;
1294bbaa8b60SDan Kruchinin goto out;
1295bbaa8b60SDan Kruchinin }
1296bbaa8b60SDan Kruchinin
1297bbaa8b60SDan Kruchinin /* Convert to local form. */
1298bbaa8b60SDan Kruchinin nlm_init_shrlock(&shr, &argp->share, host);
1299bbaa8b60SDan Kruchinin error = VOP_SHRLOCK(vp, F_UNSHARE, &shr,
1300bbaa8b60SDan Kruchinin FREAD | FWRITE, CRED(), NULL);
1301bbaa8b60SDan Kruchinin
1302bbaa8b60SDan Kruchinin (void) error;
1303bbaa8b60SDan Kruchinin resp->stat = nlm4_granted;
1304bbaa8b60SDan Kruchinin
1305bbaa8b60SDan Kruchinin out:
1306bbaa8b60SDan Kruchinin DTRACE_PROBE3(unshare__end, struct nlm_globals *, g,
1307bbaa8b60SDan Kruchinin struct nlm_host *, host, nlm4_shareres *, resp);
1308bbaa8b60SDan Kruchinin
1309bbaa8b60SDan Kruchinin if (vp != NULL)
1310bbaa8b60SDan Kruchinin VN_RELE(vp);
1311bbaa8b60SDan Kruchinin
1312bbaa8b60SDan Kruchinin nlm_host_release(g, host);
1313bbaa8b60SDan Kruchinin }
1314bbaa8b60SDan Kruchinin
1315bbaa8b60SDan Kruchinin /*
1316bbaa8b60SDan Kruchinin * NLM wrapper to VOP_FRLOCK that checks the validity of the lock before
1317bbaa8b60SDan Kruchinin * invoking the vnode operation.
1318bbaa8b60SDan Kruchinin */
1319bbaa8b60SDan Kruchinin static int
nlm_vop_frlock(vnode_t * vp,int cmd,flock64_t * bfp,int flag,offset_t offset,struct flk_callback * flk_cbp,cred_t * cr,caller_context_t * ct)1320bbaa8b60SDan Kruchinin nlm_vop_frlock(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset,
1321745caa42SMarcel Telka struct flk_callback *flk_cbp, cred_t *cr, caller_context_t *ct)
1322bbaa8b60SDan Kruchinin {
1323bbaa8b60SDan Kruchinin if (bfp->l_len != 0 && bfp->l_start + (bfp->l_len - 1) < bfp->l_start) {
1324bbaa8b60SDan Kruchinin return (EOVERFLOW);
1325bbaa8b60SDan Kruchinin }
1326bbaa8b60SDan Kruchinin
1327bbaa8b60SDan Kruchinin return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
1328bbaa8b60SDan Kruchinin }
1329