xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs3_srv.c (revision 936b7af69172dce89b577831f79c0e18d15e854b)
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 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/systm.h>
34 #include <sys/cred.h>
35 #include <sys/buf.h>
36 #include <sys/vfs.h>
37 #include <sys/vnode.h>
38 #include <sys/uio.h>
39 #include <sys/errno.h>
40 #include <sys/sysmacros.h>
41 #include <sys/statvfs.h>
42 #include <sys/kmem.h>
43 #include <sys/dirent.h>
44 #include <sys/cmn_err.h>
45 #include <sys/debug.h>
46 #include <sys/systeminfo.h>
47 #include <sys/flock.h>
48 #include <sys/nbmlock.h>
49 #include <sys/policy.h>
50 #include <sys/sdt.h>
51 
52 #include <rpc/types.h>
53 #include <rpc/auth.h>
54 #include <rpc/svc.h>
55 
56 #include <nfs/nfs.h>
57 #include <nfs/export.h>
58 
59 #include <sys/strsubr.h>
60 
61 #include <sys/tsol/label.h>
62 #include <sys/tsol/tndb.h>
63 
64 #include <inet/ip.h>
65 #include <inet/ip6.h>
66 
67 /*
68  * These are the interface routines for the server side of the
69  * Network File System.  See the NFS version 3 protocol specification
70  * for a description of this interface.
71  */
72 
73 #ifdef DEBUG
74 int rfs3_do_pre_op_attr = 1;
75 int rfs3_do_post_op_attr = 1;
76 int rfs3_do_post_op_fh3 = 1;
77 #endif
78 
79 static writeverf3 write3verf;
80 
81 static int	sattr3_to_vattr(sattr3 *, struct vattr *);
82 static int	vattr_to_fattr3(struct vattr *, fattr3 *);
83 static int	vattr_to_wcc_attr(struct vattr *, wcc_attr *);
84 static void	vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
85 static void	vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
86 
87 u_longlong_t nfs3_srv_caller_id;
88 
89 /* ARGSUSED */
90 void
91 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
92 	struct svc_req *req, cred_t *cr)
93 {
94 	int error;
95 	vnode_t *vp;
96 	struct vattr va;
97 
98 	vp = nfs3_fhtovp(&args->object, exi);
99 	if (vp == NULL) {
100 		error = ESTALE;
101 		goto out;
102 	}
103 
104 	va.va_mask = AT_ALL;
105 	error = rfs4_delegated_getattr(vp, &va, 0, cr);
106 
107 	VN_RELE(vp);
108 
109 	if (!error) {
110 		/* overflow error if time or size is out of range */
111 		error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
112 		if (error)
113 			goto out;
114 		resp->status = NFS3_OK;
115 		return;
116 	}
117 
118 out:
119 	if (curthread->t_flag & T_WOULDBLOCK) {
120 		curthread->t_flag &= ~T_WOULDBLOCK;
121 		resp->status = NFS3ERR_JUKEBOX;
122 	} else
123 		resp->status = puterrno3(error);
124 }
125 
126 void *
127 rfs3_getattr_getfh(GETATTR3args *args)
128 {
129 
130 	return (&args->object);
131 }
132 
133 void
134 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
135 	struct svc_req *req, cred_t *cr)
136 {
137 	int error;
138 	vnode_t *vp;
139 	struct vattr *bvap;
140 	struct vattr bva;
141 	struct vattr *avap;
142 	struct vattr ava;
143 	int flag;
144 	int in_crit = 0;
145 	struct flock64 bf;
146 	caller_context_t ct;
147 
148 	bvap = NULL;
149 	avap = NULL;
150 
151 	vp = nfs3_fhtovp(&args->object, exi);
152 	if (vp == NULL) {
153 		error = ESTALE;
154 		goto out;
155 	}
156 
157 	error = sattr3_to_vattr(&args->new_attributes, &ava);
158 	if (error)
159 		goto out;
160 
161 	if (is_system_labeled()) {
162 		bslabel_t *clabel = req->rq_label;
163 
164 		ASSERT(clabel != NULL);
165 		DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
166 		    "got client label from request(1)", struct svc_req *, req);
167 
168 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
169 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
170 				resp->status = NFS3ERR_ACCES;
171 				goto out1;
172 			}
173 		}
174 	}
175 
176 	/*
177 	 * We need to specially handle size changes because of
178 	 * possible conflicting NBMAND locks. Get into critical
179 	 * region before VOP_GETATTR, so the size attribute is
180 	 * valid when checking conflicts.
181 	 *
182 	 * Also, check to see if the v4 side of the server has
183 	 * delegated this file.  If so, then we return JUKEBOX to
184 	 * allow the client to retrasmit its request.
185 	 */
186 	if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
187 		if (nbl_need_check(vp)) {
188 			nbl_start_crit(vp, RW_READER);
189 			in_crit = 1;
190 		}
191 	}
192 
193 	bva.va_mask = AT_ALL;
194 	error = rfs4_delegated_getattr(vp, &bva, 0, cr);
195 
196 	/*
197 	 * If we can't get the attributes, then we can't do the
198 	 * right access checking.  So, we'll fail the request.
199 	 */
200 	if (error)
201 		goto out;
202 
203 #ifdef DEBUG
204 	if (rfs3_do_pre_op_attr)
205 		bvap = &bva;
206 #else
207 	bvap = &bva;
208 #endif
209 
210 	if (rdonly(exi, req) || vn_is_readonly(vp)) {
211 		resp->status = NFS3ERR_ROFS;
212 		goto out1;
213 	}
214 
215 	if (args->guard.check &&
216 	    (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
217 	    args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
218 		resp->status = NFS3ERR_NOT_SYNC;
219 		goto out1;
220 	}
221 
222 	if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
223 		flag = ATTR_UTIME;
224 	else
225 		flag = 0;
226 
227 	/*
228 	 * If the filesystem is exported with nosuid, then mask off
229 	 * the setuid and setgid bits.
230 	 */
231 	if ((ava.va_mask & AT_MODE) && vp->v_type == VREG &&
232 	    (exi->exi_export.ex_flags & EX_NOSUID))
233 		ava.va_mode &= ~(VSUID | VSGID);
234 
235 	ct.cc_sysid = 0;
236 	ct.cc_pid = 0;
237 	ct.cc_caller_id = nfs3_srv_caller_id;
238 	ct.cc_flags = CC_DONTBLOCK;
239 
240 	/*
241 	 * We need to specially handle size changes because it is
242 	 * possible for the client to create a file with modes
243 	 * which indicate read-only, but with the file opened for
244 	 * writing.  If the client then tries to set the size of
245 	 * the file, then the normal access checking done in
246 	 * VOP_SETATTR would prevent the client from doing so,
247 	 * although it should be legal for it to do so.  To get
248 	 * around this, we do the access checking for ourselves
249 	 * and then use VOP_SPACE which doesn't do the access
250 	 * checking which VOP_SETATTR does. VOP_SPACE can only
251 	 * operate on VREG files, let VOP_SETATTR handle the other
252 	 * extremely rare cases.
253 	 * Also the client should not be allowed to change the
254 	 * size of the file if there is a conflicting non-blocking
255 	 * mandatory lock in the region the change.
256 	 */
257 	if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
258 		if (in_crit) {
259 			u_offset_t offset;
260 			ssize_t length;
261 
262 			if (ava.va_size < bva.va_size) {
263 				offset = ava.va_size;
264 				length = bva.va_size - ava.va_size;
265 			} else {
266 				offset = bva.va_size;
267 				length = ava.va_size - bva.va_size;
268 			}
269 			if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
270 			    NULL)) {
271 				error = EACCES;
272 				goto out;
273 			}
274 		}
275 
276 		if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) {
277 			ava.va_mask &= ~AT_SIZE;
278 			bf.l_type = F_WRLCK;
279 			bf.l_whence = 0;
280 			bf.l_start = (off64_t)ava.va_size;
281 			bf.l_len = 0;
282 			bf.l_sysid = 0;
283 			bf.l_pid = 0;
284 			error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
285 			    (offset_t)ava.va_size, cr, &ct);
286 		}
287 	}
288 
289 	if (!error && ava.va_mask)
290 		error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
291 
292 	/* check if a monitor detected a delegation conflict */
293 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
294 		resp->status = NFS3ERR_JUKEBOX;
295 		goto out1;
296 	}
297 
298 #ifdef DEBUG
299 	if (rfs3_do_post_op_attr) {
300 		ava.va_mask = AT_ALL;
301 		avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
302 	} else
303 		avap = NULL;
304 #else
305 	ava.va_mask = AT_ALL;
306 	avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
307 #endif
308 
309 	/*
310 	 * Force modified metadata out to stable storage.
311 	 */
312 	(void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
313 
314 	if (error)
315 		goto out;
316 
317 	if (in_crit)
318 		nbl_end_crit(vp);
319 	VN_RELE(vp);
320 
321 	resp->status = NFS3_OK;
322 	vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
323 	return;
324 
325 out:
326 	if (curthread->t_flag & T_WOULDBLOCK) {
327 		curthread->t_flag &= ~T_WOULDBLOCK;
328 		resp->status = NFS3ERR_JUKEBOX;
329 	} else
330 		resp->status = puterrno3(error);
331 out1:
332 	if (vp != NULL) {
333 		if (in_crit)
334 			nbl_end_crit(vp);
335 		VN_RELE(vp);
336 	}
337 	vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
338 }
339 
340 void *
341 rfs3_setattr_getfh(SETATTR3args *args)
342 {
343 
344 	return (&args->object);
345 }
346 
347 /* ARGSUSED */
348 void
349 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
350 	struct svc_req *req, cred_t *cr)
351 {
352 	int error;
353 	vnode_t *vp;
354 	vnode_t *dvp;
355 	struct vattr *vap;
356 	struct vattr va;
357 	struct vattr *dvap;
358 	struct vattr dva;
359 	nfs_fh3 *fhp;
360 	struct sec_ol sec = {0, 0};
361 	bool_t publicfh_flag = FALSE, auth_weak = FALSE;
362 
363 	dvap = NULL;
364 
365 	/*
366 	 * Allow lookups from the root - the default
367 	 * location of the public filehandle.
368 	 */
369 	if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
370 		dvp = rootdir;
371 		VN_HOLD(dvp);
372 	} else {
373 		dvp = nfs3_fhtovp(&args->what.dir, exi);
374 		if (dvp == NULL) {
375 			error = ESTALE;
376 			goto out;
377 		}
378 	}
379 
380 #ifdef DEBUG
381 	if (rfs3_do_pre_op_attr) {
382 		dva.va_mask = AT_ALL;
383 		dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
384 	}
385 #else
386 	dva.va_mask = AT_ALL;
387 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
388 #endif
389 
390 	if (args->what.name == nfs3nametoolong) {
391 		resp->status = NFS3ERR_NAMETOOLONG;
392 		goto out1;
393 	}
394 
395 	if (args->what.name == NULL || *(args->what.name) == '\0') {
396 		resp->status = NFS3ERR_ACCES;
397 		goto out1;
398 	}
399 
400 	fhp = &args->what.dir;
401 	if (strcmp(args->what.name, "..") == 0 &&
402 	    EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
403 		resp->status = NFS3ERR_NOENT;
404 		goto out1;
405 	}
406 
407 	/*
408 	 * If the public filehandle is used then allow
409 	 * a multi-component lookup
410 	 */
411 	if (PUBLIC_FH3(&args->what.dir)) {
412 		publicfh_flag = TRUE;
413 		error = rfs_publicfh_mclookup(args->what.name, dvp, cr, &vp,
414 		    &exi, &sec);
415 		if (error && exi != NULL)
416 			exi_rele(exi); /* See comment below Re: publicfh_flag */
417 		/*
418 		 * Since WebNFS may bypass MOUNT, we need to ensure this
419 		 * request didn't come from an unlabeled admin_low client.
420 		 */
421 		if (is_system_labeled() && error == 0) {
422 			struct sockaddr *ca;
423 			int		addr_type;
424 			void		*ipaddr;
425 			tsol_tpc_t	*tp;
426 
427 			ca = (struct sockaddr *)svc_getrpccaller(
428 			    req->rq_xprt)->buf;
429 			if (ca->sa_family == AF_INET) {
430 				addr_type = IPV4_VERSION;
431 				ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
432 			} else if (ca->sa_family == AF_INET6) {
433 				addr_type = IPV6_VERSION;
434 				ipaddr = &((struct sockaddr_in6 *)
435 				    ca)->sin6_addr;
436 			}
437 			tp = find_tpc(ipaddr, addr_type, B_FALSE);
438 			if (tp == NULL || tp->tpc_tp.tp_doi !=
439 			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
440 			    SUN_CIPSO) {
441 				if (exi != NULL)
442 					exi_rele(exi);
443 				VN_RELE(vp);
444 				resp->status = NFS3ERR_ACCES;
445 				error = 1;
446 			}
447 			if (tp != NULL)
448 				TPC_RELE(tp);
449 		}
450 	} else {
451 		error = VOP_LOOKUP(dvp, args->what.name, &vp,
452 		    NULL, 0, NULL, cr, NULL, NULL, NULL);
453 	}
454 
455 	if (is_system_labeled() && error == 0) {
456 		bslabel_t *clabel = req->rq_label;
457 
458 		ASSERT(clabel != NULL);
459 		DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
460 		    "got client label from request(1)", struct svc_req *, req);
461 
462 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
463 			if (!do_rfs_label_check(clabel, dvp,
464 			    DOMINANCE_CHECK)) {
465 				if (publicfh_flag && exi != NULL)
466 					exi_rele(exi);
467 				VN_RELE(vp);
468 				resp->status = NFS3ERR_ACCES;
469 				error = 1;
470 			}
471 		}
472 	}
473 
474 #ifdef DEBUG
475 	if (rfs3_do_post_op_attr) {
476 		dva.va_mask = AT_ALL;
477 		dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
478 	} else
479 		dvap = NULL;
480 #else
481 	dva.va_mask = AT_ALL;
482 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
483 #endif
484 
485 	if (error)
486 		goto out;
487 
488 	if (sec.sec_flags & SEC_QUERY) {
489 		error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
490 	} else {
491 		error = makefh3(&resp->resok.object, vp, exi);
492 		if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
493 			auth_weak = TRUE;
494 	}
495 
496 	if (error) {
497 		VN_RELE(vp);
498 		goto out;
499 	}
500 
501 	/*
502 	 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
503 	 * and have obtained a new exportinfo in exi which needs to be
504 	 * released. Note the the original exportinfo pointed to by exi
505 	 * will be released by the caller, common_dispatch.
506 	 */
507 	if (publicfh_flag)
508 		exi_rele(exi);
509 
510 	VN_RELE(dvp);
511 
512 #ifdef DEBUG
513 	if (rfs3_do_post_op_attr) {
514 		va.va_mask = AT_ALL;
515 		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
516 	} else
517 		vap = NULL;
518 #else
519 	va.va_mask = AT_ALL;
520 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
521 #endif
522 
523 	VN_RELE(vp);
524 
525 	resp->status = NFS3_OK;
526 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
527 	vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
528 
529 	/*
530 	 * If it's public fh, no 0x81, and client's flavor is
531 	 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
532 	 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
533 	 */
534 	if (auth_weak)
535 		resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
536 
537 	return;
538 
539 out:
540 	if (curthread->t_flag & T_WOULDBLOCK) {
541 		curthread->t_flag &= ~T_WOULDBLOCK;
542 		resp->status = NFS3ERR_JUKEBOX;
543 	} else
544 		resp->status = puterrno3(error);
545 out1:
546 	if (dvp != NULL)
547 		VN_RELE(dvp);
548 	vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
549 
550 }
551 
552 void *
553 rfs3_lookup_getfh(LOOKUP3args *args)
554 {
555 
556 	return (&args->what.dir);
557 }
558 
559 /* ARGSUSED */
560 void
561 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
562 	struct svc_req *req, cred_t *cr)
563 {
564 	int error;
565 	vnode_t *vp;
566 	struct vattr *vap;
567 	struct vattr va;
568 	int checkwriteperm;
569 	boolean_t dominant_label = B_FALSE;
570 	boolean_t equal_label = B_FALSE;
571 	boolean_t admin_low_client;
572 
573 	vap = NULL;
574 
575 	vp = nfs3_fhtovp(&args->object, exi);
576 	if (vp == NULL) {
577 		error = ESTALE;
578 		goto out;
579 	}
580 
581 	/*
582 	 * If the file system is exported read only, it is not appropriate
583 	 * to check write permissions for regular files and directories.
584 	 * Special files are interpreted by the client, so the underlying
585 	 * permissions are sent back to the client for interpretation.
586 	 */
587 	if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR))
588 		checkwriteperm = 0;
589 	else
590 		checkwriteperm = 1;
591 
592 	/*
593 	 * We need the mode so that we can correctly determine access
594 	 * permissions relative to a mandatory lock file.  Access to
595 	 * mandatory lock files is denied on the server, so it might
596 	 * as well be reflected to the server during the open.
597 	 */
598 	va.va_mask = AT_MODE;
599 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
600 	if (error)
601 		goto out;
602 
603 #ifdef DEBUG
604 	if (rfs3_do_post_op_attr)
605 		vap = &va;
606 #else
607 	vap = &va;
608 #endif
609 
610 	resp->resok.access = 0;
611 
612 	if (is_system_labeled()) {
613 		bslabel_t *clabel = req->rq_label;
614 
615 		ASSERT(clabel != NULL);
616 		DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
617 		    "got client label from request(1)", struct svc_req *, req);
618 
619 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
620 			if ((equal_label = do_rfs_label_check(clabel, vp,
621 			    EQUALITY_CHECK)) == B_FALSE) {
622 				dominant_label = do_rfs_label_check(clabel,
623 				    vp, DOMINANCE_CHECK);
624 			} else
625 				dominant_label = B_TRUE;
626 			admin_low_client = B_FALSE;
627 		} else
628 			admin_low_client = B_TRUE;
629 	}
630 
631 	if (args->access & ACCESS3_READ) {
632 		error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
633 		if (error) {
634 			if (curthread->t_flag & T_WOULDBLOCK)
635 				goto out;
636 		} else if (!MANDLOCK(vp, va.va_mode) &&
637 		    (!is_system_labeled() || admin_low_client ||
638 		    dominant_label))
639 			resp->resok.access |= ACCESS3_READ;
640 	}
641 	if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
642 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
643 		if (error) {
644 			if (curthread->t_flag & T_WOULDBLOCK)
645 				goto out;
646 		} else if (!is_system_labeled() || admin_low_client ||
647 		    dominant_label)
648 			resp->resok.access |= ACCESS3_LOOKUP;
649 	}
650 	if (checkwriteperm &&
651 	    (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
652 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
653 		if (error) {
654 			if (curthread->t_flag & T_WOULDBLOCK)
655 				goto out;
656 		} else if (!MANDLOCK(vp, va.va_mode) &&
657 		    (!is_system_labeled() || admin_low_client || equal_label)) {
658 			resp->resok.access |=
659 			    (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND));
660 		}
661 	}
662 	if (checkwriteperm &&
663 	    (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
664 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
665 		if (error) {
666 			if (curthread->t_flag & T_WOULDBLOCK)
667 				goto out;
668 		} else if (!is_system_labeled() || admin_low_client ||
669 		    equal_label)
670 			resp->resok.access |= ACCESS3_DELETE;
671 	}
672 	if (args->access & ACCESS3_EXECUTE) {
673 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
674 		if (error) {
675 			if (curthread->t_flag & T_WOULDBLOCK)
676 				goto out;
677 		} else if (!MANDLOCK(vp, va.va_mode) &&
678 		    (!is_system_labeled() || admin_low_client ||
679 		    dominant_label))
680 			resp->resok.access |= ACCESS3_EXECUTE;
681 	}
682 
683 #ifdef DEBUG
684 	if (rfs3_do_post_op_attr) {
685 		va.va_mask = AT_ALL;
686 		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
687 	} else
688 		vap = NULL;
689 #else
690 	va.va_mask = AT_ALL;
691 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
692 #endif
693 
694 	VN_RELE(vp);
695 
696 	resp->status = NFS3_OK;
697 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
698 	return;
699 
700 out:
701 	if (curthread->t_flag & T_WOULDBLOCK) {
702 		curthread->t_flag &= ~T_WOULDBLOCK;
703 		resp->status = NFS3ERR_JUKEBOX;
704 	} else
705 		resp->status = puterrno3(error);
706 	if (vp != NULL)
707 		VN_RELE(vp);
708 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
709 }
710 
711 void *
712 rfs3_access_getfh(ACCESS3args *args)
713 {
714 
715 	return (&args->object);
716 }
717 
718 /* ARGSUSED */
719 void
720 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
721 	struct svc_req *req, cred_t *cr)
722 {
723 	int error;
724 	vnode_t *vp;
725 	struct vattr *vap;
726 	struct vattr va;
727 	struct iovec iov;
728 	struct uio uio;
729 	char *data;
730 
731 	vap = NULL;
732 
733 	vp = nfs3_fhtovp(&args->symlink, exi);
734 	if (vp == NULL) {
735 		error = ESTALE;
736 		goto out;
737 	}
738 
739 	va.va_mask = AT_ALL;
740 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
741 	if (error)
742 		goto out;
743 
744 #ifdef DEBUG
745 	if (rfs3_do_post_op_attr)
746 		vap = &va;
747 #else
748 	vap = &va;
749 #endif
750 
751 	if (vp->v_type != VLNK) {
752 		resp->status = NFS3ERR_INVAL;
753 		goto out1;
754 	}
755 
756 	if (MANDLOCK(vp, va.va_mode)) {
757 		resp->status = NFS3ERR_ACCES;
758 		goto out1;
759 	}
760 
761 	if (is_system_labeled()) {
762 		bslabel_t *clabel = req->rq_label;
763 
764 		ASSERT(clabel != NULL);
765 		DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
766 		    "got client label from request(1)", struct svc_req *, req);
767 
768 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
769 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
770 				resp->status = NFS3ERR_ACCES;
771 				goto out1;
772 			}
773 		}
774 	}
775 
776 	data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
777 
778 	iov.iov_base = data;
779 	iov.iov_len = MAXPATHLEN;
780 	uio.uio_iov = &iov;
781 	uio.uio_iovcnt = 1;
782 	uio.uio_segflg = UIO_SYSSPACE;
783 	uio.uio_extflg = UIO_COPY_CACHED;
784 	uio.uio_loffset = 0;
785 	uio.uio_resid = MAXPATHLEN;
786 
787 	error = VOP_READLINK(vp, &uio, cr, NULL);
788 
789 #ifdef DEBUG
790 	if (rfs3_do_post_op_attr) {
791 		va.va_mask = AT_ALL;
792 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
793 	} else
794 		vap = NULL;
795 #else
796 	va.va_mask = AT_ALL;
797 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
798 #endif
799 
800 #if 0 /* notyet */
801 	/*
802 	 * Don't do this.  It causes local disk writes when just
803 	 * reading the file and the overhead is deemed larger
804 	 * than the benefit.
805 	 */
806 	/*
807 	 * Force modified metadata out to stable storage.
808 	 */
809 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
810 #endif
811 
812 	if (error) {
813 		kmem_free(data, MAXPATHLEN + 1);
814 		goto out;
815 	}
816 
817 	VN_RELE(vp);
818 
819 	resp->status = NFS3_OK;
820 	vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
821 	resp->resok.data = data;
822 	*(data + MAXPATHLEN - uio.uio_resid) = '\0';
823 	return;
824 
825 out:
826 	if (curthread->t_flag & T_WOULDBLOCK) {
827 		curthread->t_flag &= ~T_WOULDBLOCK;
828 		resp->status = NFS3ERR_JUKEBOX;
829 	} else
830 		resp->status = puterrno3(error);
831 out1:
832 	if (vp != NULL)
833 		VN_RELE(vp);
834 	vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
835 }
836 
837 void *
838 rfs3_readlink_getfh(READLINK3args *args)
839 {
840 
841 	return (&args->symlink);
842 }
843 
844 void
845 rfs3_readlink_free(READLINK3res *resp)
846 {
847 
848 	if (resp->status == NFS3_OK)
849 		kmem_free(resp->resok.data, MAXPATHLEN + 1);
850 }
851 
852 /* ARGSUSED */
853 void
854 rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
855 	struct svc_req *req, cred_t *cr)
856 {
857 	int error;
858 	vnode_t *vp;
859 	struct vattr *vap;
860 	struct vattr va;
861 	struct iovec iov;
862 	struct uio uio;
863 	u_offset_t offset;
864 	mblk_t *mp;
865 	int alloc_err = 0;
866 	int in_crit = 0;
867 	int need_rwunlock = 0;
868 	caller_context_t ct;
869 
870 	vap = NULL;
871 
872 	vp = nfs3_fhtovp(&args->file, exi);
873 	if (vp == NULL) {
874 		error = ESTALE;
875 		goto out;
876 	}
877 
878 	if (is_system_labeled()) {
879 		bslabel_t *clabel = req->rq_label;
880 
881 		ASSERT(clabel != NULL);
882 		DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *,
883 		    "got client label from request(1)", struct svc_req *, req);
884 
885 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
886 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
887 				resp->status = NFS3ERR_ACCES;
888 				goto out1;
889 			}
890 		}
891 	}
892 
893 	ct.cc_sysid = 0;
894 	ct.cc_pid = 0;
895 	ct.cc_caller_id = nfs3_srv_caller_id;
896 	ct.cc_flags = CC_DONTBLOCK;
897 
898 	/*
899 	 * Enter the critical region before calling VOP_RWLOCK
900 	 * to avoid a deadlock with write requests.
901 	 */
902 	if (nbl_need_check(vp)) {
903 		nbl_start_crit(vp, RW_READER);
904 		in_crit = 1;
905 		if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
906 		    NULL)) {
907 			error = EACCES;
908 			goto out;
909 		}
910 	}
911 
912 	error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
913 
914 	/* check if a monitor detected a delegation conflict */
915 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
916 		resp->status = NFS3ERR_JUKEBOX;
917 		goto out1;
918 	}
919 
920 	need_rwunlock = 1;
921 
922 	va.va_mask = AT_ALL;
923 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
924 
925 	/*
926 	 * If we can't get the attributes, then we can't do the
927 	 * right access checking.  So, we'll fail the request.
928 	 */
929 	if (error)
930 		goto out;
931 
932 #ifdef DEBUG
933 	if (rfs3_do_post_op_attr)
934 		vap = &va;
935 #else
936 	vap = &va;
937 #endif
938 
939 	if (vp->v_type != VREG) {
940 		resp->status = NFS3ERR_INVAL;
941 		goto out1;
942 	}
943 
944 	if (crgetuid(cr) != va.va_uid) {
945 		error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
946 		if (error) {
947 			if (curthread->t_flag & T_WOULDBLOCK)
948 				goto out;
949 			error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
950 			if (error)
951 				goto out;
952 		}
953 	}
954 
955 	if (MANDLOCK(vp, va.va_mode)) {
956 		resp->status = NFS3ERR_ACCES;
957 		goto out1;
958 	}
959 
960 	offset = args->offset;
961 	if (offset >= va.va_size) {
962 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
963 		if (in_crit)
964 			nbl_end_crit(vp);
965 		VN_RELE(vp);
966 		resp->status = NFS3_OK;
967 		vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
968 		resp->resok.count = 0;
969 		resp->resok.eof = TRUE;
970 		resp->resok.data.data_len = 0;
971 		resp->resok.data.data_val = NULL;
972 		resp->resok.data.mp = NULL;
973 		return;
974 	}
975 
976 	if (args->count == 0) {
977 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
978 		if (in_crit)
979 			nbl_end_crit(vp);
980 		VN_RELE(vp);
981 		resp->status = NFS3_OK;
982 		vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
983 		resp->resok.count = 0;
984 		resp->resok.eof = FALSE;
985 		resp->resok.data.data_len = 0;
986 		resp->resok.data.data_val = NULL;
987 		resp->resok.data.mp = NULL;
988 		return;
989 	}
990 
991 	/*
992 	 * do not allocate memory more the max. allowed
993 	 * transfer size
994 	 */
995 	if (args->count > rfs3_tsize(req))
996 		args->count = rfs3_tsize(req);
997 
998 	/*
999 	 * mp will contain the data to be sent out in the read reply.
1000 	 * This will be freed after the reply has been sent out (by the
1001 	 * driver).
1002 	 * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so
1003 	 * that the call to xdrmblk_putmblk() never fails.
1004 	 */
1005 	mp = allocb_wait(RNDUP(args->count), BPRI_MED, STR_NOSIG, &alloc_err);
1006 	ASSERT(mp != NULL);
1007 	ASSERT(alloc_err == 0);
1008 
1009 	iov.iov_base = (caddr_t)mp->b_datap->db_base;
1010 	iov.iov_len = args->count;
1011 	uio.uio_iov = &iov;
1012 	uio.uio_iovcnt = 1;
1013 	uio.uio_segflg = UIO_SYSSPACE;
1014 	uio.uio_extflg = UIO_COPY_CACHED;
1015 	uio.uio_loffset = args->offset;
1016 	uio.uio_resid = args->count;
1017 
1018 	error = VOP_READ(vp, &uio, 0, cr, &ct);
1019 
1020 	if (error) {
1021 		freeb(mp);
1022 		/* check if a monitor detected a delegation conflict */
1023 		if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1024 			resp->status = NFS3ERR_JUKEBOX;
1025 			goto out1;
1026 		}
1027 		goto out;
1028 	}
1029 
1030 	va.va_mask = AT_ALL;
1031 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1032 
1033 #ifdef DEBUG
1034 	if (rfs3_do_post_op_attr) {
1035 		if (error)
1036 			vap = NULL;
1037 		else
1038 			vap = &va;
1039 	} else
1040 		vap = NULL;
1041 #else
1042 	if (error)
1043 		vap = NULL;
1044 	else
1045 		vap = &va;
1046 #endif
1047 
1048 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1049 
1050 #if 0 /* notyet */
1051 	/*
1052 	 * Don't do this.  It causes local disk writes when just
1053 	 * reading the file and the overhead is deemed larger
1054 	 * than the benefit.
1055 	 */
1056 	/*
1057 	 * Force modified metadata out to stable storage.
1058 	 */
1059 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1060 #endif
1061 
1062 	if (in_crit)
1063 		nbl_end_crit(vp);
1064 	VN_RELE(vp);
1065 
1066 	resp->status = NFS3_OK;
1067 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1068 	resp->resok.count = args->count - uio.uio_resid;
1069 	if (!error && offset + resp->resok.count == va.va_size)
1070 		resp->resok.eof = TRUE;
1071 	else
1072 		resp->resok.eof = FALSE;
1073 	resp->resok.data.data_len = resp->resok.count;
1074 	resp->resok.data.data_val = (char *)mp->b_datap->db_base;
1075 
1076 	resp->resok.data.mp = mp;
1077 
1078 	resp->resok.size = (uint_t)args->count;
1079 	return;
1080 
1081 out:
1082 	if (curthread->t_flag & T_WOULDBLOCK) {
1083 		curthread->t_flag &= ~T_WOULDBLOCK;
1084 		resp->status = NFS3ERR_JUKEBOX;
1085 	} else
1086 		resp->status = puterrno3(error);
1087 out1:
1088 	if (vp != NULL) {
1089 		if (need_rwunlock)
1090 			VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1091 		if (in_crit)
1092 			nbl_end_crit(vp);
1093 		VN_RELE(vp);
1094 	}
1095 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1096 }
1097 
1098 void
1099 rfs3_read_free(READ3res *resp)
1100 {
1101 	mblk_t *mp;
1102 
1103 	if (resp->status == NFS3_OK) {
1104 		mp = resp->resok.data.mp;
1105 		if (mp != NULL)
1106 			freeb(mp);
1107 	}
1108 }
1109 
1110 void *
1111 rfs3_read_getfh(READ3args *args)
1112 {
1113 
1114 	return (&args->file);
1115 }
1116 
1117 #define	MAX_IOVECS	12
1118 
1119 #ifdef DEBUG
1120 static int rfs3_write_hits = 0;
1121 static int rfs3_write_misses = 0;
1122 #endif
1123 
1124 void
1125 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1126 	struct svc_req *req, cred_t *cr)
1127 {
1128 	int error;
1129 	vnode_t *vp;
1130 	struct vattr *bvap = NULL;
1131 	struct vattr bva;
1132 	struct vattr *avap = NULL;
1133 	struct vattr ava;
1134 	u_offset_t rlimit;
1135 	struct uio uio;
1136 	struct iovec iov[MAX_IOVECS];
1137 	mblk_t *m;
1138 	struct iovec *iovp;
1139 	int iovcnt;
1140 	int ioflag;
1141 	cred_t *savecred;
1142 	int in_crit = 0;
1143 	int rwlock_ret = -1;
1144 	caller_context_t ct;
1145 
1146 	vp = nfs3_fhtovp(&args->file, exi);
1147 	if (vp == NULL) {
1148 		error = ESTALE;
1149 		goto out;
1150 	}
1151 
1152 	if (is_system_labeled()) {
1153 		bslabel_t *clabel = req->rq_label;
1154 
1155 		ASSERT(clabel != NULL);
1156 		DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1157 		    "got client label from request(1)", struct svc_req *, req);
1158 
1159 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1160 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
1161 				resp->status = NFS3ERR_ACCES;
1162 				goto out1;
1163 			}
1164 		}
1165 	}
1166 
1167 	ct.cc_sysid = 0;
1168 	ct.cc_pid = 0;
1169 	ct.cc_caller_id = nfs3_srv_caller_id;
1170 	ct.cc_flags = CC_DONTBLOCK;
1171 
1172 	/*
1173 	 * We have to enter the critical region before calling VOP_RWLOCK
1174 	 * to avoid a deadlock with ufs.
1175 	 */
1176 	if (nbl_need_check(vp)) {
1177 		nbl_start_crit(vp, RW_READER);
1178 		in_crit = 1;
1179 		if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
1180 		    NULL)) {
1181 			error = EACCES;
1182 			goto out;
1183 		}
1184 	}
1185 
1186 	rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
1187 
1188 	/* check if a monitor detected a delegation conflict */
1189 	if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1190 		resp->status = NFS3ERR_JUKEBOX;
1191 		rwlock_ret = -1;
1192 		goto out1;
1193 	}
1194 
1195 
1196 	bva.va_mask = AT_ALL;
1197 	error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
1198 
1199 	/*
1200 	 * If we can't get the attributes, then we can't do the
1201 	 * right access checking.  So, we'll fail the request.
1202 	 */
1203 	if (error)
1204 		goto out;
1205 
1206 	bvap = &bva;
1207 #ifdef DEBUG
1208 	if (!rfs3_do_pre_op_attr)
1209 		bvap = NULL;
1210 #endif
1211 	avap = bvap;
1212 
1213 	if (args->count != args->data.data_len) {
1214 		resp->status = NFS3ERR_INVAL;
1215 		goto out1;
1216 	}
1217 
1218 	if (rdonly(exi, req)) {
1219 		resp->status = NFS3ERR_ROFS;
1220 		goto out1;
1221 	}
1222 
1223 	if (vp->v_type != VREG) {
1224 		resp->status = NFS3ERR_INVAL;
1225 		goto out1;
1226 	}
1227 
1228 	if (crgetuid(cr) != bva.va_uid &&
1229 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1230 		goto out;
1231 
1232 	if (MANDLOCK(vp, bva.va_mode)) {
1233 		resp->status = NFS3ERR_ACCES;
1234 		goto out1;
1235 	}
1236 
1237 	if (args->count == 0) {
1238 		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1239 		VN_RELE(vp);
1240 		resp->status = NFS3_OK;
1241 		vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1242 		resp->resok.count = 0;
1243 		resp->resok.committed = args->stable;
1244 		resp->resok.verf = write3verf;
1245 		return;
1246 	}
1247 
1248 	if (args->mblk != NULL) {
1249 		iovcnt = 0;
1250 		for (m = args->mblk; m != NULL; m = m->b_cont)
1251 			iovcnt++;
1252 		if (iovcnt <= MAX_IOVECS) {
1253 #ifdef DEBUG
1254 			rfs3_write_hits++;
1255 #endif
1256 			iovp = iov;
1257 		} else {
1258 #ifdef DEBUG
1259 			rfs3_write_misses++;
1260 #endif
1261 			iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1262 		}
1263 		mblk_to_iov(args->mblk, iovcnt, iovp);
1264 	} else {
1265 		iovcnt = 1;
1266 		iovp = iov;
1267 		iovp->iov_base = args->data.data_val;
1268 		iovp->iov_len = args->count;
1269 	}
1270 
1271 	uio.uio_iov = iovp;
1272 	uio.uio_iovcnt = iovcnt;
1273 
1274 	uio.uio_segflg = UIO_SYSSPACE;
1275 	uio.uio_extflg = UIO_COPY_DEFAULT;
1276 	uio.uio_loffset = args->offset;
1277 	uio.uio_resid = args->count;
1278 	uio.uio_llimit = curproc->p_fsz_ctl;
1279 	rlimit = uio.uio_llimit - args->offset;
1280 	if (rlimit < (u_offset_t)uio.uio_resid)
1281 		uio.uio_resid = (int)rlimit;
1282 
1283 	if (args->stable == UNSTABLE)
1284 		ioflag = 0;
1285 	else if (args->stable == FILE_SYNC)
1286 		ioflag = FSYNC;
1287 	else if (args->stable == DATA_SYNC)
1288 		ioflag = FDSYNC;
1289 	else {
1290 		if (iovp != iov)
1291 			kmem_free(iovp, sizeof (*iovp) * iovcnt);
1292 		resp->status = NFS3ERR_INVAL;
1293 		goto out1;
1294 	}
1295 
1296 	/*
1297 	 * We're changing creds because VM may fault and we need
1298 	 * the cred of the current thread to be used if quota
1299 	 * checking is enabled.
1300 	 */
1301 	savecred = curthread->t_cred;
1302 	curthread->t_cred = cr;
1303 	error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
1304 	curthread->t_cred = savecred;
1305 
1306 	if (iovp != iov)
1307 		kmem_free(iovp, sizeof (*iovp) * iovcnt);
1308 
1309 	/* check if a monitor detected a delegation conflict */
1310 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1311 		resp->status = NFS3ERR_JUKEBOX;
1312 		goto out1;
1313 	}
1314 
1315 	ava.va_mask = AT_ALL;
1316 	avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
1317 
1318 #ifdef DEBUG
1319 	if (!rfs3_do_post_op_attr)
1320 		avap = NULL;
1321 #endif
1322 
1323 	if (error)
1324 		goto out;
1325 
1326 	VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1327 	if (in_crit)
1328 		nbl_end_crit(vp);
1329 	VN_RELE(vp);
1330 
1331 	/*
1332 	 * If we were unable to get the V_WRITELOCK_TRUE, then we
1333 	 * may not have accurate after attrs, so check if
1334 	 * we have both attributes, they have a non-zero va_seq, and
1335 	 * va_seq has changed by exactly one,
1336 	 * if not, turn off the before attr.
1337 	 */
1338 	if (rwlock_ret != V_WRITELOCK_TRUE) {
1339 		if (bvap == NULL || avap == NULL ||
1340 		    bvap->va_seq == 0 || avap->va_seq == 0 ||
1341 		    avap->va_seq != (bvap->va_seq + 1)) {
1342 			bvap = NULL;
1343 		}
1344 	}
1345 
1346 	resp->status = NFS3_OK;
1347 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1348 	resp->resok.count = args->count - uio.uio_resid;
1349 	resp->resok.committed = args->stable;
1350 	resp->resok.verf = write3verf;
1351 	return;
1352 
1353 out:
1354 	if (curthread->t_flag & T_WOULDBLOCK) {
1355 		curthread->t_flag &= ~T_WOULDBLOCK;
1356 		resp->status = NFS3ERR_JUKEBOX;
1357 	} else
1358 		resp->status = puterrno3(error);
1359 out1:
1360 	if (vp != NULL) {
1361 		if (rwlock_ret != -1)
1362 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1363 		if (in_crit)
1364 			nbl_end_crit(vp);
1365 		VN_RELE(vp);
1366 	}
1367 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1368 }
1369 
1370 void *
1371 rfs3_write_getfh(WRITE3args *args)
1372 {
1373 
1374 	return (&args->file);
1375 }
1376 
1377 void
1378 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1379 	struct svc_req *req, cred_t *cr)
1380 {
1381 	int error;
1382 	int in_crit = 0;
1383 	vnode_t *vp;
1384 	vnode_t *tvp = NULL;
1385 	vnode_t *dvp;
1386 	struct vattr *vap;
1387 	struct vattr va;
1388 	struct vattr *dbvap;
1389 	struct vattr dbva;
1390 	struct vattr *davap;
1391 	struct vattr dava;
1392 	enum vcexcl excl;
1393 	nfstime3 *mtime;
1394 	len_t reqsize;
1395 	bool_t trunc;
1396 
1397 	dbvap = NULL;
1398 	davap = NULL;
1399 
1400 	dvp = nfs3_fhtovp(&args->where.dir, exi);
1401 	if (dvp == NULL) {
1402 		error = ESTALE;
1403 		goto out;
1404 	}
1405 
1406 #ifdef DEBUG
1407 	if (rfs3_do_pre_op_attr) {
1408 		dbva.va_mask = AT_ALL;
1409 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1410 	} else
1411 		dbvap = NULL;
1412 #else
1413 	dbva.va_mask = AT_ALL;
1414 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1415 #endif
1416 	davap = dbvap;
1417 
1418 	if (args->where.name == nfs3nametoolong) {
1419 		resp->status = NFS3ERR_NAMETOOLONG;
1420 		goto out1;
1421 	}
1422 
1423 	if (args->where.name == NULL || *(args->where.name) == '\0') {
1424 		resp->status = NFS3ERR_ACCES;
1425 		goto out1;
1426 	}
1427 
1428 	if (rdonly(exi, req)) {
1429 		resp->status = NFS3ERR_ROFS;
1430 		goto out1;
1431 	}
1432 
1433 	if (is_system_labeled()) {
1434 		bslabel_t *clabel = req->rq_label;
1435 
1436 		ASSERT(clabel != NULL);
1437 		DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1438 		    "got client label from request(1)", struct svc_req *, req);
1439 
1440 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1441 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
1442 				resp->status = NFS3ERR_ACCES;
1443 				goto out1;
1444 			}
1445 		}
1446 	}
1447 
1448 	if (args->how.mode == EXCLUSIVE) {
1449 		va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
1450 		va.va_type = VREG;
1451 		va.va_mode = (mode_t)0;
1452 		/*
1453 		 * Ensure no time overflows and that types match
1454 		 */
1455 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1456 		va.va_mtime.tv_sec = mtime->seconds % INT32_MAX;
1457 		va.va_mtime.tv_nsec = mtime->nseconds;
1458 		excl = EXCL;
1459 	} else {
1460 		error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes,
1461 		    &va);
1462 		if (error)
1463 			goto out;
1464 		va.va_mask |= AT_TYPE;
1465 		va.va_type = VREG;
1466 		if (args->how.mode == GUARDED)
1467 			excl = EXCL;
1468 		else {
1469 			excl = NONEXCL;
1470 
1471 			/*
1472 			 * During creation of file in non-exclusive mode
1473 			 * if size of file is being set then make sure
1474 			 * that if the file already exists that no conflicting
1475 			 * non-blocking mandatory locks exists in the region
1476 			 * being modified. If there are conflicting locks fail
1477 			 * the operation with EACCES.
1478 			 */
1479 			if (va.va_mask & AT_SIZE) {
1480 				struct vattr tva;
1481 
1482 				/*
1483 				 * Does file already exist?
1484 				 */
1485 				error = VOP_LOOKUP(dvp, args->where.name, &tvp,
1486 				    NULL, 0, NULL, cr, NULL, NULL, NULL);
1487 
1488 				/*
1489 				 * Check to see if the file has been delegated
1490 				 * to a v4 client.  If so, then begin recall of
1491 				 * the delegation and return JUKEBOX to allow
1492 				 * the client to retrasmit its request.
1493 				 */
1494 
1495 				trunc = va.va_size == 0;
1496 				if (!error &&
1497 				    rfs4_check_delegated(FWRITE, tvp, trunc)) {
1498 					resp->status = NFS3ERR_JUKEBOX;
1499 					goto out1;
1500 				}
1501 
1502 				/*
1503 				 * Check for NBMAND lock conflicts
1504 				 */
1505 				if (!error && nbl_need_check(tvp)) {
1506 					u_offset_t offset;
1507 					ssize_t len;
1508 
1509 					nbl_start_crit(tvp, RW_READER);
1510 					in_crit = 1;
1511 
1512 					tva.va_mask = AT_SIZE;
1513 					error = VOP_GETATTR(tvp, &tva, 0, cr,
1514 					    NULL);
1515 					/*
1516 					 * Can't check for conflicts, so return
1517 					 * error.
1518 					 */
1519 					if (error)
1520 						goto out;
1521 
1522 					offset = tva.va_size < va.va_size ?
1523 					    tva.va_size : va.va_size;
1524 					len = tva.va_size < va.va_size ?
1525 					    va.va_size - tva.va_size :
1526 					    tva.va_size - va.va_size;
1527 					if (nbl_conflict(tvp, NBL_WRITE,
1528 					    offset, len, 0, NULL)) {
1529 						error = EACCES;
1530 						goto out;
1531 					}
1532 				} else if (tvp) {
1533 					VN_RELE(tvp);
1534 					tvp = NULL;
1535 				}
1536 			}
1537 		}
1538 		if (va.va_mask & AT_SIZE)
1539 			reqsize = va.va_size;
1540 	}
1541 
1542 	/*
1543 	 * Must specify the mode.
1544 	 */
1545 	if (!(va.va_mask & AT_MODE)) {
1546 		resp->status = NFS3ERR_INVAL;
1547 		goto out1;
1548 	}
1549 
1550 	/*
1551 	 * If the filesystem is exported with nosuid, then mask off
1552 	 * the setuid and setgid bits.
1553 	 */
1554 	if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
1555 		va.va_mode &= ~(VSUID | VSGID);
1556 
1557 tryagain:
1558 	/*
1559 	 * The file open mode used is VWRITE.  If the client needs
1560 	 * some other semantic, then it should do the access checking
1561 	 * itself.  It would have been nice to have the file open mode
1562 	 * passed as part of the arguments.
1563 	 */
1564 	error = VOP_CREATE(dvp, args->where.name, &va, excl, VWRITE,
1565 	    &vp, cr, 0, NULL, NULL);
1566 
1567 #ifdef DEBUG
1568 	if (rfs3_do_post_op_attr) {
1569 		dava.va_mask = AT_ALL;
1570 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1571 	} else
1572 		davap = NULL;
1573 #else
1574 	dava.va_mask = AT_ALL;
1575 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1576 #endif
1577 
1578 	if (error) {
1579 		/*
1580 		 * If we got something other than file already exists
1581 		 * then just return this error.  Otherwise, we got
1582 		 * EEXIST.  If we were doing a GUARDED create, then
1583 		 * just return this error.  Otherwise, we need to
1584 		 * make sure that this wasn't a duplicate of an
1585 		 * exclusive create request.
1586 		 *
1587 		 * The assumption is made that a non-exclusive create
1588 		 * request will never return EEXIST.
1589 		 */
1590 		if (error != EEXIST || args->how.mode == GUARDED)
1591 			goto out;
1592 		/*
1593 		 * Lookup the file so that we can get a vnode for it.
1594 		 */
1595 		error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0,
1596 		    NULL, cr, NULL, NULL, NULL);
1597 		if (error) {
1598 			/*
1599 			 * We couldn't find the file that we thought that
1600 			 * we just created.  So, we'll just try creating
1601 			 * it again.
1602 			 */
1603 			if (error == ENOENT)
1604 				goto tryagain;
1605 			goto out;
1606 		}
1607 
1608 		/*
1609 		 * If the file is delegated to a v4 client, go ahead
1610 		 * and initiate recall, this create is a hint that a
1611 		 * conflicting v3 open has occurred.
1612 		 */
1613 
1614 		if (rfs4_check_delegated(FWRITE, vp, FALSE)) {
1615 			VN_RELE(vp);
1616 			resp->status = NFS3ERR_JUKEBOX;
1617 			goto out1;
1618 		}
1619 
1620 		va.va_mask = AT_ALL;
1621 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1622 
1623 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1624 		/* % with INT32_MAX to prevent overflows */
1625 		if (args->how.mode == EXCLUSIVE && (vap == NULL ||
1626 		    vap->va_mtime.tv_sec !=
1627 		    (mtime->seconds % INT32_MAX) ||
1628 		    vap->va_mtime.tv_nsec != mtime->nseconds)) {
1629 			VN_RELE(vp);
1630 			error = EEXIST;
1631 			goto out;
1632 		}
1633 	} else {
1634 
1635 		if ((args->how.mode == UNCHECKED ||
1636 		    args->how.mode == GUARDED) &&
1637 		    args->how.createhow3_u.obj_attributes.size.set_it &&
1638 		    va.va_size == 0)
1639 			trunc = TRUE;
1640 		else
1641 			trunc = FALSE;
1642 
1643 		if (rfs4_check_delegated(FWRITE, vp, trunc)) {
1644 			VN_RELE(vp);
1645 			resp->status = NFS3ERR_JUKEBOX;
1646 			goto out1;
1647 		}
1648 
1649 		va.va_mask = AT_ALL;
1650 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1651 
1652 		/*
1653 		 * We need to check to make sure that the file got
1654 		 * created to the indicated size.  If not, we do a
1655 		 * setattr to try to change the size, but we don't
1656 		 * try too hard.  This shouldn't a problem as most
1657 		 * clients will only specifiy a size of zero which
1658 		 * local file systems handle.  However, even if
1659 		 * the client does specify a non-zero size, it can
1660 		 * still recover by checking the size of the file
1661 		 * after it has created it and then issue a setattr
1662 		 * request of its own to set the size of the file.
1663 		 */
1664 		if (vap != NULL &&
1665 		    (args->how.mode == UNCHECKED ||
1666 		    args->how.mode == GUARDED) &&
1667 		    args->how.createhow3_u.obj_attributes.size.set_it &&
1668 		    vap->va_size != reqsize) {
1669 			va.va_mask = AT_SIZE;
1670 			va.va_size = reqsize;
1671 			(void) VOP_SETATTR(vp, &va, 0, cr, NULL);
1672 			va.va_mask = AT_ALL;
1673 			vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1674 		}
1675 	}
1676 
1677 #ifdef DEBUG
1678 	if (!rfs3_do_post_op_attr)
1679 		vap = NULL;
1680 #endif
1681 
1682 #ifdef DEBUG
1683 	if (!rfs3_do_post_op_fh3)
1684 		resp->resok.obj.handle_follows = FALSE;
1685 	else {
1686 #endif
1687 	error = makefh3(&resp->resok.obj.handle, vp, exi);
1688 	if (error)
1689 		resp->resok.obj.handle_follows = FALSE;
1690 	else
1691 		resp->resok.obj.handle_follows = TRUE;
1692 #ifdef DEBUG
1693 	}
1694 #endif
1695 
1696 	/*
1697 	 * Force modified data and metadata out to stable storage.
1698 	 */
1699 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1700 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
1701 
1702 	VN_RELE(vp);
1703 	VN_RELE(dvp);
1704 	if (tvp != NULL) {
1705 		if (in_crit)
1706 			nbl_end_crit(tvp);
1707 		VN_RELE(tvp);
1708 	}
1709 
1710 	resp->status = NFS3_OK;
1711 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1712 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1713 	return;
1714 
1715 out:
1716 	if (curthread->t_flag & T_WOULDBLOCK) {
1717 		curthread->t_flag &= ~T_WOULDBLOCK;
1718 		resp->status = NFS3ERR_JUKEBOX;
1719 	} else
1720 		resp->status = puterrno3(error);
1721 out1:
1722 	if (tvp != NULL) {
1723 		if (in_crit)
1724 			nbl_end_crit(tvp);
1725 		VN_RELE(tvp);
1726 	}
1727 	if (dvp != NULL)
1728 		VN_RELE(dvp);
1729 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1730 }
1731 
1732 void *
1733 rfs3_create_getfh(CREATE3args *args)
1734 {
1735 
1736 	return (&args->where.dir);
1737 }
1738 
1739 void
1740 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1741 	struct svc_req *req, cred_t *cr)
1742 {
1743 	int error;
1744 	vnode_t *vp = NULL;
1745 	vnode_t *dvp;
1746 	struct vattr *vap;
1747 	struct vattr va;
1748 	struct vattr *dbvap;
1749 	struct vattr dbva;
1750 	struct vattr *davap;
1751 	struct vattr dava;
1752 
1753 	dbvap = NULL;
1754 	davap = NULL;
1755 
1756 	dvp = nfs3_fhtovp(&args->where.dir, exi);
1757 	if (dvp == NULL) {
1758 		error = ESTALE;
1759 		goto out;
1760 	}
1761 
1762 #ifdef DEBUG
1763 	if (rfs3_do_pre_op_attr) {
1764 		dbva.va_mask = AT_ALL;
1765 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1766 	} else
1767 		dbvap = NULL;
1768 #else
1769 	dbva.va_mask = AT_ALL;
1770 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1771 #endif
1772 	davap = dbvap;
1773 
1774 	if (args->where.name == nfs3nametoolong) {
1775 		resp->status = NFS3ERR_NAMETOOLONG;
1776 		goto out1;
1777 	}
1778 
1779 	if (args->where.name == NULL || *(args->where.name) == '\0') {
1780 		resp->status = NFS3ERR_ACCES;
1781 		goto out1;
1782 	}
1783 
1784 	if (rdonly(exi, req)) {
1785 		resp->status = NFS3ERR_ROFS;
1786 		goto out1;
1787 	}
1788 
1789 	if (is_system_labeled()) {
1790 		bslabel_t *clabel = req->rq_label;
1791 
1792 		ASSERT(clabel != NULL);
1793 		DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1794 		    "got client label from request(1)", struct svc_req *, req);
1795 
1796 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1797 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
1798 				resp->status = NFS3ERR_ACCES;
1799 				goto out1;
1800 			}
1801 		}
1802 	}
1803 
1804 	error = sattr3_to_vattr(&args->attributes, &va);
1805 	if (error)
1806 		goto out;
1807 
1808 	if (!(va.va_mask & AT_MODE)) {
1809 		resp->status = NFS3ERR_INVAL;
1810 		goto out1;
1811 	}
1812 
1813 	va.va_mask |= AT_TYPE;
1814 	va.va_type = VDIR;
1815 
1816 	error = VOP_MKDIR(dvp, args->where.name, &va, &vp, cr, NULL, 0, NULL);
1817 
1818 #ifdef DEBUG
1819 	if (rfs3_do_post_op_attr) {
1820 		dava.va_mask = AT_ALL;
1821 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1822 	} else
1823 		davap = NULL;
1824 #else
1825 	dava.va_mask = AT_ALL;
1826 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1827 #endif
1828 
1829 	/*
1830 	 * Force modified data and metadata out to stable storage.
1831 	 */
1832 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
1833 
1834 	if (error)
1835 		goto out;
1836 
1837 	VN_RELE(dvp);
1838 
1839 #ifdef DEBUG
1840 	if (!rfs3_do_post_op_fh3)
1841 		resp->resok.obj.handle_follows = FALSE;
1842 	else {
1843 #endif
1844 	error = makefh3(&resp->resok.obj.handle, vp, exi);
1845 	if (error)
1846 		resp->resok.obj.handle_follows = FALSE;
1847 	else
1848 		resp->resok.obj.handle_follows = TRUE;
1849 #ifdef DEBUG
1850 	}
1851 #endif
1852 
1853 #ifdef DEBUG
1854 	if (rfs3_do_post_op_attr) {
1855 		va.va_mask = AT_ALL;
1856 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1857 	} else
1858 		vap = NULL;
1859 #else
1860 	va.va_mask = AT_ALL;
1861 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1862 #endif
1863 
1864 	/*
1865 	 * Force modified data and metadata out to stable storage.
1866 	 */
1867 	(void) VOP_FSYNC(vp, 0, cr, NULL);
1868 
1869 	VN_RELE(vp);
1870 
1871 	resp->status = NFS3_OK;
1872 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1873 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1874 	return;
1875 
1876 out:
1877 	if (curthread->t_flag & T_WOULDBLOCK) {
1878 		curthread->t_flag &= ~T_WOULDBLOCK;
1879 		resp->status = NFS3ERR_JUKEBOX;
1880 	} else
1881 		resp->status = puterrno3(error);
1882 out1:
1883 	if (dvp != NULL)
1884 		VN_RELE(dvp);
1885 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1886 }
1887 
1888 void *
1889 rfs3_mkdir_getfh(MKDIR3args *args)
1890 {
1891 
1892 	return (&args->where.dir);
1893 }
1894 
1895 void
1896 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
1897 	struct svc_req *req, cred_t *cr)
1898 {
1899 	int error;
1900 	vnode_t *vp;
1901 	vnode_t *dvp;
1902 	struct vattr *vap;
1903 	struct vattr va;
1904 	struct vattr *dbvap;
1905 	struct vattr dbva;
1906 	struct vattr *davap;
1907 	struct vattr dava;
1908 
1909 	dbvap = NULL;
1910 	davap = NULL;
1911 
1912 	dvp = nfs3_fhtovp(&args->where.dir, exi);
1913 	if (dvp == NULL) {
1914 		error = ESTALE;
1915 		goto out;
1916 	}
1917 
1918 #ifdef DEBUG
1919 	if (rfs3_do_pre_op_attr) {
1920 		dbva.va_mask = AT_ALL;
1921 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1922 	} else
1923 		dbvap = NULL;
1924 #else
1925 	dbva.va_mask = AT_ALL;
1926 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1927 #endif
1928 	davap = dbvap;
1929 
1930 	if (args->where.name == nfs3nametoolong) {
1931 		resp->status = NFS3ERR_NAMETOOLONG;
1932 		goto out1;
1933 	}
1934 
1935 	if (args->where.name == NULL || *(args->where.name) == '\0') {
1936 		resp->status = NFS3ERR_ACCES;
1937 		goto out1;
1938 	}
1939 
1940 	if (rdonly(exi, req)) {
1941 		resp->status = NFS3ERR_ROFS;
1942 		goto out1;
1943 	}
1944 
1945 	if (is_system_labeled()) {
1946 		bslabel_t *clabel = req->rq_label;
1947 
1948 		ASSERT(clabel != NULL);
1949 		DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
1950 		    "got client label from request(1)", struct svc_req *, req);
1951 
1952 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1953 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
1954 				resp->status = NFS3ERR_ACCES;
1955 				goto out1;
1956 			}
1957 		}
1958 	}
1959 
1960 	error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
1961 	if (error)
1962 		goto out;
1963 
1964 	if (!(va.va_mask & AT_MODE)) {
1965 		resp->status = NFS3ERR_INVAL;
1966 		goto out1;
1967 	}
1968 
1969 	if (args->symlink.symlink_data == nfs3nametoolong) {
1970 		resp->status = NFS3ERR_NAMETOOLONG;
1971 		goto out1;
1972 	}
1973 
1974 	va.va_mask |= AT_TYPE;
1975 	va.va_type = VLNK;
1976 
1977 	error = VOP_SYMLINK(dvp, args->where.name, &va,
1978 	    args->symlink.symlink_data, cr, NULL, 0);
1979 
1980 #ifdef DEBUG
1981 	if (rfs3_do_post_op_attr) {
1982 		dava.va_mask = AT_ALL;
1983 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1984 	} else
1985 		davap = NULL;
1986 #else
1987 	dava.va_mask = AT_ALL;
1988 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1989 #endif
1990 
1991 	if (error)
1992 		goto out;
1993 
1994 	error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0, NULL, cr,
1995 	    NULL, NULL, NULL);
1996 
1997 	/*
1998 	 * Force modified data and metadata out to stable storage.
1999 	 */
2000 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
2001 
2002 	VN_RELE(dvp);
2003 
2004 	resp->status = NFS3_OK;
2005 	if (error) {
2006 		resp->resok.obj.handle_follows = FALSE;
2007 		vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
2008 		vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2009 		return;
2010 	}
2011 
2012 #ifdef DEBUG
2013 	if (!rfs3_do_post_op_fh3)
2014 		resp->resok.obj.handle_follows = FALSE;
2015 	else {
2016 #endif
2017 	error = makefh3(&resp->resok.obj.handle, vp, exi);
2018 	if (error)
2019 		resp->resok.obj.handle_follows = FALSE;
2020 	else
2021 		resp->resok.obj.handle_follows = TRUE;
2022 #ifdef DEBUG
2023 	}
2024 #endif
2025 
2026 #ifdef DEBUG
2027 	if (rfs3_do_post_op_attr) {
2028 		va.va_mask = AT_ALL;
2029 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2030 	} else
2031 		vap = NULL;
2032 #else
2033 	va.va_mask = AT_ALL;
2034 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2035 #endif
2036 
2037 	/*
2038 	 * Force modified data and metadata out to stable storage.
2039 	 */
2040 	(void) VOP_FSYNC(vp, 0, cr, NULL);
2041 
2042 	VN_RELE(vp);
2043 
2044 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2045 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2046 	return;
2047 
2048 out:
2049 	if (curthread->t_flag & T_WOULDBLOCK) {
2050 		curthread->t_flag &= ~T_WOULDBLOCK;
2051 		resp->status = NFS3ERR_JUKEBOX;
2052 	} else
2053 		resp->status = puterrno3(error);
2054 out1:
2055 	if (dvp != NULL)
2056 		VN_RELE(dvp);
2057 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2058 }
2059 
2060 void *
2061 rfs3_symlink_getfh(SYMLINK3args *args)
2062 {
2063 
2064 	return (&args->where.dir);
2065 }
2066 
2067 void
2068 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2069 	struct svc_req *req, cred_t *cr)
2070 {
2071 	int error;
2072 	vnode_t *vp;
2073 	vnode_t *dvp;
2074 	struct vattr *vap;
2075 	struct vattr va;
2076 	struct vattr *dbvap;
2077 	struct vattr dbva;
2078 	struct vattr *davap;
2079 	struct vattr dava;
2080 	int mode;
2081 	enum vcexcl excl;
2082 
2083 	dbvap = NULL;
2084 	davap = NULL;
2085 
2086 	dvp = nfs3_fhtovp(&args->where.dir, exi);
2087 	if (dvp == NULL) {
2088 		error = ESTALE;
2089 		goto out;
2090 	}
2091 
2092 #ifdef DEBUG
2093 	if (rfs3_do_pre_op_attr) {
2094 		dbva.va_mask = AT_ALL;
2095 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2096 	} else
2097 		dbvap = NULL;
2098 #else
2099 	dbva.va_mask = AT_ALL;
2100 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2101 #endif
2102 	davap = dbvap;
2103 
2104 	if (args->where.name == nfs3nametoolong) {
2105 		resp->status = NFS3ERR_NAMETOOLONG;
2106 		goto out1;
2107 	}
2108 
2109 	if (args->where.name == NULL || *(args->where.name) == '\0') {
2110 		resp->status = NFS3ERR_ACCES;
2111 		goto out1;
2112 	}
2113 
2114 	if (rdonly(exi, req)) {
2115 		resp->status = NFS3ERR_ROFS;
2116 		goto out1;
2117 	}
2118 
2119 	if (is_system_labeled()) {
2120 		bslabel_t *clabel = req->rq_label;
2121 
2122 		ASSERT(clabel != NULL);
2123 		DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2124 		    "got client label from request(1)", struct svc_req *, req);
2125 
2126 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2127 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
2128 				resp->status = NFS3ERR_ACCES;
2129 				goto out1;
2130 			}
2131 		}
2132 	}
2133 
2134 	switch (args->what.type) {
2135 	case NF3CHR:
2136 	case NF3BLK:
2137 		error = sattr3_to_vattr(
2138 		    &args->what.mknoddata3_u.device.dev_attributes, &va);
2139 		if (error)
2140 			goto out;
2141 		if (secpolicy_sys_devices(cr) != 0) {
2142 			resp->status = NFS3ERR_PERM;
2143 			goto out1;
2144 		}
2145 		if (args->what.type == NF3CHR)
2146 			va.va_type = VCHR;
2147 		else
2148 			va.va_type = VBLK;
2149 		va.va_rdev = makedevice(
2150 		    args->what.mknoddata3_u.device.spec.specdata1,
2151 		    args->what.mknoddata3_u.device.spec.specdata2);
2152 		va.va_mask |= AT_TYPE | AT_RDEV;
2153 		break;
2154 	case NF3SOCK:
2155 		error = sattr3_to_vattr(
2156 		    &args->what.mknoddata3_u.pipe_attributes, &va);
2157 		if (error)
2158 			goto out;
2159 		va.va_type = VSOCK;
2160 		va.va_mask |= AT_TYPE;
2161 		break;
2162 	case NF3FIFO:
2163 		error = sattr3_to_vattr(
2164 		    &args->what.mknoddata3_u.pipe_attributes, &va);
2165 		if (error)
2166 			goto out;
2167 		va.va_type = VFIFO;
2168 		va.va_mask |= AT_TYPE;
2169 		break;
2170 	default:
2171 		resp->status = NFS3ERR_BADTYPE;
2172 		goto out1;
2173 	}
2174 
2175 	/*
2176 	 * Must specify the mode.
2177 	 */
2178 	if (!(va.va_mask & AT_MODE)) {
2179 		resp->status = NFS3ERR_INVAL;
2180 		goto out1;
2181 	}
2182 
2183 	excl = EXCL;
2184 
2185 	mode = 0;
2186 
2187 	error = VOP_CREATE(dvp, args->where.name, &va, excl, mode,
2188 	    &vp, cr, 0, NULL, NULL);
2189 
2190 #ifdef DEBUG
2191 	if (rfs3_do_post_op_attr) {
2192 		dava.va_mask = AT_ALL;
2193 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2194 	} else
2195 		davap = NULL;
2196 #else
2197 	dava.va_mask = AT_ALL;
2198 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2199 #endif
2200 
2201 	/*
2202 	 * Force modified data and metadata out to stable storage.
2203 	 */
2204 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
2205 
2206 	if (error)
2207 		goto out;
2208 
2209 	VN_RELE(dvp);
2210 
2211 	resp->status = NFS3_OK;
2212 
2213 #ifdef DEBUG
2214 	if (!rfs3_do_post_op_fh3)
2215 		resp->resok.obj.handle_follows = FALSE;
2216 	else {
2217 #endif
2218 	error = makefh3(&resp->resok.obj.handle, vp, exi);
2219 	if (error)
2220 		resp->resok.obj.handle_follows = FALSE;
2221 	else
2222 		resp->resok.obj.handle_follows = TRUE;
2223 #ifdef DEBUG
2224 	}
2225 #endif
2226 
2227 #ifdef DEBUG
2228 	if (rfs3_do_post_op_attr) {
2229 		va.va_mask = AT_ALL;
2230 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2231 	} else
2232 		vap = NULL;
2233 #else
2234 	va.va_mask = AT_ALL;
2235 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2236 #endif
2237 
2238 	/*
2239 	 * Force modified metadata out to stable storage.
2240 	 */
2241 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2242 
2243 	VN_RELE(vp);
2244 
2245 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2246 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2247 	return;
2248 
2249 out:
2250 	if (curthread->t_flag & T_WOULDBLOCK) {
2251 		curthread->t_flag &= ~T_WOULDBLOCK;
2252 		resp->status = NFS3ERR_JUKEBOX;
2253 	} else
2254 		resp->status = puterrno3(error);
2255 out1:
2256 	if (dvp != NULL)
2257 		VN_RELE(dvp);
2258 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2259 }
2260 
2261 void *
2262 rfs3_mknod_getfh(MKNOD3args *args)
2263 {
2264 
2265 	return (&args->where.dir);
2266 }
2267 
2268 void
2269 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2270 	struct svc_req *req, cred_t *cr)
2271 {
2272 	int error = 0;
2273 	vnode_t *vp;
2274 	struct vattr *bvap;
2275 	struct vattr bva;
2276 	struct vattr *avap;
2277 	struct vattr ava;
2278 	vnode_t *targvp = NULL;
2279 
2280 	bvap = NULL;
2281 	avap = NULL;
2282 
2283 	vp = nfs3_fhtovp(&args->object.dir, exi);
2284 	if (vp == NULL) {
2285 		error = ESTALE;
2286 		goto out;
2287 	}
2288 
2289 #ifdef DEBUG
2290 	if (rfs3_do_pre_op_attr) {
2291 		bva.va_mask = AT_ALL;
2292 		bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2293 	} else
2294 		bvap = NULL;
2295 #else
2296 	bva.va_mask = AT_ALL;
2297 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2298 #endif
2299 	avap = bvap;
2300 
2301 	if (vp->v_type != VDIR) {
2302 		resp->status = NFS3ERR_NOTDIR;
2303 		goto out1;
2304 	}
2305 
2306 	if (args->object.name == nfs3nametoolong) {
2307 		resp->status = NFS3ERR_NAMETOOLONG;
2308 		goto out1;
2309 	}
2310 
2311 	if (args->object.name == NULL || *(args->object.name) == '\0') {
2312 		resp->status = NFS3ERR_ACCES;
2313 		goto out1;
2314 	}
2315 
2316 	if (rdonly(exi, req)) {
2317 		resp->status = NFS3ERR_ROFS;
2318 		goto out1;
2319 	}
2320 
2321 	if (is_system_labeled()) {
2322 		bslabel_t *clabel = req->rq_label;
2323 
2324 		ASSERT(clabel != NULL);
2325 		DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *,
2326 		    "got client label from request(1)", struct svc_req *, req);
2327 
2328 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2329 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
2330 				resp->status = NFS3ERR_ACCES;
2331 				goto out1;
2332 			}
2333 		}
2334 	}
2335 
2336 	/*
2337 	 * Check for a conflict with a non-blocking mandatory share
2338 	 * reservation and V4 delegations
2339 	 */
2340 	error = VOP_LOOKUP(vp, args->object.name, &targvp, NULL, 0,
2341 	    NULL, cr, NULL, NULL, NULL);
2342 	if (error != 0)
2343 		goto out;
2344 
2345 	if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2346 		resp->status = NFS3ERR_JUKEBOX;
2347 		goto out1;
2348 	}
2349 
2350 	if (!nbl_need_check(targvp)) {
2351 		error = VOP_REMOVE(vp, args->object.name, cr, NULL, 0);
2352 	} else {
2353 		nbl_start_crit(targvp, RW_READER);
2354 		if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
2355 			error = EACCES;
2356 		} else {
2357 			error = VOP_REMOVE(vp, args->object.name, cr, NULL, 0);
2358 		}
2359 		nbl_end_crit(targvp);
2360 	}
2361 	VN_RELE(targvp);
2362 	targvp = NULL;
2363 
2364 #ifdef DEBUG
2365 	if (rfs3_do_post_op_attr) {
2366 		ava.va_mask = AT_ALL;
2367 		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2368 	} else
2369 		avap = NULL;
2370 #else
2371 	ava.va_mask = AT_ALL;
2372 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2373 #endif
2374 
2375 	/*
2376 	 * Force modified data and metadata out to stable storage.
2377 	 */
2378 	(void) VOP_FSYNC(vp, 0, cr, NULL);
2379 
2380 	if (error)
2381 		goto out;
2382 
2383 	VN_RELE(vp);
2384 
2385 	resp->status = NFS3_OK;
2386 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2387 	return;
2388 
2389 out:
2390 	if (curthread->t_flag & T_WOULDBLOCK) {
2391 		curthread->t_flag &= ~T_WOULDBLOCK;
2392 		resp->status = NFS3ERR_JUKEBOX;
2393 	} else
2394 		resp->status = puterrno3(error);
2395 out1:
2396 	if (vp != NULL)
2397 		VN_RELE(vp);
2398 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2399 }
2400 
2401 void *
2402 rfs3_remove_getfh(REMOVE3args *args)
2403 {
2404 
2405 	return (&args->object.dir);
2406 }
2407 
2408 void
2409 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2410 	struct svc_req *req, cred_t *cr)
2411 {
2412 	int error;
2413 	vnode_t *vp;
2414 	struct vattr *bvap;
2415 	struct vattr bva;
2416 	struct vattr *avap;
2417 	struct vattr ava;
2418 
2419 	bvap = NULL;
2420 	avap = NULL;
2421 
2422 	vp = nfs3_fhtovp(&args->object.dir, exi);
2423 	if (vp == NULL) {
2424 		error = ESTALE;
2425 		goto out;
2426 	}
2427 
2428 #ifdef DEBUG
2429 	if (rfs3_do_pre_op_attr) {
2430 		bva.va_mask = AT_ALL;
2431 		bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2432 	} else
2433 		bvap = NULL;
2434 #else
2435 	bva.va_mask = AT_ALL;
2436 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2437 #endif
2438 	avap = bvap;
2439 
2440 	if (vp->v_type != VDIR) {
2441 		resp->status = NFS3ERR_NOTDIR;
2442 		goto out1;
2443 	}
2444 
2445 	if (args->object.name == nfs3nametoolong) {
2446 		resp->status = NFS3ERR_NAMETOOLONG;
2447 		goto out1;
2448 	}
2449 
2450 	if (args->object.name == NULL || *(args->object.name) == '\0') {
2451 		resp->status = NFS3ERR_ACCES;
2452 		goto out1;
2453 	}
2454 
2455 	if (rdonly(exi, req)) {
2456 		resp->status = NFS3ERR_ROFS;
2457 		goto out1;
2458 	}
2459 
2460 	if (is_system_labeled()) {
2461 		bslabel_t *clabel = req->rq_label;
2462 
2463 		ASSERT(clabel != NULL);
2464 		DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *,
2465 		    "got client label from request(1)", struct svc_req *, req);
2466 
2467 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2468 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
2469 				resp->status = NFS3ERR_ACCES;
2470 				goto out1;
2471 			}
2472 		}
2473 	}
2474 
2475 	error = VOP_RMDIR(vp, args->object.name, rootdir, cr, NULL, 0);
2476 
2477 #ifdef DEBUG
2478 	if (rfs3_do_post_op_attr) {
2479 		ava.va_mask = AT_ALL;
2480 		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2481 	} else
2482 		avap = NULL;
2483 #else
2484 	ava.va_mask = AT_ALL;
2485 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2486 #endif
2487 
2488 	/*
2489 	 * Force modified data and metadata out to stable storage.
2490 	 */
2491 	(void) VOP_FSYNC(vp, 0, cr, NULL);
2492 
2493 	if (error) {
2494 		/*
2495 		 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2496 		 * if the directory is not empty.  A System V NFS server
2497 		 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2498 		 * over the wire.
2499 		 */
2500 		if (error == EEXIST)
2501 			error = ENOTEMPTY;
2502 		goto out;
2503 	}
2504 
2505 	VN_RELE(vp);
2506 
2507 	resp->status = NFS3_OK;
2508 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2509 	return;
2510 
2511 out:
2512 	if (curthread->t_flag & T_WOULDBLOCK) {
2513 		curthread->t_flag &= ~T_WOULDBLOCK;
2514 		resp->status = NFS3ERR_JUKEBOX;
2515 	} else
2516 		resp->status = puterrno3(error);
2517 out1:
2518 	if (vp != NULL)
2519 		VN_RELE(vp);
2520 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2521 }
2522 
2523 void *
2524 rfs3_rmdir_getfh(RMDIR3args *args)
2525 {
2526 
2527 	return (&args->object.dir);
2528 }
2529 
2530 void
2531 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2532 	struct svc_req *req, cred_t *cr)
2533 {
2534 	int error = 0;
2535 	vnode_t *fvp;
2536 	vnode_t *tvp;
2537 	vnode_t *targvp;
2538 	struct vattr *fbvap;
2539 	struct vattr fbva;
2540 	struct vattr *favap;
2541 	struct vattr fava;
2542 	struct vattr *tbvap;
2543 	struct vattr tbva;
2544 	struct vattr *tavap;
2545 	struct vattr tava;
2546 	nfs_fh3 *fh3;
2547 	struct exportinfo *to_exi;
2548 	vnode_t *srcvp = NULL;
2549 	bslabel_t *clabel;
2550 
2551 	fbvap = NULL;
2552 	favap = NULL;
2553 	tbvap = NULL;
2554 	tavap = NULL;
2555 	tvp = NULL;
2556 
2557 	fvp = nfs3_fhtovp(&args->from.dir, exi);
2558 	if (fvp == NULL) {
2559 		error = ESTALE;
2560 		goto out;
2561 	}
2562 
2563 	if (is_system_labeled()) {
2564 		clabel = req->rq_label;
2565 		ASSERT(clabel != NULL);
2566 		DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2567 		    "got client label from request(1)", struct svc_req *, req);
2568 
2569 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2570 			if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK)) {
2571 				resp->status = NFS3ERR_ACCES;
2572 				goto out1;
2573 			}
2574 		}
2575 	}
2576 
2577 #ifdef DEBUG
2578 	if (rfs3_do_pre_op_attr) {
2579 		fbva.va_mask = AT_ALL;
2580 		fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2581 	} else
2582 		fbvap = NULL;
2583 #else
2584 	fbva.va_mask = AT_ALL;
2585 	fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2586 #endif
2587 	favap = fbvap;
2588 
2589 	fh3 = &args->to.dir;
2590 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2591 	if (to_exi == NULL) {
2592 		resp->status = NFS3ERR_ACCES;
2593 		goto out1;
2594 	}
2595 	exi_rele(to_exi);
2596 
2597 	if (to_exi != exi) {
2598 		resp->status = NFS3ERR_XDEV;
2599 		goto out1;
2600 	}
2601 
2602 	tvp = nfs3_fhtovp(&args->to.dir, exi);
2603 	if (tvp == NULL) {
2604 		error = ESTALE;
2605 		goto out;
2606 	}
2607 
2608 #ifdef DEBUG
2609 	if (rfs3_do_pre_op_attr) {
2610 		tbva.va_mask = AT_ALL;
2611 		tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2612 	} else
2613 		tbvap = NULL;
2614 #else
2615 	tbva.va_mask = AT_ALL;
2616 	tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2617 #endif
2618 	tavap = tbvap;
2619 
2620 	if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2621 		resp->status = NFS3ERR_NOTDIR;
2622 		goto out1;
2623 	}
2624 
2625 	if (args->from.name == nfs3nametoolong ||
2626 	    args->to.name == nfs3nametoolong) {
2627 		resp->status = NFS3ERR_NAMETOOLONG;
2628 		goto out1;
2629 	}
2630 	if (args->from.name == NULL || *(args->from.name) == '\0' ||
2631 	    args->to.name == NULL || *(args->to.name) == '\0') {
2632 		resp->status = NFS3ERR_ACCES;
2633 		goto out1;
2634 	}
2635 
2636 	if (rdonly(exi, req)) {
2637 		resp->status = NFS3ERR_ROFS;
2638 		goto out1;
2639 	}
2640 
2641 	if (is_system_labeled()) {
2642 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2643 			if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK)) {
2644 				resp->status = NFS3ERR_ACCES;
2645 				goto out1;
2646 			}
2647 		}
2648 	}
2649 
2650 	/*
2651 	 * Check for a conflict with a non-blocking mandatory share
2652 	 * reservation or V4 delegations.
2653 	 */
2654 	error = VOP_LOOKUP(fvp, args->from.name, &srcvp, NULL, 0,
2655 	    NULL, cr, NULL, NULL, NULL);
2656 	if (error != 0)
2657 		goto out;
2658 
2659 	/*
2660 	 * If we rename a delegated file we should recall the
2661 	 * delegation, since future opens should fail or would
2662 	 * refer to a new file.
2663 	 */
2664 	if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2665 		resp->status = NFS3ERR_JUKEBOX;
2666 		goto out1;
2667 	}
2668 
2669 	/*
2670 	 * Check for renaming over a delegated file.  Check rfs4_deleg_policy
2671 	 * first to avoid VOP_LOOKUP if possible.
2672 	 */
2673 	if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
2674 	    VOP_LOOKUP(tvp, args->to.name, &targvp, NULL, 0, NULL, cr,
2675 	    NULL, NULL, NULL) == 0) {
2676 
2677 		if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2678 			VN_RELE(targvp);
2679 			resp->status = NFS3ERR_JUKEBOX;
2680 			goto out1;
2681 		}
2682 		VN_RELE(targvp);
2683 	}
2684 
2685 	if (!nbl_need_check(srcvp)) {
2686 		error = VOP_RENAME(fvp, args->from.name, tvp,
2687 		    args->to.name, cr, NULL, 0);
2688 	} else {
2689 		nbl_start_crit(srcvp, RW_READER);
2690 		if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
2691 			error = EACCES;
2692 		} else {
2693 			error = VOP_RENAME(fvp, args->from.name, tvp,
2694 			    args->to.name, cr, NULL, 0);
2695 		}
2696 		nbl_end_crit(srcvp);
2697 	}
2698 	if (error == 0) {
2699 		char *tmp;
2700 
2701 		/* fix the path name for the renamed file */
2702 		mutex_enter(&srcvp->v_lock);
2703 		tmp = srcvp->v_path;
2704 		srcvp->v_path = NULL;
2705 		mutex_exit(&srcvp->v_lock);
2706 		vn_setpath(rootdir, tvp, srcvp, args->to.name,
2707 		    strlen(args->to.name));
2708 		if (tmp != NULL)
2709 			kmem_free(tmp, strlen(tmp) + 1);
2710 	}
2711 	VN_RELE(srcvp);
2712 	srcvp = NULL;
2713 
2714 #ifdef DEBUG
2715 	if (rfs3_do_post_op_attr) {
2716 		fava.va_mask = AT_ALL;
2717 		favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
2718 		tava.va_mask = AT_ALL;
2719 		tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
2720 	} else {
2721 		favap = NULL;
2722 		tavap = NULL;
2723 	}
2724 #else
2725 	fava.va_mask = AT_ALL;
2726 	favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
2727 	tava.va_mask = AT_ALL;
2728 	tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
2729 #endif
2730 
2731 	/*
2732 	 * Force modified data and metadata out to stable storage.
2733 	 */
2734 	(void) VOP_FSYNC(fvp, 0, cr, NULL);
2735 	(void) VOP_FSYNC(tvp, 0, cr, NULL);
2736 
2737 	if (error)
2738 		goto out;
2739 
2740 	VN_RELE(tvp);
2741 	VN_RELE(fvp);
2742 
2743 	resp->status = NFS3_OK;
2744 	vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
2745 	vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2746 	return;
2747 
2748 out:
2749 	if (curthread->t_flag & T_WOULDBLOCK) {
2750 		curthread->t_flag &= ~T_WOULDBLOCK;
2751 		resp->status = NFS3ERR_JUKEBOX;
2752 	} else
2753 		resp->status = puterrno3(error);
2754 out1:
2755 	if (fvp != NULL)
2756 		VN_RELE(fvp);
2757 	if (tvp != NULL)
2758 		VN_RELE(tvp);
2759 	vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2760 	vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2761 }
2762 
2763 void *
2764 rfs3_rename_getfh(RENAME3args *args)
2765 {
2766 
2767 	return (&args->from.dir);
2768 }
2769 
2770 void
2771 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2772 	struct svc_req *req, cred_t *cr)
2773 {
2774 	int error;
2775 	vnode_t *vp;
2776 	vnode_t *dvp;
2777 	struct vattr *vap;
2778 	struct vattr va;
2779 	struct vattr *bvap;
2780 	struct vattr bva;
2781 	struct vattr *avap;
2782 	struct vattr ava;
2783 	nfs_fh3	*fh3;
2784 	struct exportinfo *to_exi;
2785 	bslabel_t *clabel;
2786 
2787 	vap = NULL;
2788 	bvap = NULL;
2789 	avap = NULL;
2790 	dvp = NULL;
2791 
2792 	vp = nfs3_fhtovp(&args->file, exi);
2793 	if (vp == NULL) {
2794 		error = ESTALE;
2795 		goto out;
2796 	}
2797 
2798 #ifdef DEBUG
2799 	if (rfs3_do_pre_op_attr) {
2800 		va.va_mask = AT_ALL;
2801 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2802 	} else
2803 		vap = NULL;
2804 #else
2805 	va.va_mask = AT_ALL;
2806 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2807 #endif
2808 
2809 	fh3 = &args->link.dir;
2810 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2811 	if (to_exi == NULL) {
2812 		resp->status = NFS3ERR_ACCES;
2813 		goto out1;
2814 	}
2815 	exi_rele(to_exi);
2816 
2817 	if (to_exi != exi) {
2818 		resp->status = NFS3ERR_XDEV;
2819 		goto out1;
2820 	}
2821 
2822 	if (is_system_labeled()) {
2823 		clabel = req->rq_label;
2824 
2825 		ASSERT(clabel != NULL);
2826 		DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
2827 		    "got client label from request(1)", struct svc_req *, req);
2828 
2829 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2830 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
2831 				resp->status = NFS3ERR_ACCES;
2832 				goto out1;
2833 			}
2834 		}
2835 	}
2836 
2837 	dvp = nfs3_fhtovp(&args->link.dir, exi);
2838 	if (dvp == NULL) {
2839 		error = ESTALE;
2840 		goto out;
2841 	}
2842 
2843 #ifdef DEBUG
2844 	if (rfs3_do_pre_op_attr) {
2845 		bva.va_mask = AT_ALL;
2846 		bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
2847 	} else
2848 		bvap = NULL;
2849 #else
2850 	bva.va_mask = AT_ALL;
2851 	bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
2852 #endif
2853 
2854 	if (dvp->v_type != VDIR) {
2855 		resp->status = NFS3ERR_NOTDIR;
2856 		goto out1;
2857 	}
2858 
2859 	if (args->link.name == nfs3nametoolong) {
2860 		resp->status = NFS3ERR_NAMETOOLONG;
2861 		goto out1;
2862 	}
2863 
2864 	if (args->link.name == NULL || *(args->link.name) == '\0') {
2865 		resp->status = NFS3ERR_ACCES;
2866 		goto out1;
2867 	}
2868 
2869 	if (rdonly(exi, req)) {
2870 		resp->status = NFS3ERR_ROFS;
2871 		goto out1;
2872 	}
2873 
2874 	if (is_system_labeled()) {
2875 		DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
2876 		    "got client label from request(1)", struct svc_req *, req);
2877 
2878 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2879 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
2880 				resp->status = NFS3ERR_ACCES;
2881 				goto out1;
2882 			}
2883 		}
2884 	}
2885 
2886 	error = VOP_LINK(dvp, vp, args->link.name, cr, NULL, 0);
2887 
2888 #ifdef DEBUG
2889 	if (rfs3_do_post_op_attr) {
2890 		va.va_mask = AT_ALL;
2891 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2892 		ava.va_mask = AT_ALL;
2893 		avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
2894 	} else {
2895 		vap = NULL;
2896 		avap = NULL;
2897 	}
2898 #else
2899 	va.va_mask = AT_ALL;
2900 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2901 	ava.va_mask = AT_ALL;
2902 	avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
2903 #endif
2904 
2905 	/*
2906 	 * Force modified data and metadata out to stable storage.
2907 	 */
2908 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2909 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
2910 
2911 	if (error)
2912 		goto out;
2913 
2914 	VN_RELE(dvp);
2915 	VN_RELE(vp);
2916 
2917 	resp->status = NFS3_OK;
2918 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
2919 	vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
2920 	return;
2921 
2922 out:
2923 	if (curthread->t_flag & T_WOULDBLOCK) {
2924 		curthread->t_flag &= ~T_WOULDBLOCK;
2925 		resp->status = NFS3ERR_JUKEBOX;
2926 	} else
2927 		resp->status = puterrno3(error);
2928 out1:
2929 	if (vp != NULL)
2930 		VN_RELE(vp);
2931 	if (dvp != NULL)
2932 		VN_RELE(dvp);
2933 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
2934 	vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
2935 }
2936 
2937 void *
2938 rfs3_link_getfh(LINK3args *args)
2939 {
2940 
2941 	return (&args->file);
2942 }
2943 
2944 /*
2945  * This macro defines the size of a response which contains attribute
2946  * information and one directory entry (whose length is specified by
2947  * the macro parameter).  If the incoming request is larger than this,
2948  * then we are guaranteed to be able to return at one directory entry
2949  * if one exists.  Therefore, we do not need to check for
2950  * NFS3ERR_TOOSMALL if the requested size is larger then this.  If it
2951  * is not, then we need to check to make sure that this error does not
2952  * need to be returned.
2953  *
2954  * NFS3_READDIR_MIN_COUNT is comprised of following :
2955  *
2956  * status - 1 * BYTES_PER_XDR_UNIT
2957  * attr. flag - 1 * BYTES_PER_XDR_UNIT
2958  * cookie verifier - 2 * BYTES_PER_XDR_UNIT
2959  * attributes  - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
2960  * boolean - 1 * BYTES_PER_XDR_UNIT
2961  * file id - 2 * BYTES_PER_XDR_UNIT
2962  * directory name length - 1 * BYTES_PER_XDR_UNIT
2963  * cookie - 2 * BYTES_PER_XDR_UNIT
2964  * end of list - 1 * BYTES_PER_XDR_UNIT
2965  * end of file - 1 * BYTES_PER_XDR_UNIT
2966  * Name length of directory to the nearest byte
2967  */
2968 
2969 #define	NFS3_READDIR_MIN_COUNT(length)	\
2970 	((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
2971 		BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
2972 
2973 /* ARGSUSED */
2974 void
2975 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
2976 	struct svc_req *req, cred_t *cr)
2977 {
2978 	int error;
2979 	vnode_t *vp;
2980 	struct vattr *vap;
2981 	struct vattr va;
2982 	struct iovec iov;
2983 	struct uio uio;
2984 	char *data;
2985 	int iseof;
2986 	int bufsize;
2987 	int namlen;
2988 	uint_t count;
2989 
2990 	vap = NULL;
2991 
2992 	vp = nfs3_fhtovp(&args->dir, exi);
2993 	if (vp == NULL) {
2994 		error = ESTALE;
2995 		goto out;
2996 	}
2997 
2998 	if (is_system_labeled()) {
2999 		bslabel_t *clabel = req->rq_label;
3000 
3001 		ASSERT(clabel != NULL);
3002 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3003 		    "got client label from request(1)", struct svc_req *, req);
3004 
3005 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3006 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
3007 				resp->status = NFS3ERR_ACCES;
3008 				goto out1;
3009 			}
3010 		}
3011 	}
3012 
3013 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3014 
3015 #ifdef DEBUG
3016 	if (rfs3_do_pre_op_attr) {
3017 		va.va_mask = AT_ALL;
3018 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3019 	} else
3020 		vap = NULL;
3021 #else
3022 	va.va_mask = AT_ALL;
3023 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3024 #endif
3025 
3026 	if (vp->v_type != VDIR) {
3027 		resp->status = NFS3ERR_NOTDIR;
3028 		goto out1;
3029 	}
3030 
3031 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3032 	if (error)
3033 		goto out;
3034 
3035 	/*
3036 	 * Now don't allow arbitrary count to alloc;
3037 	 * allow the maximum not to exceed rfs3_tsize()
3038 	 */
3039 	if (args->count > rfs3_tsize(req))
3040 		args->count = rfs3_tsize(req);
3041 
3042 	/*
3043 	 * Make sure that there is room to read at least one entry
3044 	 * if any are available.
3045 	 */
3046 	if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3047 		count = DIRENT64_RECLEN(MAXNAMELEN);
3048 	else
3049 		count = args->count;
3050 
3051 	data = kmem_alloc(count, KM_SLEEP);
3052 
3053 	iov.iov_base = data;
3054 	iov.iov_len = count;
3055 	uio.uio_iov = &iov;
3056 	uio.uio_iovcnt = 1;
3057 	uio.uio_segflg = UIO_SYSSPACE;
3058 	uio.uio_extflg = UIO_COPY_CACHED;
3059 	uio.uio_loffset = (offset_t)args->cookie;
3060 	uio.uio_resid = count;
3061 
3062 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3063 
3064 #ifdef DEBUG
3065 	if (rfs3_do_post_op_attr) {
3066 		va.va_mask = AT_ALL;
3067 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3068 	} else
3069 		vap = NULL;
3070 #else
3071 	va.va_mask = AT_ALL;
3072 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3073 #endif
3074 
3075 	if (error) {
3076 		kmem_free(data, count);
3077 		goto out;
3078 	}
3079 
3080 	/*
3081 	 * If the count was not large enough to be able to guarantee
3082 	 * to be able to return at least one entry, then need to
3083 	 * check to see if NFS3ERR_TOOSMALL should be returned.
3084 	 */
3085 	if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3086 		/*
3087 		 * bufsize is used to keep track of the size of the response.
3088 		 * It is primed with:
3089 		 *	1 for the status +
3090 		 *	1 for the dir_attributes.attributes boolean +
3091 		 *	2 for the cookie verifier
3092 		 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3093 		 * to bytes.  If there are directory attributes to be
3094 		 * returned, then:
3095 		 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3096 		 * time BYTES_PER_XDR_UNIT is added to account for them.
3097 		 */
3098 		bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3099 		if (vap != NULL)
3100 			bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3101 		/*
3102 		 * An entry is composed of:
3103 		 *	1 for the true/false list indicator +
3104 		 *	2 for the fileid +
3105 		 *	1 for the length of the name +
3106 		 *	2 for the cookie +
3107 		 * all times BYTES_PER_XDR_UNIT to convert from
3108 		 * XDR units to bytes, plus the length of the name
3109 		 * rounded up to the nearest BYTES_PER_XDR_UNIT.
3110 		 */
3111 		if (count != uio.uio_resid) {
3112 			namlen = strlen(((struct dirent64 *)data)->d_name);
3113 			bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3114 			    roundup(namlen, BYTES_PER_XDR_UNIT);
3115 		}
3116 		/*
3117 		 * We need to check to see if the number of bytes left
3118 		 * to go into the buffer will actually fit into the
3119 		 * buffer.  This is calculated as the size of this
3120 		 * entry plus:
3121 		 *	1 for the true/false list indicator +
3122 		 *	1 for the eof indicator
3123 		 * times BYTES_PER_XDR_UNIT to convert from from
3124 		 * XDR units to bytes.
3125 		 */
3126 		bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
3127 		if (bufsize > args->count) {
3128 			kmem_free(data, count);
3129 			resp->status = NFS3ERR_TOOSMALL;
3130 			goto out1;
3131 		}
3132 	}
3133 
3134 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3135 
3136 #if 0 /* notyet */
3137 	/*
3138 	 * Don't do this.  It causes local disk writes when just
3139 	 * reading the file and the overhead is deemed larger
3140 	 * than the benefit.
3141 	 */
3142 	/*
3143 	 * Force modified metadata out to stable storage.
3144 	 */
3145 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3146 #endif
3147 
3148 	VN_RELE(vp);
3149 
3150 	resp->status = NFS3_OK;
3151 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3152 	resp->resok.cookieverf = 0;
3153 	resp->resok.reply.entries = (entry3 *)data;
3154 	resp->resok.reply.eof = iseof;
3155 	resp->resok.size = count - uio.uio_resid;
3156 	resp->resok.count = args->count;
3157 	resp->resok.freecount = count;
3158 	return;
3159 
3160 out:
3161 	if (curthread->t_flag & T_WOULDBLOCK) {
3162 		curthread->t_flag &= ~T_WOULDBLOCK;
3163 		resp->status = NFS3ERR_JUKEBOX;
3164 	} else
3165 		resp->status = puterrno3(error);
3166 out1:
3167 	if (vp != NULL) {
3168 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3169 		VN_RELE(vp);
3170 	}
3171 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3172 }
3173 
3174 void *
3175 rfs3_readdir_getfh(READDIR3args *args)
3176 {
3177 
3178 	return (&args->dir);
3179 }
3180 
3181 void
3182 rfs3_readdir_free(READDIR3res *resp)
3183 {
3184 
3185 	if (resp->status == NFS3_OK)
3186 		kmem_free(resp->resok.reply.entries, resp->resok.freecount);
3187 }
3188 
3189 #ifdef nextdp
3190 #undef nextdp
3191 #endif
3192 #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3193 
3194 /*
3195  * This macro computes the size of a response which contains
3196  * one directory entry including the attributes as well as file handle.
3197  * If the incoming request is larger than this, then we are guaranteed to be
3198  * able to return at least one more directory entry if one exists.
3199  *
3200  * NFS3_READDIRPLUS_ENTRY is made up of the following:
3201  *
3202  * boolean - 1 * BYTES_PER_XDR_UNIT
3203  * file id - 2 * BYTES_PER_XDR_UNIT
3204  * directory name length - 1 * BYTES_PER_XDR_UNIT
3205  * cookie - 2 * BYTES_PER_XDR_UNIT
3206  * attribute flag - 1 * BYTES_PER_XDR_UNIT
3207  * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3208  * status byte for file handle - 1 *  BYTES_PER_XDR_UNIT
3209  * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3210  * Maximum length of a file handle (NFS3_MAXFHSIZE)
3211  * name length of the entry to the nearest bytes
3212  */
3213 #define	NFS3_READDIRPLUS_ENTRY(namelen)	\
3214 	((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
3215 		BYTES_PER_XDR_UNIT + \
3216 	NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
3217 
3218 static int rfs3_readdir_unit = MAXBSIZE;
3219 
3220 /* ARGSUSED */
3221 void
3222 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3223 	struct exportinfo *exi, struct svc_req *req, cred_t *cr)
3224 {
3225 	int error;
3226 	vnode_t *vp;
3227 	struct vattr *vap;
3228 	struct vattr va;
3229 	struct iovec iov;
3230 	struct uio uio;
3231 	char *data;
3232 	int iseof;
3233 	struct dirent64 *dp;
3234 	vnode_t *nvp;
3235 	struct vattr *nvap;
3236 	struct vattr nva;
3237 	entryplus3_info *infop = NULL;
3238 	int size = 0;
3239 	int nents = 0;
3240 	int bufsize = 0;
3241 	int entrysize = 0;
3242 	int tofit = 0;
3243 	int rd_unit = rfs3_readdir_unit;
3244 	int prev_len;
3245 	int space_left;
3246 	int i;
3247 	uint_t *namlen = NULL;
3248 
3249 	vap = NULL;
3250 
3251 	vp = nfs3_fhtovp(&args->dir, exi);
3252 	if (vp == NULL) {
3253 		error = ESTALE;
3254 		goto out;
3255 	}
3256 
3257 	if (is_system_labeled()) {
3258 		bslabel_t *clabel = req->rq_label;
3259 
3260 		ASSERT(clabel != NULL);
3261 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3262 		    char *, "got client label from request(1)",
3263 		    struct svc_req *, req);
3264 
3265 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3266 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
3267 				resp->status = NFS3ERR_ACCES;
3268 				goto out1;
3269 			}
3270 		}
3271 	}
3272 
3273 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3274 
3275 #ifdef DEBUG
3276 	if (rfs3_do_pre_op_attr) {
3277 		va.va_mask = AT_ALL;
3278 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3279 	} else
3280 		vap = NULL;
3281 #else
3282 	va.va_mask = AT_ALL;
3283 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3284 #endif
3285 
3286 	if (vp->v_type != VDIR) {
3287 		error = ENOTDIR;
3288 		goto out;
3289 	}
3290 
3291 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3292 	if (error)
3293 		goto out;
3294 
3295 	/*
3296 	 * Don't allow arbitrary counts for allocation
3297 	 */
3298 	if (args->maxcount > rfs3_tsize(req))
3299 		args->maxcount = rfs3_tsize(req);
3300 
3301 	/*
3302 	 * Make sure that there is room to read at least one entry
3303 	 * if any are available
3304 	 */
3305 	args->dircount = MIN(args->dircount, args->maxcount);
3306 
3307 	if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
3308 		args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
3309 
3310 	/*
3311 	 * This allocation relies on a minimum directory entry
3312 	 * being roughly 24 bytes.  Therefore, the namlen array
3313 	 * will have enough space based on the maximum number of
3314 	 * entries to read.
3315 	 */
3316 	namlen = kmem_alloc(args->dircount, KM_SLEEP);
3317 
3318 	space_left = args->dircount;
3319 	data = kmem_alloc(args->dircount, KM_SLEEP);
3320 	dp = (struct dirent64 *)data;
3321 	uio.uio_iov = &iov;
3322 	uio.uio_iovcnt = 1;
3323 	uio.uio_segflg = UIO_SYSSPACE;
3324 	uio.uio_extflg = UIO_COPY_CACHED;
3325 	uio.uio_loffset = (offset_t)args->cookie;
3326 
3327 	/*
3328 	 * bufsize is used to keep track of the size of the response as we
3329 	 * get post op attributes and filehandles for each entry.  This is
3330 	 * an optimization as the server may have read more entries than will
3331 	 * fit in the buffer specified by maxcount.  We stop calculating
3332 	 * post op attributes and filehandles once we have exceeded maxcount.
3333 	 * This will minimize the effect of truncation.
3334 	 *
3335 	 * It is primed with:
3336 	 *	1 for the status +
3337 	 *	1 for the dir_attributes.attributes boolean +
3338 	 *	2 for the cookie verifier
3339 	 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3340 	 * to bytes.  If there are directory attributes to be
3341 	 * returned, then:
3342 	 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3343 	 * time BYTES_PER_XDR_UNIT is added to account for them.
3344 	 */
3345 	bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3346 	if (vap != NULL)
3347 		bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3348 
3349 getmoredents:
3350 	/*
3351 	 * Here we make a check so that our read unit is not larger than
3352 	 * the space left in the buffer.
3353 	 */
3354 	rd_unit = MIN(rd_unit, space_left);
3355 	iov.iov_base = (char *)dp;
3356 	iov.iov_len = rd_unit;
3357 	uio.uio_resid = rd_unit;
3358 	prev_len = rd_unit;
3359 
3360 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3361 
3362 	if (error) {
3363 		kmem_free(data, args->dircount);
3364 		goto out;
3365 	}
3366 
3367 	if (uio.uio_resid == prev_len && !iseof) {
3368 		if (nents == 0) {
3369 			kmem_free(data, args->dircount);
3370 			resp->status = NFS3ERR_TOOSMALL;
3371 			goto out1;
3372 		}
3373 
3374 		/*
3375 		 * We could not get any more entries, so get the attributes
3376 		 * and filehandle for the entries already obtained.
3377 		 */
3378 		goto good;
3379 	}
3380 
3381 	/*
3382 	 * We estimate the size of the response by assuming the
3383 	 * entry exists and attributes and filehandle are also valid
3384 	 */
3385 	for (size = prev_len - uio.uio_resid;
3386 	    size > 0;
3387 	    size -= dp->d_reclen, dp = nextdp(dp)) {
3388 
3389 		if (dp->d_ino == 0) {
3390 			nents++;
3391 			continue;
3392 		}
3393 
3394 		namlen[nents] = strlen(dp->d_name);
3395 		entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
3396 
3397 		/*
3398 		 * We need to check to see if the number of bytes left
3399 		 * to go into the buffer will actually fit into the
3400 		 * buffer.  This is calculated as the size of this
3401 		 * entry plus:
3402 		 *	1 for the true/false list indicator +
3403 		 *	1 for the eof indicator
3404 		 * times BYTES_PER_XDR_UNIT to convert from XDR units
3405 		 * to bytes.
3406 		 *
3407 		 * Also check the dircount limit against the first entry read
3408 		 *
3409 		 */
3410 		tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
3411 		if (bufsize + tofit > args->maxcount) {
3412 			/*
3413 			 * We make a check here to see if this was the
3414 			 * first entry being measured.  If so, then maxcount
3415 			 * was too small to begin with and so we need to
3416 			 * return with NFS3ERR_TOOSMALL.
3417 			 */
3418 			if (nents == 0) {
3419 				kmem_free(data, args->dircount);
3420 				resp->status = NFS3ERR_TOOSMALL;
3421 				goto out1;
3422 			}
3423 			iseof = FALSE;
3424 			goto good;
3425 		}
3426 		bufsize += entrysize;
3427 		nents++;
3428 	}
3429 
3430 	/*
3431 	 * If there is enough room to fit at least 1 more entry including
3432 	 * post op attributes and filehandle in the buffer AND that we haven't
3433 	 * exceeded dircount then go back and get some more.
3434 	 */
3435 	if (!iseof &&
3436 	    (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3437 		space_left -= (prev_len - uio.uio_resid);
3438 		if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3439 			goto getmoredents;
3440 
3441 		/* else, fall through */
3442 	}
3443 
3444 good:
3445 
3446 #ifdef DEBUG
3447 	if (rfs3_do_post_op_attr) {
3448 		va.va_mask = AT_ALL;
3449 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3450 	} else
3451 		vap = NULL;
3452 #else
3453 	va.va_mask = AT_ALL;
3454 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3455 #endif
3456 
3457 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3458 
3459 	infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3460 	resp->resok.infop = infop;
3461 
3462 	dp = (struct dirent64 *)data;
3463 	for (i = 0; i < nents; i++) {
3464 
3465 		if (dp->d_ino == 0) {
3466 			infop[i].attr.attributes = FALSE;
3467 			infop[i].fh.handle_follows = FALSE;
3468 			dp = nextdp(dp);
3469 			continue;
3470 		}
3471 
3472 		infop[i].namelen = namlen[i];
3473 
3474 		error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3475 		    NULL, NULL, NULL);
3476 		if (error) {
3477 			infop[i].attr.attributes = FALSE;
3478 			infop[i].fh.handle_follows = FALSE;
3479 			dp = nextdp(dp);
3480 			continue;
3481 		}
3482 
3483 #ifdef DEBUG
3484 		if (rfs3_do_post_op_attr) {
3485 			nva.va_mask = AT_ALL;
3486 			nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ?
3487 			    NULL : &nva;
3488 		} else
3489 			nvap = NULL;
3490 #else
3491 		nva.va_mask = AT_ALL;
3492 		nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3493 #endif
3494 		vattr_to_post_op_attr(nvap, &infop[i].attr);
3495 
3496 #ifdef DEBUG
3497 		if (!rfs3_do_post_op_fh3)
3498 			infop[i].fh.handle_follows = FALSE;
3499 		else {
3500 #endif
3501 		error = makefh3(&infop[i].fh.handle, nvp, exi);
3502 		if (!error)
3503 			infop[i].fh.handle_follows = TRUE;
3504 		else
3505 			infop[i].fh.handle_follows = FALSE;
3506 #ifdef DEBUG
3507 		}
3508 #endif
3509 
3510 		VN_RELE(nvp);
3511 		dp = nextdp(dp);
3512 	}
3513 
3514 #if 0 /* notyet */
3515 	/*
3516 	 * Don't do this.  It causes local disk writes when just
3517 	 * reading the file and the overhead is deemed larger
3518 	 * than the benefit.
3519 	 */
3520 	/*
3521 	 * Force modified metadata out to stable storage.
3522 	 */
3523 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3524 #endif
3525 
3526 	VN_RELE(vp);
3527 
3528 	kmem_free(namlen, args->dircount);
3529 
3530 	resp->status = NFS3_OK;
3531 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3532 	resp->resok.cookieverf = 0;
3533 	resp->resok.reply.entries = (entryplus3 *)data;
3534 	resp->resok.reply.eof = iseof;
3535 	resp->resok.size = nents;
3536 	resp->resok.count = args->dircount;
3537 	resp->resok.maxcount = args->maxcount;
3538 	return;
3539 
3540 out:
3541 	if (curthread->t_flag & T_WOULDBLOCK) {
3542 		curthread->t_flag &= ~T_WOULDBLOCK;
3543 		resp->status = NFS3ERR_JUKEBOX;
3544 	} else
3545 		resp->status = puterrno3(error);
3546 out1:
3547 	if (vp != NULL) {
3548 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3549 		VN_RELE(vp);
3550 	}
3551 
3552 	if (namlen != NULL)
3553 		kmem_free(namlen, args->dircount);
3554 
3555 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3556 }
3557 
3558 void *
3559 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3560 {
3561 
3562 	return (&args->dir);
3563 }
3564 
3565 void
3566 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3567 {
3568 
3569 	if (resp->status == NFS3_OK) {
3570 		kmem_free(resp->resok.reply.entries, resp->resok.count);
3571 		kmem_free(resp->resok.infop,
3572 		    resp->resok.size * sizeof (struct entryplus3_info));
3573 	}
3574 }
3575 
3576 /* ARGSUSED */
3577 void
3578 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3579 	struct svc_req *req, cred_t *cr)
3580 {
3581 	int error;
3582 	vnode_t *vp;
3583 	struct vattr *vap;
3584 	struct vattr va;
3585 	struct statvfs64 sb;
3586 
3587 	vap = NULL;
3588 
3589 	vp = nfs3_fhtovp(&args->fsroot, exi);
3590 	if (vp == NULL) {
3591 		error = ESTALE;
3592 		goto out;
3593 	}
3594 
3595 	if (is_system_labeled()) {
3596 		bslabel_t *clabel = req->rq_label;
3597 
3598 		ASSERT(clabel != NULL);
3599 		DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3600 		    "got client label from request(1)", struct svc_req *, req);
3601 
3602 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3603 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
3604 				resp->status = NFS3ERR_ACCES;
3605 				goto out1;
3606 			}
3607 		}
3608 	}
3609 
3610 	error = VFS_STATVFS(vp->v_vfsp, &sb);
3611 
3612 #ifdef DEBUG
3613 	if (rfs3_do_post_op_attr) {
3614 		va.va_mask = AT_ALL;
3615 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3616 	} else
3617 		vap = NULL;
3618 #else
3619 	va.va_mask = AT_ALL;
3620 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3621 #endif
3622 
3623 	VN_RELE(vp);
3624 	vp = NULL;
3625 
3626 	if (error)
3627 		goto out;
3628 
3629 	resp->status = NFS3_OK;
3630 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3631 	if (sb.f_blocks != (fsblkcnt64_t)-1)
3632 		resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3633 	else
3634 		resp->resok.tbytes = (size3)sb.f_blocks;
3635 	if (sb.f_bfree != (fsblkcnt64_t)-1)
3636 		resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3637 	else
3638 		resp->resok.fbytes = (size3)sb.f_bfree;
3639 	if (sb.f_bavail != (fsblkcnt64_t)-1)
3640 		resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3641 	else
3642 		resp->resok.abytes = (size3)sb.f_bavail;
3643 	resp->resok.tfiles = (size3)sb.f_files;
3644 	resp->resok.ffiles = (size3)sb.f_ffree;
3645 	resp->resok.afiles = (size3)sb.f_favail;
3646 	resp->resok.invarsec = 0;
3647 	return;
3648 
3649 out:
3650 	if (curthread->t_flag & T_WOULDBLOCK) {
3651 		curthread->t_flag &= ~T_WOULDBLOCK;
3652 		resp->status = NFS3ERR_JUKEBOX;
3653 	} else
3654 		resp->status = puterrno3(error);
3655 out1:
3656 	if (vp != NULL)
3657 		VN_RELE(vp);
3658 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3659 }
3660 
3661 void *
3662 rfs3_fsstat_getfh(FSSTAT3args *args)
3663 {
3664 
3665 	return (&args->fsroot);
3666 }
3667 
3668 /* ARGSUSED */
3669 void
3670 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3671 	struct svc_req *req, cred_t *cr)
3672 {
3673 	vnode_t *vp;
3674 	struct vattr *vap;
3675 	struct vattr va;
3676 	uint32_t xfer_size;
3677 	ulong_t l = 0;
3678 	int error;
3679 
3680 	vp = nfs3_fhtovp(&args->fsroot, exi);
3681 	if (vp == NULL) {
3682 		if (curthread->t_flag & T_WOULDBLOCK) {
3683 			curthread->t_flag &= ~T_WOULDBLOCK;
3684 			resp->status = NFS3ERR_JUKEBOX;
3685 		} else
3686 			resp->status = NFS3ERR_STALE;
3687 		vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3688 		return;
3689 	}
3690 
3691 	if (is_system_labeled()) {
3692 		bslabel_t *clabel = req->rq_label;
3693 
3694 		ASSERT(clabel != NULL);
3695 		DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3696 		    "got client label from request(1)", struct svc_req *, req);
3697 
3698 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3699 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
3700 				resp->status = NFS3ERR_STALE;
3701 				vattr_to_post_op_attr(NULL,
3702 				    &resp->resfail.obj_attributes);
3703 				return;
3704 			}
3705 		}
3706 	}
3707 
3708 #ifdef DEBUG
3709 	if (rfs3_do_post_op_attr) {
3710 		va.va_mask = AT_ALL;
3711 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3712 	} else
3713 		vap = NULL;
3714 #else
3715 	va.va_mask = AT_ALL;
3716 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3717 #endif
3718 
3719 	resp->status = NFS3_OK;
3720 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3721 	xfer_size = rfs3_tsize(req);
3722 	resp->resok.rtmax = xfer_size;
3723 	resp->resok.rtpref = xfer_size;
3724 	resp->resok.rtmult = DEV_BSIZE;
3725 	resp->resok.wtmax = xfer_size;
3726 	resp->resok.wtpref = xfer_size;
3727 	resp->resok.wtmult = DEV_BSIZE;
3728 	resp->resok.dtpref = MAXBSIZE;
3729 
3730 	/*
3731 	 * Large file spec: want maxfilesize based on limit of
3732 	 * underlying filesystem.  We can guess 2^31-1 if need be.
3733 	 */
3734 	error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
3735 
3736 	VN_RELE(vp);
3737 
3738 	if (!error && l != 0 && l <= 64)
3739 		resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3740 	else
3741 		resp->resok.maxfilesize = MAXOFF32_T;
3742 
3743 	resp->resok.time_delta.seconds = 0;
3744 	resp->resok.time_delta.nseconds = 1000;
3745 	resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3746 	    FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3747 }
3748 
3749 void *
3750 rfs3_fsinfo_getfh(FSINFO3args *args)
3751 {
3752 
3753 	return (&args->fsroot);
3754 }
3755 
3756 /* ARGSUSED */
3757 void
3758 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
3759 	struct svc_req *req, cred_t *cr)
3760 {
3761 	int error;
3762 	vnode_t *vp;
3763 	struct vattr *vap;
3764 	struct vattr va;
3765 	ulong_t val;
3766 
3767 	vap = NULL;
3768 
3769 	vp = nfs3_fhtovp(&args->object, exi);
3770 	if (vp == NULL) {
3771 		error = ESTALE;
3772 		goto out;
3773 	}
3774 
3775 	if (is_system_labeled()) {
3776 		bslabel_t *clabel = req->rq_label;
3777 
3778 		ASSERT(clabel != NULL);
3779 		DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
3780 		    "got client label from request(1)", struct svc_req *, req);
3781 
3782 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3783 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
3784 				resp->status = NFS3ERR_ACCES;
3785 				goto out1;
3786 			}
3787 		}
3788 	}
3789 
3790 #ifdef DEBUG
3791 	if (rfs3_do_post_op_attr) {
3792 		va.va_mask = AT_ALL;
3793 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3794 	} else
3795 		vap = NULL;
3796 #else
3797 	va.va_mask = AT_ALL;
3798 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3799 #endif
3800 
3801 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
3802 	if (error)
3803 		goto out;
3804 	resp->resok.info.link_max = (uint32)val;
3805 
3806 	error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
3807 	if (error)
3808 		goto out;
3809 	resp->resok.info.name_max = (uint32)val;
3810 
3811 	error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
3812 	if (error)
3813 		goto out;
3814 	if (val == 1)
3815 		resp->resok.info.no_trunc = TRUE;
3816 	else
3817 		resp->resok.info.no_trunc = FALSE;
3818 
3819 	error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
3820 	if (error)
3821 		goto out;
3822 	if (val == 1)
3823 		resp->resok.info.chown_restricted = TRUE;
3824 	else
3825 		resp->resok.info.chown_restricted = FALSE;
3826 
3827 	VN_RELE(vp);
3828 
3829 	resp->status = NFS3_OK;
3830 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3831 	resp->resok.info.case_insensitive = FALSE;
3832 	resp->resok.info.case_preserving = TRUE;
3833 	return;
3834 
3835 out:
3836 	if (curthread->t_flag & T_WOULDBLOCK) {
3837 		curthread->t_flag &= ~T_WOULDBLOCK;
3838 		resp->status = NFS3ERR_JUKEBOX;
3839 	} else
3840 		resp->status = puterrno3(error);
3841 out1:
3842 	if (vp != NULL)
3843 		VN_RELE(vp);
3844 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3845 }
3846 
3847 void *
3848 rfs3_pathconf_getfh(PATHCONF3args *args)
3849 {
3850 
3851 	return (&args->object);
3852 }
3853 
3854 void
3855 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
3856 	struct svc_req *req, cred_t *cr)
3857 {
3858 	int error;
3859 	vnode_t *vp;
3860 	struct vattr *bvap;
3861 	struct vattr bva;
3862 	struct vattr *avap;
3863 	struct vattr ava;
3864 
3865 	bvap = NULL;
3866 	avap = NULL;
3867 
3868 	vp = nfs3_fhtovp(&args->file, exi);
3869 	if (vp == NULL) {
3870 		error = ESTALE;
3871 		goto out;
3872 	}
3873 
3874 	bva.va_mask = AT_ALL;
3875 	error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
3876 
3877 	/*
3878 	 * If we can't get the attributes, then we can't do the
3879 	 * right access checking.  So, we'll fail the request.
3880 	 */
3881 	if (error)
3882 		goto out;
3883 
3884 #ifdef DEBUG
3885 	if (rfs3_do_pre_op_attr)
3886 		bvap = &bva;
3887 	else
3888 		bvap = NULL;
3889 #else
3890 	bvap = &bva;
3891 #endif
3892 
3893 	if (rdonly(exi, req)) {
3894 		resp->status = NFS3ERR_ROFS;
3895 		goto out1;
3896 	}
3897 
3898 	if (vp->v_type != VREG) {
3899 		resp->status = NFS3ERR_INVAL;
3900 		goto out1;
3901 	}
3902 
3903 	if (is_system_labeled()) {
3904 		bslabel_t *clabel = req->rq_label;
3905 
3906 		ASSERT(clabel != NULL);
3907 		DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
3908 		    "got client label from request(1)", struct svc_req *, req);
3909 
3910 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3911 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
3912 				resp->status = NFS3ERR_ACCES;
3913 				goto out1;
3914 			}
3915 		}
3916 	}
3917 
3918 	if (crgetuid(cr) != bva.va_uid &&
3919 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
3920 		goto out;
3921 
3922 	error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, NULL);
3923 	if (!error)
3924 		error = VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3925 
3926 #ifdef DEBUG
3927 	if (rfs3_do_post_op_attr) {
3928 		ava.va_mask = AT_ALL;
3929 		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
3930 	} else
3931 		avap = NULL;
3932 #else
3933 	ava.va_mask = AT_ALL;
3934 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
3935 #endif
3936 
3937 	if (error)
3938 		goto out;
3939 
3940 	VN_RELE(vp);
3941 
3942 	resp->status = NFS3_OK;
3943 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
3944 	resp->resok.verf = write3verf;
3945 	return;
3946 
3947 out:
3948 	if (curthread->t_flag & T_WOULDBLOCK) {
3949 		curthread->t_flag &= ~T_WOULDBLOCK;
3950 		resp->status = NFS3ERR_JUKEBOX;
3951 	} else
3952 		resp->status = puterrno3(error);
3953 out1:
3954 	if (vp != NULL)
3955 		VN_RELE(vp);
3956 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
3957 }
3958 
3959 void *
3960 rfs3_commit_getfh(COMMIT3args *args)
3961 {
3962 
3963 	return (&args->file);
3964 }
3965 
3966 static int
3967 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
3968 {
3969 
3970 	vap->va_mask = 0;
3971 
3972 	if (sap->mode.set_it) {
3973 		vap->va_mode = (mode_t)sap->mode.mode;
3974 		vap->va_mask |= AT_MODE;
3975 	}
3976 	if (sap->uid.set_it) {
3977 		vap->va_uid = (uid_t)sap->uid.uid;
3978 		vap->va_mask |= AT_UID;
3979 	}
3980 	if (sap->gid.set_it) {
3981 		vap->va_gid = (gid_t)sap->gid.gid;
3982 		vap->va_mask |= AT_GID;
3983 	}
3984 	if (sap->size.set_it) {
3985 		if (sap->size.size > (size3)((u_longlong_t)-1))
3986 			return (EINVAL);
3987 		vap->va_size = sap->size.size;
3988 		vap->va_mask |= AT_SIZE;
3989 	}
3990 	if (sap->atime.set_it == SET_TO_CLIENT_TIME) {
3991 #ifndef _LP64
3992 		/* check time validity */
3993 		if (!NFS3_TIME_OK(sap->atime.atime.seconds))
3994 			return (EOVERFLOW);
3995 #endif
3996 		/*
3997 		 * nfs protocol defines times as unsigned so don't extend sign,
3998 		 * unless sysadmin set nfs_allow_preepoch_time.
3999 		 */
4000 		NFS_TIME_T_CONVERT(vap->va_atime.tv_sec,
4001 		    sap->atime.atime.seconds);
4002 		vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds;
4003 		vap->va_mask |= AT_ATIME;
4004 	} else if (sap->atime.set_it == SET_TO_SERVER_TIME) {
4005 		gethrestime(&vap->va_atime);
4006 		vap->va_mask |= AT_ATIME;
4007 	}
4008 	if (sap->mtime.set_it == SET_TO_CLIENT_TIME) {
4009 #ifndef _LP64
4010 		/* check time validity */
4011 		if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4012 			return (EOVERFLOW);
4013 #endif
4014 		/*
4015 		 * nfs protocol defines times as unsigned so don't extend sign,
4016 		 * unless sysadmin set nfs_allow_preepoch_time.
4017 		 */
4018 		NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4019 		    sap->mtime.mtime.seconds);
4020 		vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4021 		vap->va_mask |= AT_MTIME;
4022 	} else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4023 		gethrestime(&vap->va_mtime);
4024 		vap->va_mask |= AT_MTIME;
4025 	}
4026 
4027 	return (0);
4028 }
4029 
4030 static ftype3 vt_to_nf3[] = {
4031 	0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4032 };
4033 
4034 static int
4035 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4036 {
4037 
4038 	ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4039 	/* Return error if time or size overflow */
4040 	if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4041 		return (EOVERFLOW);
4042 	}
4043 	fap->type = vt_to_nf3[vap->va_type];
4044 	fap->mode = (mode3)(vap->va_mode & MODEMASK);
4045 	fap->nlink = (uint32)vap->va_nlink;
4046 	if (vap->va_uid == UID_NOBODY)
4047 		fap->uid = (uid3)NFS_UID_NOBODY;
4048 	else
4049 		fap->uid = (uid3)vap->va_uid;
4050 	if (vap->va_gid == GID_NOBODY)
4051 		fap->gid = (gid3)NFS_GID_NOBODY;
4052 	else
4053 		fap->gid = (gid3)vap->va_gid;
4054 	fap->size = (size3)vap->va_size;
4055 	fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks;
4056 	fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev);
4057 	fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev);
4058 	fap->fsid = (uint64)vap->va_fsid;
4059 	fap->fileid = (fileid3)vap->va_nodeid;
4060 	fap->atime.seconds = vap->va_atime.tv_sec;
4061 	fap->atime.nseconds = vap->va_atime.tv_nsec;
4062 	fap->mtime.seconds = vap->va_mtime.tv_sec;
4063 	fap->mtime.nseconds = vap->va_mtime.tv_nsec;
4064 	fap->ctime.seconds = vap->va_ctime.tv_sec;
4065 	fap->ctime.nseconds = vap->va_ctime.tv_nsec;
4066 	return (0);
4067 }
4068 
4069 static int
4070 vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap)
4071 {
4072 
4073 	/* Return error if time or size overflow */
4074 	if (!  (NFS_TIME_T_OK(vap->va_mtime.tv_sec) &&
4075 	    NFS_TIME_T_OK(vap->va_ctime.tv_sec) &&
4076 	    NFS3_SIZE_OK(vap->va_size))) {
4077 		return (EOVERFLOW);
4078 	}
4079 	wccap->size = (size3)vap->va_size;
4080 	wccap->mtime.seconds = vap->va_mtime.tv_sec;
4081 	wccap->mtime.nseconds = vap->va_mtime.tv_nsec;
4082 	wccap->ctime.seconds = vap->va_ctime.tv_sec;
4083 	wccap->ctime.nseconds = vap->va_ctime.tv_nsec;
4084 	return (0);
4085 }
4086 
4087 static void
4088 vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap)
4089 {
4090 
4091 	/* don't return attrs if time overflow */
4092 	if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4093 		poap->attributes = TRUE;
4094 	} else
4095 		poap->attributes = FALSE;
4096 }
4097 
4098 void
4099 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4100 {
4101 
4102 	/* don't return attrs if time overflow */
4103 	if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4104 		poap->attributes = TRUE;
4105 	} else
4106 		poap->attributes = FALSE;
4107 }
4108 
4109 static void
4110 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4111 {
4112 
4113 	vattr_to_pre_op_attr(bvap, &wccp->before);
4114 	vattr_to_post_op_attr(avap, &wccp->after);
4115 }
4116 
4117 void
4118 rfs3_srvrinit(void)
4119 {
4120 	struct rfs3_verf_overlay {
4121 		uint_t id; /* a "unique" identifier */
4122 		int ts; /* a unique timestamp */
4123 	} *verfp;
4124 	timestruc_t now;
4125 
4126 	/*
4127 	 * The following algorithm attempts to find a unique verifier
4128 	 * to be used as the write verifier returned from the server
4129 	 * to the client.  It is important that this verifier change
4130 	 * whenever the server reboots.  Of secondary importance, it
4131 	 * is important for the verifier to be unique between two
4132 	 * different servers.
4133 	 *
4134 	 * Thus, an attempt is made to use the system hostid and the
4135 	 * current time in seconds when the nfssrv kernel module is
4136 	 * loaded.  It is assumed that an NFS server will not be able
4137 	 * to boot and then to reboot in less than a second.  If the
4138 	 * hostid has not been set, then the current high resolution
4139 	 * time is used.  This will ensure different verifiers each
4140 	 * time the server reboots and minimize the chances that two
4141 	 * different servers will have the same verifier.
4142 	 */
4143 
4144 #ifndef	lint
4145 	/*
4146 	 * We ASSERT that this constant logic expression is
4147 	 * always true because in the past, it wasn't.
4148 	 */
4149 	ASSERT(sizeof (*verfp) <= sizeof (write3verf));
4150 #endif
4151 
4152 	gethrestime(&now);
4153 	verfp = (struct rfs3_verf_overlay *)&write3verf;
4154 	verfp->ts = (int)now.tv_sec;
4155 	verfp->id = (uint_t)nfs_atoi(hw_serial);
4156 
4157 	if (verfp->id == 0)
4158 		verfp->id = (uint_t)now.tv_nsec;
4159 
4160 	nfs3_srv_caller_id = fs_new_caller_id();
4161 
4162 }
4163 
4164 void
4165 rfs3_srvrfini(void)
4166 {
4167 	/* Nothing to do */
4168 }
4169