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