xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c (revision 71e32251703c729dbbebef2101770135584fd8d4)
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 	caller_context_t *ct)
59 {
60 	clock_t rc;
61 	rfs4_file_t *fp;
62 
63 	/*
64 	 * Now that the NFSv4 server calls VOP_OPEN, we need to check to
65 	 * to make sure it is not us calling open (like for DELEG_CUR) or
66 	 * we will end up panicing the system.
67 	 * Since this monitor is for a read delegated file, we know that
68 	 * only an open for write will cause a conflict.
69 	 */
70 	if ((ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) &&
71 	    (mode & (FWRITE|FTRUNC))) {
72 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
73 		rfs4_recall_deleg(fp, FALSE, NULL);
74 		rfs4_dbe_lock(fp->dbe);
75 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
76 			rc = rfs4_dbe_twait(fp->dbe,
77 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
78 			if (rc == -1) { /* timed out */
79 				rfs4_dbe_unlock(fp->dbe);
80 				rfs4_recall_deleg(fp, FALSE, NULL);
81 				rfs4_dbe_lock(fp->dbe);
82 			}
83 		}
84 		rfs4_dbe_unlock(fp->dbe);
85 	}
86 
87 	return (vnext_open(arg, mode, cr, ct));
88 }
89 
90 /* monitor for open on write delegated file */
91 int
92 deleg_wropen(
93 	femarg_t *arg,
94 	int mode,
95 	cred_t *cr,
96 	caller_context_t *ct)
97 {
98 	clock_t rc;
99 	rfs4_file_t *fp;
100 
101 	/*
102 	 * Now that the NFSv4 server calls VOP_OPEN, we need to check to
103 	 * to make sure it is not us calling open (like for DELEG_CUR) or
104 	 * we will end up panicing the system.
105 	 * Since this monitor is for a write delegated file, we know that
106 	 * any open will cause a conflict.
107 	 */
108 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
109 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
110 		rfs4_recall_deleg(fp, FALSE, NULL);
111 		rfs4_dbe_lock(fp->dbe);
112 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
113 			rc = rfs4_dbe_twait(fp->dbe,
114 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
115 			if (rc == -1) { /* timed out */
116 				rfs4_dbe_unlock(fp->dbe);
117 				rfs4_recall_deleg(fp, FALSE, NULL);
118 				rfs4_dbe_lock(fp->dbe);
119 			}
120 		}
121 		rfs4_dbe_unlock(fp->dbe);
122 	}
123 
124 	return (vnext_open(arg, mode, cr, ct));
125 }
126 
127 /*
128  * this is only a write delegation op and should only be hit
129  * by the owner of the delegation.  if not, then someone is
130  * doing a read without doing an open first.  shouldn't happen.
131  */
132 int
133 deleg_read(
134 	femarg_t *arg,
135 	uio_t *uiop,
136 	int ioflag,
137 	cred_t *cr,
138 	struct caller_context *ct)
139 {
140 	clock_t rc;
141 	rfs4_file_t *fp;
142 
143 	/* use caller context to compare caller to delegation owner */
144 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
145 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
146 		rfs4_recall_deleg(fp, FALSE, NULL);
147 		rfs4_dbe_lock(fp->dbe);
148 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
149 			rc = rfs4_dbe_twait(fp->dbe,
150 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
151 			if (rc == -1) { /* timed out */
152 				rfs4_dbe_unlock(fp->dbe);
153 				rfs4_recall_deleg(fp, FALSE, NULL);
154 				rfs4_dbe_lock(fp->dbe);
155 			}
156 		}
157 		rfs4_dbe_unlock(fp->dbe);
158 	}
159 	return (vnext_read(arg, uiop, ioflag, cr, ct));
160 }
161 
162 /*
163  * this should only be hit by the owner of the delegation.  if not, then
164  * someone is doing a write without doing an open first.  shouldn't happen.
165  */
166 int
167 deleg_write(
168 	femarg_t *arg,
169 	uio_t *uiop,
170 	int ioflag,
171 	cred_t *cr,
172 	struct caller_context *ct)
173 {
174 	clock_t rc;
175 	rfs4_file_t *fp;
176 
177 	/* use caller context to compare caller to delegation owner */
178 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
179 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
180 		rfs4_recall_deleg(fp, FALSE, NULL);
181 		rfs4_dbe_lock(fp->dbe);
182 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
183 			rc = rfs4_dbe_twait(fp->dbe,
184 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
185 			if (rc == -1) { /* timed out */
186 				rfs4_dbe_unlock(fp->dbe);
187 				rfs4_recall_deleg(fp, FALSE, NULL);
188 				rfs4_dbe_lock(fp->dbe);
189 			}
190 		}
191 		rfs4_dbe_unlock(fp->dbe);
192 	}
193 	return (vnext_write(arg, uiop, ioflag, cr, ct));
194 }
195 
196 
197 int
198 deleg_setattr(
199 	femarg_t *arg,
200 	vattr_t *vap,
201 	int flags,
202 	cred_t *cr,
203 	caller_context_t *ct)
204 {
205 	clock_t rc;
206 	rfs4_file_t *fp;
207 
208 	/*
209 	 * use caller context to compare caller to delegation owner
210 	 */
211 	if (ct == NULL || (ct->cc_caller_id != nfs4_srv_caller_id)) {
212 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
213 		rfs4_recall_deleg(fp, FALSE, NULL);
214 		rfs4_dbe_lock(fp->dbe);
215 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
216 			rc = rfs4_dbe_twait(fp->dbe,
217 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
218 			if (rc == -1) { /* timed out */
219 				rfs4_dbe_unlock(fp->dbe);
220 				rfs4_recall_deleg(fp, FALSE, NULL);
221 				rfs4_dbe_lock(fp->dbe);
222 			}
223 		}
224 		rfs4_dbe_unlock(fp->dbe);
225 	}
226 
227 	return (vnext_setattr(arg, vap, flags, cr, ct));
228 }
229 
230 
231 
232 int
233 deleg_rd_rwlock(
234 	femarg_t *arg,
235 	int write_lock,
236 	caller_context_t *ct)
237 {
238 	clock_t rc;
239 	rfs4_file_t *fp;
240 
241 	/*
242 	 * if this is a write lock, then use caller context to compare
243 	 * caller to delegation owner
244 	 */
245 	if (write_lock &&
246 	    (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id)) {
247 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
248 		rfs4_recall_deleg(fp, FALSE, NULL);
249 		rfs4_dbe_lock(fp->dbe);
250 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
251 			rc = rfs4_dbe_twait(fp->dbe,
252 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
253 			if (rc == -1) { /* timed out */
254 				rfs4_dbe_unlock(fp->dbe);
255 				rfs4_recall_deleg(fp, FALSE, NULL);
256 				rfs4_dbe_lock(fp->dbe);
257 			}
258 		}
259 		rfs4_dbe_unlock(fp->dbe);
260 	}
261 
262 	return (vnext_rwlock(arg, write_lock, ct));
263 }
264 
265 int
266 deleg_wr_rwlock(
267 	femarg_t *arg,
268 	int write_lock,
269 	caller_context_t *ct)
270 {
271 	clock_t rc;
272 	rfs4_file_t *fp;
273 
274 	/* use caller context to compare caller to delegation owner */
275 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
276 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
277 		rfs4_recall_deleg(fp, FALSE, NULL);
278 		rfs4_dbe_lock(fp->dbe);
279 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
280 			rc = rfs4_dbe_twait(fp->dbe,
281 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
282 			if (rc == -1) { /* timed out */
283 				rfs4_dbe_unlock(fp->dbe);
284 				rfs4_recall_deleg(fp, FALSE, NULL);
285 				rfs4_dbe_lock(fp->dbe);
286 			}
287 		}
288 		rfs4_dbe_unlock(fp->dbe);
289 	}
290 
291 	return (vnext_rwlock(arg, write_lock, ct));
292 }
293 
294 int
295 deleg_space(
296 	femarg_t *arg,
297 	int cmd,
298 	flock64_t *bfp,
299 	int flag,
300 	offset_t offset,
301 	cred_t *cr,
302 	caller_context_t *ct)
303 {
304 	clock_t rc;
305 	rfs4_file_t *fp;
306 
307 	/* use caller context to compare caller to delegation owner */
308 	if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
309 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
310 		rfs4_recall_deleg(fp, FALSE, NULL);
311 		rfs4_dbe_lock(fp->dbe);
312 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
313 			rc = rfs4_dbe_twait(fp->dbe,
314 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
315 			if (rc == -1) { /* timed out */
316 				rfs4_dbe_unlock(fp->dbe);
317 				rfs4_recall_deleg(fp, FALSE, NULL);
318 				rfs4_dbe_lock(fp->dbe);
319 			}
320 		}
321 		rfs4_dbe_unlock(fp->dbe);
322 	}
323 
324 	return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct));
325 }
326 
327 int
328 deleg_setsecattr(
329 	femarg_t *arg,
330 	vsecattr_t *vsap,
331 	int flag,
332 	cred_t *cr,
333 	caller_context_t *ct)
334 {
335 	clock_t rc;
336 	rfs4_file_t *fp;
337 
338 	fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
339 
340 	/* changing security attribute triggers recall */
341 	rfs4_recall_deleg(fp, FALSE, NULL);
342 	rfs4_dbe_lock(fp->dbe);
343 	while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
344 		rc = rfs4_dbe_twait(fp->dbe,
345 		    lbolt + SEC_TO_TICK(rfs4_lease_time));
346 		if (rc == -1) { /* timed out */
347 			rfs4_dbe_unlock(fp->dbe);
348 			rfs4_recall_deleg(fp, FALSE, NULL);
349 			rfs4_dbe_lock(fp->dbe);
350 		}
351 	}
352 	rfs4_dbe_unlock(fp->dbe);
353 
354 	return (vnext_setsecattr(arg, vsap, flag, cr, ct));
355 }
356 
357 /* ARGSUSED */
358 int
359 deleg_vnevent(
360 	femarg_t *arg,
361 	vnevent_t vnevent,
362 	vnode_t *dvp,
363 	char *name,
364 	caller_context_t *ct)
365 {
366 	clock_t rc;
367 	rfs4_file_t *fp;
368 	bool_t trunc = FALSE;
369 
370 	switch (vnevent) {
371 	case VE_REMOVE:
372 	case VE_RENAME_DEST:
373 		trunc = TRUE;
374 		/*FALLTHROUGH*/
375 
376 	case VE_RENAME_SRC:
377 		fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
378 		rfs4_recall_deleg(fp, trunc, NULL);
379 		rfs4_dbe_lock(fp->dbe);
380 		while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
381 			rc = rfs4_dbe_twait(fp->dbe,
382 			    lbolt + SEC_TO_TICK(rfs4_lease_time));
383 			if (rc == -1) { /* timed out */
384 				rfs4_dbe_unlock(fp->dbe);
385 				rfs4_recall_deleg(fp, trunc, NULL);
386 				rfs4_dbe_lock(fp->dbe);
387 			}
388 		}
389 		rfs4_dbe_unlock(fp->dbe);
390 		break;
391 
392 	default:
393 		break;
394 	}
395 	return (vnext_vnevent(arg, vnevent, dvp, name, ct));
396 }
397