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