xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs3_srv.c (revision f837ee4a)
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 		if (resp->resok.wlist)
1073 			clist_zero_len(resp->resok.wlist);
1074 		goto done;
1075 	}
1076 
1077 	if (args->count == 0) {
1078 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1079 		if (in_crit)
1080 			nbl_end_crit(vp);
1081 		resp->status = NFS3_OK;
1082 		vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1083 		resp->resok.count = 0;
1084 		resp->resok.eof = FALSE;
1085 		resp->resok.data.data_len = 0;
1086 		resp->resok.data.data_val = NULL;
1087 		resp->resok.data.mp = NULL;
1088 		/* RDMA */
1089 		resp->resok.wlist = args->wlist;
1090 		resp->resok.wlist_len = resp->resok.count;
1091 		if (resp->resok.wlist)
1092 			clist_zero_len(resp->resok.wlist);
1093 		goto done;
1094 	}
1095 
1096 	/*
1097 	 * do not allocate memory more the max. allowed
1098 	 * transfer size
1099 	 */
1100 	if (args->count > rfs3_tsize(req))
1101 		args->count = rfs3_tsize(req);
1102 
1103 	/*
1104 	 * If returning data via RDMA Write, then grab the chunk list.
1105 	 * If we aren't returning READ data w/RDMA_WRITE, then grab
1106 	 * a mblk.
1107 	 */
1108 	if (args->wlist) {
1109 		mp = NULL;
1110 		(void) rdma_get_wchunk(req, &iov, args->wlist);
1111 	} else {
1112 		/*
1113 		 * mp will contain the data to be sent out in the read reply.
1114 		 * This will be freed after the reply has been sent out (by the
1115 		 * driver).
1116 		 * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so
1117 		 * that the call to xdrmblk_putmblk() never fails.
1118 		 */
1119 		mp = allocb_wait(RNDUP(args->count), BPRI_MED, STR_NOSIG,
1120 		    &alloc_err);
1121 		ASSERT(mp != NULL);
1122 		ASSERT(alloc_err == 0);
1123 
1124 		iov.iov_base = (caddr_t)mp->b_datap->db_base;
1125 		iov.iov_len = args->count;
1126 	}
1127 
1128 	uio.uio_iov = &iov;
1129 	uio.uio_iovcnt = 1;
1130 	uio.uio_segflg = UIO_SYSSPACE;
1131 	uio.uio_extflg = UIO_COPY_CACHED;
1132 	uio.uio_loffset = args->offset;
1133 	uio.uio_resid = args->count;
1134 
1135 	error = VOP_READ(vp, &uio, 0, cr, &ct);
1136 
1137 	if (error) {
1138 		freeb(mp);
1139 		/* check if a monitor detected a delegation conflict */
1140 		if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1141 			resp->status = NFS3ERR_JUKEBOX;
1142 			goto out1;
1143 		}
1144 		goto out;
1145 	}
1146 
1147 	va.va_mask = AT_ALL;
1148 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1149 
1150 #ifdef DEBUG
1151 	if (rfs3_do_post_op_attr) {
1152 		if (error)
1153 			vap = NULL;
1154 		else
1155 			vap = &va;
1156 	} else
1157 		vap = NULL;
1158 #else
1159 	if (error)
1160 		vap = NULL;
1161 	else
1162 		vap = &va;
1163 #endif
1164 
1165 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1166 
1167 	if (in_crit)
1168 		nbl_end_crit(vp);
1169 
1170 	resp->status = NFS3_OK;
1171 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1172 	resp->resok.count = args->count - uio.uio_resid;
1173 	if (!error && offset + resp->resok.count == va.va_size)
1174 		resp->resok.eof = TRUE;
1175 	else
1176 		resp->resok.eof = FALSE;
1177 	resp->resok.data.data_len = resp->resok.count;
1178 	resp->resok.data.mp = mp;
1179 	resp->resok.size = (uint_t)args->count;
1180 
1181 	if (args->wlist) {
1182 		resp->resok.data.data_val = (caddr_t)iov.iov_base;
1183 		if (!rdma_setup_read_data3(args, &(resp->resok))) {
1184 			resp->status = NFS3ERR_INVAL;
1185 		}
1186 	} else {
1187 		resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1188 		(resp->resok).wlist = NULL;
1189 	}
1190 
1191 done:
1192 	DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1193 	    cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1194 
1195 	VN_RELE(vp);
1196 
1197 	return;
1198 
1199 out:
1200 	if (curthread->t_flag & T_WOULDBLOCK) {
1201 		curthread->t_flag &= ~T_WOULDBLOCK;
1202 		resp->status = NFS3ERR_JUKEBOX;
1203 	} else
1204 		resp->status = puterrno3(error);
1205 out1:
1206 	DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1207 	    cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1208 
1209 	if (vp != NULL) {
1210 		if (need_rwunlock)
1211 			VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1212 		if (in_crit)
1213 			nbl_end_crit(vp);
1214 		VN_RELE(vp);
1215 	}
1216 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1217 }
1218 
1219 void
1220 rfs3_read_free(READ3res *resp)
1221 {
1222 	mblk_t *mp;
1223 
1224 	if (resp->status == NFS3_OK) {
1225 		mp = resp->resok.data.mp;
1226 		if (mp != NULL)
1227 			freeb(mp);
1228 	}
1229 }
1230 
1231 void *
1232 rfs3_read_getfh(READ3args *args)
1233 {
1234 
1235 	return (&args->file);
1236 }
1237 
1238 #define	MAX_IOVECS	12
1239 
1240 #ifdef DEBUG
1241 static int rfs3_write_hits = 0;
1242 static int rfs3_write_misses = 0;
1243 #endif
1244 
1245 void
1246 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1247 	struct svc_req *req, cred_t *cr)
1248 {
1249 	int error;
1250 	vnode_t *vp;
1251 	struct vattr *bvap = NULL;
1252 	struct vattr bva;
1253 	struct vattr *avap = NULL;
1254 	struct vattr ava;
1255 	u_offset_t rlimit;
1256 	struct uio uio;
1257 	struct iovec iov[MAX_IOVECS];
1258 	mblk_t *m;
1259 	struct iovec *iovp;
1260 	int iovcnt;
1261 	int ioflag;
1262 	cred_t *savecred;
1263 	int in_crit = 0;
1264 	int rwlock_ret = -1;
1265 	caller_context_t ct;
1266 
1267 	vp = nfs3_fhtovp(&args->file, exi);
1268 
1269 	DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
1270 	    cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
1271 
1272 	if (vp == NULL) {
1273 		error = ESTALE;
1274 		goto err;
1275 	}
1276 
1277 	if (is_system_labeled()) {
1278 		bslabel_t *clabel = req->rq_label;
1279 
1280 		ASSERT(clabel != NULL);
1281 		DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1282 		    "got client label from request(1)", struct svc_req *, req);
1283 
1284 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1285 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
1286 				resp->status = NFS3ERR_ACCES;
1287 				goto err1;
1288 			}
1289 		}
1290 	}
1291 
1292 	ct.cc_sysid = 0;
1293 	ct.cc_pid = 0;
1294 	ct.cc_caller_id = nfs3_srv_caller_id;
1295 	ct.cc_flags = CC_DONTBLOCK;
1296 
1297 	/*
1298 	 * We have to enter the critical region before calling VOP_RWLOCK
1299 	 * to avoid a deadlock with ufs.
1300 	 */
1301 	if (nbl_need_check(vp)) {
1302 		nbl_start_crit(vp, RW_READER);
1303 		in_crit = 1;
1304 		if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
1305 		    NULL)) {
1306 			error = EACCES;
1307 			goto err;
1308 		}
1309 	}
1310 
1311 	rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
1312 
1313 	/* check if a monitor detected a delegation conflict */
1314 	if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1315 		resp->status = NFS3ERR_JUKEBOX;
1316 		rwlock_ret = -1;
1317 		goto err1;
1318 	}
1319 
1320 
1321 	bva.va_mask = AT_ALL;
1322 	error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
1323 
1324 	/*
1325 	 * If we can't get the attributes, then we can't do the
1326 	 * right access checking.  So, we'll fail the request.
1327 	 */
1328 	if (error)
1329 		goto err;
1330 
1331 	bvap = &bva;
1332 #ifdef DEBUG
1333 	if (!rfs3_do_pre_op_attr)
1334 		bvap = NULL;
1335 #endif
1336 	avap = bvap;
1337 
1338 	if (args->count != args->data.data_len) {
1339 		resp->status = NFS3ERR_INVAL;
1340 		goto err1;
1341 	}
1342 
1343 	if (rdonly(exi, req)) {
1344 		resp->status = NFS3ERR_ROFS;
1345 		goto err1;
1346 	}
1347 
1348 	if (vp->v_type != VREG) {
1349 		resp->status = NFS3ERR_INVAL;
1350 		goto err1;
1351 	}
1352 
1353 	if (crgetuid(cr) != bva.va_uid &&
1354 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1355 		goto err;
1356 
1357 	if (MANDLOCK(vp, bva.va_mode)) {
1358 		resp->status = NFS3ERR_ACCES;
1359 		goto err1;
1360 	}
1361 
1362 	if (args->count == 0) {
1363 		resp->status = NFS3_OK;
1364 		vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1365 		resp->resok.count = 0;
1366 		resp->resok.committed = args->stable;
1367 		resp->resok.verf = write3verf;
1368 		goto out;
1369 	}
1370 
1371 	if (args->mblk != NULL) {
1372 		iovcnt = 0;
1373 		for (m = args->mblk; m != NULL; m = m->b_cont)
1374 			iovcnt++;
1375 		if (iovcnt <= MAX_IOVECS) {
1376 #ifdef DEBUG
1377 			rfs3_write_hits++;
1378 #endif
1379 			iovp = iov;
1380 		} else {
1381 #ifdef DEBUG
1382 			rfs3_write_misses++;
1383 #endif
1384 			iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1385 		}
1386 		mblk_to_iov(args->mblk, iovcnt, iovp);
1387 
1388 	} else if (args->rlist != NULL) {
1389 		iovcnt = 1;
1390 		iovp = iov;
1391 		iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
1392 		iovp->iov_len = args->count;
1393 	} else {
1394 		iovcnt = 1;
1395 		iovp = iov;
1396 		iovp->iov_base = args->data.data_val;
1397 		iovp->iov_len = args->count;
1398 	}
1399 
1400 	uio.uio_iov = iovp;
1401 	uio.uio_iovcnt = iovcnt;
1402 
1403 	uio.uio_segflg = UIO_SYSSPACE;
1404 	uio.uio_extflg = UIO_COPY_DEFAULT;
1405 	uio.uio_loffset = args->offset;
1406 	uio.uio_resid = args->count;
1407 	uio.uio_llimit = curproc->p_fsz_ctl;
1408 	rlimit = uio.uio_llimit - args->offset;
1409 	if (rlimit < (u_offset_t)uio.uio_resid)
1410 		uio.uio_resid = (int)rlimit;
1411 
1412 	if (args->stable == UNSTABLE)
1413 		ioflag = 0;
1414 	else if (args->stable == FILE_SYNC)
1415 		ioflag = FSYNC;
1416 	else if (args->stable == DATA_SYNC)
1417 		ioflag = FDSYNC;
1418 	else {
1419 		if (iovp != iov)
1420 			kmem_free(iovp, sizeof (*iovp) * iovcnt);
1421 		resp->status = NFS3ERR_INVAL;
1422 		goto err1;
1423 	}
1424 
1425 	/*
1426 	 * We're changing creds because VM may fault and we need
1427 	 * the cred of the current thread to be used if quota
1428 	 * checking is enabled.
1429 	 */
1430 	savecred = curthread->t_cred;
1431 	curthread->t_cred = cr;
1432 	error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
1433 	curthread->t_cred = savecred;
1434 
1435 	if (iovp != iov)
1436 		kmem_free(iovp, sizeof (*iovp) * iovcnt);
1437 
1438 	/* check if a monitor detected a delegation conflict */
1439 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1440 		resp->status = NFS3ERR_JUKEBOX;
1441 		goto err1;
1442 	}
1443 
1444 	ava.va_mask = AT_ALL;
1445 	avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
1446 
1447 #ifdef DEBUG
1448 	if (!rfs3_do_post_op_attr)
1449 		avap = NULL;
1450 #endif
1451 
1452 	if (error)
1453 		goto err;
1454 
1455 	/*
1456 	 * If we were unable to get the V_WRITELOCK_TRUE, then we
1457 	 * may not have accurate after attrs, so check if
1458 	 * we have both attributes, they have a non-zero va_seq, and
1459 	 * va_seq has changed by exactly one,
1460 	 * if not, turn off the before attr.
1461 	 */
1462 	if (rwlock_ret != V_WRITELOCK_TRUE) {
1463 		if (bvap == NULL || avap == NULL ||
1464 		    bvap->va_seq == 0 || avap->va_seq == 0 ||
1465 		    avap->va_seq != (bvap->va_seq + 1)) {
1466 			bvap = NULL;
1467 		}
1468 	}
1469 
1470 	resp->status = NFS3_OK;
1471 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1472 	resp->resok.count = args->count - uio.uio_resid;
1473 	resp->resok.committed = args->stable;
1474 	resp->resok.verf = write3verf;
1475 	goto out;
1476 
1477 err:
1478 	if (curthread->t_flag & T_WOULDBLOCK) {
1479 		curthread->t_flag &= ~T_WOULDBLOCK;
1480 		resp->status = NFS3ERR_JUKEBOX;
1481 	} else
1482 		resp->status = puterrno3(error);
1483 err1:
1484 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1485 out:
1486 	DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
1487 	    cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
1488 
1489 	if (vp != NULL) {
1490 		if (rwlock_ret != -1)
1491 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1492 		if (in_crit)
1493 			nbl_end_crit(vp);
1494 		VN_RELE(vp);
1495 	}
1496 }
1497 
1498 void *
1499 rfs3_write_getfh(WRITE3args *args)
1500 {
1501 
1502 	return (&args->file);
1503 }
1504 
1505 void
1506 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1507 	struct svc_req *req, cred_t *cr)
1508 {
1509 	int error;
1510 	int in_crit = 0;
1511 	vnode_t *vp;
1512 	vnode_t *tvp = NULL;
1513 	vnode_t *dvp;
1514 	struct vattr *vap;
1515 	struct vattr va;
1516 	struct vattr *dbvap;
1517 	struct vattr dbva;
1518 	struct vattr *davap;
1519 	struct vattr dava;
1520 	enum vcexcl excl;
1521 	nfstime3 *mtime;
1522 	len_t reqsize;
1523 	bool_t trunc;
1524 	struct sockaddr *ca;
1525 	char *name = NULL;
1526 
1527 	dbvap = NULL;
1528 	davap = NULL;
1529 
1530 	dvp = nfs3_fhtovp(&args->where.dir, exi);
1531 
1532 	DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1533 	    cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
1534 
1535 	if (dvp == NULL) {
1536 		error = ESTALE;
1537 		goto out;
1538 	}
1539 
1540 #ifdef DEBUG
1541 	if (rfs3_do_pre_op_attr) {
1542 		dbva.va_mask = AT_ALL;
1543 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1544 	} else
1545 		dbvap = NULL;
1546 #else
1547 	dbva.va_mask = AT_ALL;
1548 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1549 #endif
1550 	davap = dbvap;
1551 
1552 	if (args->where.name == nfs3nametoolong) {
1553 		resp->status = NFS3ERR_NAMETOOLONG;
1554 		goto out1;
1555 	}
1556 
1557 	if (args->where.name == NULL || *(args->where.name) == '\0') {
1558 		resp->status = NFS3ERR_ACCES;
1559 		goto out1;
1560 	}
1561 
1562 	if (rdonly(exi, req)) {
1563 		resp->status = NFS3ERR_ROFS;
1564 		goto out1;
1565 	}
1566 
1567 	if (is_system_labeled()) {
1568 		bslabel_t *clabel = req->rq_label;
1569 
1570 		ASSERT(clabel != NULL);
1571 		DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1572 		    "got client label from request(1)", struct svc_req *, req);
1573 
1574 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1575 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
1576 				resp->status = NFS3ERR_ACCES;
1577 				goto out1;
1578 			}
1579 		}
1580 	}
1581 
1582 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1583 	name = nfscmd_convname(ca, exi, args->where.name,
1584 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1585 
1586 	if (name == NULL) {
1587 		/* This is really a Solaris EILSEQ */
1588 		resp->status = NFS3ERR_INVAL;
1589 		goto out1;
1590 	}
1591 
1592 	if (args->how.mode == EXCLUSIVE) {
1593 		va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
1594 		va.va_type = VREG;
1595 		va.va_mode = (mode_t)0;
1596 		/*
1597 		 * Ensure no time overflows and that types match
1598 		 */
1599 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1600 		va.va_mtime.tv_sec = mtime->seconds % INT32_MAX;
1601 		va.va_mtime.tv_nsec = mtime->nseconds;
1602 		excl = EXCL;
1603 	} else {
1604 		error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes,
1605 		    &va);
1606 		if (error)
1607 			goto out;
1608 		va.va_mask |= AT_TYPE;
1609 		va.va_type = VREG;
1610 		if (args->how.mode == GUARDED)
1611 			excl = EXCL;
1612 		else {
1613 			excl = NONEXCL;
1614 
1615 			/*
1616 			 * During creation of file in non-exclusive mode
1617 			 * if size of file is being set then make sure
1618 			 * that if the file already exists that no conflicting
1619 			 * non-blocking mandatory locks exists in the region
1620 			 * being modified. If there are conflicting locks fail
1621 			 * the operation with EACCES.
1622 			 */
1623 			if (va.va_mask & AT_SIZE) {
1624 				struct vattr tva;
1625 
1626 				/*
1627 				 * Does file already exist?
1628 				 */
1629 				error = VOP_LOOKUP(dvp, name, &tvp,
1630 				    NULL, 0, NULL, cr, NULL, NULL, NULL);
1631 
1632 				/*
1633 				 * Check to see if the file has been delegated
1634 				 * to a v4 client.  If so, then begin recall of
1635 				 * the delegation and return JUKEBOX to allow
1636 				 * the client to retrasmit its request.
1637 				 */
1638 
1639 				trunc = va.va_size == 0;
1640 				if (!error &&
1641 				    rfs4_check_delegated(FWRITE, tvp, trunc)) {
1642 					resp->status = NFS3ERR_JUKEBOX;
1643 					goto out1;
1644 				}
1645 
1646 				/*
1647 				 * Check for NBMAND lock conflicts
1648 				 */
1649 				if (!error && nbl_need_check(tvp)) {
1650 					u_offset_t offset;
1651 					ssize_t len;
1652 
1653 					nbl_start_crit(tvp, RW_READER);
1654 					in_crit = 1;
1655 
1656 					tva.va_mask = AT_SIZE;
1657 					error = VOP_GETATTR(tvp, &tva, 0, cr,
1658 					    NULL);
1659 					/*
1660 					 * Can't check for conflicts, so return
1661 					 * error.
1662 					 */
1663 					if (error)
1664 						goto out;
1665 
1666 					offset = tva.va_size < va.va_size ?
1667 					    tva.va_size : va.va_size;
1668 					len = tva.va_size < va.va_size ?
1669 					    va.va_size - tva.va_size :
1670 					    tva.va_size - va.va_size;
1671 					if (nbl_conflict(tvp, NBL_WRITE,
1672 					    offset, len, 0, NULL)) {
1673 						error = EACCES;
1674 						goto out;
1675 					}
1676 				} else if (tvp) {
1677 					VN_RELE(tvp);
1678 					tvp = NULL;
1679 				}
1680 			}
1681 		}
1682 		if (va.va_mask & AT_SIZE)
1683 			reqsize = va.va_size;
1684 	}
1685 
1686 	/*
1687 	 * Must specify the mode.
1688 	 */
1689 	if (!(va.va_mask & AT_MODE)) {
1690 		resp->status = NFS3ERR_INVAL;
1691 		goto out1;
1692 	}
1693 
1694 	/*
1695 	 * If the filesystem is exported with nosuid, then mask off
1696 	 * the setuid and setgid bits.
1697 	 */
1698 	if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
1699 		va.va_mode &= ~(VSUID | VSGID);
1700 
1701 tryagain:
1702 	/*
1703 	 * The file open mode used is VWRITE.  If the client needs
1704 	 * some other semantic, then it should do the access checking
1705 	 * itself.  It would have been nice to have the file open mode
1706 	 * passed as part of the arguments.
1707 	 */
1708 	error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
1709 	    &vp, cr, 0, NULL, NULL);
1710 
1711 #ifdef DEBUG
1712 	if (rfs3_do_post_op_attr) {
1713 		dava.va_mask = AT_ALL;
1714 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1715 	} else
1716 		davap = NULL;
1717 #else
1718 	dava.va_mask = AT_ALL;
1719 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1720 #endif
1721 
1722 	if (error) {
1723 		/*
1724 		 * If we got something other than file already exists
1725 		 * then just return this error.  Otherwise, we got
1726 		 * EEXIST.  If we were doing a GUARDED create, then
1727 		 * just return this error.  Otherwise, we need to
1728 		 * make sure that this wasn't a duplicate of an
1729 		 * exclusive create request.
1730 		 *
1731 		 * The assumption is made that a non-exclusive create
1732 		 * request will never return EEXIST.
1733 		 */
1734 		if (error != EEXIST || args->how.mode == GUARDED)
1735 			goto out;
1736 		/*
1737 		 * Lookup the file so that we can get a vnode for it.
1738 		 */
1739 		error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
1740 		    NULL, cr, NULL, NULL, NULL);
1741 		if (error) {
1742 			/*
1743 			 * We couldn't find the file that we thought that
1744 			 * we just created.  So, we'll just try creating
1745 			 * it again.
1746 			 */
1747 			if (error == ENOENT)
1748 				goto tryagain;
1749 			goto out;
1750 		}
1751 
1752 		/*
1753 		 * If the file is delegated to a v4 client, go ahead
1754 		 * and initiate recall, this create is a hint that a
1755 		 * conflicting v3 open has occurred.
1756 		 */
1757 
1758 		if (rfs4_check_delegated(FWRITE, vp, FALSE)) {
1759 			VN_RELE(vp);
1760 			resp->status = NFS3ERR_JUKEBOX;
1761 			goto out1;
1762 		}
1763 
1764 		va.va_mask = AT_ALL;
1765 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1766 
1767 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1768 		/* % with INT32_MAX to prevent overflows */
1769 		if (args->how.mode == EXCLUSIVE && (vap == NULL ||
1770 		    vap->va_mtime.tv_sec !=
1771 		    (mtime->seconds % INT32_MAX) ||
1772 		    vap->va_mtime.tv_nsec != mtime->nseconds)) {
1773 			VN_RELE(vp);
1774 			error = EEXIST;
1775 			goto out;
1776 		}
1777 	} else {
1778 
1779 		if ((args->how.mode == UNCHECKED ||
1780 		    args->how.mode == GUARDED) &&
1781 		    args->how.createhow3_u.obj_attributes.size.set_it &&
1782 		    va.va_size == 0)
1783 			trunc = TRUE;
1784 		else
1785 			trunc = FALSE;
1786 
1787 		if (rfs4_check_delegated(FWRITE, vp, trunc)) {
1788 			VN_RELE(vp);
1789 			resp->status = NFS3ERR_JUKEBOX;
1790 			goto out1;
1791 		}
1792 
1793 		va.va_mask = AT_ALL;
1794 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1795 
1796 		/*
1797 		 * We need to check to make sure that the file got
1798 		 * created to the indicated size.  If not, we do a
1799 		 * setattr to try to change the size, but we don't
1800 		 * try too hard.  This shouldn't a problem as most
1801 		 * clients will only specifiy a size of zero which
1802 		 * local file systems handle.  However, even if
1803 		 * the client does specify a non-zero size, it can
1804 		 * still recover by checking the size of the file
1805 		 * after it has created it and then issue a setattr
1806 		 * request of its own to set the size of the file.
1807 		 */
1808 		if (vap != NULL &&
1809 		    (args->how.mode == UNCHECKED ||
1810 		    args->how.mode == GUARDED) &&
1811 		    args->how.createhow3_u.obj_attributes.size.set_it &&
1812 		    vap->va_size != reqsize) {
1813 			va.va_mask = AT_SIZE;
1814 			va.va_size = reqsize;
1815 			(void) VOP_SETATTR(vp, &va, 0, cr, NULL);
1816 			va.va_mask = AT_ALL;
1817 			vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1818 		}
1819 	}
1820 
1821 	if (name != args->where.name)
1822 		kmem_free(name, MAXPATHLEN + 1);
1823 
1824 #ifdef DEBUG
1825 	if (!rfs3_do_post_op_attr)
1826 		vap = NULL;
1827 #endif
1828 
1829 #ifdef DEBUG
1830 	if (!rfs3_do_post_op_fh3)
1831 		resp->resok.obj.handle_follows = FALSE;
1832 	else {
1833 #endif
1834 	error = makefh3(&resp->resok.obj.handle, vp, exi);
1835 	if (error)
1836 		resp->resok.obj.handle_follows = FALSE;
1837 	else
1838 		resp->resok.obj.handle_follows = TRUE;
1839 #ifdef DEBUG
1840 	}
1841 #endif
1842 
1843 	/*
1844 	 * Force modified data and metadata out to stable storage.
1845 	 */
1846 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1847 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
1848 
1849 	VN_RELE(vp);
1850 	if (tvp != NULL) {
1851 		if (in_crit)
1852 			nbl_end_crit(tvp);
1853 		VN_RELE(tvp);
1854 	}
1855 
1856 	resp->status = NFS3_OK;
1857 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1858 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1859 
1860 	DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1861 	    cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1862 
1863 	VN_RELE(dvp);
1864 	return;
1865 
1866 out:
1867 	if (curthread->t_flag & T_WOULDBLOCK) {
1868 		curthread->t_flag &= ~T_WOULDBLOCK;
1869 		resp->status = NFS3ERR_JUKEBOX;
1870 	} else
1871 		resp->status = puterrno3(error);
1872 out1:
1873 	DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1874 	    cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1875 
1876 	if (name != NULL && name != args->where.name)
1877 		kmem_free(name, MAXPATHLEN + 1);
1878 
1879 	if (tvp != NULL) {
1880 		if (in_crit)
1881 			nbl_end_crit(tvp);
1882 		VN_RELE(tvp);
1883 	}
1884 	if (dvp != NULL)
1885 		VN_RELE(dvp);
1886 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1887 }
1888 
1889 void *
1890 rfs3_create_getfh(CREATE3args *args)
1891 {
1892 
1893 	return (&args->where.dir);
1894 }
1895 
1896 void
1897 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1898 	struct svc_req *req, cred_t *cr)
1899 {
1900 	int error;
1901 	vnode_t *vp = NULL;
1902 	vnode_t *dvp;
1903 	struct vattr *vap;
1904 	struct vattr va;
1905 	struct vattr *dbvap;
1906 	struct vattr dbva;
1907 	struct vattr *davap;
1908 	struct vattr dava;
1909 	struct sockaddr *ca;
1910 	char *name = NULL;
1911 
1912 	dbvap = NULL;
1913 	davap = NULL;
1914 
1915 	dvp = nfs3_fhtovp(&args->where.dir, exi);
1916 
1917 	DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
1918 	    cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
1919 
1920 	if (dvp == NULL) {
1921 		error = ESTALE;
1922 		goto out;
1923 	}
1924 
1925 #ifdef DEBUG
1926 	if (rfs3_do_pre_op_attr) {
1927 		dbva.va_mask = AT_ALL;
1928 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1929 	} else
1930 		dbvap = NULL;
1931 #else
1932 	dbva.va_mask = AT_ALL;
1933 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1934 #endif
1935 	davap = dbvap;
1936 
1937 	if (args->where.name == nfs3nametoolong) {
1938 		resp->status = NFS3ERR_NAMETOOLONG;
1939 		goto out1;
1940 	}
1941 
1942 	if (args->where.name == NULL || *(args->where.name) == '\0') {
1943 		resp->status = NFS3ERR_ACCES;
1944 		goto out1;
1945 	}
1946 
1947 	if (rdonly(exi, req)) {
1948 		resp->status = NFS3ERR_ROFS;
1949 		goto out1;
1950 	}
1951 
1952 	if (is_system_labeled()) {
1953 		bslabel_t *clabel = req->rq_label;
1954 
1955 		ASSERT(clabel != NULL);
1956 		DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1957 		    "got client label from request(1)", struct svc_req *, req);
1958 
1959 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1960 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
1961 				resp->status = NFS3ERR_ACCES;
1962 				goto out1;
1963 			}
1964 		}
1965 	}
1966 
1967 	error = sattr3_to_vattr(&args->attributes, &va);
1968 	if (error)
1969 		goto out;
1970 
1971 	if (!(va.va_mask & AT_MODE)) {
1972 		resp->status = NFS3ERR_INVAL;
1973 		goto out1;
1974 	}
1975 
1976 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1977 	name = nfscmd_convname(ca, exi, args->where.name,
1978 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1979 
1980 	if (name == NULL) {
1981 		resp->status = NFS3ERR_INVAL;
1982 		goto out1;
1983 	}
1984 
1985 	va.va_mask |= AT_TYPE;
1986 	va.va_type = VDIR;
1987 
1988 	error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
1989 
1990 	if (name != args->where.name)
1991 		kmem_free(name, MAXPATHLEN + 1);
1992 
1993 #ifdef DEBUG
1994 	if (rfs3_do_post_op_attr) {
1995 		dava.va_mask = AT_ALL;
1996 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1997 	} else
1998 		davap = NULL;
1999 #else
2000 	dava.va_mask = AT_ALL;
2001 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2002 #endif
2003 
2004 	/*
2005 	 * Force modified data and metadata out to stable storage.
2006 	 */
2007 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
2008 
2009 	if (error)
2010 		goto out;
2011 
2012 #ifdef DEBUG
2013 	if (!rfs3_do_post_op_fh3)
2014 		resp->resok.obj.handle_follows = FALSE;
2015 	else {
2016 #endif
2017 	error = makefh3(&resp->resok.obj.handle, vp, exi);
2018 	if (error)
2019 		resp->resok.obj.handle_follows = FALSE;
2020 	else
2021 		resp->resok.obj.handle_follows = TRUE;
2022 #ifdef DEBUG
2023 	}
2024 #endif
2025 
2026 #ifdef DEBUG
2027 	if (rfs3_do_post_op_attr) {
2028 		va.va_mask = AT_ALL;
2029 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2030 	} else
2031 		vap = NULL;
2032 #else
2033 	va.va_mask = AT_ALL;
2034 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2035 #endif
2036 
2037 	/*
2038 	 * Force modified data and metadata out to stable storage.
2039 	 */
2040 	(void) VOP_FSYNC(vp, 0, cr, NULL);
2041 
2042 	VN_RELE(vp);
2043 
2044 	resp->status = NFS3_OK;
2045 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2046 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2047 
2048 	DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2049 	    cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2050 	VN_RELE(dvp);
2051 
2052 	return;
2053 
2054 out:
2055 	if (curthread->t_flag & T_WOULDBLOCK) {
2056 		curthread->t_flag &= ~T_WOULDBLOCK;
2057 		resp->status = NFS3ERR_JUKEBOX;
2058 	} else
2059 		resp->status = puterrno3(error);
2060 out1:
2061 	DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2062 	    cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2063 	if (dvp != NULL)
2064 		VN_RELE(dvp);
2065 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2066 }
2067 
2068 void *
2069 rfs3_mkdir_getfh(MKDIR3args *args)
2070 {
2071 
2072 	return (&args->where.dir);
2073 }
2074 
2075 void
2076 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2077 	struct svc_req *req, cred_t *cr)
2078 {
2079 	int error;
2080 	vnode_t *vp;
2081 	vnode_t *dvp;
2082 	struct vattr *vap;
2083 	struct vattr va;
2084 	struct vattr *dbvap;
2085 	struct vattr dbva;
2086 	struct vattr *davap;
2087 	struct vattr dava;
2088 	struct sockaddr *ca;
2089 	char *name = NULL;
2090 	char *symdata = NULL;
2091 
2092 	dbvap = NULL;
2093 	davap = NULL;
2094 
2095 	dvp = nfs3_fhtovp(&args->where.dir, exi);
2096 
2097 	DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2098 	    cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
2099 
2100 	if (dvp == NULL) {
2101 		error = ESTALE;
2102 		goto err;
2103 	}
2104 
2105 #ifdef DEBUG
2106 	if (rfs3_do_pre_op_attr) {
2107 		dbva.va_mask = AT_ALL;
2108 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2109 	} else
2110 		dbvap = NULL;
2111 #else
2112 	dbva.va_mask = AT_ALL;
2113 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2114 #endif
2115 	davap = dbvap;
2116 
2117 	if (args->where.name == nfs3nametoolong) {
2118 		resp->status = NFS3ERR_NAMETOOLONG;
2119 		goto err1;
2120 	}
2121 
2122 	if (args->where.name == NULL || *(args->where.name) == '\0') {
2123 		resp->status = NFS3ERR_ACCES;
2124 		goto err1;
2125 	}
2126 
2127 	if (rdonly(exi, req)) {
2128 		resp->status = NFS3ERR_ROFS;
2129 		goto err1;
2130 	}
2131 
2132 	if (is_system_labeled()) {
2133 		bslabel_t *clabel = req->rq_label;
2134 
2135 		ASSERT(clabel != NULL);
2136 		DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
2137 		    "got client label from request(1)", struct svc_req *, req);
2138 
2139 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2140 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
2141 				resp->status = NFS3ERR_ACCES;
2142 				goto err1;
2143 			}
2144 		}
2145 	}
2146 
2147 	error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
2148 	if (error)
2149 		goto err;
2150 
2151 	if (!(va.va_mask & AT_MODE)) {
2152 		resp->status = NFS3ERR_INVAL;
2153 		goto err1;
2154 	}
2155 
2156 	if (args->symlink.symlink_data == nfs3nametoolong) {
2157 		resp->status = NFS3ERR_NAMETOOLONG;
2158 		goto err1;
2159 	}
2160 
2161 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2162 	name = nfscmd_convname(ca, exi, args->where.name,
2163 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2164 
2165 	if (name == NULL) {
2166 		/* This is really a Solaris EILSEQ */
2167 		resp->status = NFS3ERR_INVAL;
2168 		goto err1;
2169 	}
2170 
2171 	symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
2172 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2173 	if (symdata == NULL) {
2174 		/* This is really a Solaris EILSEQ */
2175 		resp->status = NFS3ERR_INVAL;
2176 		goto err1;
2177 	}
2178 
2179 
2180 	va.va_mask |= AT_TYPE;
2181 	va.va_type = VLNK;
2182 
2183 	error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
2184 
2185 #ifdef DEBUG
2186 	if (rfs3_do_post_op_attr) {
2187 		dava.va_mask = AT_ALL;
2188 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2189 	} else
2190 		davap = NULL;
2191 #else
2192 	dava.va_mask = AT_ALL;
2193 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2194 #endif
2195 
2196 	if (error)
2197 		goto err;
2198 
2199 	error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
2200 	    NULL, NULL, NULL);
2201 
2202 	/*
2203 	 * Force modified data and metadata out to stable storage.
2204 	 */
2205 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
2206 
2207 
2208 	resp->status = NFS3_OK;
2209 	if (error) {
2210 		resp->resok.obj.handle_follows = FALSE;
2211 		vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
2212 		vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2213 		goto out;
2214 	}
2215 
2216 #ifdef DEBUG
2217 	if (!rfs3_do_post_op_fh3)
2218 		resp->resok.obj.handle_follows = FALSE;
2219 	else {
2220 #endif
2221 	error = makefh3(&resp->resok.obj.handle, vp, exi);
2222 	if (error)
2223 		resp->resok.obj.handle_follows = FALSE;
2224 	else
2225 		resp->resok.obj.handle_follows = TRUE;
2226 #ifdef DEBUG
2227 	}
2228 #endif
2229 
2230 #ifdef DEBUG
2231 	if (rfs3_do_post_op_attr) {
2232 		va.va_mask = AT_ALL;
2233 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2234 	} else
2235 		vap = NULL;
2236 #else
2237 	va.va_mask = AT_ALL;
2238 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2239 #endif
2240 
2241 	/*
2242 	 * Force modified data and metadata out to stable storage.
2243 	 */
2244 	(void) VOP_FSYNC(vp, 0, cr, NULL);
2245 
2246 	VN_RELE(vp);
2247 
2248 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2249 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2250 	goto out;
2251 
2252 err:
2253 	if (curthread->t_flag & T_WOULDBLOCK) {
2254 		curthread->t_flag &= ~T_WOULDBLOCK;
2255 		resp->status = NFS3ERR_JUKEBOX;
2256 	} else
2257 		resp->status = puterrno3(error);
2258 err1:
2259 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2260 out:
2261 	if (name != NULL && name != args->where.name)
2262 		kmem_free(name, MAXPATHLEN + 1);
2263 	if (symdata != NULL && symdata != args->symlink.symlink_data)
2264 		kmem_free(symdata, MAXPATHLEN + 1);
2265 
2266 	DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
2267 	    cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
2268 
2269 	if (dvp != NULL)
2270 		VN_RELE(dvp);
2271 }
2272 
2273 void *
2274 rfs3_symlink_getfh(SYMLINK3args *args)
2275 {
2276 
2277 	return (&args->where.dir);
2278 }
2279 
2280 void
2281 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2282 	struct svc_req *req, cred_t *cr)
2283 {
2284 	int error;
2285 	vnode_t *vp;
2286 	vnode_t *realvp;
2287 	vnode_t *dvp;
2288 	struct vattr *vap;
2289 	struct vattr va;
2290 	struct vattr *dbvap;
2291 	struct vattr dbva;
2292 	struct vattr *davap;
2293 	struct vattr dava;
2294 	int mode;
2295 	enum vcexcl excl;
2296 	struct sockaddr *ca;
2297 	char *name = NULL;
2298 
2299 	dbvap = NULL;
2300 	davap = NULL;
2301 
2302 	dvp = nfs3_fhtovp(&args->where.dir, exi);
2303 
2304 	DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2305 	    cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
2306 
2307 	if (dvp == NULL) {
2308 		error = ESTALE;
2309 		goto out;
2310 	}
2311 
2312 #ifdef DEBUG
2313 	if (rfs3_do_pre_op_attr) {
2314 		dbva.va_mask = AT_ALL;
2315 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2316 	} else
2317 		dbvap = NULL;
2318 #else
2319 	dbva.va_mask = AT_ALL;
2320 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2321 #endif
2322 	davap = dbvap;
2323 
2324 	if (args->where.name == nfs3nametoolong) {
2325 		resp->status = NFS3ERR_NAMETOOLONG;
2326 		goto out1;
2327 	}
2328 
2329 	if (args->where.name == NULL || *(args->where.name) == '\0') {
2330 		resp->status = NFS3ERR_ACCES;
2331 		goto out1;
2332 	}
2333 
2334 	if (rdonly(exi, req)) {
2335 		resp->status = NFS3ERR_ROFS;
2336 		goto out1;
2337 	}
2338 
2339 	if (is_system_labeled()) {
2340 		bslabel_t *clabel = req->rq_label;
2341 
2342 		ASSERT(clabel != NULL);
2343 		DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2344 		    "got client label from request(1)", struct svc_req *, req);
2345 
2346 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2347 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
2348 				resp->status = NFS3ERR_ACCES;
2349 				goto out1;
2350 			}
2351 		}
2352 	}
2353 
2354 	switch (args->what.type) {
2355 	case NF3CHR:
2356 	case NF3BLK:
2357 		error = sattr3_to_vattr(
2358 		    &args->what.mknoddata3_u.device.dev_attributes, &va);
2359 		if (error)
2360 			goto out;
2361 		if (secpolicy_sys_devices(cr) != 0) {
2362 			resp->status = NFS3ERR_PERM;
2363 			goto out1;
2364 		}
2365 		if (args->what.type == NF3CHR)
2366 			va.va_type = VCHR;
2367 		else
2368 			va.va_type = VBLK;
2369 		va.va_rdev = makedevice(
2370 		    args->what.mknoddata3_u.device.spec.specdata1,
2371 		    args->what.mknoddata3_u.device.spec.specdata2);
2372 		va.va_mask |= AT_TYPE | AT_RDEV;
2373 		break;
2374 	case NF3SOCK:
2375 		error = sattr3_to_vattr(
2376 		    &args->what.mknoddata3_u.pipe_attributes, &va);
2377 		if (error)
2378 			goto out;
2379 		va.va_type = VSOCK;
2380 		va.va_mask |= AT_TYPE;
2381 		break;
2382 	case NF3FIFO:
2383 		error = sattr3_to_vattr(
2384 		    &args->what.mknoddata3_u.pipe_attributes, &va);
2385 		if (error)
2386 			goto out;
2387 		va.va_type = VFIFO;
2388 		va.va_mask |= AT_TYPE;
2389 		break;
2390 	default:
2391 		resp->status = NFS3ERR_BADTYPE;
2392 		goto out1;
2393 	}
2394 
2395 	/*
2396 	 * Must specify the mode.
2397 	 */
2398 	if (!(va.va_mask & AT_MODE)) {
2399 		resp->status = NFS3ERR_INVAL;
2400 		goto out1;
2401 	}
2402 
2403 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2404 	name = nfscmd_convname(ca, exi, args->where.name,
2405 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2406 
2407 	if (name == NULL) {
2408 		resp->status = NFS3ERR_INVAL;
2409 		goto out1;
2410 	}
2411 
2412 	excl = EXCL;
2413 
2414 	mode = 0;
2415 
2416 	error = VOP_CREATE(dvp, name, &va, excl, mode,
2417 	    &vp, cr, 0, NULL, NULL);
2418 
2419 	if (name != args->where.name)
2420 		kmem_free(name, MAXPATHLEN + 1);
2421 
2422 #ifdef DEBUG
2423 	if (rfs3_do_post_op_attr) {
2424 		dava.va_mask = AT_ALL;
2425 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2426 	} else
2427 		davap = NULL;
2428 #else
2429 	dava.va_mask = AT_ALL;
2430 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2431 #endif
2432 
2433 	/*
2434 	 * Force modified data and metadata out to stable storage.
2435 	 */
2436 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
2437 
2438 	if (error)
2439 		goto out;
2440 
2441 	resp->status = NFS3_OK;
2442 
2443 #ifdef DEBUG
2444 	if (!rfs3_do_post_op_fh3)
2445 		resp->resok.obj.handle_follows = FALSE;
2446 	else {
2447 #endif
2448 	error = makefh3(&resp->resok.obj.handle, vp, exi);
2449 	if (error)
2450 		resp->resok.obj.handle_follows = FALSE;
2451 	else
2452 		resp->resok.obj.handle_follows = TRUE;
2453 #ifdef DEBUG
2454 	}
2455 #endif
2456 
2457 #ifdef DEBUG
2458 	if (rfs3_do_post_op_attr) {
2459 		va.va_mask = AT_ALL;
2460 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2461 	} else
2462 		vap = NULL;
2463 #else
2464 	va.va_mask = AT_ALL;
2465 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2466 #endif
2467 
2468 	/*
2469 	 * Force modified metadata out to stable storage.
2470 	 *
2471 	 * if a underlying vp exists, pass it to VOP_FSYNC
2472 	 */
2473 	if (VOP_REALVP(vp, &realvp, NULL) == 0)
2474 		(void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2475 	else
2476 		(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2477 
2478 	VN_RELE(vp);
2479 
2480 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2481 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2482 	DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2483 	    cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2484 	VN_RELE(dvp);
2485 	return;
2486 
2487 out:
2488 	if (curthread->t_flag & T_WOULDBLOCK) {
2489 		curthread->t_flag &= ~T_WOULDBLOCK;
2490 		resp->status = NFS3ERR_JUKEBOX;
2491 	} else
2492 		resp->status = puterrno3(error);
2493 out1:
2494 	DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2495 	    cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2496 	if (dvp != NULL)
2497 		VN_RELE(dvp);
2498 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2499 }
2500 
2501 void *
2502 rfs3_mknod_getfh(MKNOD3args *args)
2503 {
2504 
2505 	return (&args->where.dir);
2506 }
2507 
2508 void
2509 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2510 	struct svc_req *req, cred_t *cr)
2511 {
2512 	int error = 0;
2513 	vnode_t *vp;
2514 	struct vattr *bvap;
2515 	struct vattr bva;
2516 	struct vattr *avap;
2517 	struct vattr ava;
2518 	vnode_t *targvp = NULL;
2519 	struct sockaddr *ca;
2520 	char *name = NULL;
2521 
2522 	bvap = NULL;
2523 	avap = NULL;
2524 
2525 	vp = nfs3_fhtovp(&args->object.dir, exi);
2526 
2527 	DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2528 	    cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
2529 
2530 	if (vp == NULL) {
2531 		error = ESTALE;
2532 		goto err;
2533 	}
2534 
2535 #ifdef DEBUG
2536 	if (rfs3_do_pre_op_attr) {
2537 		bva.va_mask = AT_ALL;
2538 		bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2539 	} else
2540 		bvap = NULL;
2541 #else
2542 	bva.va_mask = AT_ALL;
2543 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2544 #endif
2545 	avap = bvap;
2546 
2547 	if (vp->v_type != VDIR) {
2548 		resp->status = NFS3ERR_NOTDIR;
2549 		goto err1;
2550 	}
2551 
2552 	if (args->object.name == nfs3nametoolong) {
2553 		resp->status = NFS3ERR_NAMETOOLONG;
2554 		goto err1;
2555 	}
2556 
2557 	if (args->object.name == NULL || *(args->object.name) == '\0') {
2558 		resp->status = NFS3ERR_ACCES;
2559 		goto err1;
2560 	}
2561 
2562 	if (rdonly(exi, req)) {
2563 		resp->status = NFS3ERR_ROFS;
2564 		goto err1;
2565 	}
2566 
2567 	if (is_system_labeled()) {
2568 		bslabel_t *clabel = req->rq_label;
2569 
2570 		ASSERT(clabel != NULL);
2571 		DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *,
2572 		    "got client label from request(1)", struct svc_req *, req);
2573 
2574 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2575 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
2576 				resp->status = NFS3ERR_ACCES;
2577 				goto err1;
2578 			}
2579 		}
2580 	}
2581 
2582 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2583 	name = nfscmd_convname(ca, exi, args->object.name,
2584 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2585 
2586 	if (name == NULL) {
2587 		resp->status = NFS3ERR_INVAL;
2588 		goto err1;
2589 	}
2590 
2591 	/*
2592 	 * Check for a conflict with a non-blocking mandatory share
2593 	 * reservation and V4 delegations
2594 	 */
2595 	error = VOP_LOOKUP(vp, name, &targvp, NULL, 0,
2596 	    NULL, cr, NULL, NULL, NULL);
2597 	if (error != 0)
2598 		goto err;
2599 
2600 	if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2601 		resp->status = NFS3ERR_JUKEBOX;
2602 		goto err1;
2603 	}
2604 
2605 	if (!nbl_need_check(targvp)) {
2606 		error = VOP_REMOVE(vp, name, cr, NULL, 0);
2607 	} else {
2608 		nbl_start_crit(targvp, RW_READER);
2609 		if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
2610 			error = EACCES;
2611 		} else {
2612 			error = VOP_REMOVE(vp, name, cr, NULL, 0);
2613 		}
2614 		nbl_end_crit(targvp);
2615 	}
2616 	VN_RELE(targvp);
2617 	targvp = NULL;
2618 
2619 #ifdef DEBUG
2620 	if (rfs3_do_post_op_attr) {
2621 		ava.va_mask = AT_ALL;
2622 		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2623 	} else
2624 		avap = NULL;
2625 #else
2626 	ava.va_mask = AT_ALL;
2627 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2628 #endif
2629 
2630 	/*
2631 	 * Force modified data and metadata out to stable storage.
2632 	 */
2633 	(void) VOP_FSYNC(vp, 0, cr, NULL);
2634 
2635 	if (error)
2636 		goto err;
2637 
2638 	resp->status = NFS3_OK;
2639 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2640 	goto out;
2641 
2642 err:
2643 	if (curthread->t_flag & T_WOULDBLOCK) {
2644 		curthread->t_flag &= ~T_WOULDBLOCK;
2645 		resp->status = NFS3ERR_JUKEBOX;
2646 	} else
2647 		resp->status = puterrno3(error);
2648 err1:
2649 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2650 out:
2651 	DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
2652 	    cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
2653 
2654 	if (name != NULL && name != args->object.name)
2655 		kmem_free(name, MAXPATHLEN + 1);
2656 
2657 	if (vp != NULL)
2658 		VN_RELE(vp);
2659 }
2660 
2661 void *
2662 rfs3_remove_getfh(REMOVE3args *args)
2663 {
2664 
2665 	return (&args->object.dir);
2666 }
2667 
2668 void
2669 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2670 	struct svc_req *req, cred_t *cr)
2671 {
2672 	int error;
2673 	vnode_t *vp;
2674 	struct vattr *bvap;
2675 	struct vattr bva;
2676 	struct vattr *avap;
2677 	struct vattr ava;
2678 	struct sockaddr *ca;
2679 	char *name = NULL;
2680 
2681 	bvap = NULL;
2682 	avap = NULL;
2683 
2684 	vp = nfs3_fhtovp(&args->object.dir, exi);
2685 
2686 	DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2687 	    cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
2688 
2689 	if (vp == NULL) {
2690 		error = ESTALE;
2691 		goto err;
2692 	}
2693 
2694 #ifdef DEBUG
2695 	if (rfs3_do_pre_op_attr) {
2696 		bva.va_mask = AT_ALL;
2697 		bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2698 	} else
2699 		bvap = NULL;
2700 #else
2701 	bva.va_mask = AT_ALL;
2702 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2703 #endif
2704 	avap = bvap;
2705 
2706 	if (vp->v_type != VDIR) {
2707 		resp->status = NFS3ERR_NOTDIR;
2708 		goto err1;
2709 	}
2710 
2711 	if (args->object.name == nfs3nametoolong) {
2712 		resp->status = NFS3ERR_NAMETOOLONG;
2713 		goto err1;
2714 	}
2715 
2716 	if (args->object.name == NULL || *(args->object.name) == '\0') {
2717 		resp->status = NFS3ERR_ACCES;
2718 		goto err1;
2719 	}
2720 
2721 	if (rdonly(exi, req)) {
2722 		resp->status = NFS3ERR_ROFS;
2723 		goto err1;
2724 	}
2725 
2726 	if (is_system_labeled()) {
2727 		bslabel_t *clabel = req->rq_label;
2728 
2729 		ASSERT(clabel != NULL);
2730 		DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *,
2731 		    "got client label from request(1)", struct svc_req *, req);
2732 
2733 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2734 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
2735 				resp->status = NFS3ERR_ACCES;
2736 				goto err1;
2737 			}
2738 		}
2739 	}
2740 
2741 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2742 	name = nfscmd_convname(ca, exi, args->object.name,
2743 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2744 
2745 	if (name == NULL) {
2746 		resp->status = NFS3ERR_INVAL;
2747 		goto err1;
2748 	}
2749 
2750 	error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
2751 
2752 	if (name != args->object.name)
2753 		kmem_free(name, MAXPATHLEN + 1);
2754 
2755 #ifdef DEBUG
2756 	if (rfs3_do_post_op_attr) {
2757 		ava.va_mask = AT_ALL;
2758 		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2759 	} else
2760 		avap = NULL;
2761 #else
2762 	ava.va_mask = AT_ALL;
2763 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2764 #endif
2765 
2766 	/*
2767 	 * Force modified data and metadata out to stable storage.
2768 	 */
2769 	(void) VOP_FSYNC(vp, 0, cr, NULL);
2770 
2771 	if (error) {
2772 		/*
2773 		 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2774 		 * if the directory is not empty.  A System V NFS server
2775 		 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2776 		 * over the wire.
2777 		 */
2778 		if (error == EEXIST)
2779 			error = ENOTEMPTY;
2780 		goto err;
2781 	}
2782 
2783 	resp->status = NFS3_OK;
2784 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2785 	goto out;
2786 
2787 err:
2788 	if (curthread->t_flag & T_WOULDBLOCK) {
2789 		curthread->t_flag &= ~T_WOULDBLOCK;
2790 		resp->status = NFS3ERR_JUKEBOX;
2791 	} else
2792 		resp->status = puterrno3(error);
2793 err1:
2794 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2795 out:
2796 	DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
2797 	    cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
2798 	if (vp != NULL)
2799 		VN_RELE(vp);
2800 
2801 }
2802 
2803 void *
2804 rfs3_rmdir_getfh(RMDIR3args *args)
2805 {
2806 
2807 	return (&args->object.dir);
2808 }
2809 
2810 void
2811 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2812 	struct svc_req *req, cred_t *cr)
2813 {
2814 	int error = 0;
2815 	vnode_t *fvp;
2816 	vnode_t *tvp;
2817 	vnode_t *targvp;
2818 	struct vattr *fbvap;
2819 	struct vattr fbva;
2820 	struct vattr *favap;
2821 	struct vattr fava;
2822 	struct vattr *tbvap;
2823 	struct vattr tbva;
2824 	struct vattr *tavap;
2825 	struct vattr tava;
2826 	nfs_fh3 *fh3;
2827 	struct exportinfo *to_exi;
2828 	vnode_t *srcvp = NULL;
2829 	bslabel_t *clabel;
2830 	struct sockaddr *ca;
2831 	char *name = NULL;
2832 	char *toname = NULL;
2833 
2834 	fbvap = NULL;
2835 	favap = NULL;
2836 	tbvap = NULL;
2837 	tavap = NULL;
2838 	tvp = NULL;
2839 
2840 	fvp = nfs3_fhtovp(&args->from.dir, exi);
2841 
2842 	DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
2843 	    cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
2844 
2845 	if (fvp == NULL) {
2846 		error = ESTALE;
2847 		goto err;
2848 	}
2849 
2850 	if (is_system_labeled()) {
2851 		clabel = req->rq_label;
2852 		ASSERT(clabel != NULL);
2853 		DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2854 		    "got client label from request(1)", struct svc_req *, req);
2855 
2856 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2857 			if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK)) {
2858 				resp->status = NFS3ERR_ACCES;
2859 				goto err1;
2860 			}
2861 		}
2862 	}
2863 
2864 #ifdef DEBUG
2865 	if (rfs3_do_pre_op_attr) {
2866 		fbva.va_mask = AT_ALL;
2867 		fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2868 	} else
2869 		fbvap = NULL;
2870 #else
2871 	fbva.va_mask = AT_ALL;
2872 	fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2873 #endif
2874 	favap = fbvap;
2875 
2876 	fh3 = &args->to.dir;
2877 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2878 	if (to_exi == NULL) {
2879 		resp->status = NFS3ERR_ACCES;
2880 		goto err1;
2881 	}
2882 	exi_rele(to_exi);
2883 
2884 	if (to_exi != exi) {
2885 		resp->status = NFS3ERR_XDEV;
2886 		goto err1;
2887 	}
2888 
2889 	tvp = nfs3_fhtovp(&args->to.dir, exi);
2890 	if (tvp == NULL) {
2891 		error = ESTALE;
2892 		goto err;
2893 	}
2894 
2895 #ifdef DEBUG
2896 	if (rfs3_do_pre_op_attr) {
2897 		tbva.va_mask = AT_ALL;
2898 		tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2899 	} else
2900 		tbvap = NULL;
2901 #else
2902 	tbva.va_mask = AT_ALL;
2903 	tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2904 #endif
2905 	tavap = tbvap;
2906 
2907 	if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2908 		resp->status = NFS3ERR_NOTDIR;
2909 		goto err1;
2910 	}
2911 
2912 	if (args->from.name == nfs3nametoolong ||
2913 	    args->to.name == nfs3nametoolong) {
2914 		resp->status = NFS3ERR_NAMETOOLONG;
2915 		goto err1;
2916 	}
2917 	if (args->from.name == NULL || *(args->from.name) == '\0' ||
2918 	    args->to.name == NULL || *(args->to.name) == '\0') {
2919 		resp->status = NFS3ERR_ACCES;
2920 		goto err1;
2921 	}
2922 
2923 	if (rdonly(exi, req)) {
2924 		resp->status = NFS3ERR_ROFS;
2925 		goto err1;
2926 	}
2927 
2928 	if (is_system_labeled()) {
2929 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2930 			if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK)) {
2931 				resp->status = NFS3ERR_ACCES;
2932 				goto err1;
2933 			}
2934 		}
2935 	}
2936 
2937 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2938 	name = nfscmd_convname(ca, exi, args->from.name,
2939 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2940 
2941 	if (name == NULL) {
2942 		resp->status = NFS3ERR_INVAL;
2943 		goto err1;
2944 	}
2945 
2946 	toname = nfscmd_convname(ca, exi, args->to.name,
2947 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2948 
2949 	if (toname == NULL) {
2950 		resp->status = NFS3ERR_INVAL;
2951 		goto err1;
2952 	}
2953 
2954 	/*
2955 	 * Check for a conflict with a non-blocking mandatory share
2956 	 * reservation or V4 delegations.
2957 	 */
2958 	error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2959 	    NULL, cr, NULL, NULL, NULL);
2960 	if (error != 0)
2961 		goto err;
2962 
2963 	/*
2964 	 * If we rename a delegated file we should recall the
2965 	 * delegation, since future opens should fail or would
2966 	 * refer to a new file.
2967 	 */
2968 	if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2969 		resp->status = NFS3ERR_JUKEBOX;
2970 		goto err1;
2971 	}
2972 
2973 	/*
2974 	 * Check for renaming over a delegated file.  Check rfs4_deleg_policy
2975 	 * first to avoid VOP_LOOKUP if possible.
2976 	 */
2977 	if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
2978 	    VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2979 	    NULL, NULL, NULL) == 0) {
2980 
2981 		if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2982 			VN_RELE(targvp);
2983 			resp->status = NFS3ERR_JUKEBOX;
2984 			goto err1;
2985 		}
2986 		VN_RELE(targvp);
2987 	}
2988 
2989 	if (!nbl_need_check(srcvp)) {
2990 		error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2991 	} else {
2992 		nbl_start_crit(srcvp, RW_READER);
2993 		if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2994 			error = EACCES;
2995 		else
2996 			error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2997 		nbl_end_crit(srcvp);
2998 	}
2999 	if (error == 0)
3000 		vn_renamepath(tvp, srcvp, args->to.name,
3001 		    strlen(args->to.name));
3002 	VN_RELE(srcvp);
3003 	srcvp = NULL;
3004 
3005 #ifdef DEBUG
3006 	if (rfs3_do_post_op_attr) {
3007 		fava.va_mask = AT_ALL;
3008 		favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
3009 		tava.va_mask = AT_ALL;
3010 		tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
3011 	} else {
3012 		favap = NULL;
3013 		tavap = NULL;
3014 	}
3015 #else
3016 	fava.va_mask = AT_ALL;
3017 	favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
3018 	tava.va_mask = AT_ALL;
3019 	tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
3020 #endif
3021 
3022 	/*
3023 	 * Force modified data and metadata out to stable storage.
3024 	 */
3025 	(void) VOP_FSYNC(fvp, 0, cr, NULL);
3026 	(void) VOP_FSYNC(tvp, 0, cr, NULL);
3027 
3028 	if (error)
3029 		goto err;
3030 
3031 	resp->status = NFS3_OK;
3032 	vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
3033 	vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
3034 	goto out;
3035 
3036 err:
3037 	if (curthread->t_flag & T_WOULDBLOCK) {
3038 		curthread->t_flag &= ~T_WOULDBLOCK;
3039 		resp->status = NFS3ERR_JUKEBOX;
3040 	} else {
3041 		resp->status = puterrno3(error);
3042 	}
3043 err1:
3044 	vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
3045 	vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
3046 
3047 out:
3048 	if (name != NULL && name != args->from.name)
3049 		kmem_free(name, MAXPATHLEN + 1);
3050 	if (toname != NULL && toname != args->to.name)
3051 		kmem_free(toname, MAXPATHLEN + 1);
3052 
3053 	DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
3054 	    cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
3055 	if (fvp != NULL)
3056 		VN_RELE(fvp);
3057 	if (tvp != NULL)
3058 		VN_RELE(tvp);
3059 }
3060 
3061 void *
3062 rfs3_rename_getfh(RENAME3args *args)
3063 {
3064 
3065 	return (&args->from.dir);
3066 }
3067 
3068 void
3069 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
3070 	struct svc_req *req, cred_t *cr)
3071 {
3072 	int error;
3073 	vnode_t *vp;
3074 	vnode_t *dvp;
3075 	struct vattr *vap;
3076 	struct vattr va;
3077 	struct vattr *bvap;
3078 	struct vattr bva;
3079 	struct vattr *avap;
3080 	struct vattr ava;
3081 	nfs_fh3	*fh3;
3082 	struct exportinfo *to_exi;
3083 	bslabel_t *clabel;
3084 	struct sockaddr *ca;
3085 	char *name = NULL;
3086 
3087 	vap = NULL;
3088 	bvap = NULL;
3089 	avap = NULL;
3090 	dvp = NULL;
3091 
3092 	vp = nfs3_fhtovp(&args->file, exi);
3093 
3094 	DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
3095 	    cred_t *, cr, vnode_t *, vp, LINK3args *, args);
3096 
3097 	if (vp == NULL) {
3098 		error = ESTALE;
3099 		goto out;
3100 	}
3101 
3102 #ifdef DEBUG
3103 	if (rfs3_do_pre_op_attr) {
3104 		va.va_mask = AT_ALL;
3105 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3106 	} else
3107 		vap = NULL;
3108 #else
3109 	va.va_mask = AT_ALL;
3110 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3111 #endif
3112 
3113 	fh3 = &args->link.dir;
3114 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
3115 	if (to_exi == NULL) {
3116 		resp->status = NFS3ERR_ACCES;
3117 		goto out1;
3118 	}
3119 	exi_rele(to_exi);
3120 
3121 	if (to_exi != exi) {
3122 		resp->status = NFS3ERR_XDEV;
3123 		goto out1;
3124 	}
3125 
3126 	if (is_system_labeled()) {
3127 		clabel = req->rq_label;
3128 
3129 		ASSERT(clabel != NULL);
3130 		DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
3131 		    "got client label from request(1)", struct svc_req *, req);
3132 
3133 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3134 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
3135 				resp->status = NFS3ERR_ACCES;
3136 				goto out1;
3137 			}
3138 		}
3139 	}
3140 
3141 	dvp = nfs3_fhtovp(&args->link.dir, exi);
3142 	if (dvp == NULL) {
3143 		error = ESTALE;
3144 		goto out;
3145 	}
3146 
3147 #ifdef DEBUG
3148 	if (rfs3_do_pre_op_attr) {
3149 		bva.va_mask = AT_ALL;
3150 		bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
3151 	} else
3152 		bvap = NULL;
3153 #else
3154 	bva.va_mask = AT_ALL;
3155 	bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
3156 #endif
3157 
3158 	if (dvp->v_type != VDIR) {
3159 		resp->status = NFS3ERR_NOTDIR;
3160 		goto out1;
3161 	}
3162 
3163 	if (args->link.name == nfs3nametoolong) {
3164 		resp->status = NFS3ERR_NAMETOOLONG;
3165 		goto out1;
3166 	}
3167 
3168 	if (args->link.name == NULL || *(args->link.name) == '\0') {
3169 		resp->status = NFS3ERR_ACCES;
3170 		goto out1;
3171 	}
3172 
3173 	if (rdonly(exi, req)) {
3174 		resp->status = NFS3ERR_ROFS;
3175 		goto out1;
3176 	}
3177 
3178 	if (is_system_labeled()) {
3179 		DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
3180 		    "got client label from request(1)", struct svc_req *, req);
3181 
3182 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3183 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
3184 				resp->status = NFS3ERR_ACCES;
3185 				goto out1;
3186 			}
3187 		}
3188 	}
3189 
3190 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3191 	name = nfscmd_convname(ca, exi, args->link.name,
3192 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3193 
3194 	if (name == NULL) {
3195 		resp->status = NFS3ERR_SERVERFAULT;
3196 		goto out1;
3197 	}
3198 
3199 	error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
3200 
3201 #ifdef DEBUG
3202 	if (rfs3_do_post_op_attr) {
3203 		va.va_mask = AT_ALL;
3204 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3205 		ava.va_mask = AT_ALL;
3206 		avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3207 	} else {
3208 		vap = NULL;
3209 		avap = NULL;
3210 	}
3211 #else
3212 	va.va_mask = AT_ALL;
3213 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3214 	ava.va_mask = AT_ALL;
3215 	avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3216 #endif
3217 
3218 	/*
3219 	 * Force modified data and metadata out to stable storage.
3220 	 */
3221 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3222 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
3223 
3224 	if (error)
3225 		goto out;
3226 
3227 	VN_RELE(dvp);
3228 
3229 	resp->status = NFS3_OK;
3230 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3231 	vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3232 
3233 	DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3234 	    cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3235 
3236 	VN_RELE(vp);
3237 
3238 	return;
3239 
3240 out:
3241 	if (curthread->t_flag & T_WOULDBLOCK) {
3242 		curthread->t_flag &= ~T_WOULDBLOCK;
3243 		resp->status = NFS3ERR_JUKEBOX;
3244 	} else
3245 		resp->status = puterrno3(error);
3246 out1:
3247 	if (name != NULL && name != args->link.name)
3248 		kmem_free(name, MAXPATHLEN + 1);
3249 
3250 	DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3251 	    cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3252 
3253 	if (vp != NULL)
3254 		VN_RELE(vp);
3255 	if (dvp != NULL)
3256 		VN_RELE(dvp);
3257 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3258 	vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3259 }
3260 
3261 void *
3262 rfs3_link_getfh(LINK3args *args)
3263 {
3264 
3265 	return (&args->file);
3266 }
3267 
3268 /*
3269  * This macro defines the size of a response which contains attribute
3270  * information and one directory entry (whose length is specified by
3271  * the macro parameter).  If the incoming request is larger than this,
3272  * then we are guaranteed to be able to return at one directory entry
3273  * if one exists.  Therefore, we do not need to check for
3274  * NFS3ERR_TOOSMALL if the requested size is larger then this.  If it
3275  * is not, then we need to check to make sure that this error does not
3276  * need to be returned.
3277  *
3278  * NFS3_READDIR_MIN_COUNT is comprised of following :
3279  *
3280  * status - 1 * BYTES_PER_XDR_UNIT
3281  * attr. flag - 1 * BYTES_PER_XDR_UNIT
3282  * cookie verifier - 2 * BYTES_PER_XDR_UNIT
3283  * attributes  - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3284  * boolean - 1 * BYTES_PER_XDR_UNIT
3285  * file id - 2 * BYTES_PER_XDR_UNIT
3286  * directory name length - 1 * BYTES_PER_XDR_UNIT
3287  * cookie - 2 * BYTES_PER_XDR_UNIT
3288  * end of list - 1 * BYTES_PER_XDR_UNIT
3289  * end of file - 1 * BYTES_PER_XDR_UNIT
3290  * Name length of directory to the nearest byte
3291  */
3292 
3293 #define	NFS3_READDIR_MIN_COUNT(length)	\
3294 	((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
3295 		BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
3296 
3297 /* ARGSUSED */
3298 void
3299 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3300 	struct svc_req *req, cred_t *cr)
3301 {
3302 	int error;
3303 	vnode_t *vp;
3304 	struct vattr *vap;
3305 	struct vattr va;
3306 	struct iovec iov;
3307 	struct uio uio;
3308 	char *data;
3309 	int iseof;
3310 	int bufsize;
3311 	int namlen;
3312 	uint_t count;
3313 	struct sockaddr *ca;
3314 
3315 	vap = NULL;
3316 
3317 	vp = nfs3_fhtovp(&args->dir, exi);
3318 
3319 	DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
3320 	    cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
3321 
3322 	if (vp == NULL) {
3323 		error = ESTALE;
3324 		goto out;
3325 	}
3326 
3327 	if (is_system_labeled()) {
3328 		bslabel_t *clabel = req->rq_label;
3329 
3330 		ASSERT(clabel != NULL);
3331 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3332 		    "got client label from request(1)", struct svc_req *, req);
3333 
3334 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3335 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
3336 				resp->status = NFS3ERR_ACCES;
3337 				goto out1;
3338 			}
3339 		}
3340 	}
3341 
3342 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3343 
3344 #ifdef DEBUG
3345 	if (rfs3_do_pre_op_attr) {
3346 		va.va_mask = AT_ALL;
3347 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3348 	} else
3349 		vap = NULL;
3350 #else
3351 	va.va_mask = AT_ALL;
3352 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3353 #endif
3354 
3355 	if (vp->v_type != VDIR) {
3356 		resp->status = NFS3ERR_NOTDIR;
3357 		goto out1;
3358 	}
3359 
3360 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3361 	if (error)
3362 		goto out;
3363 
3364 	/*
3365 	 * Now don't allow arbitrary count to alloc;
3366 	 * allow the maximum not to exceed rfs3_tsize()
3367 	 */
3368 	if (args->count > rfs3_tsize(req))
3369 		args->count = rfs3_tsize(req);
3370 
3371 	/*
3372 	 * Make sure that there is room to read at least one entry
3373 	 * if any are available.
3374 	 */
3375 	if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3376 		count = DIRENT64_RECLEN(MAXNAMELEN);
3377 	else
3378 		count = args->count;
3379 
3380 	data = kmem_alloc(count, KM_SLEEP);
3381 
3382 	iov.iov_base = data;
3383 	iov.iov_len = count;
3384 	uio.uio_iov = &iov;
3385 	uio.uio_iovcnt = 1;
3386 	uio.uio_segflg = UIO_SYSSPACE;
3387 	uio.uio_extflg = UIO_COPY_CACHED;
3388 	uio.uio_loffset = (offset_t)args->cookie;
3389 	uio.uio_resid = count;
3390 
3391 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3392 
3393 #ifdef DEBUG
3394 	if (rfs3_do_post_op_attr) {
3395 		va.va_mask = AT_ALL;
3396 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3397 	} else
3398 		vap = NULL;
3399 #else
3400 	va.va_mask = AT_ALL;
3401 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3402 #endif
3403 
3404 	if (error) {
3405 		kmem_free(data, count);
3406 		goto out;
3407 	}
3408 
3409 	/*
3410 	 * If the count was not large enough to be able to guarantee
3411 	 * to be able to return at least one entry, then need to
3412 	 * check to see if NFS3ERR_TOOSMALL should be returned.
3413 	 */
3414 	if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3415 		/*
3416 		 * bufsize is used to keep track of the size of the response.
3417 		 * It is primed with:
3418 		 *	1 for the status +
3419 		 *	1 for the dir_attributes.attributes boolean +
3420 		 *	2 for the cookie verifier
3421 		 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3422 		 * to bytes.  If there are directory attributes to be
3423 		 * returned, then:
3424 		 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3425 		 * time BYTES_PER_XDR_UNIT is added to account for them.
3426 		 */
3427 		bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3428 		if (vap != NULL)
3429 			bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3430 		/*
3431 		 * An entry is composed of:
3432 		 *	1 for the true/false list indicator +
3433 		 *	2 for the fileid +
3434 		 *	1 for the length of the name +
3435 		 *	2 for the cookie +
3436 		 * all times BYTES_PER_XDR_UNIT to convert from
3437 		 * XDR units to bytes, plus the length of the name
3438 		 * rounded up to the nearest BYTES_PER_XDR_UNIT.
3439 		 */
3440 		if (count != uio.uio_resid) {
3441 			namlen = strlen(((struct dirent64 *)data)->d_name);
3442 			bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3443 			    roundup(namlen, BYTES_PER_XDR_UNIT);
3444 		}
3445 		/*
3446 		 * We need to check to see if the number of bytes left
3447 		 * to go into the buffer will actually fit into the
3448 		 * buffer.  This is calculated as the size of this
3449 		 * entry plus:
3450 		 *	1 for the true/false list indicator +
3451 		 *	1 for the eof indicator
3452 		 * times BYTES_PER_XDR_UNIT to convert from from
3453 		 * XDR units to bytes.
3454 		 */
3455 		bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
3456 		if (bufsize > args->count) {
3457 			kmem_free(data, count);
3458 			resp->status = NFS3ERR_TOOSMALL;
3459 			goto out1;
3460 		}
3461 	}
3462 
3463 	/*
3464 	 * Have a valid readir buffer for the native character
3465 	 * set. Need to check if a conversion is necessary and
3466 	 * potentially rewrite the whole buffer. Note that if the
3467 	 * conversion expands names enough, the structure may not
3468 	 * fit. In this case, we need to drop entries until if fits
3469 	 * and patch the counts in order that the next readdir will
3470 	 * get the correct entries.
3471 	 */
3472 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3473 	data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
3474 
3475 
3476 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3477 
3478 #if 0 /* notyet */
3479 	/*
3480 	 * Don't do this.  It causes local disk writes when just
3481 	 * reading the file and the overhead is deemed larger
3482 	 * than the benefit.
3483 	 */
3484 	/*
3485 	 * Force modified metadata out to stable storage.
3486 	 */
3487 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3488 #endif
3489 
3490 	resp->status = NFS3_OK;
3491 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3492 	resp->resok.cookieverf = 0;
3493 	resp->resok.reply.entries = (entry3 *)data;
3494 	resp->resok.reply.eof = iseof;
3495 	resp->resok.size = count - uio.uio_resid;
3496 	resp->resok.count = args->count;
3497 	resp->resok.freecount = count;
3498 
3499 	DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3500 	    cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3501 
3502 	VN_RELE(vp);
3503 
3504 	return;
3505 
3506 out:
3507 	if (curthread->t_flag & T_WOULDBLOCK) {
3508 		curthread->t_flag &= ~T_WOULDBLOCK;
3509 		resp->status = NFS3ERR_JUKEBOX;
3510 	} else
3511 		resp->status = puterrno3(error);
3512 out1:
3513 	DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3514 	    cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3515 
3516 	if (vp != NULL) {
3517 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3518 		VN_RELE(vp);
3519 	}
3520 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3521 }
3522 
3523 void *
3524 rfs3_readdir_getfh(READDIR3args *args)
3525 {
3526 
3527 	return (&args->dir);
3528 }
3529 
3530 void
3531 rfs3_readdir_free(READDIR3res *resp)
3532 {
3533 
3534 	if (resp->status == NFS3_OK)
3535 		kmem_free(resp->resok.reply.entries, resp->resok.freecount);
3536 }
3537 
3538 #ifdef nextdp
3539 #undef nextdp
3540 #endif
3541 #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3542 
3543 /*
3544  * This macro computes the size of a response which contains
3545  * one directory entry including the attributes as well as file handle.
3546  * If the incoming request is larger than this, then we are guaranteed to be
3547  * able to return at least one more directory entry if one exists.
3548  *
3549  * NFS3_READDIRPLUS_ENTRY is made up of the following:
3550  *
3551  * boolean - 1 * BYTES_PER_XDR_UNIT
3552  * file id - 2 * BYTES_PER_XDR_UNIT
3553  * directory name length - 1 * BYTES_PER_XDR_UNIT
3554  * cookie - 2 * BYTES_PER_XDR_UNIT
3555  * attribute flag - 1 * BYTES_PER_XDR_UNIT
3556  * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3557  * status byte for file handle - 1 *  BYTES_PER_XDR_UNIT
3558  * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3559  * Maximum length of a file handle (NFS3_MAXFHSIZE)
3560  * name length of the entry to the nearest bytes
3561  */
3562 #define	NFS3_READDIRPLUS_ENTRY(namelen)	\
3563 	((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
3564 		BYTES_PER_XDR_UNIT + \
3565 	NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
3566 
3567 static int rfs3_readdir_unit = MAXBSIZE;
3568 
3569 /* ARGSUSED */
3570 void
3571 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3572 	struct exportinfo *exi, struct svc_req *req, cred_t *cr)
3573 {
3574 	int error;
3575 	vnode_t *vp;
3576 	struct vattr *vap;
3577 	struct vattr va;
3578 	struct iovec iov;
3579 	struct uio uio;
3580 	char *data;
3581 	int iseof;
3582 	struct dirent64 *dp;
3583 	vnode_t *nvp;
3584 	struct vattr *nvap;
3585 	struct vattr nva;
3586 	entryplus3_info *infop = NULL;
3587 	int size = 0;
3588 	int nents = 0;
3589 	int bufsize = 0;
3590 	int entrysize = 0;
3591 	int tofit = 0;
3592 	int rd_unit = rfs3_readdir_unit;
3593 	int prev_len;
3594 	int space_left;
3595 	int i;
3596 	uint_t *namlen = NULL;
3597 	char *ndata = NULL;
3598 	struct sockaddr *ca;
3599 	size_t ret;
3600 
3601 	vap = NULL;
3602 
3603 	vp = nfs3_fhtovp(&args->dir, exi);
3604 
3605 	DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
3606 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
3607 
3608 	if (vp == NULL) {
3609 		error = ESTALE;
3610 		goto out;
3611 	}
3612 
3613 	if (is_system_labeled()) {
3614 		bslabel_t *clabel = req->rq_label;
3615 
3616 		ASSERT(clabel != NULL);
3617 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3618 		    char *, "got client label from request(1)",
3619 		    struct svc_req *, req);
3620 
3621 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3622 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
3623 				resp->status = NFS3ERR_ACCES;
3624 				goto out1;
3625 			}
3626 		}
3627 	}
3628 
3629 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3630 
3631 #ifdef DEBUG
3632 	if (rfs3_do_pre_op_attr) {
3633 		va.va_mask = AT_ALL;
3634 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3635 	} else
3636 		vap = NULL;
3637 #else
3638 	va.va_mask = AT_ALL;
3639 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3640 #endif
3641 
3642 	if (vp->v_type != VDIR) {
3643 		error = ENOTDIR;
3644 		goto out;
3645 	}
3646 
3647 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3648 	if (error)
3649 		goto out;
3650 
3651 	/*
3652 	 * Don't allow arbitrary counts for allocation
3653 	 */
3654 	if (args->maxcount > rfs3_tsize(req))
3655 		args->maxcount = rfs3_tsize(req);
3656 
3657 	/*
3658 	 * Make sure that there is room to read at least one entry
3659 	 * if any are available
3660 	 */
3661 	args->dircount = MIN(args->dircount, args->maxcount);
3662 
3663 	if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
3664 		args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
3665 
3666 	/*
3667 	 * This allocation relies on a minimum directory entry
3668 	 * being roughly 24 bytes.  Therefore, the namlen array
3669 	 * will have enough space based on the maximum number of
3670 	 * entries to read.
3671 	 */
3672 	namlen = kmem_alloc(args->dircount, KM_SLEEP);
3673 
3674 	space_left = args->dircount;
3675 	data = kmem_alloc(args->dircount, KM_SLEEP);
3676 	dp = (struct dirent64 *)data;
3677 	uio.uio_iov = &iov;
3678 	uio.uio_iovcnt = 1;
3679 	uio.uio_segflg = UIO_SYSSPACE;
3680 	uio.uio_extflg = UIO_COPY_CACHED;
3681 	uio.uio_loffset = (offset_t)args->cookie;
3682 
3683 	/*
3684 	 * bufsize is used to keep track of the size of the response as we
3685 	 * get post op attributes and filehandles for each entry.  This is
3686 	 * an optimization as the server may have read more entries than will
3687 	 * fit in the buffer specified by maxcount.  We stop calculating
3688 	 * post op attributes and filehandles once we have exceeded maxcount.
3689 	 * This will minimize the effect of truncation.
3690 	 *
3691 	 * It is primed with:
3692 	 *	1 for the status +
3693 	 *	1 for the dir_attributes.attributes boolean +
3694 	 *	2 for the cookie verifier
3695 	 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3696 	 * to bytes.  If there are directory attributes to be
3697 	 * returned, then:
3698 	 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3699 	 * time BYTES_PER_XDR_UNIT is added to account for them.
3700 	 */
3701 	bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3702 	if (vap != NULL)
3703 		bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3704 
3705 getmoredents:
3706 	/*
3707 	 * Here we make a check so that our read unit is not larger than
3708 	 * the space left in the buffer.
3709 	 */
3710 	rd_unit = MIN(rd_unit, space_left);
3711 	iov.iov_base = (char *)dp;
3712 	iov.iov_len = rd_unit;
3713 	uio.uio_resid = rd_unit;
3714 	prev_len = rd_unit;
3715 
3716 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3717 
3718 	if (error) {
3719 		kmem_free(data, args->dircount);
3720 		goto out;
3721 	}
3722 
3723 	if (uio.uio_resid == prev_len && !iseof) {
3724 		if (nents == 0) {
3725 			kmem_free(data, args->dircount);
3726 			resp->status = NFS3ERR_TOOSMALL;
3727 			goto out1;
3728 		}
3729 
3730 		/*
3731 		 * We could not get any more entries, so get the attributes
3732 		 * and filehandle for the entries already obtained.
3733 		 */
3734 		goto good;
3735 	}
3736 
3737 	/*
3738 	 * We estimate the size of the response by assuming the
3739 	 * entry exists and attributes and filehandle are also valid
3740 	 */
3741 	for (size = prev_len - uio.uio_resid;
3742 	    size > 0;
3743 	    size -= dp->d_reclen, dp = nextdp(dp)) {
3744 
3745 		if (dp->d_ino == 0) {
3746 			nents++;
3747 			continue;
3748 		}
3749 
3750 		namlen[nents] = strlen(dp->d_name);
3751 		entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
3752 
3753 		/*
3754 		 * We need to check to see if the number of bytes left
3755 		 * to go into the buffer will actually fit into the
3756 		 * buffer.  This is calculated as the size of this
3757 		 * entry plus:
3758 		 *	1 for the true/false list indicator +
3759 		 *	1 for the eof indicator
3760 		 * times BYTES_PER_XDR_UNIT to convert from XDR units
3761 		 * to bytes.
3762 		 *
3763 		 * Also check the dircount limit against the first entry read
3764 		 *
3765 		 */
3766 		tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
3767 		if (bufsize + tofit > args->maxcount) {
3768 			/*
3769 			 * We make a check here to see if this was the
3770 			 * first entry being measured.  If so, then maxcount
3771 			 * was too small to begin with and so we need to
3772 			 * return with NFS3ERR_TOOSMALL.
3773 			 */
3774 			if (nents == 0) {
3775 				kmem_free(data, args->dircount);
3776 				resp->status = NFS3ERR_TOOSMALL;
3777 				goto out1;
3778 			}
3779 			iseof = FALSE;
3780 			goto good;
3781 		}
3782 		bufsize += entrysize;
3783 		nents++;
3784 	}
3785 
3786 	/*
3787 	 * If there is enough room to fit at least 1 more entry including
3788 	 * post op attributes and filehandle in the buffer AND that we haven't
3789 	 * exceeded dircount then go back and get some more.
3790 	 */
3791 	if (!iseof &&
3792 	    (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3793 		space_left -= (prev_len - uio.uio_resid);
3794 		if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3795 			goto getmoredents;
3796 
3797 		/* else, fall through */
3798 	}
3799 
3800 good:
3801 
3802 #ifdef DEBUG
3803 	if (rfs3_do_post_op_attr) {
3804 		va.va_mask = AT_ALL;
3805 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3806 	} else
3807 		vap = NULL;
3808 #else
3809 	va.va_mask = AT_ALL;
3810 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3811 #endif
3812 
3813 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3814 
3815 	infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3816 	resp->resok.infop = infop;
3817 
3818 	dp = (struct dirent64 *)data;
3819 	for (i = 0; i < nents; i++) {
3820 
3821 		if (dp->d_ino == 0) {
3822 			infop[i].attr.attributes = FALSE;
3823 			infop[i].fh.handle_follows = FALSE;
3824 			dp = nextdp(dp);
3825 			continue;
3826 		}
3827 
3828 		infop[i].namelen = namlen[i];
3829 
3830 		error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3831 		    NULL, NULL, NULL);
3832 		if (error) {
3833 			infop[i].attr.attributes = FALSE;
3834 			infop[i].fh.handle_follows = FALSE;
3835 			dp = nextdp(dp);
3836 			continue;
3837 		}
3838 
3839 #ifdef DEBUG
3840 		if (rfs3_do_post_op_attr) {
3841 			nva.va_mask = AT_ALL;
3842 			nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ?
3843 			    NULL : &nva;
3844 		} else
3845 			nvap = NULL;
3846 #else
3847 		nva.va_mask = AT_ALL;
3848 		nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3849 #endif
3850 		vattr_to_post_op_attr(nvap, &infop[i].attr);
3851 
3852 #ifdef DEBUG
3853 		if (!rfs3_do_post_op_fh3)
3854 			infop[i].fh.handle_follows = FALSE;
3855 		else {
3856 #endif
3857 		error = makefh3(&infop[i].fh.handle, nvp, exi);
3858 		if (!error)
3859 			infop[i].fh.handle_follows = TRUE;
3860 		else
3861 			infop[i].fh.handle_follows = FALSE;
3862 #ifdef DEBUG
3863 		}
3864 #endif
3865 
3866 		VN_RELE(nvp);
3867 		dp = nextdp(dp);
3868 	}
3869 
3870 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3871 	ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3872 	if (ndata == NULL)
3873 		ndata = data;
3874 
3875 	if (ret > 0) {
3876 		/*
3877 		 * We had to drop one or more entries in order to fit
3878 		 * during the character conversion.  We need to patch
3879 		 * up the size and eof info.
3880 		 */
3881 		if (iseof)
3882 			iseof = FALSE;
3883 
3884 		ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3885 		    nents, ret);
3886 	}
3887 
3888 
3889 #if 0 /* notyet */
3890 	/*
3891 	 * Don't do this.  It causes local disk writes when just
3892 	 * reading the file and the overhead is deemed larger
3893 	 * than the benefit.
3894 	 */
3895 	/*
3896 	 * Force modified metadata out to stable storage.
3897 	 */
3898 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3899 #endif
3900 
3901 	kmem_free(namlen, args->dircount);
3902 
3903 	resp->status = NFS3_OK;
3904 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3905 	resp->resok.cookieverf = 0;
3906 	resp->resok.reply.entries = (entryplus3 *)ndata;
3907 	resp->resok.reply.eof = iseof;
3908 	resp->resok.size = nents;
3909 	resp->resok.count = args->dircount - ret;
3910 	resp->resok.maxcount = args->maxcount;
3911 
3912 	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3913 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3914 	if (ndata != data)
3915 		kmem_free(data, args->dircount);
3916 
3917 
3918 	VN_RELE(vp);
3919 
3920 	return;
3921 
3922 out:
3923 	if (curthread->t_flag & T_WOULDBLOCK) {
3924 		curthread->t_flag &= ~T_WOULDBLOCK;
3925 		resp->status = NFS3ERR_JUKEBOX;
3926 	} else {
3927 		resp->status = puterrno3(error);
3928 	}
3929 out1:
3930 	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3931 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3932 
3933 	if (vp != NULL) {
3934 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3935 		VN_RELE(vp);
3936 	}
3937 
3938 	if (namlen != NULL)
3939 		kmem_free(namlen, args->dircount);
3940 
3941 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3942 }
3943 
3944 void *
3945 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3946 {
3947 
3948 	return (&args->dir);
3949 }
3950 
3951 void
3952 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3953 {
3954 
3955 	if (resp->status == NFS3_OK) {
3956 		kmem_free(resp->resok.reply.entries, resp->resok.count);
3957 		kmem_free(resp->resok.infop,
3958 		    resp->resok.size * sizeof (struct entryplus3_info));
3959 	}
3960 }
3961 
3962 /* ARGSUSED */
3963 void
3964 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3965 	struct svc_req *req, cred_t *cr)
3966 {
3967 	int error;
3968 	vnode_t *vp;
3969 	struct vattr *vap;
3970 	struct vattr va;
3971 	struct statvfs64 sb;
3972 
3973 	vap = NULL;
3974 
3975 	vp = nfs3_fhtovp(&args->fsroot, exi);
3976 
3977 	DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
3978 	    cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
3979 
3980 	if (vp == NULL) {
3981 		error = ESTALE;
3982 		goto out;
3983 	}
3984 
3985 	if (is_system_labeled()) {
3986 		bslabel_t *clabel = req->rq_label;
3987 
3988 		ASSERT(clabel != NULL);
3989 		DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3990 		    "got client label from request(1)", struct svc_req *, req);
3991 
3992 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3993 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
3994 				resp->status = NFS3ERR_ACCES;
3995 				goto out1;
3996 			}
3997 		}
3998 	}
3999 
4000 	error = VFS_STATVFS(vp->v_vfsp, &sb);
4001 
4002 #ifdef DEBUG
4003 	if (rfs3_do_post_op_attr) {
4004 		va.va_mask = AT_ALL;
4005 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4006 	} else
4007 		vap = NULL;
4008 #else
4009 	va.va_mask = AT_ALL;
4010 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4011 #endif
4012 
4013 	if (error)
4014 		goto out;
4015 
4016 	resp->status = NFS3_OK;
4017 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4018 	if (sb.f_blocks != (fsblkcnt64_t)-1)
4019 		resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
4020 	else
4021 		resp->resok.tbytes = (size3)sb.f_blocks;
4022 	if (sb.f_bfree != (fsblkcnt64_t)-1)
4023 		resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
4024 	else
4025 		resp->resok.fbytes = (size3)sb.f_bfree;
4026 	if (sb.f_bavail != (fsblkcnt64_t)-1)
4027 		resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
4028 	else
4029 		resp->resok.abytes = (size3)sb.f_bavail;
4030 	resp->resok.tfiles = (size3)sb.f_files;
4031 	resp->resok.ffiles = (size3)sb.f_ffree;
4032 	resp->resok.afiles = (size3)sb.f_favail;
4033 	resp->resok.invarsec = 0;
4034 
4035 	DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
4036 	    cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
4037 	VN_RELE(vp);
4038 
4039 	return;
4040 
4041 out:
4042 	if (curthread->t_flag & T_WOULDBLOCK) {
4043 		curthread->t_flag &= ~T_WOULDBLOCK;
4044 		resp->status = NFS3ERR_JUKEBOX;
4045 	} else
4046 		resp->status = puterrno3(error);
4047 out1:
4048 	DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
4049 	    cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
4050 
4051 	if (vp != NULL)
4052 		VN_RELE(vp);
4053 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4054 }
4055 
4056 void *
4057 rfs3_fsstat_getfh(FSSTAT3args *args)
4058 {
4059 
4060 	return (&args->fsroot);
4061 }
4062 
4063 /* ARGSUSED */
4064 void
4065 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
4066 	struct svc_req *req, cred_t *cr)
4067 {
4068 	vnode_t *vp;
4069 	struct vattr *vap;
4070 	struct vattr va;
4071 	uint32_t xfer_size;
4072 	ulong_t l = 0;
4073 	int error;
4074 
4075 	vp = nfs3_fhtovp(&args->fsroot, exi);
4076 
4077 	DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
4078 	    cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
4079 
4080 	if (vp == NULL) {
4081 		if (curthread->t_flag & T_WOULDBLOCK) {
4082 			curthread->t_flag &= ~T_WOULDBLOCK;
4083 			resp->status = NFS3ERR_JUKEBOX;
4084 		} else
4085 			resp->status = NFS3ERR_STALE;
4086 		vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
4087 		goto out;
4088 	}
4089 
4090 	if (is_system_labeled()) {
4091 		bslabel_t *clabel = req->rq_label;
4092 
4093 		ASSERT(clabel != NULL);
4094 		DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
4095 		    "got client label from request(1)", struct svc_req *, req);
4096 
4097 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
4098 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
4099 				resp->status = NFS3ERR_STALE;
4100 				vattr_to_post_op_attr(NULL,
4101 				    &resp->resfail.obj_attributes);
4102 				goto out;
4103 			}
4104 		}
4105 	}
4106 
4107 #ifdef DEBUG
4108 	if (rfs3_do_post_op_attr) {
4109 		va.va_mask = AT_ALL;
4110 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4111 	} else
4112 		vap = NULL;
4113 #else
4114 	va.va_mask = AT_ALL;
4115 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4116 #endif
4117 
4118 	resp->status = NFS3_OK;
4119 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4120 	xfer_size = rfs3_tsize(req);
4121 	resp->resok.rtmax = xfer_size;
4122 	resp->resok.rtpref = xfer_size;
4123 	resp->resok.rtmult = DEV_BSIZE;
4124 	resp->resok.wtmax = xfer_size;
4125 	resp->resok.wtpref = xfer_size;
4126 	resp->resok.wtmult = DEV_BSIZE;
4127 	resp->resok.dtpref = MAXBSIZE;
4128 
4129 	/*
4130 	 * Large file spec: want maxfilesize based on limit of
4131 	 * underlying filesystem.  We can guess 2^31-1 if need be.
4132 	 */
4133 	error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
4134 
4135 	if (!error && l != 0 && l <= 64)
4136 		resp->resok.maxfilesize = (1LL << (l-1)) - 1;
4137 	else
4138 		resp->resok.maxfilesize = MAXOFF32_T;
4139 
4140 	resp->resok.time_delta.seconds = 0;
4141 	resp->resok.time_delta.nseconds = 1000;
4142 	resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
4143 	    FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
4144 
4145 	DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
4146 	    cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
4147 
4148 	VN_RELE(vp);
4149 
4150 	return;
4151 
4152 out:
4153 	DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
4154 	    cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
4155 	if (vp != NULL)
4156 		VN_RELE(vp);
4157 }
4158 
4159 void *
4160 rfs3_fsinfo_getfh(FSINFO3args *args)
4161 {
4162 
4163 	return (&args->fsroot);
4164 }
4165 
4166 /* ARGSUSED */
4167 void
4168 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
4169 	struct svc_req *req, cred_t *cr)
4170 {
4171 	int error;
4172 	vnode_t *vp;
4173 	struct vattr *vap;
4174 	struct vattr va;
4175 	ulong_t val;
4176 
4177 	vap = NULL;
4178 
4179 	vp = nfs3_fhtovp(&args->object, exi);
4180 
4181 	DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
4182 	    cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
4183 
4184 	if (vp == NULL) {
4185 		error = ESTALE;
4186 		goto out;
4187 	}
4188 
4189 	if (is_system_labeled()) {
4190 		bslabel_t *clabel = req->rq_label;
4191 
4192 		ASSERT(clabel != NULL);
4193 		DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
4194 		    "got client label from request(1)", struct svc_req *, req);
4195 
4196 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
4197 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
4198 				resp->status = NFS3ERR_ACCES;
4199 				goto out1;
4200 			}
4201 		}
4202 	}
4203 
4204 #ifdef DEBUG
4205 	if (rfs3_do_post_op_attr) {
4206 		va.va_mask = AT_ALL;
4207 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4208 	} else
4209 		vap = NULL;
4210 #else
4211 	va.va_mask = AT_ALL;
4212 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4213 #endif
4214 
4215 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
4216 	if (error)
4217 		goto out;
4218 	resp->resok.info.link_max = (uint32)val;
4219 
4220 	error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
4221 	if (error)
4222 		goto out;
4223 	resp->resok.info.name_max = (uint32)val;
4224 
4225 	error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
4226 	if (error)
4227 		goto out;
4228 	if (val == 1)
4229 		resp->resok.info.no_trunc = TRUE;
4230 	else
4231 		resp->resok.info.no_trunc = FALSE;
4232 
4233 	error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
4234 	if (error)
4235 		goto out;
4236 	if (val == 1)
4237 		resp->resok.info.chown_restricted = TRUE;
4238 	else
4239 		resp->resok.info.chown_restricted = FALSE;
4240 
4241 	resp->status = NFS3_OK;
4242 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4243 	resp->resok.info.case_insensitive = FALSE;
4244 	resp->resok.info.case_preserving = TRUE;
4245 	DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4246 	    cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4247 	VN_RELE(vp);
4248 	return;
4249 
4250 out:
4251 	if (curthread->t_flag & T_WOULDBLOCK) {
4252 		curthread->t_flag &= ~T_WOULDBLOCK;
4253 		resp->status = NFS3ERR_JUKEBOX;
4254 	} else
4255 		resp->status = puterrno3(error);
4256 out1:
4257 	DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4258 	    cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4259 	if (vp != NULL)
4260 		VN_RELE(vp);
4261 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4262 }
4263 
4264 void *
4265 rfs3_pathconf_getfh(PATHCONF3args *args)
4266 {
4267 
4268 	return (&args->object);
4269 }
4270 
4271 void
4272 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4273 	struct svc_req *req, cred_t *cr)
4274 {
4275 	int error;
4276 	vnode_t *vp;
4277 	struct vattr *bvap;
4278 	struct vattr bva;
4279 	struct vattr *avap;
4280 	struct vattr ava;
4281 
4282 	bvap = NULL;
4283 	avap = NULL;
4284 
4285 	vp = nfs3_fhtovp(&args->file, exi);
4286 
4287 	DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4288 	    cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
4289 
4290 	if (vp == NULL) {
4291 		error = ESTALE;
4292 		goto out;
4293 	}
4294 
4295 	bva.va_mask = AT_ALL;
4296 	error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4297 
4298 	/*
4299 	 * If we can't get the attributes, then we can't do the
4300 	 * right access checking.  So, we'll fail the request.
4301 	 */
4302 	if (error)
4303 		goto out;
4304 
4305 #ifdef DEBUG
4306 	if (rfs3_do_pre_op_attr)
4307 		bvap = &bva;
4308 	else
4309 		bvap = NULL;
4310 #else
4311 	bvap = &bva;
4312 #endif
4313 
4314 	if (rdonly(exi, req)) {
4315 		resp->status = NFS3ERR_ROFS;
4316 		goto out1;
4317 	}
4318 
4319 	if (vp->v_type != VREG) {
4320 		resp->status = NFS3ERR_INVAL;
4321 		goto out1;
4322 	}
4323 
4324 	if (is_system_labeled()) {
4325 		bslabel_t *clabel = req->rq_label;
4326 
4327 		ASSERT(clabel != NULL);
4328 		DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
4329 		    "got client label from request(1)", struct svc_req *, req);
4330 
4331 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
4332 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
4333 				resp->status = NFS3ERR_ACCES;
4334 				goto out1;
4335 			}
4336 		}
4337 	}
4338 
4339 	if (crgetuid(cr) != bva.va_uid &&
4340 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4341 		goto out;
4342 
4343 	error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, NULL);
4344 	if (!error)
4345 		error = VOP_FSYNC(vp, FNODSYNC, cr, NULL);
4346 
4347 #ifdef DEBUG
4348 	if (rfs3_do_post_op_attr) {
4349 		ava.va_mask = AT_ALL;
4350 		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4351 	} else
4352 		avap = NULL;
4353 #else
4354 	ava.va_mask = AT_ALL;
4355 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4356 #endif
4357 
4358 	if (error)
4359 		goto out;
4360 
4361 	resp->status = NFS3_OK;
4362 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4363 	resp->resok.verf = write3verf;
4364 
4365 	DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4366 	    cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4367 
4368 	VN_RELE(vp);
4369 
4370 	return;
4371 
4372 out:
4373 	if (curthread->t_flag & T_WOULDBLOCK) {
4374 		curthread->t_flag &= ~T_WOULDBLOCK;
4375 		resp->status = NFS3ERR_JUKEBOX;
4376 	} else
4377 		resp->status = puterrno3(error);
4378 out1:
4379 	DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4380 	    cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4381 
4382 	if (vp != NULL)
4383 		VN_RELE(vp);
4384 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4385 }
4386 
4387 void *
4388 rfs3_commit_getfh(COMMIT3args *args)
4389 {
4390 
4391 	return (&args->file);
4392 }
4393 
4394 static int
4395 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4396 {
4397 
4398 	vap->va_mask = 0;
4399 
4400 	if (sap->mode.set_it) {
4401 		vap->va_mode = (mode_t)sap->mode.mode;
4402 		vap->va_mask |= AT_MODE;
4403 	}
4404 	if (sap->uid.set_it) {
4405 		vap->va_uid = (uid_t)sap->uid.uid;
4406 		vap->va_mask |= AT_UID;
4407 	}
4408 	if (sap->gid.set_it) {
4409 		vap->va_gid = (gid_t)sap->gid.gid;
4410 		vap->va_mask |= AT_GID;
4411 	}
4412 	if (sap->size.set_it) {
4413 		if (sap->size.size > (size3)((u_longlong_t)-1))
4414 			return (EINVAL);
4415 		vap->va_size = sap->size.size;
4416 		vap->va_mask |= AT_SIZE;
4417 	}
4418 	if (sap->atime.set_it == SET_TO_CLIENT_TIME) {
4419 #ifndef _LP64
4420 		/* check time validity */
4421 		if (!NFS3_TIME_OK(sap->atime.atime.seconds))
4422 			return (EOVERFLOW);
4423 #endif
4424 		/*
4425 		 * nfs protocol defines times as unsigned so don't extend sign,
4426 		 * unless sysadmin set nfs_allow_preepoch_time.
4427 		 */
4428 		NFS_TIME_T_CONVERT(vap->va_atime.tv_sec,
4429 		    sap->atime.atime.seconds);
4430 		vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds;
4431 		vap->va_mask |= AT_ATIME;
4432 	} else if (sap->atime.set_it == SET_TO_SERVER_TIME) {
4433 		gethrestime(&vap->va_atime);
4434 		vap->va_mask |= AT_ATIME;
4435 	}
4436 	if (sap->mtime.set_it == SET_TO_CLIENT_TIME) {
4437 #ifndef _LP64
4438 		/* check time validity */
4439 		if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4440 			return (EOVERFLOW);
4441 #endif
4442 		/*
4443 		 * nfs protocol defines times as unsigned so don't extend sign,
4444 		 * unless sysadmin set nfs_allow_preepoch_time.
4445 		 */
4446 		NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4447 		    sap->mtime.mtime.seconds);
4448 		vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4449 		vap->va_mask |= AT_MTIME;
4450 	} else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4451 		gethrestime(&vap->va_mtime);
4452 		vap->va_mask |= AT_MTIME;
4453 	}
4454 
4455 	return (0);
4456 }
4457 
4458 static ftype3 vt_to_nf3[] = {
4459 	0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4460 };
4461 
4462 static int
4463 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4464 {
4465 
4466 	ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4467 	/* Return error if time or size overflow */
4468 	if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4469 		return (EOVERFLOW);
4470 	}
4471 	fap->type = vt_to_nf3[vap->va_type];
4472 	fap->mode = (mode3)(vap->va_mode & MODEMASK);
4473 	fap->nlink = (uint32)vap->va_nlink;
4474 	if (vap->va_uid == UID_NOBODY)
4475 		fap->uid = (uid3)NFS_UID_NOBODY;
4476 	else
4477 		fap->uid = (uid3)vap->va_uid;
4478 	if (vap->va_gid == GID_NOBODY)
4479 		fap->gid = (gid3)NFS_GID_NOBODY;
4480 	else
4481 		fap->gid = (gid3)vap->va_gid;
4482 	fap->size = (size3)vap->va_size;
4483 	fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks;
4484 	fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev);
4485 	fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev);
4486 	fap->fsid = (uint64)vap->va_fsid;
4487 	fap->fileid = (fileid3)vap->va_nodeid;
4488 	fap->atime.seconds = vap->va_atime.tv_sec;
4489 	fap->atime.nseconds = vap->va_atime.tv_nsec;
4490 	fap->mtime.seconds = vap->va_mtime.tv_sec;
4491 	fap->mtime.nseconds = vap->va_mtime.tv_nsec;
4492 	fap->ctime.seconds = vap->va_ctime.tv_sec;
4493 	fap->ctime.nseconds = vap->va_ctime.tv_nsec;
4494 	return (0);
4495 }
4496 
4497 static int
4498 vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap)
4499 {
4500 
4501 	/* Return error if time or size overflow */
4502 	if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) &&
4503 	    NFS_TIME_T_OK(vap->va_ctime.tv_sec) &&
4504 	    NFS3_SIZE_OK(vap->va_size))) {
4505 		return (EOVERFLOW);
4506 	}
4507 	wccap->size = (size3)vap->va_size;
4508 	wccap->mtime.seconds = vap->va_mtime.tv_sec;
4509 	wccap->mtime.nseconds = vap->va_mtime.tv_nsec;
4510 	wccap->ctime.seconds = vap->va_ctime.tv_sec;
4511 	wccap->ctime.nseconds = vap->va_ctime.tv_nsec;
4512 	return (0);
4513 }
4514 
4515 static void
4516 vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap)
4517 {
4518 
4519 	/* don't return attrs if time overflow */
4520 	if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4521 		poap->attributes = TRUE;
4522 	} else
4523 		poap->attributes = FALSE;
4524 }
4525 
4526 void
4527 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4528 {
4529 
4530 	/* don't return attrs if time overflow */
4531 	if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4532 		poap->attributes = TRUE;
4533 	} else
4534 		poap->attributes = FALSE;
4535 }
4536 
4537 static void
4538 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4539 {
4540 
4541 	vattr_to_pre_op_attr(bvap, &wccp->before);
4542 	vattr_to_post_op_attr(avap, &wccp->after);
4543 }
4544 
4545 void
4546 rfs3_srvrinit(void)
4547 {
4548 	struct rfs3_verf_overlay {
4549 		uint_t id; /* a "unique" identifier */
4550 		int ts; /* a unique timestamp */
4551 	} *verfp;
4552 	timestruc_t now;
4553 
4554 	/*
4555 	 * The following algorithm attempts to find a unique verifier
4556 	 * to be used as the write verifier returned from the server
4557 	 * to the client.  It is important that this verifier change
4558 	 * whenever the server reboots.  Of secondary importance, it
4559 	 * is important for the verifier to be unique between two
4560 	 * different servers.
4561 	 *
4562 	 * Thus, an attempt is made to use the system hostid and the
4563 	 * current time in seconds when the nfssrv kernel module is
4564 	 * loaded.  It is assumed that an NFS server will not be able
4565 	 * to boot and then to reboot in less than a second.  If the
4566 	 * hostid has not been set, then the current high resolution
4567 	 * time is used.  This will ensure different verifiers each
4568 	 * time the server reboots and minimize the chances that two
4569 	 * different servers will have the same verifier.
4570 	 */
4571 
4572 #ifndef	lint
4573 	/*
4574 	 * We ASSERT that this constant logic expression is
4575 	 * always true because in the past, it wasn't.
4576 	 */
4577 	ASSERT(sizeof (*verfp) <= sizeof (write3verf));
4578 #endif
4579 
4580 	gethrestime(&now);
4581 	verfp = (struct rfs3_verf_overlay *)&write3verf;
4582 	verfp->ts = (int)now.tv_sec;
4583 	verfp->id = zone_get_hostid(NULL);
4584 
4585 	if (verfp->id == 0)
4586 		verfp->id = (uint_t)now.tv_nsec;
4587 
4588 	nfs3_srv_caller_id = fs_new_caller_id();
4589 
4590 }
4591 
4592 static int
4593 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4594 {
4595 	struct clist	*wcl;
4596 	int		wlist_len;
4597 	count3		count = rok->count;
4598 
4599 	wcl = args->wlist;
4600 	if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
4601 		return (FALSE);
4602 	}
4603 
4604 	wcl = args->wlist;
4605 	rok->wlist_len = wlist_len;
4606 	rok->wlist = wcl;
4607 	return (TRUE);
4608 }
4609 
4610 void
4611 rfs3_srvrfini(void)
4612 {
4613 	/* Nothing to do */
4614 }
4615