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