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