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