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