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