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