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