17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5df2381bfSpraks  * Common Development and Distribution License (the "License").
6df2381bfSpraks  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d216dff5SRobert Mastors  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*54207fd2SJerry Jelinek  * Copyright 2015 Joyent, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/systm.h>
287c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
297c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
307c478bd9Sstevel@tonic-gate #include <nfs/nfs4_kprot.h>
317c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/mutex.h>
347c478bd9Sstevel@tonic-gate #include <sys/condvar.h>
357c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
367c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
377c478bd9Sstevel@tonic-gate #include <sys/time.h>
387c478bd9Sstevel@tonic-gate #include <sys/fem.h>
397c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate extern u_longlong_t nfs4_srv_caller_id;
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate  * This file contains the code for the monitors which are placed on the vnodes
467c478bd9Sstevel@tonic-gate  * of files that are granted delegations by the nfsV4 server.  These monitors
47cfae96c2Sjwahlig  * will detect local access, as well as access from other servers
48cfae96c2Sjwahlig  * (NFS and CIFS), that conflict with the delegations and recall the
497c478bd9Sstevel@tonic-gate  * delegation from the client before letting the offending operation continue.
50cfae96c2Sjwahlig  *
51cfae96c2Sjwahlig  * If the caller does not want to block while waiting for the delegation to
52cfae96c2Sjwahlig  * be returned, then it should set CC_DONTBLOCK in the flags of caller context.
53cfae96c2Sjwahlig  * This does not work for vnevnents; remove and rename, they always block.
54cfae96c2Sjwahlig  */
55cfae96c2Sjwahlig 
56cfae96c2Sjwahlig /*
57cfae96c2Sjwahlig  * This is the function to recall a delegation.  It will check if the caller
58cfae96c2Sjwahlig  * wishes to block or not while waiting for the delegation to be returned.
59cfae96c2Sjwahlig  * If the caller context flag has CC_DONTBLOCK set, then it will return
60cfae96c2Sjwahlig  * an error and set CC_WOULDBLOCK instead of waiting for the delegation.
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate 
63cfae96c2Sjwahlig int
recall_all_delegations(rfs4_file_t * fp,bool_t trunc,caller_context_t * ct)64d216dff5SRobert Mastors recall_all_delegations(rfs4_file_t *fp, bool_t trunc, caller_context_t *ct)
65cfae96c2Sjwahlig {
66cfae96c2Sjwahlig 	clock_t rc;
67cfae96c2Sjwahlig 
68cfae96c2Sjwahlig 	rfs4_recall_deleg(fp, trunc, NULL);
69cfae96c2Sjwahlig 
70cfae96c2Sjwahlig 	/* optimization that may not stay */
71cfae96c2Sjwahlig 	delay(NFS4_DELEGATION_CONFLICT_DELAY);
72cfae96c2Sjwahlig 
73cfae96c2Sjwahlig 	/* if it has been returned, we're done. */
74d216dff5SRobert Mastors 	rfs4_dbe_lock(fp->rf_dbe);
75d216dff5SRobert Mastors 	if (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) {
76d216dff5SRobert Mastors 		rfs4_dbe_unlock(fp->rf_dbe);
77cfae96c2Sjwahlig 		return (0);
78cfae96c2Sjwahlig 	}
79cfae96c2Sjwahlig 
807e60cf9bSjwahlig 	if (ct != NULL && ct->cc_flags & CC_DONTBLOCK) {
81d216dff5SRobert Mastors 		rfs4_dbe_unlock(fp->rf_dbe);
82cfae96c2Sjwahlig 		ct->cc_flags |= CC_WOULDBLOCK;
83cfae96c2Sjwahlig 		return (NFS4ERR_DELAY);
84cfae96c2Sjwahlig 	}
85cfae96c2Sjwahlig 
86d216dff5SRobert Mastors 	while (fp->rf_dinfo.rd_dtype != OPEN_DELEGATE_NONE) {
87d216dff5SRobert Mastors 		rc = rfs4_dbe_twait(fp->rf_dbe,
88d3d50737SRafael Vanoni 		    ddi_get_lbolt() + SEC_TO_TICK(rfs4_lease_time));
89cfae96c2Sjwahlig 		if (rc == -1) { /* timed out */
90d216dff5SRobert Mastors 			rfs4_dbe_unlock(fp->rf_dbe);
91cfae96c2Sjwahlig 			rfs4_recall_deleg(fp, trunc, NULL);
92d216dff5SRobert Mastors 			rfs4_dbe_lock(fp->rf_dbe);
93cfae96c2Sjwahlig 		}
94cfae96c2Sjwahlig 	}
95d216dff5SRobert Mastors 	rfs4_dbe_unlock(fp->rf_dbe);
96cfae96c2Sjwahlig 
97cfae96c2Sjwahlig 	return (0);
98cfae96c2Sjwahlig }
99cfae96c2Sjwahlig 
1007c478bd9Sstevel@tonic-gate /* monitor for open on read delegated file */
1017c478bd9Sstevel@tonic-gate int
deleg_rd_open(femarg_t * arg,int mode,cred_t * cr,caller_context_t * ct)102d216dff5SRobert Mastors deleg_rd_open(femarg_t *arg, int mode, cred_t *cr, caller_context_t *ct)
1037c478bd9Sstevel@tonic-gate {
104cfae96c2Sjwahlig 	int rc;
1057c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/*
108da6c28aaSamw 	 * Now that the NFSv4 server calls VOP_OPEN, we need to check to
109da6c28aaSamw 	 * to make sure it is not us calling open (like for DELEG_CUR) or
110da6c28aaSamw 	 * we will end up panicing the system.
1117c478bd9Sstevel@tonic-gate 	 * Since this monitor is for a read delegated file, we know that
1127c478bd9Sstevel@tonic-gate 	 * only an open for write will cause a conflict.
1137c478bd9Sstevel@tonic-gate 	 */
114da6c28aaSamw 	if ((ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) &&
115da6c28aaSamw 	    (mode & (FWRITE|FTRUNC))) {
1167c478bd9Sstevel@tonic-gate 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
117cfae96c2Sjwahlig 		rc = recall_all_delegations(fp, FALSE, ct);
118cfae96c2Sjwahlig 		if (rc == NFS4ERR_DELAY)
119cfae96c2Sjwahlig 			return (EAGAIN);
1207c478bd9Sstevel@tonic-gate 	}
1217c478bd9Sstevel@tonic-gate 
122da6c28aaSamw 	return (vnext_open(arg, mode, cr, ct));
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /* monitor for open on write delegated file */
1267c478bd9Sstevel@tonic-gate int
deleg_wr_open(femarg_t * arg,int mode,cred_t * cr,caller_context_t * ct)127d216dff5SRobert Mastors deleg_wr_open(femarg_t *arg, int mode, cred_t *cr, caller_context_t *ct)
1287c478bd9Sstevel@tonic-gate {
129cfae96c2Sjwahlig 	int rc;
1307c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	/*
133da6c28aaSamw 	 * Now that the NFSv4 server calls VOP_OPEN, we need to check to
134da6c28aaSamw 	 * to make sure it is not us calling open (like for DELEG_CUR) or
135da6c28aaSamw 	 * we will end up panicing the system.
1367c478bd9Sstevel@tonic-gate 	 * Since this monitor is for a write delegated file, we know that
1377c478bd9Sstevel@tonic-gate 	 * any open will cause a conflict.
1387c478bd9Sstevel@tonic-gate 	 */
139da6c28aaSamw 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
140da6c28aaSamw 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
141cfae96c2Sjwahlig 		rc = recall_all_delegations(fp, FALSE, ct);
142cfae96c2Sjwahlig 		if (rc == NFS4ERR_DELAY)
143cfae96c2Sjwahlig 			return (EAGAIN);
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 
146da6c28aaSamw 	return (vnext_open(arg, mode, cr, ct));
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
150cfae96c2Sjwahlig  * This is op is for write delegations only and should only be hit
151cfae96c2Sjwahlig  * by the owner of the delegation.  If not, then someone is
152cfae96c2Sjwahlig  * doing a read without doing an open first. Like from nfs2/3.
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate int
deleg_wr_read(femarg_t * arg,uio_t * uiop,int ioflag,cred_t * cr,struct caller_context * ct)155d216dff5SRobert Mastors deleg_wr_read(femarg_t *arg, uio_t *uiop, int ioflag, cred_t *cr,
156d216dff5SRobert Mastors     struct caller_context *ct)
1577c478bd9Sstevel@tonic-gate {
158cfae96c2Sjwahlig 	int rc;
1597c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
1607c478bd9Sstevel@tonic-gate 
161cfae96c2Sjwahlig 	/* Use caller context to compare caller to delegation owner */
1627c478bd9Sstevel@tonic-gate 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
1637c478bd9Sstevel@tonic-gate 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
164cfae96c2Sjwahlig 		rc = recall_all_delegations(fp, FALSE, ct);
165cfae96c2Sjwahlig 		if (rc == NFS4ERR_DELAY)
166cfae96c2Sjwahlig 			return (EAGAIN);
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 	return (vnext_read(arg, uiop, ioflag, cr, ct));
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*
172cfae96c2Sjwahlig  * If someone is doing a write on a read delegated file, it is a conflict.
173cfae96c2Sjwahlig  * conflicts should be caught at open, but NFSv2&3 don't use OPEN.
1747c478bd9Sstevel@tonic-gate  */
1757c478bd9Sstevel@tonic-gate int
deleg_rd_write(femarg_t * arg,uio_t * uiop,int ioflag,cred_t * cr,struct caller_context * ct)176d216dff5SRobert Mastors deleg_rd_write(femarg_t *arg, uio_t *uiop, int ioflag, cred_t *cr,
177d216dff5SRobert Mastors     struct caller_context *ct)
1787c478bd9Sstevel@tonic-gate {
179cfae96c2Sjwahlig 	int rc;
180cfae96c2Sjwahlig 	rfs4_file_t *fp;
181cfae96c2Sjwahlig 
182cfae96c2Sjwahlig 	fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
183cfae96c2Sjwahlig 	rc = recall_all_delegations(fp, FALSE, ct);
184cfae96c2Sjwahlig 	if (rc == NFS4ERR_DELAY)
185cfae96c2Sjwahlig 		return (EAGAIN);
186cfae96c2Sjwahlig 
187cfae96c2Sjwahlig 	return (vnext_write(arg, uiop, ioflag, cr, ct));
188cfae96c2Sjwahlig }
189cfae96c2Sjwahlig 
190cfae96c2Sjwahlig /*
191cfae96c2Sjwahlig  * The owner of the delegation can write the file, but nobody else can.
192cfae96c2Sjwahlig  * Conflicts should be caught at open, but NFSv2&3 don't use OPEN.
193cfae96c2Sjwahlig  */
194cfae96c2Sjwahlig int
deleg_wr_write(femarg_t * arg,uio_t * uiop,int ioflag,cred_t * cr,struct caller_context * ct)195d216dff5SRobert Mastors deleg_wr_write(femarg_t *arg, uio_t *uiop, int ioflag, cred_t *cr,
196d216dff5SRobert Mastors     struct caller_context *ct)
197cfae96c2Sjwahlig {
198cfae96c2Sjwahlig 	int rc;
1997c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
2007c478bd9Sstevel@tonic-gate 
201cfae96c2Sjwahlig 	/* Use caller context to compare caller to delegation owner */
2027c478bd9Sstevel@tonic-gate 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
2037c478bd9Sstevel@tonic-gate 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
204cfae96c2Sjwahlig 		rc = recall_all_delegations(fp, FALSE, ct);
205cfae96c2Sjwahlig 		if (rc == NFS4ERR_DELAY)
206cfae96c2Sjwahlig 			return (EAGAIN);
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 	return (vnext_write(arg, uiop, ioflag, cr, ct));
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
211cfae96c2Sjwahlig /* Doing a setattr on a read delegated file is a conflict. */
212cfae96c2Sjwahlig int
deleg_rd_setattr(femarg_t * arg,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)213d216dff5SRobert Mastors deleg_rd_setattr(femarg_t *arg, vattr_t *vap, int flags, cred_t *cr,
214d216dff5SRobert Mastors     caller_context_t *ct)
215cfae96c2Sjwahlig {
216cfae96c2Sjwahlig 	int rc;
217cfae96c2Sjwahlig 	bool_t trunc = FALSE;
218cfae96c2Sjwahlig 	rfs4_file_t *fp;
219cfae96c2Sjwahlig 
220cfae96c2Sjwahlig 	if ((vap->va_mask & AT_SIZE) && (vap->va_size == 0))
221cfae96c2Sjwahlig 		trunc = TRUE;
2227c478bd9Sstevel@tonic-gate 
223cfae96c2Sjwahlig 	fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
224cfae96c2Sjwahlig 	rc = recall_all_delegations(fp, trunc, ct);
225cfae96c2Sjwahlig 	if (rc == NFS4ERR_DELAY)
226cfae96c2Sjwahlig 		return (EAGAIN);
227cfae96c2Sjwahlig 
228cfae96c2Sjwahlig 	return (vnext_setattr(arg, vap, flags, cr, ct));
229cfae96c2Sjwahlig }
230cfae96c2Sjwahlig 
231cfae96c2Sjwahlig /* Only the owner of the write delegation can do a setattr */
2327c478bd9Sstevel@tonic-gate int
deleg_wr_setattr(femarg_t * arg,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)233d216dff5SRobert Mastors deleg_wr_setattr(femarg_t *arg, vattr_t *vap, int flags, cred_t *cr,
234d216dff5SRobert Mastors     caller_context_t *ct)
2357c478bd9Sstevel@tonic-gate {
236cfae96c2Sjwahlig 	int rc;
237cfae96c2Sjwahlig 	bool_t trunc = FALSE;
2387c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	/*
241cfae96c2Sjwahlig 	 * Use caller context to compare caller to delegation owner
2427c478bd9Sstevel@tonic-gate 	 */
24345100b72Sjwahlig 	if (ct == NULL || (ct->cc_caller_id != nfs4_srv_caller_id)) {
244cfae96c2Sjwahlig 		if ((vap->va_mask & AT_SIZE) && (vap->va_size == 0))
245cfae96c2Sjwahlig 			trunc = TRUE;
246cfae96c2Sjwahlig 
2477c478bd9Sstevel@tonic-gate 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
248cfae96c2Sjwahlig 		rc = recall_all_delegations(fp, trunc, ct);
249cfae96c2Sjwahlig 		if (rc == NFS4ERR_DELAY)
250cfae96c2Sjwahlig 			return (EAGAIN);
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	return (vnext_setattr(arg, vap, flags, cr, ct));
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate int
deleg_rd_rwlock(femarg_t * arg,int write_lock,caller_context_t * ct)257d216dff5SRobert Mastors deleg_rd_rwlock(femarg_t *arg, int write_lock, caller_context_t *ct)
2587c478bd9Sstevel@tonic-gate {
259cfae96c2Sjwahlig 	int rc;
2607c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	/*
263cfae96c2Sjwahlig 	 * If this is a write lock, then we got us a conflict.
2647c478bd9Sstevel@tonic-gate 	 */
265cfae96c2Sjwahlig 	if (write_lock) {
2667c478bd9Sstevel@tonic-gate 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
267cfae96c2Sjwahlig 		rc = recall_all_delegations(fp, FALSE, ct);
268cfae96c2Sjwahlig 		if (rc == NFS4ERR_DELAY)
269cfae96c2Sjwahlig 			return (EAGAIN);
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	return (vnext_rwlock(arg, write_lock, ct));
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
275cfae96c2Sjwahlig /* Only the owner of the write delegation should be doing this. */
2767c478bd9Sstevel@tonic-gate int
deleg_wr_rwlock(femarg_t * arg,int write_lock,caller_context_t * ct)277d216dff5SRobert Mastors deleg_wr_rwlock(femarg_t *arg, int write_lock, caller_context_t *ct)
2787c478bd9Sstevel@tonic-gate {
279cfae96c2Sjwahlig 	int rc;
2807c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
2817c478bd9Sstevel@tonic-gate 
282cfae96c2Sjwahlig 	/* Use caller context to compare caller to delegation owner */
2837c478bd9Sstevel@tonic-gate 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
2847c478bd9Sstevel@tonic-gate 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
285cfae96c2Sjwahlig 		rc = recall_all_delegations(fp, FALSE, ct);
286cfae96c2Sjwahlig 		if (rc == NFS4ERR_DELAY)
287cfae96c2Sjwahlig 			return (EAGAIN);
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	return (vnext_rwlock(arg, write_lock, ct));
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate int
deleg_rd_space(femarg_t * arg,int cmd,flock64_t * bfp,int flag,offset_t offset,cred_t * cr,caller_context_t * ct)294d216dff5SRobert Mastors deleg_rd_space(femarg_t *arg, int cmd, flock64_t *bfp, int flag,
295d216dff5SRobert Mastors     offset_t offset, cred_t *cr, caller_context_t *ct)
2967c478bd9Sstevel@tonic-gate {
297cfae96c2Sjwahlig 	int rc;
298cfae96c2Sjwahlig 	rfs4_file_t *fp;
299cfae96c2Sjwahlig 
300cfae96c2Sjwahlig 	fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
301cfae96c2Sjwahlig 	rc = recall_all_delegations(fp, FALSE, ct);
302cfae96c2Sjwahlig 	if (rc == NFS4ERR_DELAY)
303cfae96c2Sjwahlig 		return (EAGAIN);
304cfae96c2Sjwahlig 
305cfae96c2Sjwahlig 	return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct));
306cfae96c2Sjwahlig }
307cfae96c2Sjwahlig 
308cfae96c2Sjwahlig int
deleg_wr_space(femarg_t * arg,int cmd,flock64_t * bfp,int flag,offset_t offset,cred_t * cr,caller_context_t * ct)309d216dff5SRobert Mastors deleg_wr_space(femarg_t *arg, int cmd, flock64_t *bfp, int flag,
310d216dff5SRobert Mastors     offset_t offset, cred_t *cr, caller_context_t *ct)
311cfae96c2Sjwahlig {
312cfae96c2Sjwahlig 	int rc;
3137c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
3147c478bd9Sstevel@tonic-gate 
315cfae96c2Sjwahlig 	/* Use caller context to compare caller to delegation owner */
3167c478bd9Sstevel@tonic-gate 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
3177c478bd9Sstevel@tonic-gate 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
318cfae96c2Sjwahlig 		rc = recall_all_delegations(fp, FALSE, ct);
319cfae96c2Sjwahlig 		if (rc == NFS4ERR_DELAY)
320cfae96c2Sjwahlig 			return (EAGAIN);
3217c478bd9Sstevel@tonic-gate 	}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct));
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate int
deleg_rd_setsecattr(femarg_t * arg,vsecattr_t * vsap,int flag,cred_t * cr,caller_context_t * ct)327d216dff5SRobert Mastors deleg_rd_setsecattr(femarg_t *arg, vsecattr_t *vsap, int flag, cred_t *cr,
328d216dff5SRobert Mastors     caller_context_t *ct)
3297c478bd9Sstevel@tonic-gate {
330cfae96c2Sjwahlig 	int rc;
3317c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
3347c478bd9Sstevel@tonic-gate 
335cfae96c2Sjwahlig 	/* Changing security attribute triggers recall */
336cfae96c2Sjwahlig 	rc = recall_all_delegations(fp, FALSE, ct);
337cfae96c2Sjwahlig 	if (rc == NFS4ERR_DELAY)
338cfae96c2Sjwahlig 		return (EAGAIN);
339cfae96c2Sjwahlig 
340cfae96c2Sjwahlig 	return (vnext_setsecattr(arg, vsap, flag, cr, ct));
341cfae96c2Sjwahlig }
342cfae96c2Sjwahlig 
343cfae96c2Sjwahlig int
deleg_wr_setsecattr(femarg_t * arg,vsecattr_t * vsap,int flag,cred_t * cr,caller_context_t * ct)344d216dff5SRobert Mastors deleg_wr_setsecattr(femarg_t *arg, vsecattr_t *vsap, int flag, cred_t *cr,
345d216dff5SRobert Mastors     caller_context_t *ct)
346cfae96c2Sjwahlig {
347cfae96c2Sjwahlig 	int rc;
348cfae96c2Sjwahlig 	rfs4_file_t *fp;
349cfae96c2Sjwahlig 
350cfae96c2Sjwahlig 	fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
351cfae96c2Sjwahlig 
352cfae96c2Sjwahlig 	/* Changing security attribute triggers recall */
353cfae96c2Sjwahlig 	rc = recall_all_delegations(fp, FALSE, ct);
354cfae96c2Sjwahlig 	if (rc == NFS4ERR_DELAY)
355cfae96c2Sjwahlig 		return (EAGAIN);
3567c478bd9Sstevel@tonic-gate 
357da6c28aaSamw 	return (vnext_setsecattr(arg, vsap, flag, cr, ct));
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate int
deleg_rd_vnevent(femarg_t * arg,vnevent_t vnevent,vnode_t * dvp,char * name,caller_context_t * ct)361d216dff5SRobert Mastors deleg_rd_vnevent(femarg_t *arg, vnevent_t vnevent, vnode_t *dvp, char *name,
362d216dff5SRobert Mastors     caller_context_t *ct)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	clock_t rc;
3657c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
3667c478bd9Sstevel@tonic-gate 	bool_t trunc = FALSE;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	switch (vnevent) {
3697c478bd9Sstevel@tonic-gate 	case VE_REMOVE:
370*54207fd2SJerry Jelinek 	case VE_PRE_RENAME_DEST:
3717c478bd9Sstevel@tonic-gate 	case VE_RENAME_DEST:
3727c478bd9Sstevel@tonic-gate 		trunc = TRUE;
3737c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
3747c478bd9Sstevel@tonic-gate 
375*54207fd2SJerry Jelinek 	case VE_PRE_RENAME_SRC:
3767c478bd9Sstevel@tonic-gate 	case VE_RENAME_SRC:
3777c478bd9Sstevel@tonic-gate 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
3787c478bd9Sstevel@tonic-gate 		rfs4_recall_deleg(fp, trunc, NULL);
379cfae96c2Sjwahlig 
380d216dff5SRobert Mastors 		rfs4_dbe_lock(fp->rf_dbe);
381d216dff5SRobert Mastors 		while (fp->rf_dinfo.rd_dtype != OPEN_DELEGATE_NONE) {
382d216dff5SRobert Mastors 			rc = rfs4_dbe_twait(fp->rf_dbe,
383d3d50737SRafael Vanoni 			    ddi_get_lbolt() + SEC_TO_TICK(rfs4_lease_time));
3847c478bd9Sstevel@tonic-gate 			if (rc == -1) { /* timed out */
385d216dff5SRobert Mastors 				rfs4_dbe_unlock(fp->rf_dbe);
3867c478bd9Sstevel@tonic-gate 				rfs4_recall_deleg(fp, trunc, NULL);
387d216dff5SRobert Mastors 				rfs4_dbe_lock(fp->rf_dbe);
3887c478bd9Sstevel@tonic-gate 			}
3897c478bd9Sstevel@tonic-gate 		}
390d216dff5SRobert Mastors 		rfs4_dbe_unlock(fp->rf_dbe);
391cfae96c2Sjwahlig 
392cfae96c2Sjwahlig 		break;
393cfae96c2Sjwahlig 
394cfae96c2Sjwahlig 	default:
395cfae96c2Sjwahlig 		break;
396cfae96c2Sjwahlig 	}
397cfae96c2Sjwahlig 	return (vnext_vnevent(arg, vnevent, dvp, name, ct));
398cfae96c2Sjwahlig }
399cfae96c2Sjwahlig 
400cfae96c2Sjwahlig int
deleg_wr_vnevent(femarg_t * arg,vnevent_t vnevent,vnode_t * dvp,char * name,caller_context_t * ct)401d216dff5SRobert Mastors deleg_wr_vnevent(femarg_t *arg, vnevent_t vnevent, vnode_t *dvp, char *name,
402d216dff5SRobert Mastors     caller_context_t *ct)
403cfae96c2Sjwahlig {
404cfae96c2Sjwahlig 	clock_t rc;
405cfae96c2Sjwahlig 	rfs4_file_t *fp;
406cfae96c2Sjwahlig 	bool_t trunc = FALSE;
407cfae96c2Sjwahlig 
408cfae96c2Sjwahlig 	switch (vnevent) {
409cfae96c2Sjwahlig 	case VE_REMOVE:
410*54207fd2SJerry Jelinek 	case VE_PRE_RENAME_DEST:
411cfae96c2Sjwahlig 	case VE_RENAME_DEST:
412cfae96c2Sjwahlig 		trunc = TRUE;
413cfae96c2Sjwahlig 		/*FALLTHROUGH*/
414cfae96c2Sjwahlig 
415*54207fd2SJerry Jelinek 	case VE_PRE_RENAME_SRC:
416cfae96c2Sjwahlig 	case VE_RENAME_SRC:
417cfae96c2Sjwahlig 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
418cfae96c2Sjwahlig 		rfs4_recall_deleg(fp, trunc, NULL);
419d216dff5SRobert Mastors 		rfs4_dbe_lock(fp->rf_dbe);
420d216dff5SRobert Mastors 		while (fp->rf_dinfo.rd_dtype != OPEN_DELEGATE_NONE) {
421d216dff5SRobert Mastors 			rc = rfs4_dbe_twait(fp->rf_dbe,
422d3d50737SRafael Vanoni 			    ddi_get_lbolt() + SEC_TO_TICK(rfs4_lease_time));
423cfae96c2Sjwahlig 			if (rc == -1) { /* timed out */
424d216dff5SRobert Mastors 				rfs4_dbe_unlock(fp->rf_dbe);
425cfae96c2Sjwahlig 				rfs4_recall_deleg(fp, trunc, NULL);
426d216dff5SRobert Mastors 				rfs4_dbe_lock(fp->rf_dbe);
427cfae96c2Sjwahlig 			}
428cfae96c2Sjwahlig 		}
429d216dff5SRobert Mastors 		rfs4_dbe_unlock(fp->rf_dbe);
430cfae96c2Sjwahlig 
4317c478bd9Sstevel@tonic-gate 		break;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	default:
4347c478bd9Sstevel@tonic-gate 		break;
4357c478bd9Sstevel@tonic-gate 	}
436da6c28aaSamw 	return (vnext_vnevent(arg, vnevent, dvp, name, ct));
4377c478bd9Sstevel@tonic-gate }
438