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