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