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 2011 Nexenta Systems, Inc. All rights reserved. 30bbaa8b60SDan Kruchinin * Copyright (c) 2012 by Delphix. All rights reserved. 315cd496e3SBryan Cantrill * Copyright (c) 2014, Joyent, Inc. All rights reserved. 32bbaa8b60SDan Kruchinin */ 33bbaa8b60SDan Kruchinin 34bbaa8b60SDan Kruchinin /* 35bbaa8b60SDan Kruchinin * Client-side support for (NFS) VOP_FRLOCK, VOP_SHRLOCK. 36bbaa8b60SDan Kruchinin * (called via klmops.c: lm_frlock, lm4_frlock) 37bbaa8b60SDan Kruchinin * 38bbaa8b60SDan Kruchinin * Source code derived from FreeBSD nlm_advlock.c 39bbaa8b60SDan Kruchinin */ 40bbaa8b60SDan Kruchinin 41bbaa8b60SDan Kruchinin #include <sys/param.h> 42bbaa8b60SDan Kruchinin #include <sys/fcntl.h> 43bbaa8b60SDan Kruchinin #include <sys/lock.h> 44bbaa8b60SDan Kruchinin #include <sys/flock.h> 45bbaa8b60SDan Kruchinin #include <sys/mount.h> 46bbaa8b60SDan Kruchinin #include <sys/mutex.h> 47bbaa8b60SDan Kruchinin #include <sys/proc.h> 48bbaa8b60SDan Kruchinin #include <sys/share.h> 49bbaa8b60SDan Kruchinin #include <sys/syslog.h> 50bbaa8b60SDan Kruchinin #include <sys/systm.h> 51bbaa8b60SDan Kruchinin #include <sys/unistd.h> 52bbaa8b60SDan Kruchinin #include <sys/vnode.h> 53bbaa8b60SDan Kruchinin #include <sys/queue.h> 54bbaa8b60SDan Kruchinin #include <sys/sdt.h> 55bbaa8b60SDan Kruchinin #include <netinet/in.h> 56bbaa8b60SDan Kruchinin 57bbaa8b60SDan Kruchinin #include <fs/fs_subr.h> 58bbaa8b60SDan Kruchinin #include <rpcsvc/nlm_prot.h> 59bbaa8b60SDan Kruchinin 60bbaa8b60SDan Kruchinin #include <nfs/nfs.h> 61bbaa8b60SDan Kruchinin #include <nfs/nfs_clnt.h> 62bbaa8b60SDan Kruchinin #include <nfs/export.h> 63bbaa8b60SDan Kruchinin #include <nfs/rnode.h> 64bbaa8b60SDan Kruchinin #include <nfs/lm.h> 65bbaa8b60SDan Kruchinin 66bbaa8b60SDan Kruchinin #include "nlm_impl.h" 67bbaa8b60SDan Kruchinin 68bbaa8b60SDan Kruchinin /* Extra flags for nlm_call_lock() - xflags */ 69bbaa8b60SDan Kruchinin #define NLM_X_RECLAIM 1 70bbaa8b60SDan Kruchinin #define NLM_X_BLOCKING 2 71bbaa8b60SDan Kruchinin 72bbaa8b60SDan Kruchinin /* 73bbaa8b60SDan Kruchinin * Max. number of retries nlm_call_cancel() does 74bbaa8b60SDan Kruchinin * when NLM server is in grace period or doesn't 75bbaa8b60SDan Kruchinin * respond correctly. 76bbaa8b60SDan Kruchinin */ 77bbaa8b60SDan Kruchinin #define NLM_CANCEL_NRETRS 5 78bbaa8b60SDan Kruchinin 79bbaa8b60SDan Kruchinin /* 80bbaa8b60SDan Kruchinin * Determines wether given lock "flp" is safe. 81bbaa8b60SDan Kruchinin * The lock is considered to be safe when it 82bbaa8b60SDan Kruchinin * acquires the whole file (i.e. its start 83bbaa8b60SDan Kruchinin * and len are zeroes). 84bbaa8b60SDan Kruchinin */ 85bbaa8b60SDan Kruchinin #define NLM_FLOCK_IS_SAFE(flp) \ 86bbaa8b60SDan Kruchinin ((flp)->l_start == 0 && (flp)->l_len == 0) 87bbaa8b60SDan Kruchinin 88bbaa8b60SDan Kruchinin static volatile uint32_t nlm_xid = 1; 89bbaa8b60SDan Kruchinin 90bbaa8b60SDan Kruchinin static int nlm_init_fh_by_vp(vnode_t *, struct netobj *, rpcvers_t *); 91bbaa8b60SDan Kruchinin static int nlm_map_status(nlm4_stats); 92bbaa8b60SDan Kruchinin static int nlm_map_clnt_stat(enum clnt_stat); 93bbaa8b60SDan Kruchinin static void nlm_send_siglost(pid_t); 94bbaa8b60SDan Kruchinin 95bbaa8b60SDan Kruchinin static int nlm_frlock_getlk(struct nlm_host *, vnode_t *, 96bbaa8b60SDan Kruchinin struct flock64 *, int, u_offset_t, struct netobj *, int); 97bbaa8b60SDan Kruchinin 98bbaa8b60SDan Kruchinin static int nlm_frlock_setlk(struct nlm_host *, vnode_t *, 99bbaa8b60SDan Kruchinin struct flock64 *, int, u_offset_t, struct netobj *, 100bbaa8b60SDan Kruchinin struct flk_callback *, int, bool_t); 101bbaa8b60SDan Kruchinin 102bbaa8b60SDan Kruchinin static int nlm_reclaim_lock(struct nlm_host *, vnode_t *, 103bbaa8b60SDan Kruchinin struct flock64 *, int32_t); 104bbaa8b60SDan Kruchinin 105bbaa8b60SDan Kruchinin static void nlm_init_lock(struct nlm4_lock *, 106bbaa8b60SDan Kruchinin const struct flock64 *, struct netobj *, 107bbaa8b60SDan Kruchinin struct nlm_owner_handle *); 108bbaa8b60SDan Kruchinin 109bbaa8b60SDan Kruchinin static int nlm_call_lock(vnode_t *, struct flock64 *, 110bbaa8b60SDan Kruchinin struct nlm_host *, struct netobj *, 111bbaa8b60SDan Kruchinin struct flk_callback *, int, int); 112bbaa8b60SDan Kruchinin static int nlm_call_unlock(struct flock64 *, struct nlm_host *, 113bbaa8b60SDan Kruchinin struct netobj *, int); 114bbaa8b60SDan Kruchinin static int nlm_call_test(struct flock64 *, struct nlm_host *, 115bbaa8b60SDan Kruchinin struct netobj *, int); 116bbaa8b60SDan Kruchinin static int nlm_call_cancel(struct nlm4_lockargs *, 117bbaa8b60SDan Kruchinin struct nlm_host *, int); 118bbaa8b60SDan Kruchinin 119bbaa8b60SDan Kruchinin static int nlm_local_getlk(vnode_t *, struct flock64 *, int); 120bbaa8b60SDan Kruchinin static int nlm_local_setlk(vnode_t *, struct flock64 *, int); 121bbaa8b60SDan Kruchinin static void nlm_local_cancelk(vnode_t *, struct flock64 *); 122bbaa8b60SDan Kruchinin 123bbaa8b60SDan Kruchinin static void nlm_init_share(struct nlm4_share *, 124bbaa8b60SDan Kruchinin const struct shrlock *, struct netobj *); 125bbaa8b60SDan Kruchinin 126bbaa8b60SDan Kruchinin static int nlm_call_share(struct shrlock *, struct nlm_host *, 127bbaa8b60SDan Kruchinin struct netobj *, int, int); 128bbaa8b60SDan Kruchinin static int nlm_call_unshare(struct shrlock *, struct nlm_host *, 129bbaa8b60SDan Kruchinin struct netobj *, int); 130bbaa8b60SDan Kruchinin static int nlm_reclaim_share(struct nlm_host *, vnode_t *, 131bbaa8b60SDan Kruchinin struct shrlock *, uint32_t); 132bbaa8b60SDan Kruchinin static int nlm_local_shrlock(vnode_t *, struct shrlock *, int, int); 133bbaa8b60SDan Kruchinin static void nlm_local_shrcancel(vnode_t *, struct shrlock *); 134bbaa8b60SDan Kruchinin 135bbaa8b60SDan Kruchinin /* 136bbaa8b60SDan Kruchinin * Reclaim locks/shares acquired by the client side 137bbaa8b60SDan Kruchinin * on the given server represented by hostp. 138bbaa8b60SDan Kruchinin * The function is called from a dedicated thread 139bbaa8b60SDan Kruchinin * when server reports us that it's entered grace 140bbaa8b60SDan Kruchinin * period. 141bbaa8b60SDan Kruchinin */ 142bbaa8b60SDan Kruchinin void 143bbaa8b60SDan Kruchinin nlm_reclaim_client(struct nlm_globals *g, struct nlm_host *hostp) 144bbaa8b60SDan Kruchinin { 145bbaa8b60SDan Kruchinin int32_t state; 146bbaa8b60SDan Kruchinin int error, sysid; 147bbaa8b60SDan Kruchinin struct locklist *llp_head, *llp; 148bbaa8b60SDan Kruchinin struct nlm_shres *nsp_head, *nsp; 149bbaa8b60SDan Kruchinin bool_t restart; 150bbaa8b60SDan Kruchinin 151bbaa8b60SDan Kruchinin sysid = hostp->nh_sysid | LM_SYSID_CLIENT; 152bbaa8b60SDan Kruchinin do { 153bbaa8b60SDan Kruchinin error = 0; 154bbaa8b60SDan Kruchinin restart = FALSE; 155bbaa8b60SDan Kruchinin state = nlm_host_get_state(hostp); 156bbaa8b60SDan Kruchinin 157bbaa8b60SDan Kruchinin DTRACE_PROBE3(reclaim__iter, struct nlm_globals *, g, 158bbaa8b60SDan Kruchinin struct nlm_host *, hostp, int, state); 159bbaa8b60SDan Kruchinin 160bbaa8b60SDan Kruchinin /* 161bbaa8b60SDan Kruchinin * We cancel all sleeping locks that were 162bbaa8b60SDan Kruchinin * done by the host, because we don't allow 163bbaa8b60SDan Kruchinin * reclamation of sleeping locks. The reason 164bbaa8b60SDan Kruchinin * we do this is that allowing of sleeping locks 165bbaa8b60SDan Kruchinin * reclamation can potentially break locks recovery 166bbaa8b60SDan Kruchinin * order. 167bbaa8b60SDan Kruchinin * 168bbaa8b60SDan Kruchinin * Imagine that we have two client machines A and B 169bbaa8b60SDan Kruchinin * and an NLM server machine. A adds a non sleeping 170bbaa8b60SDan Kruchinin * lock to the file F and aquires this file. Machine 171bbaa8b60SDan Kruchinin * B in its turn adds sleeping lock to the file 172bbaa8b60SDan Kruchinin * F and blocks because F is already aquired by 173bbaa8b60SDan Kruchinin * the machine A. Then server crashes and after the 174bbaa8b60SDan Kruchinin * reboot it notifies its clients about the crash. 175bbaa8b60SDan Kruchinin * If we would allow sleeping locks reclamation, 176bbaa8b60SDan Kruchinin * there would be possible that machine B recovers 177bbaa8b60SDan Kruchinin * its lock faster than machine A (by some reason). 178bbaa8b60SDan Kruchinin * So that B aquires the file F after server crash and 179bbaa8b60SDan Kruchinin * machine A (that by some reason recovers slower) fails 180bbaa8b60SDan Kruchinin * to recover its non sleeping lock. Thus the original 181bbaa8b60SDan Kruchinin * locks order becames broken. 182bbaa8b60SDan Kruchinin */ 183bbaa8b60SDan Kruchinin nlm_host_cancel_slocks(g, hostp); 184bbaa8b60SDan Kruchinin 185bbaa8b60SDan Kruchinin /* 186bbaa8b60SDan Kruchinin * Try to reclaim all active locks we have 187bbaa8b60SDan Kruchinin */ 188bbaa8b60SDan Kruchinin llp_head = llp = flk_get_active_locks(sysid, NOPID); 189bbaa8b60SDan Kruchinin while (llp != NULL) { 190bbaa8b60SDan Kruchinin error = nlm_reclaim_lock(hostp, llp->ll_vp, 191bbaa8b60SDan Kruchinin &llp->ll_flock, state); 192bbaa8b60SDan Kruchinin 193bbaa8b60SDan Kruchinin if (error == 0) { 194bbaa8b60SDan Kruchinin llp = llp->ll_next; 195bbaa8b60SDan Kruchinin continue; 196bbaa8b60SDan Kruchinin } else if (error == ERESTART) { 197bbaa8b60SDan Kruchinin restart = TRUE; 198bbaa8b60SDan Kruchinin break; 199bbaa8b60SDan Kruchinin } else { 200bbaa8b60SDan Kruchinin /* 201bbaa8b60SDan Kruchinin * Critical error occurred, the lock 202bbaa8b60SDan Kruchinin * can not be recovered, just take it away. 203bbaa8b60SDan Kruchinin */ 204bbaa8b60SDan Kruchinin nlm_local_cancelk(llp->ll_vp, &llp->ll_flock); 205bbaa8b60SDan Kruchinin } 206bbaa8b60SDan Kruchinin 207bbaa8b60SDan Kruchinin llp = llp->ll_next; 208bbaa8b60SDan Kruchinin } 209bbaa8b60SDan Kruchinin 210bbaa8b60SDan Kruchinin flk_free_locklist(llp_head); 211bbaa8b60SDan Kruchinin if (restart) { 212bbaa8b60SDan Kruchinin /* 213bbaa8b60SDan Kruchinin * Lock reclamation fucntion reported us that 214bbaa8b60SDan Kruchinin * the server state was changed (again), so 215bbaa8b60SDan Kruchinin * try to repeat the whole reclamation process. 216bbaa8b60SDan Kruchinin */ 217bbaa8b60SDan Kruchinin continue; 218bbaa8b60SDan Kruchinin } 219bbaa8b60SDan Kruchinin 220bbaa8b60SDan Kruchinin nsp_head = nsp = nlm_get_active_shres(hostp); 221bbaa8b60SDan Kruchinin while (nsp != NULL) { 222bbaa8b60SDan Kruchinin error = nlm_reclaim_share(hostp, nsp->ns_vp, 223bbaa8b60SDan Kruchinin nsp->ns_shr, state); 224bbaa8b60SDan Kruchinin 225bbaa8b60SDan Kruchinin if (error == 0) { 226bbaa8b60SDan Kruchinin nsp = nsp->ns_next; 227bbaa8b60SDan Kruchinin continue; 228bbaa8b60SDan Kruchinin } else if (error == ERESTART) { 229bbaa8b60SDan Kruchinin break; 230bbaa8b60SDan Kruchinin } else { 231bbaa8b60SDan Kruchinin /* Failed to reclaim share */ 232bbaa8b60SDan Kruchinin nlm_shres_untrack(hostp, nsp->ns_vp, 233bbaa8b60SDan Kruchinin nsp->ns_shr); 234bbaa8b60SDan Kruchinin nlm_local_shrcancel(nsp->ns_vp, 235bbaa8b60SDan Kruchinin nsp->ns_shr); 236bbaa8b60SDan Kruchinin } 237bbaa8b60SDan Kruchinin 238bbaa8b60SDan Kruchinin nsp = nsp->ns_next; 239bbaa8b60SDan Kruchinin } 240bbaa8b60SDan Kruchinin 241bbaa8b60SDan Kruchinin nlm_free_shrlist(nsp_head); 242bbaa8b60SDan Kruchinin } while (state != nlm_host_get_state(hostp)); 243bbaa8b60SDan Kruchinin } 244bbaa8b60SDan Kruchinin 245bbaa8b60SDan Kruchinin /* 246bbaa8b60SDan Kruchinin * nlm_frlock -- 247bbaa8b60SDan Kruchinin * NFS advisory byte-range locks. 248bbaa8b60SDan Kruchinin * Called in klmops.c 249bbaa8b60SDan Kruchinin * 250bbaa8b60SDan Kruchinin * Note that the local locking code (os/flock.c) is used to 251bbaa8b60SDan Kruchinin * keep track of remote locks granted by some server, so we 252bbaa8b60SDan Kruchinin * can reclaim those locks after a server restarts. We can 253bbaa8b60SDan Kruchinin * also sometimes use this as a cache of lock information. 254bbaa8b60SDan Kruchinin * 255bbaa8b60SDan Kruchinin * Was: nlm_advlock() 256bbaa8b60SDan Kruchinin */ 257bbaa8b60SDan Kruchinin /* ARGSUSED */ 258bbaa8b60SDan Kruchinin int 259bbaa8b60SDan Kruchinin nlm_frlock(struct vnode *vp, int cmd, struct flock64 *flkp, 260bbaa8b60SDan Kruchinin int flags, u_offset_t offset, struct cred *crp, 261bbaa8b60SDan Kruchinin struct netobj *fhp, struct flk_callback *flcb, int vers) 262bbaa8b60SDan Kruchinin { 263bbaa8b60SDan Kruchinin mntinfo_t *mi; 264bbaa8b60SDan Kruchinin servinfo_t *sv; 265bbaa8b60SDan Kruchinin const char *netid; 266bbaa8b60SDan Kruchinin struct nlm_host *hostp; 267bbaa8b60SDan Kruchinin int error; 268bbaa8b60SDan Kruchinin struct nlm_globals *g; 269bbaa8b60SDan Kruchinin 270bbaa8b60SDan Kruchinin mi = VTOMI(vp); 271bbaa8b60SDan Kruchinin sv = mi->mi_curr_serv; 272bbaa8b60SDan Kruchinin 273bbaa8b60SDan Kruchinin netid = nlm_knc_to_netid(sv->sv_knconf); 274bbaa8b60SDan Kruchinin if (netid == NULL) { 275bbaa8b60SDan Kruchinin NLM_ERR("nlm_frlock: unknown NFS netid"); 276bbaa8b60SDan Kruchinin return (ENOSYS); 277bbaa8b60SDan Kruchinin } 278bbaa8b60SDan Kruchinin 279bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone); 280bbaa8b60SDan Kruchinin hostp = nlm_host_findcreate(g, sv->sv_hostname, netid, &sv->sv_addr); 281bbaa8b60SDan Kruchinin if (hostp == NULL) 282bbaa8b60SDan Kruchinin return (ENOSYS); 283bbaa8b60SDan Kruchinin 284bbaa8b60SDan Kruchinin /* 285bbaa8b60SDan Kruchinin * Purge cached attributes in order to make sure that 286bbaa8b60SDan Kruchinin * future calls of convoff()/VOP_GETATTR() will get the 287bbaa8b60SDan Kruchinin * latest data. 288bbaa8b60SDan Kruchinin */ 289bbaa8b60SDan Kruchinin if (flkp->l_whence == SEEK_END) 290bbaa8b60SDan Kruchinin PURGE_ATTRCACHE(vp); 291bbaa8b60SDan Kruchinin 292bbaa8b60SDan Kruchinin /* Now flk0 is the zero-based lock request. */ 293bbaa8b60SDan Kruchinin switch (cmd) { 294bbaa8b60SDan Kruchinin case F_GETLK: 295bbaa8b60SDan Kruchinin error = nlm_frlock_getlk(hostp, vp, flkp, flags, 296bbaa8b60SDan Kruchinin offset, fhp, vers); 297bbaa8b60SDan Kruchinin break; 298bbaa8b60SDan Kruchinin 299bbaa8b60SDan Kruchinin case F_SETLK: 300bbaa8b60SDan Kruchinin case F_SETLKW: 301bbaa8b60SDan Kruchinin error = nlm_frlock_setlk(hostp, vp, flkp, flags, 302bbaa8b60SDan Kruchinin offset, fhp, flcb, vers, (cmd == F_SETLKW)); 303bbaa8b60SDan Kruchinin if (error == 0) 304bbaa8b60SDan Kruchinin nlm_host_monitor(g, hostp, 0); 305bbaa8b60SDan Kruchinin break; 306bbaa8b60SDan Kruchinin 307bbaa8b60SDan Kruchinin default: 308bbaa8b60SDan Kruchinin error = EINVAL; 309bbaa8b60SDan Kruchinin break; 310bbaa8b60SDan Kruchinin } 311bbaa8b60SDan Kruchinin 312bbaa8b60SDan Kruchinin nlm_host_release(g, hostp); 313bbaa8b60SDan Kruchinin return (error); 314bbaa8b60SDan Kruchinin } 315bbaa8b60SDan Kruchinin 316bbaa8b60SDan Kruchinin static int 317bbaa8b60SDan Kruchinin nlm_frlock_getlk(struct nlm_host *hostp, vnode_t *vp, 318bbaa8b60SDan Kruchinin struct flock64 *flkp, int flags, u_offset_t offset, 319bbaa8b60SDan Kruchinin struct netobj *fhp, int vers) 320bbaa8b60SDan Kruchinin { 321bbaa8b60SDan Kruchinin struct flock64 flk0; 322bbaa8b60SDan Kruchinin int error; 323bbaa8b60SDan Kruchinin 324bbaa8b60SDan Kruchinin /* 325bbaa8b60SDan Kruchinin * Check local (cached) locks first. 326bbaa8b60SDan Kruchinin * If we find one, no need for RPC. 327bbaa8b60SDan Kruchinin */ 328bbaa8b60SDan Kruchinin flk0 = *flkp; 329bbaa8b60SDan Kruchinin flk0.l_pid = curproc->p_pid; 330bbaa8b60SDan Kruchinin error = nlm_local_getlk(vp, &flk0, flags); 331bbaa8b60SDan Kruchinin if (error != 0) 332bbaa8b60SDan Kruchinin return (error); 333bbaa8b60SDan Kruchinin if (flk0.l_type != F_UNLCK) { 334bbaa8b60SDan Kruchinin *flkp = flk0; 335bbaa8b60SDan Kruchinin return (0); 336bbaa8b60SDan Kruchinin } 337bbaa8b60SDan Kruchinin 338bbaa8b60SDan Kruchinin /* Not found locally. Try remote. */ 339bbaa8b60SDan Kruchinin flk0 = *flkp; 340bbaa8b60SDan Kruchinin flk0.l_pid = curproc->p_pid; 341bbaa8b60SDan Kruchinin error = convoff(vp, &flk0, 0, (offset_t)offset); 342bbaa8b60SDan Kruchinin if (error != 0) 343bbaa8b60SDan Kruchinin return (error); 344bbaa8b60SDan Kruchinin 345bbaa8b60SDan Kruchinin error = nlm_call_test(&flk0, hostp, fhp, vers); 346bbaa8b60SDan Kruchinin if (error != 0) 347bbaa8b60SDan Kruchinin return (error); 348bbaa8b60SDan Kruchinin 349bbaa8b60SDan Kruchinin if (flk0.l_type == F_UNLCK) { 350bbaa8b60SDan Kruchinin /* 351bbaa8b60SDan Kruchinin * Update the caller's *flkp with information 352bbaa8b60SDan Kruchinin * on the conflicting lock (or lack thereof). 353bbaa8b60SDan Kruchinin */ 354bbaa8b60SDan Kruchinin flkp->l_type = F_UNLCK; 355bbaa8b60SDan Kruchinin } else { 356bbaa8b60SDan Kruchinin /* 357bbaa8b60SDan Kruchinin * Found a conflicting lock. Set the 358bbaa8b60SDan Kruchinin * caller's *flkp with the info, first 359bbaa8b60SDan Kruchinin * converting to the caller's whence. 360bbaa8b60SDan Kruchinin */ 361bbaa8b60SDan Kruchinin (void) convoff(vp, &flk0, flkp->l_whence, (offset_t)offset); 362bbaa8b60SDan Kruchinin *flkp = flk0; 363bbaa8b60SDan Kruchinin } 364bbaa8b60SDan Kruchinin 365bbaa8b60SDan Kruchinin return (0); 366bbaa8b60SDan Kruchinin } 367bbaa8b60SDan Kruchinin 368bbaa8b60SDan Kruchinin static int 369bbaa8b60SDan Kruchinin nlm_frlock_setlk(struct nlm_host *hostp, vnode_t *vp, 370bbaa8b60SDan Kruchinin struct flock64 *flkp, int flags, u_offset_t offset, 371bbaa8b60SDan Kruchinin struct netobj *fhp, struct flk_callback *flcb, 372bbaa8b60SDan Kruchinin int vers, bool_t do_block) 373bbaa8b60SDan Kruchinin { 374bbaa8b60SDan Kruchinin int error, xflags; 375bbaa8b60SDan Kruchinin 376bbaa8b60SDan Kruchinin error = convoff(vp, flkp, 0, (offset_t)offset); 377bbaa8b60SDan Kruchinin if (error != 0) 378bbaa8b60SDan Kruchinin return (error); 379bbaa8b60SDan Kruchinin 380bbaa8b60SDan Kruchinin /* 381bbaa8b60SDan Kruchinin * NFS v2 clients should not request locks where any part 382bbaa8b60SDan Kruchinin * of the lock range is beyond 0xffffffff. The NFS code 383bbaa8b60SDan Kruchinin * checks that (see nfs_frlock, flk_check_lock_data), but 384bbaa8b60SDan Kruchinin * as that's outside this module, let's check here too. 385bbaa8b60SDan Kruchinin * This check ensures that we will be able to convert this 386bbaa8b60SDan Kruchinin * lock request into 32-bit form without change, and that 387bbaa8b60SDan Kruchinin * (more importantly) when the granted call back arrives, 388bbaa8b60SDan Kruchinin * it's unchanged when converted back into 64-bit form. 389bbaa8b60SDan Kruchinin * If this lock range were to change in any way during 390bbaa8b60SDan Kruchinin * either of those conversions, the "granted" call back 391bbaa8b60SDan Kruchinin * from the NLM server would not find our sleeping lock. 392bbaa8b60SDan Kruchinin */ 393bbaa8b60SDan Kruchinin if (vers < NLM4_VERS) { 394bbaa8b60SDan Kruchinin if (flkp->l_start > MAX_UOFF32 || 395bbaa8b60SDan Kruchinin flkp->l_start + flkp->l_len > MAX_UOFF32 + 1) 396bbaa8b60SDan Kruchinin return (EINVAL); 397bbaa8b60SDan Kruchinin } 398bbaa8b60SDan Kruchinin 399bbaa8b60SDan Kruchinin /* 400bbaa8b60SDan Kruchinin * Fill in l_sysid for the local locking calls. 401bbaa8b60SDan Kruchinin * Also, let's not trust the caller's l_pid. 402bbaa8b60SDan Kruchinin */ 403bbaa8b60SDan Kruchinin flkp->l_sysid = hostp->nh_sysid | LM_SYSID_CLIENT; 404bbaa8b60SDan Kruchinin flkp->l_pid = curproc->p_pid; 405bbaa8b60SDan Kruchinin 406bbaa8b60SDan Kruchinin if (flkp->l_type == F_UNLCK) { 407bbaa8b60SDan Kruchinin /* 408bbaa8b60SDan Kruchinin * Purge local (cached) lock information first, 409bbaa8b60SDan Kruchinin * then clear the remote lock. 410bbaa8b60SDan Kruchinin */ 411bbaa8b60SDan Kruchinin (void) nlm_local_setlk(vp, flkp, flags); 412bbaa8b60SDan Kruchinin error = nlm_call_unlock(flkp, hostp, fhp, vers); 413bbaa8b60SDan Kruchinin 414bbaa8b60SDan Kruchinin return (error); 415bbaa8b60SDan Kruchinin } 416bbaa8b60SDan Kruchinin 417bbaa8b60SDan Kruchinin if (!do_block) { 418bbaa8b60SDan Kruchinin /* 419bbaa8b60SDan Kruchinin * This is a non-blocking "set" request, 420bbaa8b60SDan Kruchinin * so we can check locally first, and 421bbaa8b60SDan Kruchinin * sometimes avoid an RPC call. 422bbaa8b60SDan Kruchinin */ 423bbaa8b60SDan Kruchinin struct flock64 flk0; 424bbaa8b60SDan Kruchinin 425bbaa8b60SDan Kruchinin flk0 = *flkp; 426bbaa8b60SDan Kruchinin error = nlm_local_getlk(vp, &flk0, flags); 427bbaa8b60SDan Kruchinin if (error != 0 && flk0.l_type != F_UNLCK) { 428bbaa8b60SDan Kruchinin /* Found a conflicting lock. */ 429bbaa8b60SDan Kruchinin return (EAGAIN); 430bbaa8b60SDan Kruchinin } 431bbaa8b60SDan Kruchinin 432bbaa8b60SDan Kruchinin xflags = 0; 433bbaa8b60SDan Kruchinin } else { 434bbaa8b60SDan Kruchinin xflags = NLM_X_BLOCKING; 435bbaa8b60SDan Kruchinin } 436bbaa8b60SDan Kruchinin 437bbaa8b60SDan Kruchinin nfs_add_locking_id(vp, curproc->p_pid, RLMPL_PID, 438bbaa8b60SDan Kruchinin (char *)&curproc->p_pid, sizeof (pid_t)); 439bbaa8b60SDan Kruchinin 440bbaa8b60SDan Kruchinin error = nlm_call_lock(vp, flkp, hostp, fhp, flcb, vers, xflags); 441bbaa8b60SDan Kruchinin if (error != 0) 442bbaa8b60SDan Kruchinin return (error); 443bbaa8b60SDan Kruchinin 444bbaa8b60SDan Kruchinin /* 445bbaa8b60SDan Kruchinin * Save the lock locally. This should not fail, 446bbaa8b60SDan Kruchinin * because the server is authoritative about locks 447bbaa8b60SDan Kruchinin * and it just told us we have the lock! 448bbaa8b60SDan Kruchinin */ 449bbaa8b60SDan Kruchinin error = nlm_local_setlk(vp, flkp, flags); 450bbaa8b60SDan Kruchinin if (error != 0) { 451bbaa8b60SDan Kruchinin /* 452bbaa8b60SDan Kruchinin * That's unexpected situation. Just ignore the error. 453bbaa8b60SDan Kruchinin */ 454bbaa8b60SDan Kruchinin NLM_WARN("nlm_frlock_setlk: Failed to set local lock. " 455bbaa8b60SDan Kruchinin "[err=%d]\n", error); 456bbaa8b60SDan Kruchinin error = 0; 457bbaa8b60SDan Kruchinin } 458bbaa8b60SDan Kruchinin 459bbaa8b60SDan Kruchinin return (error); 460bbaa8b60SDan Kruchinin } 461bbaa8b60SDan Kruchinin 462bbaa8b60SDan Kruchinin /* 463bbaa8b60SDan Kruchinin * Cancel all client side remote locks/shares on the 464bbaa8b60SDan Kruchinin * given host. Report to the processes that own 465bbaa8b60SDan Kruchinin * cancelled locks that they are removed by force 466bbaa8b60SDan Kruchinin * by sending SIGLOST. 467bbaa8b60SDan Kruchinin */ 468bbaa8b60SDan Kruchinin void 469bbaa8b60SDan Kruchinin nlm_client_cancel_all(struct nlm_globals *g, struct nlm_host *hostp) 470bbaa8b60SDan Kruchinin { 471bbaa8b60SDan Kruchinin struct locklist *llp_head, *llp; 472bbaa8b60SDan Kruchinin struct nlm_shres *nsp_head, *nsp; 473bbaa8b60SDan Kruchinin struct netobj lm_fh; 474bbaa8b60SDan Kruchinin rpcvers_t vers; 475bbaa8b60SDan Kruchinin int error, sysid; 476bbaa8b60SDan Kruchinin 477bbaa8b60SDan Kruchinin sysid = hostp->nh_sysid | LM_SYSID_CLIENT; 478bbaa8b60SDan Kruchinin nlm_host_cancel_slocks(g, hostp); 479bbaa8b60SDan Kruchinin 480bbaa8b60SDan Kruchinin /* 481bbaa8b60SDan Kruchinin * Destroy all active locks 482bbaa8b60SDan Kruchinin */ 483bbaa8b60SDan Kruchinin llp_head = llp = flk_get_active_locks(sysid, NOPID); 484bbaa8b60SDan Kruchinin while (llp != NULL) { 485bbaa8b60SDan Kruchinin llp->ll_flock.l_type = F_UNLCK; 486bbaa8b60SDan Kruchinin 487bbaa8b60SDan Kruchinin error = nlm_init_fh_by_vp(llp->ll_vp, &lm_fh, &vers); 488bbaa8b60SDan Kruchinin if (error == 0) 489bbaa8b60SDan Kruchinin (void) nlm_call_unlock(&llp->ll_flock, hostp, 490bbaa8b60SDan Kruchinin &lm_fh, vers); 491bbaa8b60SDan Kruchinin 492bbaa8b60SDan Kruchinin nlm_local_cancelk(llp->ll_vp, &llp->ll_flock); 493bbaa8b60SDan Kruchinin llp = llp->ll_next; 494bbaa8b60SDan Kruchinin } 495bbaa8b60SDan Kruchinin 496bbaa8b60SDan Kruchinin flk_free_locklist(llp_head); 497bbaa8b60SDan Kruchinin 498bbaa8b60SDan Kruchinin /* 499bbaa8b60SDan Kruchinin * Destroy all active share reservations 500bbaa8b60SDan Kruchinin */ 501bbaa8b60SDan Kruchinin nsp_head = nsp = nlm_get_active_shres(hostp); 502bbaa8b60SDan Kruchinin while (nsp != NULL) { 503bbaa8b60SDan Kruchinin error = nlm_init_fh_by_vp(nsp->ns_vp, &lm_fh, &vers); 504bbaa8b60SDan Kruchinin if (error == 0) 505bbaa8b60SDan Kruchinin (void) nlm_call_unshare(nsp->ns_shr, hostp, 506bbaa8b60SDan Kruchinin &lm_fh, vers); 507bbaa8b60SDan Kruchinin 508bbaa8b60SDan Kruchinin nlm_local_shrcancel(nsp->ns_vp, nsp->ns_shr); 509bbaa8b60SDan Kruchinin nlm_shres_untrack(hostp, nsp->ns_vp, nsp->ns_shr); 510bbaa8b60SDan Kruchinin nsp = nsp->ns_next; 511bbaa8b60SDan Kruchinin } 512bbaa8b60SDan Kruchinin 513bbaa8b60SDan Kruchinin nlm_free_shrlist(nsp_head); 514bbaa8b60SDan Kruchinin } 515bbaa8b60SDan Kruchinin 516bbaa8b60SDan Kruchinin /* 517bbaa8b60SDan Kruchinin * The function determines whether the lock "fl" can 518bbaa8b60SDan Kruchinin * be safely applied to the file vnode "vp" corresponds to. 519bbaa8b60SDan Kruchinin * The lock can be "safely" applied if all the conditions 520bbaa8b60SDan Kruchinin * above are held: 521bbaa8b60SDan Kruchinin * - It's not a mandatory lock 522bbaa8b60SDan Kruchinin * - The vnode wasn't mapped by anyone 523bbaa8b60SDan Kruchinin * - The vnode was mapped, but it hasn't any locks on it. 524bbaa8b60SDan Kruchinin * - The vnode was mapped and all locks it has occupies 525bbaa8b60SDan Kruchinin * the whole file. 526bbaa8b60SDan Kruchinin */ 527bbaa8b60SDan Kruchinin int 528bbaa8b60SDan Kruchinin nlm_safelock(vnode_t *vp, const struct flock64 *fl, cred_t *cr) 529bbaa8b60SDan Kruchinin { 530bbaa8b60SDan Kruchinin rnode_t *rp = VTOR(vp); 531bbaa8b60SDan Kruchinin struct vattr va; 532bbaa8b60SDan Kruchinin int err; 533bbaa8b60SDan Kruchinin 534bbaa8b60SDan Kruchinin if ((rp->r_mapcnt > 0) && (fl->l_start != 0 || fl->l_len != 0)) 535bbaa8b60SDan Kruchinin return (0); 536bbaa8b60SDan Kruchinin 537bbaa8b60SDan Kruchinin va.va_mask = AT_MODE; 538bbaa8b60SDan Kruchinin err = VOP_GETATTR(vp, &va, 0, cr, NULL); 539bbaa8b60SDan Kruchinin if (err != 0) 540bbaa8b60SDan Kruchinin return (0); 541bbaa8b60SDan Kruchinin 542bbaa8b60SDan Kruchinin /* NLM4 doesn't allow mandatory file locking */ 543bbaa8b60SDan Kruchinin if (MANDLOCK(vp, va.va_mode)) 544bbaa8b60SDan Kruchinin return (0); 545bbaa8b60SDan Kruchinin 546bbaa8b60SDan Kruchinin return (1); 547bbaa8b60SDan Kruchinin } 548bbaa8b60SDan Kruchinin 549bbaa8b60SDan Kruchinin /* 550bbaa8b60SDan Kruchinin * The function determines whether it's safe to map 551bbaa8b60SDan Kruchinin * a file correspoding to vnode vp. 552bbaa8b60SDan Kruchinin * The mapping is considered to be "safe" if file 553bbaa8b60SDan Kruchinin * either has no any locks on it or all locks it 554bbaa8b60SDan Kruchinin * has occupy the whole file. 555bbaa8b60SDan Kruchinin */ 556bbaa8b60SDan Kruchinin int 557bbaa8b60SDan Kruchinin nlm_safemap(const vnode_t *vp) 558bbaa8b60SDan Kruchinin { 559bbaa8b60SDan Kruchinin struct locklist *llp, *llp_next; 560bbaa8b60SDan Kruchinin struct nlm_slock *nslp; 561bbaa8b60SDan Kruchinin struct nlm_globals *g; 562bbaa8b60SDan Kruchinin int safe = 1; 563bbaa8b60SDan Kruchinin 564bbaa8b60SDan Kruchinin /* Check active locks at first */ 565bbaa8b60SDan Kruchinin llp = flk_active_locks_for_vp(vp); 566bbaa8b60SDan Kruchinin while (llp != NULL) { 567bbaa8b60SDan Kruchinin if ((llp->ll_vp == vp) && 568bbaa8b60SDan Kruchinin !NLM_FLOCK_IS_SAFE(&llp->ll_flock)) 569bbaa8b60SDan Kruchinin safe = 0; 570bbaa8b60SDan Kruchinin 571bbaa8b60SDan Kruchinin llp_next = llp->ll_next; 572bbaa8b60SDan Kruchinin VN_RELE(llp->ll_vp); 573bbaa8b60SDan Kruchinin kmem_free(llp, sizeof (*llp)); 574bbaa8b60SDan Kruchinin llp = llp_next; 575bbaa8b60SDan Kruchinin } 576bbaa8b60SDan Kruchinin if (!safe) 577bbaa8b60SDan Kruchinin return (safe); 578bbaa8b60SDan Kruchinin 579bbaa8b60SDan Kruchinin /* Then check sleeping locks if any */ 580bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone); 581bbaa8b60SDan Kruchinin mutex_enter(&g->lock); 582bbaa8b60SDan Kruchinin TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) { 583bbaa8b60SDan Kruchinin if (nslp->nsl_state == NLM_SL_BLOCKED && 584bbaa8b60SDan Kruchinin nslp->nsl_vp == vp && 585bbaa8b60SDan Kruchinin (nslp->nsl_lock.l_offset != 0 || 586bbaa8b60SDan Kruchinin nslp->nsl_lock.l_len != 0)) { 587bbaa8b60SDan Kruchinin safe = 0; 588bbaa8b60SDan Kruchinin break; 589bbaa8b60SDan Kruchinin } 590bbaa8b60SDan Kruchinin } 591bbaa8b60SDan Kruchinin 592bbaa8b60SDan Kruchinin mutex_exit(&g->lock); 593bbaa8b60SDan Kruchinin return (safe); 594bbaa8b60SDan Kruchinin } 595bbaa8b60SDan Kruchinin 596bbaa8b60SDan Kruchinin int 597bbaa8b60SDan Kruchinin nlm_has_sleep(const vnode_t *vp) 598bbaa8b60SDan Kruchinin { 599bbaa8b60SDan Kruchinin struct nlm_globals *g; 600bbaa8b60SDan Kruchinin struct nlm_slock *nslp; 601bbaa8b60SDan Kruchinin int has_slocks = FALSE; 602bbaa8b60SDan Kruchinin 603bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone); 604bbaa8b60SDan Kruchinin mutex_enter(&g->lock); 605bbaa8b60SDan Kruchinin TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) { 606bbaa8b60SDan Kruchinin if (nslp->nsl_state == NLM_SL_BLOCKED && 607bbaa8b60SDan Kruchinin nslp->nsl_vp == vp) { 608bbaa8b60SDan Kruchinin has_slocks = TRUE; 609bbaa8b60SDan Kruchinin break; 610bbaa8b60SDan Kruchinin } 611bbaa8b60SDan Kruchinin } 612bbaa8b60SDan Kruchinin 613bbaa8b60SDan Kruchinin mutex_exit(&g->lock); 614bbaa8b60SDan Kruchinin return (has_slocks); 615bbaa8b60SDan Kruchinin } 616bbaa8b60SDan Kruchinin 617bbaa8b60SDan Kruchinin void 618bbaa8b60SDan Kruchinin nlm_register_lock_locally(struct vnode *vp, struct nlm_host *hostp, 619bbaa8b60SDan Kruchinin struct flock64 *flk, int flags, u_offset_t offset) 620bbaa8b60SDan Kruchinin { 621*310a15feSMarcel Telka struct nlm_globals *g = NULL; 622bbaa8b60SDan Kruchinin int sysid = 0; 623bbaa8b60SDan Kruchinin 6245cd496e3SBryan Cantrill if (hostp == NULL) { 6255cd496e3SBryan Cantrill mntinfo_t *mi; 6265cd496e3SBryan Cantrill servinfo_t *sv; 6275cd496e3SBryan Cantrill const char *netid; 6285cd496e3SBryan Cantrill 6295cd496e3SBryan Cantrill mi = VTOMI(vp); 6305cd496e3SBryan Cantrill sv = mi->mi_curr_serv; 6315cd496e3SBryan Cantrill netid = nlm_knc_to_netid(sv->sv_knconf); 6325cd496e3SBryan Cantrill 6335cd496e3SBryan Cantrill if (netid != NULL) { 6345cd496e3SBryan Cantrill g = zone_getspecific(nlm_zone_key, curzone); 6355cd496e3SBryan Cantrill hostp = nlm_host_findcreate(g, sv->sv_hostname, 6365cd496e3SBryan Cantrill netid, &sv->sv_addr); 6375cd496e3SBryan Cantrill } 6385cd496e3SBryan Cantrill } 6395cd496e3SBryan Cantrill 640bbaa8b60SDan Kruchinin if (hostp != NULL) { 641bbaa8b60SDan Kruchinin sysid = hostp->nh_sysid | LM_SYSID_CLIENT; 642*310a15feSMarcel Telka 643*310a15feSMarcel Telka if (g != NULL) 644*310a15feSMarcel Telka nlm_host_release(g, hostp); 645bbaa8b60SDan Kruchinin } 646bbaa8b60SDan Kruchinin 647bbaa8b60SDan Kruchinin flk->l_sysid = sysid; 648bbaa8b60SDan Kruchinin (void) convoff(vp, flk, 0, (offset_t)offset); 649bbaa8b60SDan Kruchinin (void) nlm_local_setlk(vp, flk, flags); 650bbaa8b60SDan Kruchinin } 651bbaa8b60SDan Kruchinin 652bbaa8b60SDan Kruchinin 653bbaa8b60SDan Kruchinin /* 654bbaa8b60SDan Kruchinin * The BSD code had functions here to "reclaim" (destroy) 655bbaa8b60SDan Kruchinin * remote locks when a vnode is being forcibly destroyed. 656bbaa8b60SDan Kruchinin * We just keep vnodes around until statd tells us the 657bbaa8b60SDan Kruchinin * client has gone away. 658bbaa8b60SDan Kruchinin */ 659bbaa8b60SDan Kruchinin 660bbaa8b60SDan Kruchinin static int 661bbaa8b60SDan Kruchinin nlm_reclaim_lock(struct nlm_host *hostp, vnode_t *vp, 662bbaa8b60SDan Kruchinin struct flock64 *flp, int32_t orig_state) 663bbaa8b60SDan Kruchinin { 664bbaa8b60SDan Kruchinin struct netobj lm_fh; 665bbaa8b60SDan Kruchinin int error, state; 666bbaa8b60SDan Kruchinin rpcvers_t vers; 667bbaa8b60SDan Kruchinin 668bbaa8b60SDan Kruchinin /* 669bbaa8b60SDan Kruchinin * If the remote NSM state changes during recovery, the host 670bbaa8b60SDan Kruchinin * must have rebooted a second time. In that case, we must 671bbaa8b60SDan Kruchinin * restart the recovery. 672bbaa8b60SDan Kruchinin */ 673bbaa8b60SDan Kruchinin state = nlm_host_get_state(hostp); 674bbaa8b60SDan Kruchinin if (state != orig_state) 675bbaa8b60SDan Kruchinin return (ERESTART); 676bbaa8b60SDan Kruchinin 677bbaa8b60SDan Kruchinin error = nlm_init_fh_by_vp(vp, &lm_fh, &vers); 678bbaa8b60SDan Kruchinin if (error != 0) 679bbaa8b60SDan Kruchinin return (error); 680bbaa8b60SDan Kruchinin 681bbaa8b60SDan Kruchinin return (nlm_call_lock(vp, flp, hostp, &lm_fh, 682bbaa8b60SDan Kruchinin NULL, vers, NLM_X_RECLAIM)); 683bbaa8b60SDan Kruchinin } 684bbaa8b60SDan Kruchinin 685bbaa8b60SDan Kruchinin /* 686bbaa8b60SDan Kruchinin * Get local lock information for some NFS server. 687bbaa8b60SDan Kruchinin * 688bbaa8b60SDan Kruchinin * This gets (checks for) a local conflicting lock. 689bbaa8b60SDan Kruchinin * Note: Modifies passed flock, if a conflict is found, 690bbaa8b60SDan Kruchinin * but the caller expects that. 691bbaa8b60SDan Kruchinin */ 692bbaa8b60SDan Kruchinin static int 693bbaa8b60SDan Kruchinin nlm_local_getlk(vnode_t *vp, struct flock64 *fl, int flags) 694bbaa8b60SDan Kruchinin { 695bbaa8b60SDan Kruchinin VERIFY(fl->l_whence == SEEK_SET); 696bbaa8b60SDan Kruchinin return (reclock(vp, fl, 0, flags, 0, NULL)); 697bbaa8b60SDan Kruchinin } 698bbaa8b60SDan Kruchinin 699bbaa8b60SDan Kruchinin /* 700bbaa8b60SDan Kruchinin * Set local lock information for some NFS server. 701bbaa8b60SDan Kruchinin * 702bbaa8b60SDan Kruchinin * Called after a lock request (set or clear) succeeded. We record the 703bbaa8b60SDan Kruchinin * details in the local lock manager. Note that since the remote 704bbaa8b60SDan Kruchinin * server has granted the lock, we can be sure that it doesn't 705bbaa8b60SDan Kruchinin * conflict with any other locks we have in the local lock manager. 706bbaa8b60SDan Kruchinin * 707bbaa8b60SDan Kruchinin * Since it is possible that host may also make NLM client requests to 708bbaa8b60SDan Kruchinin * our NLM server, we use a different sysid value to record our own 709bbaa8b60SDan Kruchinin * client locks. 710bbaa8b60SDan Kruchinin * 711bbaa8b60SDan Kruchinin * Note that since it is possible for us to receive replies from the 712bbaa8b60SDan Kruchinin * server in a different order than the locks were granted (e.g. if 713bbaa8b60SDan Kruchinin * many local threads are contending for the same lock), we must use a 714bbaa8b60SDan Kruchinin * blocking operation when registering with the local lock manager. 715bbaa8b60SDan Kruchinin * We expect that any actual wait will be rare and short hence we 716bbaa8b60SDan Kruchinin * ignore signals for this. 717bbaa8b60SDan Kruchinin */ 718bbaa8b60SDan Kruchinin static int 719bbaa8b60SDan Kruchinin nlm_local_setlk(vnode_t *vp, struct flock64 *fl, int flags) 720bbaa8b60SDan Kruchinin { 721bbaa8b60SDan Kruchinin VERIFY(fl->l_whence == SEEK_SET); 722bbaa8b60SDan Kruchinin return (reclock(vp, fl, SETFLCK, flags, 0, NULL)); 723bbaa8b60SDan Kruchinin } 724bbaa8b60SDan Kruchinin 725bbaa8b60SDan Kruchinin /* 726bbaa8b60SDan Kruchinin * Cancel local lock and send send SIGLOST signal 727bbaa8b60SDan Kruchinin * to the lock owner. 728bbaa8b60SDan Kruchinin * 729bbaa8b60SDan Kruchinin * NOTE: modifies flp 730bbaa8b60SDan Kruchinin */ 731bbaa8b60SDan Kruchinin static void 732bbaa8b60SDan Kruchinin nlm_local_cancelk(vnode_t *vp, struct flock64 *flp) 733bbaa8b60SDan Kruchinin { 734bbaa8b60SDan Kruchinin flp->l_type = F_UNLCK; 735bbaa8b60SDan Kruchinin (void) nlm_local_setlk(vp, flp, FREAD | FWRITE); 736bbaa8b60SDan Kruchinin nlm_send_siglost(flp->l_pid); 737bbaa8b60SDan Kruchinin } 738bbaa8b60SDan Kruchinin 739bbaa8b60SDan Kruchinin /* 740bbaa8b60SDan Kruchinin * Do NLM_LOCK call. 741bbaa8b60SDan Kruchinin * Was: nlm_setlock() 742bbaa8b60SDan Kruchinin * 743bbaa8b60SDan Kruchinin * NOTE: nlm_call_lock() function should care about locking/unlocking 744bbaa8b60SDan Kruchinin * of rnode->r_lkserlock which should be released before nlm_call_lock() 745bbaa8b60SDan Kruchinin * sleeps on waiting lock and acquired when it wakes up. 746bbaa8b60SDan Kruchinin */ 747bbaa8b60SDan Kruchinin static int 748bbaa8b60SDan Kruchinin nlm_call_lock(vnode_t *vp, struct flock64 *flp, 749bbaa8b60SDan Kruchinin struct nlm_host *hostp, struct netobj *fhp, 750bbaa8b60SDan Kruchinin struct flk_callback *flcb, int vers, int xflags) 751bbaa8b60SDan Kruchinin { 752bbaa8b60SDan Kruchinin struct nlm4_lockargs args; 753bbaa8b60SDan Kruchinin struct nlm_owner_handle oh; 754bbaa8b60SDan Kruchinin struct nlm_globals *g; 755bbaa8b60SDan Kruchinin rnode_t *rnp = VTOR(vp); 756bbaa8b60SDan Kruchinin struct nlm_slock *nslp = NULL; 757bbaa8b60SDan Kruchinin uint32_t xid; 758bbaa8b60SDan Kruchinin int error = 0; 759bbaa8b60SDan Kruchinin 760bbaa8b60SDan Kruchinin bzero(&args, sizeof (args)); 761bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone); 762bbaa8b60SDan Kruchinin nlm_init_lock(&args.alock, flp, fhp, &oh); 763bbaa8b60SDan Kruchinin 764bbaa8b60SDan Kruchinin args.exclusive = (flp->l_type == F_WRLCK); 765bbaa8b60SDan Kruchinin args.reclaim = xflags & NLM_X_RECLAIM; 766bbaa8b60SDan Kruchinin args.state = g->nsm_state; 767bbaa8b60SDan Kruchinin args.cookie.n_len = sizeof (xid); 768bbaa8b60SDan Kruchinin args.cookie.n_bytes = (char *)&xid; 769bbaa8b60SDan Kruchinin 770bbaa8b60SDan Kruchinin oh.oh_sysid = hostp->nh_sysid; 771bbaa8b60SDan Kruchinin xid = atomic_inc_32_nv(&nlm_xid); 772bbaa8b60SDan Kruchinin 773bbaa8b60SDan Kruchinin if (xflags & NLM_X_BLOCKING) { 774bbaa8b60SDan Kruchinin args.block = TRUE; 775bbaa8b60SDan Kruchinin nslp = nlm_slock_register(g, hostp, &args.alock, vp); 776bbaa8b60SDan Kruchinin } 777bbaa8b60SDan Kruchinin 778bbaa8b60SDan Kruchinin for (;;) { 779bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp; 780bbaa8b60SDan Kruchinin enum clnt_stat stat; 781bbaa8b60SDan Kruchinin struct nlm4_res res; 782bbaa8b60SDan Kruchinin enum nlm4_stats nlm_err; 783bbaa8b60SDan Kruchinin 784bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(hostp, vers, &rpcp); 785bbaa8b60SDan Kruchinin if (error != 0) { 786bbaa8b60SDan Kruchinin error = ENOLCK; 787bbaa8b60SDan Kruchinin goto out; 788bbaa8b60SDan Kruchinin } 789bbaa8b60SDan Kruchinin 790bbaa8b60SDan Kruchinin bzero(&res, sizeof (res)); 791bbaa8b60SDan Kruchinin stat = nlm_lock_rpc(&args, &res, rpcp->nr_handle, vers); 792bbaa8b60SDan Kruchinin nlm_host_rele_rpc(hostp, rpcp); 793bbaa8b60SDan Kruchinin 794bbaa8b60SDan Kruchinin error = nlm_map_clnt_stat(stat); 795bbaa8b60SDan Kruchinin if (error != 0) { 796bbaa8b60SDan Kruchinin if (error == EAGAIN) 797bbaa8b60SDan Kruchinin continue; 798bbaa8b60SDan Kruchinin 799bbaa8b60SDan Kruchinin goto out; 800bbaa8b60SDan Kruchinin } 801bbaa8b60SDan Kruchinin 802bbaa8b60SDan Kruchinin DTRACE_PROBE1(lock__res, enum nlm4_stats, res.stat.stat); 803bbaa8b60SDan Kruchinin nlm_err = res.stat.stat; 804bbaa8b60SDan Kruchinin xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res); 805bbaa8b60SDan Kruchinin if (nlm_err == nlm4_denied_grace_period) { 806bbaa8b60SDan Kruchinin if (args.reclaim) { 807bbaa8b60SDan Kruchinin error = ENOLCK; 808bbaa8b60SDan Kruchinin goto out; 809bbaa8b60SDan Kruchinin } 810bbaa8b60SDan Kruchinin 811bbaa8b60SDan Kruchinin error = nlm_host_wait_grace(hostp); 812bbaa8b60SDan Kruchinin if (error != 0) 813bbaa8b60SDan Kruchinin goto out; 814bbaa8b60SDan Kruchinin 815bbaa8b60SDan Kruchinin continue; 816bbaa8b60SDan Kruchinin } 817bbaa8b60SDan Kruchinin 818bbaa8b60SDan Kruchinin switch (nlm_err) { 819bbaa8b60SDan Kruchinin case nlm4_granted: 820bbaa8b60SDan Kruchinin case nlm4_blocked: 821bbaa8b60SDan Kruchinin error = 0; 822bbaa8b60SDan Kruchinin break; 823bbaa8b60SDan Kruchinin 824bbaa8b60SDan Kruchinin case nlm4_denied: 825bbaa8b60SDan Kruchinin if (nslp != NULL) { 826bbaa8b60SDan Kruchinin NLM_WARN("nlm_call_lock: got nlm4_denied for " 827bbaa8b60SDan Kruchinin "blocking lock\n"); 828bbaa8b60SDan Kruchinin } 829bbaa8b60SDan Kruchinin 830bbaa8b60SDan Kruchinin error = EAGAIN; 831bbaa8b60SDan Kruchinin break; 832bbaa8b60SDan Kruchinin 833bbaa8b60SDan Kruchinin default: 834bbaa8b60SDan Kruchinin error = nlm_map_status(nlm_err); 835bbaa8b60SDan Kruchinin } 836bbaa8b60SDan Kruchinin 837bbaa8b60SDan Kruchinin /* 838bbaa8b60SDan Kruchinin * If we deal with either non-blocking lock or 839bbaa8b60SDan Kruchinin * with a blocking locks that wasn't blocked on 840bbaa8b60SDan Kruchinin * the server side (by some reason), our work 841bbaa8b60SDan Kruchinin * is finished. 842bbaa8b60SDan Kruchinin */ 843bbaa8b60SDan Kruchinin if (nslp == NULL || 844bbaa8b60SDan Kruchinin nlm_err != nlm4_blocked || 845bbaa8b60SDan Kruchinin error != 0) 846bbaa8b60SDan Kruchinin goto out; 847bbaa8b60SDan Kruchinin 848bbaa8b60SDan Kruchinin /* 849bbaa8b60SDan Kruchinin * Before releasing the r_lkserlock of rnode, we should 850bbaa8b60SDan Kruchinin * check whether the new lock is "safe". If it's not 851bbaa8b60SDan Kruchinin * safe, disable caching for the given vnode. That is done 852bbaa8b60SDan Kruchinin * for sleeping locks only that are waiting for a GRANT reply 853bbaa8b60SDan Kruchinin * from the NLM server. 854bbaa8b60SDan Kruchinin * 855bbaa8b60SDan Kruchinin * NOTE: the vnode cache can be enabled back later if an 856bbaa8b60SDan Kruchinin * unsafe lock will be merged with existent locks so that 857bbaa8b60SDan Kruchinin * it will become safe. This condition is checked in the 858bbaa8b60SDan Kruchinin * NFSv3 code (see nfs_lockcompletion). 859bbaa8b60SDan Kruchinin */ 860bbaa8b60SDan Kruchinin if (!NLM_FLOCK_IS_SAFE(flp)) { 861bbaa8b60SDan Kruchinin mutex_enter(&vp->v_lock); 862bbaa8b60SDan Kruchinin vp->v_flag &= ~VNOCACHE; 863bbaa8b60SDan Kruchinin mutex_exit(&vp->v_lock); 864bbaa8b60SDan Kruchinin } 865bbaa8b60SDan Kruchinin 866bbaa8b60SDan Kruchinin /* 867bbaa8b60SDan Kruchinin * The server should call us back with a 868bbaa8b60SDan Kruchinin * granted message when the lock succeeds. 869bbaa8b60SDan Kruchinin * In order to deal with broken servers, 870bbaa8b60SDan Kruchinin * lost granted messages, or server reboots, 871bbaa8b60SDan Kruchinin * we will also re-try every few seconds. 872bbaa8b60SDan Kruchinin * 873bbaa8b60SDan Kruchinin * Note: We're supposed to call these 874bbaa8b60SDan Kruchinin * flk_invoke_callbacks when blocking. 875bbaa8b60SDan Kruchinin * Take care on rnode->r_lkserlock, we should 876bbaa8b60SDan Kruchinin * release it before going to sleep. 877bbaa8b60SDan Kruchinin */ 878bbaa8b60SDan Kruchinin (void) flk_invoke_callbacks(flcb, FLK_BEFORE_SLEEP); 879bbaa8b60SDan Kruchinin nfs_rw_exit(&rnp->r_lkserlock); 880bbaa8b60SDan Kruchinin 881bbaa8b60SDan Kruchinin error = nlm_slock_wait(g, nslp, g->retrans_tmo); 882bbaa8b60SDan Kruchinin 883bbaa8b60SDan Kruchinin /* 884bbaa8b60SDan Kruchinin * NFS expects that we return with rnode->r_lkserlock 885bbaa8b60SDan Kruchinin * locked on write, lock it back. 886bbaa8b60SDan Kruchinin * 887bbaa8b60SDan Kruchinin * NOTE: nfs_rw_enter_sig() can be either interruptible 888bbaa8b60SDan Kruchinin * or not. It depends on options of NFS mount. Here 889bbaa8b60SDan Kruchinin * we're _always_ uninterruptible (independently of mount 890bbaa8b60SDan Kruchinin * options), because nfs_frlock/nfs3_frlock expects that 891bbaa8b60SDan Kruchinin * we return with rnode->r_lkserlock acquired. So we don't 892bbaa8b60SDan Kruchinin * want our lock attempt to be interrupted by a signal. 893bbaa8b60SDan Kruchinin */ 894bbaa8b60SDan Kruchinin (void) nfs_rw_enter_sig(&rnp->r_lkserlock, RW_WRITER, 0); 895bbaa8b60SDan Kruchinin (void) flk_invoke_callbacks(flcb, FLK_AFTER_SLEEP); 896bbaa8b60SDan Kruchinin 897bbaa8b60SDan Kruchinin if (error == 0) { 898bbaa8b60SDan Kruchinin break; 899bbaa8b60SDan Kruchinin } else if (error == EINTR) { 900bbaa8b60SDan Kruchinin /* 901bbaa8b60SDan Kruchinin * We need to call the server to cancel our 902bbaa8b60SDan Kruchinin * lock request. 903bbaa8b60SDan Kruchinin */ 904bbaa8b60SDan Kruchinin DTRACE_PROBE1(cancel__lock, int, error); 905bbaa8b60SDan Kruchinin (void) nlm_call_cancel(&args, hostp, vers); 906bbaa8b60SDan Kruchinin break; 907bbaa8b60SDan Kruchinin } else { 908bbaa8b60SDan Kruchinin /* 909bbaa8b60SDan Kruchinin * Timeout happened, resend the lock request to 910bbaa8b60SDan Kruchinin * the server. Well, we're a bit paranoid here, 911bbaa8b60SDan Kruchinin * but keep in mind previous request could lost 912bbaa8b60SDan Kruchinin * (especially with conectionless transport). 913bbaa8b60SDan Kruchinin */ 914bbaa8b60SDan Kruchinin 915bbaa8b60SDan Kruchinin ASSERT(error == ETIMEDOUT); 916bbaa8b60SDan Kruchinin continue; 917bbaa8b60SDan Kruchinin } 918bbaa8b60SDan Kruchinin } 919bbaa8b60SDan Kruchinin 920bbaa8b60SDan Kruchinin /* 921bbaa8b60SDan Kruchinin * We could disable the vnode cache for the given _sleeping_ 922bbaa8b60SDan Kruchinin * (codition: nslp != NULL) lock if it was unsafe. Normally, 923bbaa8b60SDan Kruchinin * nfs_lockcompletion() function can enable the vnode cache 924bbaa8b60SDan Kruchinin * back if the lock becomes safe after activativation. But it 925bbaa8b60SDan Kruchinin * will not happen if any error occurs on the locking path. 926bbaa8b60SDan Kruchinin * 927bbaa8b60SDan Kruchinin * Here we enable the vnode cache back if the error occurred 928bbaa8b60SDan Kruchinin * and if there aren't any unsafe locks on the given vnode. 929bbaa8b60SDan Kruchinin * Note that if error happened, sleeping lock was derigistered. 930bbaa8b60SDan Kruchinin */ 931bbaa8b60SDan Kruchinin if (error != 0 && nslp != NULL && nlm_safemap(vp)) { 932bbaa8b60SDan Kruchinin mutex_enter(&vp->v_lock); 933bbaa8b60SDan Kruchinin vp->v_flag |= VNOCACHE; 934bbaa8b60SDan Kruchinin mutex_exit(&vp->v_lock); 935bbaa8b60SDan Kruchinin } 936bbaa8b60SDan Kruchinin 937bbaa8b60SDan Kruchinin out: 938bbaa8b60SDan Kruchinin if (nslp != NULL) 939bbaa8b60SDan Kruchinin nlm_slock_unregister(g, nslp); 940bbaa8b60SDan Kruchinin 941bbaa8b60SDan Kruchinin return (error); 942bbaa8b60SDan Kruchinin } 943bbaa8b60SDan Kruchinin 944bbaa8b60SDan Kruchinin /* 945bbaa8b60SDan Kruchinin * Do NLM_CANCEL call. 946bbaa8b60SDan Kruchinin * Helper for nlm_call_lock() error recovery. 947bbaa8b60SDan Kruchinin */ 948bbaa8b60SDan Kruchinin static int 949bbaa8b60SDan Kruchinin nlm_call_cancel(struct nlm4_lockargs *largs, 950bbaa8b60SDan Kruchinin struct nlm_host *hostp, int vers) 951bbaa8b60SDan Kruchinin { 952bbaa8b60SDan Kruchinin nlm4_cancargs cargs; 953bbaa8b60SDan Kruchinin uint32_t xid; 954bbaa8b60SDan Kruchinin int error, retries; 955bbaa8b60SDan Kruchinin 956bbaa8b60SDan Kruchinin bzero(&cargs, sizeof (cargs)); 957bbaa8b60SDan Kruchinin 958bbaa8b60SDan Kruchinin xid = atomic_inc_32_nv(&nlm_xid); 959bbaa8b60SDan Kruchinin cargs.cookie.n_len = sizeof (xid); 960bbaa8b60SDan Kruchinin cargs.cookie.n_bytes = (char *)&xid; 961bbaa8b60SDan Kruchinin cargs.block = largs->block; 962bbaa8b60SDan Kruchinin cargs.exclusive = largs->exclusive; 963bbaa8b60SDan Kruchinin cargs.alock = largs->alock; 964bbaa8b60SDan Kruchinin 965bbaa8b60SDan Kruchinin /* 966bbaa8b60SDan Kruchinin * Unlike all other nlm_call_* functions, nlm_call_cancel 967bbaa8b60SDan Kruchinin * doesn't spin forever until it gets reasonable response 968bbaa8b60SDan Kruchinin * from NLM server. It makes limited number of retries and 969bbaa8b60SDan Kruchinin * if server doesn't send a reasonable reply, it returns an 970bbaa8b60SDan Kruchinin * error. It behaves like that because it's called from nlm_call_lock 971bbaa8b60SDan Kruchinin * with blocked signals and thus it can not be interrupted from 972bbaa8b60SDan Kruchinin * user space. 973bbaa8b60SDan Kruchinin */ 974bbaa8b60SDan Kruchinin for (retries = 0; retries < NLM_CANCEL_NRETRS; retries++) { 975bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp; 976bbaa8b60SDan Kruchinin enum clnt_stat stat; 977bbaa8b60SDan Kruchinin struct nlm4_res res; 978bbaa8b60SDan Kruchinin 979bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(hostp, vers, &rpcp); 980bbaa8b60SDan Kruchinin if (error != 0) 981bbaa8b60SDan Kruchinin return (ENOLCK); 982bbaa8b60SDan Kruchinin 983bbaa8b60SDan Kruchinin bzero(&res, sizeof (res)); 984bbaa8b60SDan Kruchinin stat = nlm_cancel_rpc(&cargs, &res, rpcp->nr_handle, vers); 985bbaa8b60SDan Kruchinin nlm_host_rele_rpc(hostp, rpcp); 986bbaa8b60SDan Kruchinin 987bbaa8b60SDan Kruchinin DTRACE_PROBE1(cancel__rloop_end, enum clnt_stat, stat); 988bbaa8b60SDan Kruchinin error = nlm_map_clnt_stat(stat); 989bbaa8b60SDan Kruchinin if (error != 0) { 990bbaa8b60SDan Kruchinin if (error == EAGAIN) 991bbaa8b60SDan Kruchinin continue; 992bbaa8b60SDan Kruchinin 993bbaa8b60SDan Kruchinin return (error); 994bbaa8b60SDan Kruchinin } 995bbaa8b60SDan Kruchinin 996bbaa8b60SDan Kruchinin DTRACE_PROBE1(cancel__res, enum nlm4_stats, res.stat.stat); 997bbaa8b60SDan Kruchinin switch (res.stat.stat) { 998bbaa8b60SDan Kruchinin /* 999bbaa8b60SDan Kruchinin * There was nothing to cancel. We are going to go ahead 1000bbaa8b60SDan Kruchinin * and assume we got the lock. 1001bbaa8b60SDan Kruchinin */ 1002bbaa8b60SDan Kruchinin case nlm_denied: 1003bbaa8b60SDan Kruchinin /* 1004bbaa8b60SDan Kruchinin * The server has recently rebooted. Treat this as a 1005bbaa8b60SDan Kruchinin * successful cancellation. 1006bbaa8b60SDan Kruchinin */ 1007bbaa8b60SDan Kruchinin case nlm4_denied_grace_period: 1008bbaa8b60SDan Kruchinin /* 1009bbaa8b60SDan Kruchinin * We managed to cancel. 1010bbaa8b60SDan Kruchinin */ 1011bbaa8b60SDan Kruchinin case nlm4_granted: 1012bbaa8b60SDan Kruchinin error = 0; 1013bbaa8b60SDan Kruchinin break; 1014bbaa8b60SDan Kruchinin 1015bbaa8b60SDan Kruchinin default: 1016bbaa8b60SDan Kruchinin /* 1017bbaa8b60SDan Kruchinin * Broken server implementation. Can't really do 1018bbaa8b60SDan Kruchinin * anything here. 1019bbaa8b60SDan Kruchinin */ 1020bbaa8b60SDan Kruchinin error = EIO; 1021bbaa8b60SDan Kruchinin break; 1022bbaa8b60SDan Kruchinin } 1023bbaa8b60SDan Kruchinin 1024bbaa8b60SDan Kruchinin xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res); 1025bbaa8b60SDan Kruchinin break; 1026bbaa8b60SDan Kruchinin } 1027bbaa8b60SDan Kruchinin 1028bbaa8b60SDan Kruchinin return (error); 1029bbaa8b60SDan Kruchinin } 1030bbaa8b60SDan Kruchinin 1031bbaa8b60SDan Kruchinin /* 1032bbaa8b60SDan Kruchinin * Do NLM_UNLOCK call. 1033bbaa8b60SDan Kruchinin * Was: nlm_clearlock 1034bbaa8b60SDan Kruchinin */ 1035bbaa8b60SDan Kruchinin static int 1036bbaa8b60SDan Kruchinin nlm_call_unlock(struct flock64 *flp, struct nlm_host *hostp, 1037bbaa8b60SDan Kruchinin struct netobj *fhp, int vers) 1038bbaa8b60SDan Kruchinin { 1039bbaa8b60SDan Kruchinin struct nlm4_unlockargs args; 1040bbaa8b60SDan Kruchinin struct nlm_owner_handle oh; 1041bbaa8b60SDan Kruchinin enum nlm4_stats nlm_err; 1042bbaa8b60SDan Kruchinin uint32_t xid; 1043bbaa8b60SDan Kruchinin int error; 1044bbaa8b60SDan Kruchinin 1045bbaa8b60SDan Kruchinin bzero(&args, sizeof (args)); 1046bbaa8b60SDan Kruchinin nlm_init_lock(&args.alock, flp, fhp, &oh); 1047bbaa8b60SDan Kruchinin 1048bbaa8b60SDan Kruchinin oh.oh_sysid = hostp->nh_sysid; 1049bbaa8b60SDan Kruchinin xid = atomic_inc_32_nv(&nlm_xid); 1050bbaa8b60SDan Kruchinin args.cookie.n_len = sizeof (xid); 1051bbaa8b60SDan Kruchinin args.cookie.n_bytes = (char *)&xid; 1052bbaa8b60SDan Kruchinin 1053bbaa8b60SDan Kruchinin for (;;) { 1054bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp; 1055bbaa8b60SDan Kruchinin struct nlm4_res res; 1056bbaa8b60SDan Kruchinin enum clnt_stat stat; 1057bbaa8b60SDan Kruchinin 1058bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(hostp, vers, &rpcp); 1059bbaa8b60SDan Kruchinin if (error != 0) 1060bbaa8b60SDan Kruchinin return (ENOLCK); 1061bbaa8b60SDan Kruchinin 1062bbaa8b60SDan Kruchinin bzero(&res, sizeof (res)); 1063bbaa8b60SDan Kruchinin stat = nlm_unlock_rpc(&args, &res, rpcp->nr_handle, vers); 1064bbaa8b60SDan Kruchinin nlm_host_rele_rpc(hostp, rpcp); 1065bbaa8b60SDan Kruchinin 1066bbaa8b60SDan Kruchinin error = nlm_map_clnt_stat(stat); 1067bbaa8b60SDan Kruchinin if (error != 0) { 1068bbaa8b60SDan Kruchinin if (error == EAGAIN) 1069bbaa8b60SDan Kruchinin continue; 1070bbaa8b60SDan Kruchinin 1071bbaa8b60SDan Kruchinin return (error); 1072bbaa8b60SDan Kruchinin } 1073bbaa8b60SDan Kruchinin 1074bbaa8b60SDan Kruchinin DTRACE_PROBE1(unlock__res, enum nlm4_stats, res.stat.stat); 1075bbaa8b60SDan Kruchinin nlm_err = res.stat.stat; 1076bbaa8b60SDan Kruchinin xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res); 1077bbaa8b60SDan Kruchinin if (nlm_err == nlm4_denied_grace_period) { 1078bbaa8b60SDan Kruchinin error = nlm_host_wait_grace(hostp); 1079bbaa8b60SDan Kruchinin if (error != 0) 1080bbaa8b60SDan Kruchinin return (error); 1081bbaa8b60SDan Kruchinin 1082bbaa8b60SDan Kruchinin continue; 1083bbaa8b60SDan Kruchinin } 1084bbaa8b60SDan Kruchinin 1085bbaa8b60SDan Kruchinin break; 1086bbaa8b60SDan Kruchinin } 1087bbaa8b60SDan Kruchinin 1088bbaa8b60SDan Kruchinin /* special cases */ 1089bbaa8b60SDan Kruchinin switch (nlm_err) { 1090bbaa8b60SDan Kruchinin case nlm4_denied: 1091bbaa8b60SDan Kruchinin error = EINVAL; 1092bbaa8b60SDan Kruchinin break; 1093bbaa8b60SDan Kruchinin default: 1094bbaa8b60SDan Kruchinin error = nlm_map_status(nlm_err); 1095bbaa8b60SDan Kruchinin break; 1096bbaa8b60SDan Kruchinin } 1097bbaa8b60SDan Kruchinin 1098bbaa8b60SDan Kruchinin return (error); 1099bbaa8b60SDan Kruchinin } 1100bbaa8b60SDan Kruchinin 1101bbaa8b60SDan Kruchinin /* 1102bbaa8b60SDan Kruchinin * Do NLM_TEST call. 1103bbaa8b60SDan Kruchinin * Was: nlm_getlock() 1104bbaa8b60SDan Kruchinin */ 1105bbaa8b60SDan Kruchinin static int 1106bbaa8b60SDan Kruchinin nlm_call_test(struct flock64 *flp, struct nlm_host *hostp, 1107bbaa8b60SDan Kruchinin struct netobj *fhp, int vers) 1108bbaa8b60SDan Kruchinin { 1109bbaa8b60SDan Kruchinin struct nlm4_testargs args; 1110bbaa8b60SDan Kruchinin struct nlm4_holder h; 1111bbaa8b60SDan Kruchinin struct nlm_owner_handle oh; 1112bbaa8b60SDan Kruchinin enum nlm4_stats nlm_err; 1113bbaa8b60SDan Kruchinin uint32_t xid; 1114bbaa8b60SDan Kruchinin int error; 1115bbaa8b60SDan Kruchinin 1116bbaa8b60SDan Kruchinin bzero(&args, sizeof (args)); 1117bbaa8b60SDan Kruchinin nlm_init_lock(&args.alock, flp, fhp, &oh); 1118bbaa8b60SDan Kruchinin 1119bbaa8b60SDan Kruchinin args.exclusive = (flp->l_type == F_WRLCK); 1120bbaa8b60SDan Kruchinin oh.oh_sysid = hostp->nh_sysid; 1121bbaa8b60SDan Kruchinin xid = atomic_inc_32_nv(&nlm_xid); 1122bbaa8b60SDan Kruchinin args.cookie.n_len = sizeof (xid); 1123bbaa8b60SDan Kruchinin args.cookie.n_bytes = (char *)&xid; 1124bbaa8b60SDan Kruchinin 1125bbaa8b60SDan Kruchinin for (;;) { 1126bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp; 1127bbaa8b60SDan Kruchinin struct nlm4_testres res; 1128bbaa8b60SDan Kruchinin enum clnt_stat stat; 1129bbaa8b60SDan Kruchinin 1130bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(hostp, vers, &rpcp); 1131bbaa8b60SDan Kruchinin if (error != 0) 1132bbaa8b60SDan Kruchinin return (ENOLCK); 1133bbaa8b60SDan Kruchinin 1134bbaa8b60SDan Kruchinin bzero(&res, sizeof (res)); 1135bbaa8b60SDan Kruchinin stat = nlm_test_rpc(&args, &res, rpcp->nr_handle, vers); 1136bbaa8b60SDan Kruchinin nlm_host_rele_rpc(hostp, rpcp); 1137bbaa8b60SDan Kruchinin 1138bbaa8b60SDan Kruchinin error = nlm_map_clnt_stat(stat); 1139bbaa8b60SDan Kruchinin if (error != 0) { 1140bbaa8b60SDan Kruchinin if (error == EAGAIN) 1141bbaa8b60SDan Kruchinin continue; 1142bbaa8b60SDan Kruchinin 1143bbaa8b60SDan Kruchinin return (error); 1144bbaa8b60SDan Kruchinin } 1145bbaa8b60SDan Kruchinin 1146bbaa8b60SDan Kruchinin DTRACE_PROBE1(test__res, enum nlm4_stats, res.stat.stat); 1147bbaa8b60SDan Kruchinin nlm_err = res.stat.stat; 1148bbaa8b60SDan Kruchinin bcopy(&res.stat.nlm4_testrply_u.holder, &h, sizeof (h)); 1149bbaa8b60SDan Kruchinin xdr_free((xdrproc_t)xdr_nlm4_testres, (void *)&res); 1150bbaa8b60SDan Kruchinin if (nlm_err == nlm4_denied_grace_period) { 1151bbaa8b60SDan Kruchinin error = nlm_host_wait_grace(hostp); 1152bbaa8b60SDan Kruchinin if (error != 0) 1153bbaa8b60SDan Kruchinin return (error); 1154bbaa8b60SDan Kruchinin 1155bbaa8b60SDan Kruchinin continue; 1156bbaa8b60SDan Kruchinin } 1157bbaa8b60SDan Kruchinin 1158bbaa8b60SDan Kruchinin break; 1159bbaa8b60SDan Kruchinin } 1160bbaa8b60SDan Kruchinin 1161bbaa8b60SDan Kruchinin switch (nlm_err) { 1162bbaa8b60SDan Kruchinin case nlm4_granted: 1163bbaa8b60SDan Kruchinin flp->l_type = F_UNLCK; 1164bbaa8b60SDan Kruchinin error = 0; 1165bbaa8b60SDan Kruchinin break; 1166bbaa8b60SDan Kruchinin 1167bbaa8b60SDan Kruchinin case nlm4_denied: 1168bbaa8b60SDan Kruchinin flp->l_start = h.l_offset; 1169bbaa8b60SDan Kruchinin flp->l_len = h.l_len; 1170bbaa8b60SDan Kruchinin flp->l_pid = h.svid; 1171bbaa8b60SDan Kruchinin flp->l_type = (h.exclusive) ? F_WRLCK : F_RDLCK; 1172bbaa8b60SDan Kruchinin flp->l_whence = SEEK_SET; 1173bbaa8b60SDan Kruchinin flp->l_sysid = 0; 1174bbaa8b60SDan Kruchinin error = 0; 1175bbaa8b60SDan Kruchinin break; 1176bbaa8b60SDan Kruchinin 1177bbaa8b60SDan Kruchinin default: 1178bbaa8b60SDan Kruchinin error = nlm_map_status(nlm_err); 1179bbaa8b60SDan Kruchinin break; 1180bbaa8b60SDan Kruchinin } 1181bbaa8b60SDan Kruchinin 1182bbaa8b60SDan Kruchinin return (error); 1183bbaa8b60SDan Kruchinin } 1184bbaa8b60SDan Kruchinin 1185bbaa8b60SDan Kruchinin 1186bbaa8b60SDan Kruchinin static void 1187bbaa8b60SDan Kruchinin nlm_init_lock(struct nlm4_lock *lock, 1188bbaa8b60SDan Kruchinin const struct flock64 *fl, struct netobj *fh, 1189bbaa8b60SDan Kruchinin struct nlm_owner_handle *oh) 1190bbaa8b60SDan Kruchinin { 1191bbaa8b60SDan Kruchinin 1192bbaa8b60SDan Kruchinin /* Caller converts to zero-base. */ 1193bbaa8b60SDan Kruchinin VERIFY(fl->l_whence == SEEK_SET); 1194bbaa8b60SDan Kruchinin bzero(lock, sizeof (*lock)); 1195bbaa8b60SDan Kruchinin bzero(oh, sizeof (*oh)); 1196bbaa8b60SDan Kruchinin 1197bbaa8b60SDan Kruchinin lock->caller_name = uts_nodename(); 1198bbaa8b60SDan Kruchinin lock->fh.n_len = fh->n_len; 1199bbaa8b60SDan Kruchinin lock->fh.n_bytes = fh->n_bytes; 1200bbaa8b60SDan Kruchinin lock->oh.n_len = sizeof (*oh); 1201bbaa8b60SDan Kruchinin lock->oh.n_bytes = (void *)oh; 1202bbaa8b60SDan Kruchinin lock->svid = fl->l_pid; 1203bbaa8b60SDan Kruchinin lock->l_offset = fl->l_start; 1204bbaa8b60SDan Kruchinin lock->l_len = fl->l_len; 1205bbaa8b60SDan Kruchinin } 1206bbaa8b60SDan Kruchinin 1207bbaa8b60SDan Kruchinin /* ************************************************************** */ 1208bbaa8b60SDan Kruchinin 1209bbaa8b60SDan Kruchinin int 1210bbaa8b60SDan Kruchinin nlm_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, 1211bbaa8b60SDan Kruchinin int flags, struct netobj *fh, int vers) 1212bbaa8b60SDan Kruchinin { 1213bbaa8b60SDan Kruchinin struct shrlock shlk; 1214bbaa8b60SDan Kruchinin mntinfo_t *mi; 1215bbaa8b60SDan Kruchinin servinfo_t *sv; 1216bbaa8b60SDan Kruchinin const char *netid; 1217bbaa8b60SDan Kruchinin struct nlm_host *host = NULL; 1218bbaa8b60SDan Kruchinin int error; 1219bbaa8b60SDan Kruchinin struct nlm_globals *g; 1220bbaa8b60SDan Kruchinin 1221bbaa8b60SDan Kruchinin mi = VTOMI(vp); 1222bbaa8b60SDan Kruchinin sv = mi->mi_curr_serv; 1223bbaa8b60SDan Kruchinin 1224bbaa8b60SDan Kruchinin netid = nlm_knc_to_netid(sv->sv_knconf); 1225bbaa8b60SDan Kruchinin if (netid == NULL) { 1226bbaa8b60SDan Kruchinin NLM_ERR("nlm_shrlock: unknown NFS netid\n"); 1227bbaa8b60SDan Kruchinin return (ENOSYS); 1228bbaa8b60SDan Kruchinin } 1229bbaa8b60SDan Kruchinin 1230bbaa8b60SDan Kruchinin g = zone_getspecific(nlm_zone_key, curzone); 1231bbaa8b60SDan Kruchinin host = nlm_host_findcreate(g, sv->sv_hostname, netid, &sv->sv_addr); 1232bbaa8b60SDan Kruchinin if (host == NULL) 1233bbaa8b60SDan Kruchinin return (ENOSYS); 1234bbaa8b60SDan Kruchinin 1235bbaa8b60SDan Kruchinin /* 1236bbaa8b60SDan Kruchinin * Fill in s_sysid for the local locking calls. 1237bbaa8b60SDan Kruchinin * Also, let's not trust the caller's l_pid. 1238bbaa8b60SDan Kruchinin */ 1239bbaa8b60SDan Kruchinin shlk = *shr; 1240bbaa8b60SDan Kruchinin shlk.s_sysid = host->nh_sysid | LM_SYSID_CLIENT; 1241bbaa8b60SDan Kruchinin shlk.s_pid = curproc->p_pid; 1242bbaa8b60SDan Kruchinin 1243bbaa8b60SDan Kruchinin if (cmd == F_UNSHARE) { 1244bbaa8b60SDan Kruchinin /* 1245bbaa8b60SDan Kruchinin * Purge local (cached) share information first, 1246bbaa8b60SDan Kruchinin * then clear the remote share. 1247bbaa8b60SDan Kruchinin */ 1248bbaa8b60SDan Kruchinin (void) nlm_local_shrlock(vp, &shlk, cmd, flags); 1249bbaa8b60SDan Kruchinin nlm_shres_untrack(host, vp, &shlk); 1250bbaa8b60SDan Kruchinin error = nlm_call_unshare(&shlk, host, fh, vers); 1251bbaa8b60SDan Kruchinin goto out; 1252bbaa8b60SDan Kruchinin } 1253bbaa8b60SDan Kruchinin 1254bbaa8b60SDan Kruchinin nfs_add_locking_id(vp, curproc->p_pid, RLMPL_OWNER, 1255bbaa8b60SDan Kruchinin shr->s_owner, shr->s_own_len); 1256bbaa8b60SDan Kruchinin 1257bbaa8b60SDan Kruchinin error = nlm_call_share(&shlk, host, fh, vers, FALSE); 1258bbaa8b60SDan Kruchinin if (error != 0) 1259bbaa8b60SDan Kruchinin goto out; 1260bbaa8b60SDan Kruchinin 1261bbaa8b60SDan Kruchinin /* 1262bbaa8b60SDan Kruchinin * Save the share locally. This should not fail, 1263bbaa8b60SDan Kruchinin * because the server is authoritative about shares 1264bbaa8b60SDan Kruchinin * and it just told us we have the share reservation! 1265bbaa8b60SDan Kruchinin */ 1266bbaa8b60SDan Kruchinin error = nlm_local_shrlock(vp, shr, cmd, flags); 1267bbaa8b60SDan Kruchinin if (error != 0) { 1268bbaa8b60SDan Kruchinin /* 1269bbaa8b60SDan Kruchinin * Oh oh, we really don't expect an error here. 1270bbaa8b60SDan Kruchinin */ 1271bbaa8b60SDan Kruchinin NLM_WARN("nlm_shrlock: set locally, err %d\n", error); 1272bbaa8b60SDan Kruchinin error = 0; 1273bbaa8b60SDan Kruchinin } 1274bbaa8b60SDan Kruchinin 1275bbaa8b60SDan Kruchinin nlm_shres_track(host, vp, &shlk); 1276bbaa8b60SDan Kruchinin nlm_host_monitor(g, host, 0); 1277bbaa8b60SDan Kruchinin 1278bbaa8b60SDan Kruchinin out: 1279bbaa8b60SDan Kruchinin nlm_host_release(g, host); 1280bbaa8b60SDan Kruchinin 1281bbaa8b60SDan Kruchinin return (error); 1282bbaa8b60SDan Kruchinin } 1283bbaa8b60SDan Kruchinin 1284bbaa8b60SDan Kruchinin static int 1285bbaa8b60SDan Kruchinin nlm_reclaim_share(struct nlm_host *hostp, vnode_t *vp, 1286bbaa8b60SDan Kruchinin struct shrlock *shr, uint32_t orig_state) 1287bbaa8b60SDan Kruchinin { 1288bbaa8b60SDan Kruchinin struct netobj lm_fh; 1289bbaa8b60SDan Kruchinin int error, state; 1290bbaa8b60SDan Kruchinin rpcvers_t vers; 1291bbaa8b60SDan Kruchinin 1292bbaa8b60SDan Kruchinin state = nlm_host_get_state(hostp); 1293bbaa8b60SDan Kruchinin if (state != orig_state) { 1294bbaa8b60SDan Kruchinin /* 1295bbaa8b60SDan Kruchinin * It seems that NLM server rebooted while 1296bbaa8b60SDan Kruchinin * we were busy with recovery. 1297bbaa8b60SDan Kruchinin */ 1298bbaa8b60SDan Kruchinin return (ERESTART); 1299bbaa8b60SDan Kruchinin } 1300bbaa8b60SDan Kruchinin 1301bbaa8b60SDan Kruchinin error = nlm_init_fh_by_vp(vp, &lm_fh, &vers); 1302bbaa8b60SDan Kruchinin if (error != 0) 1303bbaa8b60SDan Kruchinin return (error); 1304bbaa8b60SDan Kruchinin 1305bbaa8b60SDan Kruchinin return (nlm_call_share(shr, hostp, &lm_fh, vers, 1)); 1306bbaa8b60SDan Kruchinin } 1307bbaa8b60SDan Kruchinin 1308bbaa8b60SDan Kruchinin /* 1309bbaa8b60SDan Kruchinin * Set local share information for some NFS server. 1310bbaa8b60SDan Kruchinin * 1311bbaa8b60SDan Kruchinin * Called after a share request (set or clear) succeeded. We record 1312bbaa8b60SDan Kruchinin * the details in the local lock manager. Note that since the remote 1313bbaa8b60SDan Kruchinin * server has granted the share, we can be sure that it doesn't 1314bbaa8b60SDan Kruchinin * conflict with any other shares we have in the local lock manager. 1315bbaa8b60SDan Kruchinin * 1316bbaa8b60SDan Kruchinin * Since it is possible that host may also make NLM client requests to 1317bbaa8b60SDan Kruchinin * our NLM server, we use a different sysid value to record our own 1318bbaa8b60SDan Kruchinin * client shares. 1319bbaa8b60SDan Kruchinin */ 1320bbaa8b60SDan Kruchinin int 1321bbaa8b60SDan Kruchinin nlm_local_shrlock(vnode_t *vp, struct shrlock *shr, int cmd, int flags) 1322bbaa8b60SDan Kruchinin { 1323bbaa8b60SDan Kruchinin return (fs_shrlock(vp, cmd, shr, flags, CRED(), NULL)); 1324bbaa8b60SDan Kruchinin } 1325bbaa8b60SDan Kruchinin 1326bbaa8b60SDan Kruchinin static void 1327bbaa8b60SDan Kruchinin nlm_local_shrcancel(vnode_t *vp, struct shrlock *shr) 1328bbaa8b60SDan Kruchinin { 1329bbaa8b60SDan Kruchinin (void) nlm_local_shrlock(vp, shr, F_UNSHARE, FREAD | FWRITE); 1330bbaa8b60SDan Kruchinin nlm_send_siglost(shr->s_pid); 1331bbaa8b60SDan Kruchinin } 1332bbaa8b60SDan Kruchinin 1333bbaa8b60SDan Kruchinin /* 1334bbaa8b60SDan Kruchinin * Do NLM_SHARE call. 1335bbaa8b60SDan Kruchinin * Was: nlm_setshare() 1336bbaa8b60SDan Kruchinin */ 1337bbaa8b60SDan Kruchinin static int 1338bbaa8b60SDan Kruchinin nlm_call_share(struct shrlock *shr, struct nlm_host *host, 1339bbaa8b60SDan Kruchinin struct netobj *fh, int vers, int reclaim) 1340bbaa8b60SDan Kruchinin { 1341bbaa8b60SDan Kruchinin struct nlm4_shareargs args; 1342bbaa8b60SDan Kruchinin enum nlm4_stats nlm_err; 1343bbaa8b60SDan Kruchinin uint32_t xid; 1344bbaa8b60SDan Kruchinin int error; 1345bbaa8b60SDan Kruchinin 1346bbaa8b60SDan Kruchinin bzero(&args, sizeof (args)); 1347bbaa8b60SDan Kruchinin nlm_init_share(&args.share, shr, fh); 1348bbaa8b60SDan Kruchinin 1349bbaa8b60SDan Kruchinin args.reclaim = reclaim; 1350bbaa8b60SDan Kruchinin xid = atomic_inc_32_nv(&nlm_xid); 1351bbaa8b60SDan Kruchinin args.cookie.n_len = sizeof (xid); 1352bbaa8b60SDan Kruchinin args.cookie.n_bytes = (char *)&xid; 1353bbaa8b60SDan Kruchinin 1354bbaa8b60SDan Kruchinin 1355bbaa8b60SDan Kruchinin for (;;) { 1356bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp; 1357bbaa8b60SDan Kruchinin struct nlm4_shareres res; 1358bbaa8b60SDan Kruchinin enum clnt_stat stat; 1359bbaa8b60SDan Kruchinin 1360bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(host, vers, &rpcp); 1361bbaa8b60SDan Kruchinin if (error != 0) 1362bbaa8b60SDan Kruchinin return (ENOLCK); 1363bbaa8b60SDan Kruchinin 1364bbaa8b60SDan Kruchinin bzero(&res, sizeof (res)); 1365bbaa8b60SDan Kruchinin stat = nlm_share_rpc(&args, &res, rpcp->nr_handle, vers); 1366bbaa8b60SDan Kruchinin nlm_host_rele_rpc(host, rpcp); 1367bbaa8b60SDan Kruchinin 1368bbaa8b60SDan Kruchinin error = nlm_map_clnt_stat(stat); 1369bbaa8b60SDan Kruchinin if (error != 0) { 1370bbaa8b60SDan Kruchinin if (error == EAGAIN) 1371bbaa8b60SDan Kruchinin continue; 1372bbaa8b60SDan Kruchinin 1373bbaa8b60SDan Kruchinin return (error); 1374bbaa8b60SDan Kruchinin } 1375bbaa8b60SDan Kruchinin 1376bbaa8b60SDan Kruchinin DTRACE_PROBE1(share__res, enum nlm4_stats, res.stat); 1377bbaa8b60SDan Kruchinin nlm_err = res.stat; 1378bbaa8b60SDan Kruchinin xdr_free((xdrproc_t)xdr_nlm4_shareres, (void *)&res); 1379bbaa8b60SDan Kruchinin if (nlm_err == nlm4_denied_grace_period) { 1380bbaa8b60SDan Kruchinin if (args.reclaim) 1381bbaa8b60SDan Kruchinin return (ENOLCK); 1382bbaa8b60SDan Kruchinin 1383bbaa8b60SDan Kruchinin error = nlm_host_wait_grace(host); 1384bbaa8b60SDan Kruchinin if (error != 0) 1385bbaa8b60SDan Kruchinin return (error); 1386bbaa8b60SDan Kruchinin 1387bbaa8b60SDan Kruchinin continue; 1388bbaa8b60SDan Kruchinin } 1389bbaa8b60SDan Kruchinin 1390bbaa8b60SDan Kruchinin break; 1391bbaa8b60SDan Kruchinin } 1392bbaa8b60SDan Kruchinin 1393bbaa8b60SDan Kruchinin switch (nlm_err) { 1394bbaa8b60SDan Kruchinin case nlm4_granted: 1395bbaa8b60SDan Kruchinin error = 0; 1396bbaa8b60SDan Kruchinin break; 1397bbaa8b60SDan Kruchinin case nlm4_blocked: 1398bbaa8b60SDan Kruchinin case nlm4_denied: 1399bbaa8b60SDan Kruchinin error = EAGAIN; 1400bbaa8b60SDan Kruchinin break; 1401bbaa8b60SDan Kruchinin case nlm4_denied_nolocks: 1402bbaa8b60SDan Kruchinin case nlm4_deadlck: 1403bbaa8b60SDan Kruchinin error = ENOLCK; 1404bbaa8b60SDan Kruchinin break; 1405bbaa8b60SDan Kruchinin default: 1406bbaa8b60SDan Kruchinin error = EINVAL; 1407bbaa8b60SDan Kruchinin break; 1408bbaa8b60SDan Kruchinin } 1409bbaa8b60SDan Kruchinin 1410bbaa8b60SDan Kruchinin return (error); 1411bbaa8b60SDan Kruchinin } 1412bbaa8b60SDan Kruchinin 1413bbaa8b60SDan Kruchinin /* 1414bbaa8b60SDan Kruchinin * Do NLM_UNSHARE call. 1415bbaa8b60SDan Kruchinin */ 1416bbaa8b60SDan Kruchinin static int 1417bbaa8b60SDan Kruchinin nlm_call_unshare(struct shrlock *shr, struct nlm_host *host, 1418bbaa8b60SDan Kruchinin struct netobj *fh, int vers) 1419bbaa8b60SDan Kruchinin { 1420bbaa8b60SDan Kruchinin struct nlm4_shareargs args; 1421bbaa8b60SDan Kruchinin enum nlm4_stats nlm_err; 1422bbaa8b60SDan Kruchinin uint32_t xid; 1423bbaa8b60SDan Kruchinin int error; 1424bbaa8b60SDan Kruchinin 1425bbaa8b60SDan Kruchinin bzero(&args, sizeof (args)); 1426bbaa8b60SDan Kruchinin nlm_init_share(&args.share, shr, fh); 1427bbaa8b60SDan Kruchinin 1428bbaa8b60SDan Kruchinin xid = atomic_inc_32_nv(&nlm_xid); 1429bbaa8b60SDan Kruchinin args.cookie.n_len = sizeof (xid); 1430bbaa8b60SDan Kruchinin args.cookie.n_bytes = (char *)&xid; 1431bbaa8b60SDan Kruchinin 1432bbaa8b60SDan Kruchinin for (;;) { 1433bbaa8b60SDan Kruchinin nlm_rpc_t *rpcp; 1434bbaa8b60SDan Kruchinin struct nlm4_shareres res; 1435bbaa8b60SDan Kruchinin enum clnt_stat stat; 1436bbaa8b60SDan Kruchinin 1437bbaa8b60SDan Kruchinin error = nlm_host_get_rpc(host, vers, &rpcp); 1438bbaa8b60SDan Kruchinin if (error != 0) 1439bbaa8b60SDan Kruchinin return (ENOLCK); 1440bbaa8b60SDan Kruchinin 1441bbaa8b60SDan Kruchinin bzero(&res, sizeof (res)); 1442bbaa8b60SDan Kruchinin stat = nlm_unshare_rpc(&args, &res, rpcp->nr_handle, vers); 1443bbaa8b60SDan Kruchinin nlm_host_rele_rpc(host, rpcp); 1444bbaa8b60SDan Kruchinin 1445bbaa8b60SDan Kruchinin error = nlm_map_clnt_stat(stat); 1446bbaa8b60SDan Kruchinin if (error != 0) { 1447bbaa8b60SDan Kruchinin if (error == EAGAIN) 1448bbaa8b60SDan Kruchinin continue; 1449bbaa8b60SDan Kruchinin 1450bbaa8b60SDan Kruchinin return (error); 1451bbaa8b60SDan Kruchinin } 1452bbaa8b60SDan Kruchinin 1453bbaa8b60SDan Kruchinin DTRACE_PROBE1(unshare__res, enum nlm4_stats, res.stat); 1454bbaa8b60SDan Kruchinin nlm_err = res.stat; 1455bbaa8b60SDan Kruchinin xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res); 1456bbaa8b60SDan Kruchinin if (nlm_err == nlm4_denied_grace_period) { 1457bbaa8b60SDan Kruchinin error = nlm_host_wait_grace(host); 1458bbaa8b60SDan Kruchinin if (error != 0) 1459bbaa8b60SDan Kruchinin return (error); 1460bbaa8b60SDan Kruchinin 1461bbaa8b60SDan Kruchinin continue; 1462bbaa8b60SDan Kruchinin } 1463bbaa8b60SDan Kruchinin 1464bbaa8b60SDan Kruchinin break; 1465bbaa8b60SDan Kruchinin } 1466bbaa8b60SDan Kruchinin 1467bbaa8b60SDan Kruchinin switch (nlm_err) { 1468bbaa8b60SDan Kruchinin case nlm4_granted: 1469bbaa8b60SDan Kruchinin error = 0; 1470bbaa8b60SDan Kruchinin break; 1471bbaa8b60SDan Kruchinin case nlm4_denied: 1472bbaa8b60SDan Kruchinin error = EAGAIN; 1473bbaa8b60SDan Kruchinin break; 1474bbaa8b60SDan Kruchinin case nlm4_denied_nolocks: 1475bbaa8b60SDan Kruchinin error = ENOLCK; 1476bbaa8b60SDan Kruchinin break; 1477bbaa8b60SDan Kruchinin default: 1478bbaa8b60SDan Kruchinin error = EINVAL; 1479bbaa8b60SDan Kruchinin break; 1480bbaa8b60SDan Kruchinin } 1481bbaa8b60SDan Kruchinin 1482bbaa8b60SDan Kruchinin return (error); 1483bbaa8b60SDan Kruchinin } 1484bbaa8b60SDan Kruchinin 1485bbaa8b60SDan Kruchinin static void 1486bbaa8b60SDan Kruchinin nlm_init_share(struct nlm4_share *args, 1487bbaa8b60SDan Kruchinin const struct shrlock *shr, struct netobj *fh) 1488bbaa8b60SDan Kruchinin { 1489bbaa8b60SDan Kruchinin 1490bbaa8b60SDan Kruchinin bzero(args, sizeof (*args)); 1491bbaa8b60SDan Kruchinin 1492bbaa8b60SDan Kruchinin args->caller_name = uts_nodename(); 1493bbaa8b60SDan Kruchinin args->fh.n_len = fh->n_len; 1494bbaa8b60SDan Kruchinin args->fh.n_bytes = fh->n_bytes; 1495bbaa8b60SDan Kruchinin args->oh.n_len = shr->s_own_len; 1496bbaa8b60SDan Kruchinin args->oh.n_bytes = (void *)shr->s_owner; 1497bbaa8b60SDan Kruchinin 1498bbaa8b60SDan Kruchinin switch (shr->s_deny) { 1499bbaa8b60SDan Kruchinin default: 1500bbaa8b60SDan Kruchinin case F_NODNY: 1501bbaa8b60SDan Kruchinin args->mode = fsm_DN; 1502bbaa8b60SDan Kruchinin break; 1503bbaa8b60SDan Kruchinin case F_RDDNY: 1504bbaa8b60SDan Kruchinin args->mode = fsm_DR; 1505bbaa8b60SDan Kruchinin break; 1506bbaa8b60SDan Kruchinin case F_WRDNY: 1507bbaa8b60SDan Kruchinin args->mode = fsm_DW; 1508bbaa8b60SDan Kruchinin break; 1509bbaa8b60SDan Kruchinin case F_RWDNY: 1510bbaa8b60SDan Kruchinin args->mode = fsm_DRW; 1511bbaa8b60SDan Kruchinin break; 1512bbaa8b60SDan Kruchinin } 1513bbaa8b60SDan Kruchinin 1514bbaa8b60SDan Kruchinin switch (shr->s_access) { 1515bbaa8b60SDan Kruchinin default: 1516bbaa8b60SDan Kruchinin case 0: /* seen with F_UNSHARE */ 1517bbaa8b60SDan Kruchinin args->access = fsa_NONE; 1518bbaa8b60SDan Kruchinin break; 1519bbaa8b60SDan Kruchinin case F_RDACC: 1520bbaa8b60SDan Kruchinin args->access = fsa_R; 1521bbaa8b60SDan Kruchinin break; 1522bbaa8b60SDan Kruchinin case F_WRACC: 1523bbaa8b60SDan Kruchinin args->access = fsa_W; 1524bbaa8b60SDan Kruchinin break; 1525bbaa8b60SDan Kruchinin case F_RWACC: 1526bbaa8b60SDan Kruchinin args->access = fsa_RW; 1527bbaa8b60SDan Kruchinin break; 1528bbaa8b60SDan Kruchinin } 1529bbaa8b60SDan Kruchinin } 1530bbaa8b60SDan Kruchinin 1531bbaa8b60SDan Kruchinin /* 1532bbaa8b60SDan Kruchinin * Initialize filehandle according to the version 1533bbaa8b60SDan Kruchinin * of NFS vnode was created on. The version of 1534bbaa8b60SDan Kruchinin * NLM that can be used with given NFS version 1535bbaa8b60SDan Kruchinin * is saved to lm_vers. 1536bbaa8b60SDan Kruchinin */ 1537bbaa8b60SDan Kruchinin static int 1538bbaa8b60SDan Kruchinin nlm_init_fh_by_vp(vnode_t *vp, struct netobj *fh, rpcvers_t *lm_vers) 1539bbaa8b60SDan Kruchinin { 1540bbaa8b60SDan Kruchinin mntinfo_t *mi = VTOMI(vp); 1541bbaa8b60SDan Kruchinin 1542bbaa8b60SDan Kruchinin /* 1543bbaa8b60SDan Kruchinin * Too bad the NFS code doesn't just carry the FH 1544bbaa8b60SDan Kruchinin * in a netobj or a netbuf. 1545bbaa8b60SDan Kruchinin */ 1546bbaa8b60SDan Kruchinin switch (mi->mi_vers) { 1547bbaa8b60SDan Kruchinin case NFS_V3: 1548bbaa8b60SDan Kruchinin /* See nfs3_frlock() */ 1549bbaa8b60SDan Kruchinin *lm_vers = NLM4_VERS; 1550bbaa8b60SDan Kruchinin fh->n_len = VTOFH3(vp)->fh3_length; 1551bbaa8b60SDan Kruchinin fh->n_bytes = (char *)&(VTOFH3(vp)->fh3_u.data); 1552bbaa8b60SDan Kruchinin break; 1553bbaa8b60SDan Kruchinin 1554bbaa8b60SDan Kruchinin case NFS_VERSION: 1555bbaa8b60SDan Kruchinin /* See nfs_frlock() */ 1556bbaa8b60SDan Kruchinin *lm_vers = NLM_VERS; 1557bbaa8b60SDan Kruchinin fh->n_len = sizeof (fhandle_t); 1558bbaa8b60SDan Kruchinin /* LINTED E_BAD_PTR_CAST_ALIGN */ 1559bbaa8b60SDan Kruchinin fh->n_bytes = (char *)VTOFH(vp); 1560bbaa8b60SDan Kruchinin break; 1561bbaa8b60SDan Kruchinin default: 1562bbaa8b60SDan Kruchinin return (ENOSYS); 1563bbaa8b60SDan Kruchinin } 1564bbaa8b60SDan Kruchinin 1565bbaa8b60SDan Kruchinin return (0); 1566bbaa8b60SDan Kruchinin } 1567bbaa8b60SDan Kruchinin 1568bbaa8b60SDan Kruchinin /* 1569bbaa8b60SDan Kruchinin * Send SIGLOST to the process identified by pid. 1570bbaa8b60SDan Kruchinin * NOTE: called when NLM decides to remove lock 1571bbaa8b60SDan Kruchinin * or share reservation ownder by the process 1572bbaa8b60SDan Kruchinin * by force. 1573bbaa8b60SDan Kruchinin */ 1574bbaa8b60SDan Kruchinin static void 1575bbaa8b60SDan Kruchinin nlm_send_siglost(pid_t pid) 1576bbaa8b60SDan Kruchinin { 1577bbaa8b60SDan Kruchinin proc_t *p; 1578bbaa8b60SDan Kruchinin 1579bbaa8b60SDan Kruchinin mutex_enter(&pidlock); 1580bbaa8b60SDan Kruchinin p = prfind(pid); 1581bbaa8b60SDan Kruchinin if (p != NULL) 1582bbaa8b60SDan Kruchinin psignal(p, SIGLOST); 1583bbaa8b60SDan Kruchinin 1584bbaa8b60SDan Kruchinin mutex_exit(&pidlock); 1585bbaa8b60SDan Kruchinin } 1586bbaa8b60SDan Kruchinin 1587bbaa8b60SDan Kruchinin static int 1588bbaa8b60SDan Kruchinin nlm_map_clnt_stat(enum clnt_stat stat) 1589bbaa8b60SDan Kruchinin { 1590bbaa8b60SDan Kruchinin switch (stat) { 1591bbaa8b60SDan Kruchinin case RPC_SUCCESS: 1592bbaa8b60SDan Kruchinin return (0); 1593bbaa8b60SDan Kruchinin 1594bbaa8b60SDan Kruchinin case RPC_TIMEDOUT: 1595bbaa8b60SDan Kruchinin case RPC_PROGUNAVAIL: 1596bbaa8b60SDan Kruchinin return (EAGAIN); 1597bbaa8b60SDan Kruchinin 1598bbaa8b60SDan Kruchinin case RPC_INTR: 1599bbaa8b60SDan Kruchinin return (EINTR); 1600bbaa8b60SDan Kruchinin 1601bbaa8b60SDan Kruchinin default: 1602bbaa8b60SDan Kruchinin return (EINVAL); 1603bbaa8b60SDan Kruchinin } 1604bbaa8b60SDan Kruchinin } 1605bbaa8b60SDan Kruchinin 1606bbaa8b60SDan Kruchinin static int 1607bbaa8b60SDan Kruchinin nlm_map_status(enum nlm4_stats stat) 1608bbaa8b60SDan Kruchinin { 1609bbaa8b60SDan Kruchinin switch (stat) { 1610bbaa8b60SDan Kruchinin case nlm4_granted: 1611bbaa8b60SDan Kruchinin return (0); 1612bbaa8b60SDan Kruchinin 1613bbaa8b60SDan Kruchinin case nlm4_denied: 1614bbaa8b60SDan Kruchinin return (EAGAIN); 1615bbaa8b60SDan Kruchinin 1616bbaa8b60SDan Kruchinin case nlm4_denied_nolocks: 1617bbaa8b60SDan Kruchinin return (ENOLCK); 1618bbaa8b60SDan Kruchinin 1619bbaa8b60SDan Kruchinin case nlm4_blocked: 1620bbaa8b60SDan Kruchinin return (EAGAIN); 1621bbaa8b60SDan Kruchinin 1622bbaa8b60SDan Kruchinin case nlm4_denied_grace_period: 1623bbaa8b60SDan Kruchinin return (EAGAIN); 1624bbaa8b60SDan Kruchinin 1625bbaa8b60SDan Kruchinin case nlm4_deadlck: 1626bbaa8b60SDan Kruchinin return (EDEADLK); 1627bbaa8b60SDan Kruchinin 1628bbaa8b60SDan Kruchinin case nlm4_rofs: 1629bbaa8b60SDan Kruchinin return (EROFS); 1630bbaa8b60SDan Kruchinin 1631bbaa8b60SDan Kruchinin case nlm4_stale_fh: 1632bbaa8b60SDan Kruchinin return (ESTALE); 1633bbaa8b60SDan Kruchinin 1634bbaa8b60SDan Kruchinin case nlm4_fbig: 1635bbaa8b60SDan Kruchinin return (EFBIG); 1636bbaa8b60SDan Kruchinin 1637bbaa8b60SDan Kruchinin case nlm4_failed: 1638bbaa8b60SDan Kruchinin return (EACCES); 1639bbaa8b60SDan Kruchinin 1640bbaa8b60SDan Kruchinin default: 1641bbaa8b60SDan Kruchinin return (EINVAL); 1642bbaa8b60SDan Kruchinin } 1643bbaa8b60SDan Kruchinin } 1644