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