4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2015 Joyent, Inc.
27 #include <sys/systm.h>
30 #include <nfs/nfs4_kprot.h>
32 #include <sys/types.h>
33 #include <sys/mutex.h>
34 #include <sys/condvar.h>
36 #include <sys/vnode.h>
39 #include <sys/cmn_err.h>
42 extern u_longlong_t nfs4_srv_caller_id
;
45 * This file contains the code for the monitors which are placed on the vnodes
46 * of files that are granted delegations by the nfsV4 server. These monitors
47 * will detect local access, as well as access from other servers
48 * (NFS and CIFS), that conflict with the delegations and recall the
49 * delegation from the client before letting the offending operation continue.
51 * If the caller does not want to block while waiting for the delegation to
52 * be returned, then it should set CC_DONTBLOCK in the flags of caller context.
53 * This does not work for vnevnents; remove and rename, they always block.
57 * This is the function to recall a delegation. It will check if the caller
58 * wishes to block or not while waiting for the delegation to be returned.
59 * If the caller context flag has CC_DONTBLOCK set, then it will return
60 * an error and set CC_WOULDBLOCK instead of waiting for the delegation.
64 recall_all_delegations(rfs4_file_t
*fp
, bool_t trunc
, caller_context_t
*ct
)
68 rfs4_recall_deleg(fp
, trunc
, NULL
);
70 /* optimization that may not stay */
71 delay(NFS4_DELEGATION_CONFLICT_DELAY
);
73 /* if it has been returned, we're done. */
74 rfs4_dbe_lock(fp
->rf_dbe
);
75 if (fp
->rf_dinfo
.rd_dtype
== OPEN_DELEGATE_NONE
) {
76 rfs4_dbe_unlock(fp
->rf_dbe
);
80 if (ct
!= NULL
&& ct
->cc_flags
& CC_DONTBLOCK
) {
81 rfs4_dbe_unlock(fp
->rf_dbe
);
82 ct
->cc_flags
|= CC_WOULDBLOCK
;
83 return (NFS4ERR_DELAY
);
86 while (fp
->rf_dinfo
.rd_dtype
!= OPEN_DELEGATE_NONE
) {
87 rc
= rfs4_dbe_twait(fp
->rf_dbe
,
88 ddi_get_lbolt() + SEC_TO_TICK(rfs4_lease_time
));
89 if (rc
== -1) { /* timed out */
90 rfs4_dbe_unlock(fp
->rf_dbe
);
91 rfs4_recall_deleg(fp
, trunc
, NULL
);
92 rfs4_dbe_lock(fp
->rf_dbe
);
95 rfs4_dbe_unlock(fp
->rf_dbe
);
100 /* monitor for open on read delegated file */
102 deleg_rd_open(femarg_t
*arg
, int mode
, cred_t
*cr
, caller_context_t
*ct
)
108 * Now that the NFSv4 server calls fop_open, we need to check to
109 * to make sure it is not us calling open (like for DELEG_CUR) or
110 * we will end up panicing the system.
111 * Since this monitor is for a read delegated file, we know that
112 * only an open for write will cause a conflict.
114 if ((ct
== NULL
|| ct
->cc_caller_id
!= nfs4_srv_caller_id
) &&
115 (mode
& (FWRITE
|FTRUNC
))) {
116 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
117 rc
= recall_all_delegations(fp
, FALSE
, ct
);
118 if (rc
== NFS4ERR_DELAY
)
122 return (vnext_open(arg
, mode
, cr
, ct
));
125 /* monitor for open on write delegated file */
127 deleg_wr_open(femarg_t
*arg
, int mode
, cred_t
*cr
, caller_context_t
*ct
)
133 * Now that the NFSv4 server calls fop_open, we need to check to
134 * to make sure it is not us calling open (like for DELEG_CUR) or
135 * we will end up panicing the system.
136 * Since this monitor is for a write delegated file, we know that
137 * any open will cause a conflict.
139 if (ct
== NULL
|| ct
->cc_caller_id
!= nfs4_srv_caller_id
) {
140 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
141 rc
= recall_all_delegations(fp
, FALSE
, ct
);
142 if (rc
== NFS4ERR_DELAY
)
146 return (vnext_open(arg
, mode
, cr
, ct
));
150 * This is op is for write delegations only and should only be hit
151 * by the owner of the delegation. If not, then someone is
152 * doing a read without doing an open first. Like from nfs2/3.
155 deleg_wr_read(femarg_t
*arg
, uio_t
*uiop
, int ioflag
, cred_t
*cr
,
156 struct caller_context
*ct
)
161 /* Use caller context to compare caller to delegation owner */
162 if (ct
== NULL
|| ct
->cc_caller_id
!= nfs4_srv_caller_id
) {
163 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
164 rc
= recall_all_delegations(fp
, FALSE
, ct
);
165 if (rc
== NFS4ERR_DELAY
)
168 return (vnext_read(arg
, uiop
, ioflag
, cr
, ct
));
172 * If someone is doing a write on a read delegated file, it is a conflict.
173 * conflicts should be caught at open, but NFSv2&3 don't use OPEN.
176 deleg_rd_write(femarg_t
*arg
, uio_t
*uiop
, int ioflag
, cred_t
*cr
,
177 struct caller_context
*ct
)
182 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
183 rc
= recall_all_delegations(fp
, FALSE
, ct
);
184 if (rc
== NFS4ERR_DELAY
)
187 return (vnext_write(arg
, uiop
, ioflag
, cr
, ct
));
191 * The owner of the delegation can write the file, but nobody else can.
192 * Conflicts should be caught at open, but NFSv2&3 don't use OPEN.
195 deleg_wr_write(femarg_t
*arg
, uio_t
*uiop
, int ioflag
, cred_t
*cr
,
196 struct caller_context
*ct
)
201 /* Use caller context to compare caller to delegation owner */
202 if (ct
== NULL
|| ct
->cc_caller_id
!= nfs4_srv_caller_id
) {
203 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
204 rc
= recall_all_delegations(fp
, FALSE
, ct
);
205 if (rc
== NFS4ERR_DELAY
)
208 return (vnext_write(arg
, uiop
, ioflag
, cr
, ct
));
211 /* Doing a setattr on a read delegated file is a conflict. */
213 deleg_rd_setattr(femarg_t
*arg
, vattr_t
*vap
, int flags
, cred_t
*cr
,
214 caller_context_t
*ct
)
217 bool_t trunc
= FALSE
;
220 if ((vap
->va_mask
& AT_SIZE
) && (vap
->va_size
== 0))
223 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
224 rc
= recall_all_delegations(fp
, trunc
, ct
);
225 if (rc
== NFS4ERR_DELAY
)
228 return (vnext_setattr(arg
, vap
, flags
, cr
, ct
));
231 /* Only the owner of the write delegation can do a setattr */
233 deleg_wr_setattr(femarg_t
*arg
, vattr_t
*vap
, int flags
, cred_t
*cr
,
234 caller_context_t
*ct
)
237 bool_t trunc
= FALSE
;
241 * Use caller context to compare caller to delegation owner
243 if (ct
== NULL
|| (ct
->cc_caller_id
!= nfs4_srv_caller_id
)) {
244 if ((vap
->va_mask
& AT_SIZE
) && (vap
->va_size
== 0))
247 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
248 rc
= recall_all_delegations(fp
, trunc
, ct
);
249 if (rc
== NFS4ERR_DELAY
)
253 return (vnext_setattr(arg
, vap
, flags
, cr
, ct
));
257 deleg_rd_rwlock(femarg_t
*arg
, int write_lock
, caller_context_t
*ct
)
263 * If this is a write lock, then we got us a conflict.
266 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
267 rc
= recall_all_delegations(fp
, FALSE
, ct
);
268 if (rc
== NFS4ERR_DELAY
)
272 return (vnext_rwlock(arg
, write_lock
, ct
));
275 /* Only the owner of the write delegation should be doing this. */
277 deleg_wr_rwlock(femarg_t
*arg
, int write_lock
, caller_context_t
*ct
)
282 /* Use caller context to compare caller to delegation owner */
283 if (ct
== NULL
|| ct
->cc_caller_id
!= nfs4_srv_caller_id
) {
284 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
285 rc
= recall_all_delegations(fp
, FALSE
, ct
);
286 if (rc
== NFS4ERR_DELAY
)
290 return (vnext_rwlock(arg
, write_lock
, ct
));
294 deleg_rd_space(femarg_t
*arg
, int cmd
, flock64_t
*bfp
, int flag
,
295 offset_t offset
, cred_t
*cr
, caller_context_t
*ct
)
300 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
301 rc
= recall_all_delegations(fp
, FALSE
, ct
);
302 if (rc
== NFS4ERR_DELAY
)
305 return (vnext_space(arg
, cmd
, bfp
, flag
, offset
, cr
, ct
));
309 deleg_wr_space(femarg_t
*arg
, int cmd
, flock64_t
*bfp
, int flag
,
310 offset_t offset
, cred_t
*cr
, caller_context_t
*ct
)
315 /* Use caller context to compare caller to delegation owner */
316 if (ct
== NULL
|| ct
->cc_caller_id
!= nfs4_srv_caller_id
) {
317 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
318 rc
= recall_all_delegations(fp
, FALSE
, ct
);
319 if (rc
== NFS4ERR_DELAY
)
323 return (vnext_space(arg
, cmd
, bfp
, flag
, offset
, cr
, ct
));
327 deleg_rd_setsecattr(femarg_t
*arg
, vsecattr_t
*vsap
, int flag
, cred_t
*cr
,
328 caller_context_t
*ct
)
333 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
335 /* Changing security attribute triggers recall */
336 rc
= recall_all_delegations(fp
, FALSE
, ct
);
337 if (rc
== NFS4ERR_DELAY
)
340 return (vnext_setsecattr(arg
, vsap
, flag
, cr
, ct
));
344 deleg_wr_setsecattr(femarg_t
*arg
, vsecattr_t
*vsap
, int flag
, cred_t
*cr
,
345 caller_context_t
*ct
)
350 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
352 /* Changing security attribute triggers recall */
353 rc
= recall_all_delegations(fp
, FALSE
, ct
);
354 if (rc
== NFS4ERR_DELAY
)
357 return (vnext_setsecattr(arg
, vsap
, flag
, cr
, ct
));
361 deleg_rd_vnevent(femarg_t
*arg
, vnevent_t vnevent
, vnode_t
*dvp
, char *name
,
362 caller_context_t
*ct
)
366 bool_t trunc
= FALSE
;
370 case VE_PRE_RENAME_DEST
:
375 case VE_PRE_RENAME_SRC
:
377 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
378 rfs4_recall_deleg(fp
, trunc
, NULL
);
380 rfs4_dbe_lock(fp
->rf_dbe
);
381 while (fp
->rf_dinfo
.rd_dtype
!= OPEN_DELEGATE_NONE
) {
382 rc
= rfs4_dbe_twait(fp
->rf_dbe
,
383 ddi_get_lbolt() + SEC_TO_TICK(rfs4_lease_time
));
384 if (rc
== -1) { /* timed out */
385 rfs4_dbe_unlock(fp
->rf_dbe
);
386 rfs4_recall_deleg(fp
, trunc
, NULL
);
387 rfs4_dbe_lock(fp
->rf_dbe
);
390 rfs4_dbe_unlock(fp
->rf_dbe
);
397 return (vnext_vnevent(arg
, vnevent
, dvp
, name
, ct
));
401 deleg_wr_vnevent(femarg_t
*arg
, vnevent_t vnevent
, vnode_t
*dvp
, char *name
,
402 caller_context_t
*ct
)
406 bool_t trunc
= FALSE
;
410 case VE_PRE_RENAME_DEST
:
415 case VE_PRE_RENAME_SRC
:
417 fp
= (rfs4_file_t
*)arg
->fa_fnode
->fn_available
;
418 rfs4_recall_deleg(fp
, trunc
, NULL
);
419 rfs4_dbe_lock(fp
->rf_dbe
);
420 while (fp
->rf_dinfo
.rd_dtype
!= OPEN_DELEGATE_NONE
) {
421 rc
= rfs4_dbe_twait(fp
->rf_dbe
,
422 ddi_get_lbolt() + SEC_TO_TICK(rfs4_lease_time
));
423 if (rc
== -1) { /* timed out */
424 rfs4_dbe_unlock(fp
->rf_dbe
);
425 rfs4_recall_deleg(fp
, trunc
, NULL
);
426 rfs4_dbe_lock(fp
->rf_dbe
);
429 rfs4_dbe_unlock(fp
->rf_dbe
);
436 return (vnext_vnevent(arg
, vnevent
, dvp
, name
, ct
));