fs: rename AT_* to VATTR_*
[unleashed/lotheac.git] / kernel / fs / nfs / nfs4_deleg_ops.c
blobe6aebda983586f1d574edb394fed5cb337d18c4d
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
28 #include <rpc/auth.h>
29 #include <rpc/clnt.h>
30 #include <nfs/nfs4_kprot.h>
31 #include <nfs/nfs4.h>
32 #include <sys/types.h>
33 #include <sys/mutex.h>
34 #include <sys/condvar.h>
35 #include <sys/vfs.h>
36 #include <sys/vnode.h>
37 #include <sys/time.h>
38 #include <sys/fem.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.
63 int
64 recall_all_delegations(rfs4_file_t *fp, bool_t trunc, caller_context_t *ct)
66 clock_t rc;
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);
77 return (0);
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);
97 return (0);
100 /* monitor for open on read delegated file */
102 deleg_rd_open(femarg_t *arg, int mode, cred_t *cr, caller_context_t *ct)
104 int rc;
105 rfs4_file_t *fp;
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)
119 return (EAGAIN);
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)
129 int rc;
130 rfs4_file_t *fp;
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)
143 return (EAGAIN);
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)
158 int rc;
159 rfs4_file_t *fp;
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)
166 return (EAGAIN);
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)
179 int rc;
180 rfs4_file_t *fp;
182 fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
183 rc = recall_all_delegations(fp, FALSE, ct);
184 if (rc == NFS4ERR_DELAY)
185 return (EAGAIN);
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)
198 int rc;
199 rfs4_file_t *fp;
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)
206 return (EAGAIN);
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)
216 int rc;
217 bool_t trunc = FALSE;
218 rfs4_file_t *fp;
220 if ((vap->va_mask & VATTR_SIZE) && (vap->va_size == 0))
221 trunc = TRUE;
223 fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
224 rc = recall_all_delegations(fp, trunc, ct);
225 if (rc == NFS4ERR_DELAY)
226 return (EAGAIN);
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)
236 int rc;
237 bool_t trunc = FALSE;
238 rfs4_file_t *fp;
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 & VATTR_SIZE) && (vap->va_size == 0))
245 trunc = TRUE;
247 fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
248 rc = recall_all_delegations(fp, trunc, ct);
249 if (rc == NFS4ERR_DELAY)
250 return (EAGAIN);
253 return (vnext_setattr(arg, vap, flags, cr, ct));
257 deleg_rd_rwlock(femarg_t *arg, int write_lock, caller_context_t *ct)
259 int rc;
260 rfs4_file_t *fp;
263 * If this is a write lock, then we got us a conflict.
265 if (write_lock) {
266 fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
267 rc = recall_all_delegations(fp, FALSE, ct);
268 if (rc == NFS4ERR_DELAY)
269 return (EAGAIN);
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)
279 int rc;
280 rfs4_file_t *fp;
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)
287 return (EAGAIN);
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)
297 int rc;
298 rfs4_file_t *fp;
300 fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
301 rc = recall_all_delegations(fp, FALSE, ct);
302 if (rc == NFS4ERR_DELAY)
303 return (EAGAIN);
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)
312 int rc;
313 rfs4_file_t *fp;
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)
320 return (EAGAIN);
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)
330 int rc;
331 rfs4_file_t *fp;
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)
338 return (EAGAIN);
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)
347 int rc;
348 rfs4_file_t *fp;
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)
355 return (EAGAIN);
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)
364 clock_t rc;
365 rfs4_file_t *fp;
366 bool_t trunc = FALSE;
368 switch (vnevent) {
369 case VE_REMOVE:
370 case VE_PRE_RENAME_DEST:
371 case VE_RENAME_DEST:
372 trunc = TRUE;
373 /*FALLTHROUGH*/
375 case VE_PRE_RENAME_SRC:
376 case VE_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);
392 break;
394 default:
395 break;
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)
404 clock_t rc;
405 rfs4_file_t *fp;
406 bool_t trunc = FALSE;
408 switch (vnevent) {
409 case VE_REMOVE:
410 case VE_PRE_RENAME_DEST:
411 case VE_RENAME_DEST:
412 trunc = TRUE;
413 /*FALLTHROUGH*/
415 case VE_PRE_RENAME_SRC:
416 case VE_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);
431 break;
433 default:
434 break;
436 return (vnext_vnevent(arg, vnevent, dvp, name, ct));