xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c (revision 6a3b10db10504576d94f22ea0d7aaf12b96b0bbe)
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 	 */
201 	if (ct == NULL || (ct->cc_caller_id != nfs4_srv_caller_id)) {
202 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
203 		rfs4_recall_deleg(fp, FALSE, NULL);
204 		rfs4_dbe_lock(fp->dbe);
205 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
206 			rc = rfs4_dbe_twait(fp->dbe,
207 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
208 			if (rc == -1) { /* timed out */
209 				rfs4_dbe_unlock(fp->dbe);
210 				rfs4_recall_deleg(fp, FALSE, NULL);
211 				rfs4_dbe_lock(fp->dbe);
212 			}
213 		}
214 		rfs4_dbe_unlock(fp->dbe);
215 	}
216 
217 	return (vnext_setattr(arg, vap, flags, cr, ct));
218 }
219 
220 
221 
222 int
223 deleg_rd_rwlock(
224 	femarg_t *arg,
225 	int write_lock,
226 	caller_context_t *ct)
227 {
228 	clock_t rc;
229 	rfs4_file_t *fp;
230 
231 	/*
232 	 * if this is a write lock, then use caller context to compare
233 	 * caller to delegation owner
234 	 */
235 	if (write_lock &&
236 	    (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id)) {
237 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
238 		rfs4_recall_deleg(fp, FALSE, NULL);
239 		rfs4_dbe_lock(fp->dbe);
240 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
241 			rc = rfs4_dbe_twait(fp->dbe,
242 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
243 			if (rc == -1) { /* timed out */
244 				rfs4_dbe_unlock(fp->dbe);
245 				rfs4_recall_deleg(fp, FALSE, NULL);
246 				rfs4_dbe_lock(fp->dbe);
247 			}
248 		}
249 		rfs4_dbe_unlock(fp->dbe);
250 	}
251 
252 	return (vnext_rwlock(arg, write_lock, ct));
253 }
254 
255 int
256 deleg_wr_rwlock(
257 	femarg_t *arg,
258 	int write_lock,
259 	caller_context_t *ct)
260 {
261 	clock_t rc;
262 	rfs4_file_t *fp;
263 
264 	/* use caller context to compare caller to delegation owner */
265 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
266 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
267 		rfs4_recall_deleg(fp, FALSE, NULL);
268 		rfs4_dbe_lock(fp->dbe);
269 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
270 			rc = rfs4_dbe_twait(fp->dbe,
271 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
272 			if (rc == -1) { /* timed out */
273 				rfs4_dbe_unlock(fp->dbe);
274 				rfs4_recall_deleg(fp, FALSE, NULL);
275 				rfs4_dbe_lock(fp->dbe);
276 			}
277 		}
278 		rfs4_dbe_unlock(fp->dbe);
279 	}
280 
281 	return (vnext_rwlock(arg, write_lock, ct));
282 }
283 
284 int
285 deleg_space(
286 	femarg_t *arg,
287 	int cmd,
288 	flock64_t *bfp,
289 	int flag,
290 	offset_t offset,
291 	cred_t *cr,
292 	caller_context_t *ct)
293 {
294 	clock_t rc;
295 	rfs4_file_t *fp;
296 
297 	/* use caller context to compare caller to delegation owner */
298 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
299 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
300 		rfs4_recall_deleg(fp, FALSE, NULL);
301 		rfs4_dbe_lock(fp->dbe);
302 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
303 			rc = rfs4_dbe_twait(fp->dbe,
304 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
305 			if (rc == -1) { /* timed out */
306 				rfs4_dbe_unlock(fp->dbe);
307 				rfs4_recall_deleg(fp, FALSE, NULL);
308 				rfs4_dbe_lock(fp->dbe);
309 			}
310 		}
311 		rfs4_dbe_unlock(fp->dbe);
312 	}
313 
314 	return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct));
315 }
316 
317 int
318 deleg_setsecattr(
319 	femarg_t *arg,
320 	vsecattr_t *vsap,
321 	int flag,
322 	cred_t *cr)
323 {
324 	clock_t rc;
325 	rfs4_file_t *fp;
326 
327 	fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
328 
329 	/* changing security attribute triggers recall */
330 	rfs4_recall_deleg(fp, FALSE, NULL);
331 	rfs4_dbe_lock(fp->dbe);
332 	while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
333 		rc = rfs4_dbe_twait(fp->dbe,
334 		    lbolt + SEC_TO_TICK(rfs4_lease_time));
335 		if (rc == -1) { /* timed out */
336 			rfs4_dbe_unlock(fp->dbe);
337 			rfs4_recall_deleg(fp, FALSE, NULL);
338 			rfs4_dbe_lock(fp->dbe);
339 		}
340 	}
341 	rfs4_dbe_unlock(fp->dbe);
342 
343 	return (vnext_setsecattr(arg, vsap, flag, cr));
344 }
345 
346 /* ARGSUSED */
347 int
348 deleg_vnevent(
349 	femarg_t *arg,
350 	vnevent_t vnevent,
351 	vnode_t *dvp,
352 	char *name)
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, dvp, name));
384 }
385