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