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