xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c (revision 437220cd296f6d8b6654d6d52508b40b1e2d1ac7)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/systm.h>
29 #include <rpc/auth.h>
30 #include <rpc/clnt.h>
31 #include <nfs/nfs4_kprot.h>
32 #include <nfs/nfs4.h>
33 #include <sys/types.h>
34 #include <sys/mutex.h>
35 #include <sys/condvar.h>
36 #include <sys/vfs.h>
37 #include <sys/vnode.h>
38 #include <sys/time.h>
39 #include <sys/fem.h>
40 #include <sys/cmn_err.h>
41 
42 
43 extern u_longlong_t nfs4_srv_caller_id;
44 
45 /*
46  * This file contains the code for the monitors which are placed on the vnodes
47  * of files that are granted delegations by the nfsV4 server.  These monitors
48  * will detect local access that conflict with the delegations and recall the
49  * delegation from the client before letting the offending operation continue.
50  */
51 
52 /* monitor for open on read delegated file */
53 int
54 deleg_rdopen(
55 	femarg_t *arg,
56 	int mode,
57 	cred_t *cr)
58 {
59 	clock_t rc;
60 	rfs4_file_t *fp;
61 
62 	/*
63 	 * Since this monitor is for a read delegated file, we know that
64 	 * only an open for write will cause a conflict.
65 	 */
66 	if (mode & (FWRITE|FTRUNC)) {
67 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
68 		rfs4_recall_deleg(fp, FALSE, NULL);
69 		rfs4_dbe_lock(fp->dbe);
70 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
71 			rc = rfs4_dbe_twait(fp->dbe,
72 					lbolt + SEC_TO_TICK(rfs4_lease_time));
73 			if (rc == -1) { /* timed out */
74 				rfs4_dbe_unlock(fp->dbe);
75 				rfs4_recall_deleg(fp, FALSE, NULL);
76 				rfs4_dbe_lock(fp->dbe);
77 			}
78 		}
79 		rfs4_dbe_unlock(fp->dbe);
80 	}
81 
82 	return (vnext_open(arg, mode, cr));
83 }
84 
85 /* monitor for open on write delegated file */
86 int
87 deleg_wropen(
88 	femarg_t *arg,
89 	int mode,
90 	cred_t *cr)
91 {
92 	clock_t rc;
93 	rfs4_file_t *fp;
94 
95 	fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
96 
97 	/*
98 	 * Since this monitor is for a write delegated file, we know that
99 	 * any open will cause a conflict.
100 	 */
101 	rfs4_recall_deleg(fp, FALSE, NULL);
102 	rfs4_dbe_lock(fp->dbe);
103 	while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
104 		rc = rfs4_dbe_twait(fp->dbe,
105 				lbolt + SEC_TO_TICK(rfs4_lease_time));
106 		if (rc == -1) { /* timed out */
107 			rfs4_dbe_unlock(fp->dbe);
108 			rfs4_recall_deleg(fp, FALSE, NULL);
109 			rfs4_dbe_lock(fp->dbe);
110 		}
111 	}
112 	rfs4_dbe_unlock(fp->dbe);
113 
114 	return (vnext_open(arg, mode, cr));
115 }
116 
117 /*
118  * this is only a write delegation op and should only be hit
119  * by the owner of the delegation.  if not, then someone is
120  * doing a read without doing an open first.  shouldn't happen.
121  */
122 int
123 deleg_read(
124 	femarg_t *arg,
125 	uio_t *uiop,
126 	int ioflag,
127 	cred_t *cr,
128 	struct caller_context *ct)
129 {
130 	clock_t rc;
131 	rfs4_file_t *fp;
132 
133 	/* use caller context to compare caller to delegation owner */
134 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
135 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
136 		rfs4_recall_deleg(fp, FALSE, NULL);
137 		rfs4_dbe_lock(fp->dbe);
138 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
139 			rc = rfs4_dbe_twait(fp->dbe,
140 					lbolt + SEC_TO_TICK(rfs4_lease_time));
141 			if (rc == -1) { /* timed out */
142 				rfs4_dbe_unlock(fp->dbe);
143 				rfs4_recall_deleg(fp, FALSE, NULL);
144 				rfs4_dbe_lock(fp->dbe);
145 			}
146 		}
147 		rfs4_dbe_unlock(fp->dbe);
148 	}
149 	return (vnext_read(arg, uiop, ioflag, cr, ct));
150 }
151 
152 /*
153  * this should only be hit by the owner of the delegation.  if not, then
154  * someone is doing a write without doing an open first.  shouldn't happen.
155  */
156 int
157 deleg_write(
158 	femarg_t *arg,
159 	uio_t *uiop,
160 	int ioflag,
161 	cred_t *cr,
162 	struct caller_context *ct)
163 {
164 	clock_t rc;
165 	rfs4_file_t *fp;
166 
167 	/* use caller context to compare caller to delegation owner */
168 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
169 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
170 		rfs4_recall_deleg(fp, FALSE, NULL);
171 		rfs4_dbe_lock(fp->dbe);
172 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
173 			rc = rfs4_dbe_twait(fp->dbe,
174 					lbolt + SEC_TO_TICK(rfs4_lease_time));
175 			if (rc == -1) { /* timed out */
176 				rfs4_dbe_unlock(fp->dbe);
177 				rfs4_recall_deleg(fp, FALSE, NULL);
178 				rfs4_dbe_lock(fp->dbe);
179 			}
180 		}
181 		rfs4_dbe_unlock(fp->dbe);
182 	}
183 	return (vnext_write(arg, uiop, ioflag, cr, ct));
184 }
185 
186 
187 int
188 deleg_setattr(
189 	femarg_t *arg,
190 	vattr_t *vap,
191 	int flags,
192 	cred_t *cr,
193 	caller_context_t *ct)
194 {
195 	clock_t rc;
196 	rfs4_file_t *fp;
197 
198 	/*
199 	 * use caller context to compare caller to delegation owner
200 	 * and if (changing mode, owner, group, or size)
201 	 */
202 	if ((vap->va_mask & (AT_MODE|AT_UID|AT_GID|AT_SIZE)) &&
203 	    (ct == NULL || (ct->cc_caller_id != nfs4_srv_caller_id))) {
204 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
205 		rfs4_recall_deleg(fp, FALSE, NULL);
206 		rfs4_dbe_lock(fp->dbe);
207 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
208 			rc = rfs4_dbe_twait(fp->dbe,
209 					lbolt + SEC_TO_TICK(rfs4_lease_time));
210 			if (rc == -1) { /* timed out */
211 				rfs4_dbe_unlock(fp->dbe);
212 				rfs4_recall_deleg(fp, FALSE, NULL);
213 				rfs4_dbe_lock(fp->dbe);
214 			}
215 		}
216 		rfs4_dbe_unlock(fp->dbe);
217 	}
218 
219 	return (vnext_setattr(arg, vap, flags, cr, ct));
220 }
221 
222 
223 
224 int
225 deleg_rd_rwlock(
226 	femarg_t *arg,
227 	int write_lock,
228 	caller_context_t *ct)
229 {
230 	clock_t rc;
231 	rfs4_file_t *fp;
232 
233 	/*
234 	 * if this is a write lock, then use caller context to compare
235 	 * caller to delegation owner
236 	 */
237 	if (write_lock &&
238 	    (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id)) {
239 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
240 		rfs4_recall_deleg(fp, FALSE, NULL);
241 		rfs4_dbe_lock(fp->dbe);
242 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
243 			rc = rfs4_dbe_twait(fp->dbe,
244 					lbolt + SEC_TO_TICK(rfs4_lease_time));
245 			if (rc == -1) { /* timed out */
246 				rfs4_dbe_unlock(fp->dbe);
247 				rfs4_recall_deleg(fp, FALSE, NULL);
248 				rfs4_dbe_lock(fp->dbe);
249 			}
250 		}
251 		rfs4_dbe_unlock(fp->dbe);
252 	}
253 
254 	return (vnext_rwlock(arg, write_lock, ct));
255 }
256 
257 int
258 deleg_wr_rwlock(
259 	femarg_t *arg,
260 	int write_lock,
261 	caller_context_t *ct)
262 {
263 	clock_t rc;
264 	rfs4_file_t *fp;
265 
266 	/* use caller context to compare caller to delegation owner */
267 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
268 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
269 		rfs4_recall_deleg(fp, FALSE, NULL);
270 		rfs4_dbe_lock(fp->dbe);
271 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
272 			rc = rfs4_dbe_twait(fp->dbe,
273 					lbolt + SEC_TO_TICK(rfs4_lease_time));
274 			if (rc == -1) { /* timed out */
275 				rfs4_dbe_unlock(fp->dbe);
276 				rfs4_recall_deleg(fp, FALSE, NULL);
277 				rfs4_dbe_lock(fp->dbe);
278 			}
279 		}
280 		rfs4_dbe_unlock(fp->dbe);
281 	}
282 
283 	return (vnext_rwlock(arg, write_lock, ct));
284 }
285 
286 int
287 deleg_space(
288 	femarg_t *arg,
289 	int cmd,
290 	flock64_t *bfp,
291 	int flag,
292 	offset_t offset,
293 	cred_t *cr,
294 	caller_context_t *ct)
295 {
296 	clock_t rc;
297 	rfs4_file_t *fp;
298 
299 	/* use caller context to compare caller to delegation owner */
300 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
301 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
302 		rfs4_recall_deleg(fp, FALSE, NULL);
303 		rfs4_dbe_lock(fp->dbe);
304 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
305 			rc = rfs4_dbe_twait(fp->dbe,
306 					lbolt + SEC_TO_TICK(rfs4_lease_time));
307 			if (rc == -1) { /* timed out */
308 				rfs4_dbe_unlock(fp->dbe);
309 				rfs4_recall_deleg(fp, FALSE, NULL);
310 				rfs4_dbe_lock(fp->dbe);
311 			}
312 		}
313 		rfs4_dbe_unlock(fp->dbe);
314 	}
315 
316 	return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct));
317 }
318 
319 int
320 deleg_setsecattr(
321 	femarg_t *arg,
322 	vsecattr_t *vsap,
323 	int flag,
324 	cred_t *cr)
325 {
326 	clock_t rc;
327 	rfs4_file_t *fp;
328 
329 	fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
330 
331 	/* changing security attribute triggers recall */
332 	rfs4_recall_deleg(fp, FALSE, NULL);
333 	rfs4_dbe_lock(fp->dbe);
334 	while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
335 		rc = rfs4_dbe_twait(fp->dbe,
336 				lbolt + SEC_TO_TICK(rfs4_lease_time));
337 		if (rc == -1) { /* timed out */
338 			rfs4_dbe_unlock(fp->dbe);
339 			rfs4_recall_deleg(fp, FALSE, NULL);
340 			rfs4_dbe_lock(fp->dbe);
341 		}
342 	}
343 	rfs4_dbe_unlock(fp->dbe);
344 
345 	return (vnext_setsecattr(arg, vsap, flag, cr));
346 }
347 
348 /* ARGSUSED */
349 int
350 deleg_vnevent(
351 	femarg_t *arg,
352 	vnevent_t vnevent,
353 	vnode_t *dvp,
354 	char *name)
355 {
356 	clock_t rc;
357 	rfs4_file_t *fp;
358 	bool_t trunc = FALSE;
359 
360 	switch (vnevent) {
361 	case VE_REMOVE:
362 	case VE_RENAME_DEST:
363 		trunc = TRUE;
364 		/*FALLTHROUGH*/
365 
366 	case VE_RENAME_SRC:
367 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
368 		rfs4_recall_deleg(fp, trunc, NULL);
369 		rfs4_dbe_lock(fp->dbe);
370 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
371 			rc = rfs4_dbe_twait(fp->dbe,
372 					lbolt + SEC_TO_TICK(rfs4_lease_time));
373 			if (rc == -1) { /* timed out */
374 				rfs4_dbe_unlock(fp->dbe);
375 				rfs4_recall_deleg(fp, trunc, NULL);
376 				rfs4_dbe_lock(fp->dbe);
377 			}
378 		}
379 		rfs4_dbe_unlock(fp->dbe);
380 		break;
381 
382 	default:
383 		break;
384 	}
385 	return (vnext_vnevent(arg, vnevent, dvp, name));
386 }
387