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