xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs3_srv.c (revision dfdcac05)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
527242a7cSthurlow  * Common Development and Distribution License (the "License").
627242a7cSthurlow  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21f46abf18SMarcel Telka 
227c478bd9Sstevel@tonic-gate /*
230dfe541eSEvan Layton  * Copyright 2018 Nexenta Systems, Inc.
2435bbd688SKaren Rochford  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
25e36d7b11SSebastien Roy  * Copyright (c) 2013 by Delphix. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
297c478bd9Sstevel@tonic-gate /* All Rights Reserved */
307c478bd9Sstevel@tonic-gate 
310dfe541eSEvan Layton 
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/systm.h>
357c478bd9Sstevel@tonic-gate #include <sys/cred.h>
367c478bd9Sstevel@tonic-gate #include <sys/buf.h>
377c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
387c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
397c478bd9Sstevel@tonic-gate #include <sys/uio.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
437c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
447c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
457c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
467c478bd9Sstevel@tonic-gate #include <sys/debug.h>
477c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
487c478bd9Sstevel@tonic-gate #include <sys/flock.h>
497c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h>
507c478bd9Sstevel@tonic-gate #include <sys/policy.h>
5103986916Sjarrett #include <sys/sdt.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include <rpc/types.h>
547c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
557c478bd9Sstevel@tonic-gate #include <rpc/svc.h>
560a701b1eSRobert Gordon #include <rpc/rpc_rdma.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
597c478bd9Sstevel@tonic-gate #include <nfs/export.h>
60b89a8333Snatalie li - Sun Microsystems - Irvine United States #include <nfs/nfs_cmd.h>
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
6303986916Sjarrett #include <sys/tsol/label.h>
6403986916Sjarrett #include <sys/tsol/tndb.h>
6503986916Sjarrett 
665679c89fSjv #include <sys/zone.h>
675679c89fSjv 
6803986916Sjarrett #include <inet/ip.h>
6903986916Sjarrett #include <inet/ip6.h>
7003986916Sjarrett 
710dfe541eSEvan Layton /*
720dfe541eSEvan Layton  * Zone global variables of NFSv3 server
730dfe541eSEvan Layton  */
740dfe541eSEvan Layton typedef struct nfs3_srv {
750dfe541eSEvan Layton 	writeverf3	write3verf;
760dfe541eSEvan Layton } nfs3_srv_t;
770dfe541eSEvan Layton 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * These are the interface routines for the server side of the
807c478bd9Sstevel@tonic-gate  * Network File System.  See the NFS version 3 protocol specification
817c478bd9Sstevel@tonic-gate  * for a description of this interface.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate static int	sattr3_to_vattr(sattr3 *, struct vattr *);
857c478bd9Sstevel@tonic-gate static int	vattr_to_fattr3(struct vattr *, fattr3 *);
867c478bd9Sstevel@tonic-gate static int	vattr_to_wcc_attr(struct vattr *, wcc_attr *);
877c478bd9Sstevel@tonic-gate static void	vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
887c478bd9Sstevel@tonic-gate static void	vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
890a701b1eSRobert Gordon static int	rdma_setup_read_data3(READ3args *, READ3resok *);
907c478bd9Sstevel@tonic-gate 
91c242f9a0Schunli zhang - Sun Microsystems - Irvine United States extern int nfs_loaned_buffers;
92c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
93cfae96c2Sjwahlig u_longlong_t nfs3_srv_caller_id;
94cfae96c2Sjwahlig 
950dfe541eSEvan Layton static nfs3_srv_t *
nfs3_get_srv(void)960dfe541eSEvan Layton nfs3_get_srv(void)
970dfe541eSEvan Layton {
980dfe541eSEvan Layton 	nfs_globals_t *ng = nfs_srv_getzg();
990dfe541eSEvan Layton 	nfs3_srv_t *srv = ng->nfs3_srv;
1000dfe541eSEvan Layton 	ASSERT(srv != NULL);
1010dfe541eSEvan Layton 	return (srv);
1020dfe541eSEvan Layton }
1030dfe541eSEvan Layton 
1047c478bd9Sstevel@tonic-gate /* ARGSUSED */
1057c478bd9Sstevel@tonic-gate void
rfs3_getattr(GETATTR3args * args,GETATTR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)1067c478bd9Sstevel@tonic-gate rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
1075cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	int error;
1107c478bd9Sstevel@tonic-gate 	vnode_t *vp;
1117c478bd9Sstevel@tonic-gate 	struct vattr va;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
114e1adf50cSahl 
1150dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req,
1160dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1170dfe541eSEvan Layton 	    GETATTR3args *, args);
118e1adf50cSahl 
1197c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
1207c478bd9Sstevel@tonic-gate 		error = ESTALE;
1217c478bd9Sstevel@tonic-gate 		goto out;
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1257c478bd9Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &va, 0, cr);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	if (!error) {
1282f172c55SRobert Thurlow 		/* Lie about the object type for a referral */
1292f172c55SRobert Thurlow 		if (vn_is_nfs_reparse(vp, cr))
1302f172c55SRobert Thurlow 			va.va_type = VLNK;
1312f172c55SRobert Thurlow 
1327c478bd9Sstevel@tonic-gate 		/* overflow error if time or size is out of range */
1337c478bd9Sstevel@tonic-gate 		error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
1347c478bd9Sstevel@tonic-gate 		if (error)
1357c478bd9Sstevel@tonic-gate 			goto out;
1367c478bd9Sstevel@tonic-gate 		resp->status = NFS3_OK;
137e1adf50cSahl 
1380dfe541eSEvan Layton 		DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
1390dfe541eSEvan Layton 		    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1400dfe541eSEvan Layton 		    GETATTR3res *, resp);
141e1adf50cSahl 
142e1adf50cSahl 		VN_RELE(vp);
143e1adf50cSahl 
1447c478bd9Sstevel@tonic-gate 		return;
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate out:
1487c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
1497c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
1507c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
1517c478bd9Sstevel@tonic-gate 	} else
1527c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
153e1adf50cSahl 
1540dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
1550dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1560dfe541eSEvan Layton 	    GETATTR3res *, resp);
157e1adf50cSahl 
158e1adf50cSahl 	if (vp != NULL)
159e1adf50cSahl 		VN_RELE(vp);
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate 
16227242a7cSthurlow void *
rfs3_getattr_getfh(GETATTR3args * args)1637c478bd9Sstevel@tonic-gate rfs3_getattr_getfh(GETATTR3args *args)
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 
16627242a7cSthurlow 	return (&args->object);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate void
rfs3_setattr(SETATTR3args * args,SETATTR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)1707c478bd9Sstevel@tonic-gate rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
1715cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	int error;
1747c478bd9Sstevel@tonic-gate 	vnode_t *vp;
1757c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
1767c478bd9Sstevel@tonic-gate 	struct vattr bva;
1777c478bd9Sstevel@tonic-gate 	struct vattr *avap;
1787c478bd9Sstevel@tonic-gate 	struct vattr ava;
1797c478bd9Sstevel@tonic-gate 	int flag;
1807c478bd9Sstevel@tonic-gate 	int in_crit = 0;
1817c478bd9Sstevel@tonic-gate 	struct flock64 bf;
182cfae96c2Sjwahlig 	caller_context_t ct;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	bvap = NULL;
1857c478bd9Sstevel@tonic-gate 	avap = NULL;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
188e1adf50cSahl 
1890dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req,
1900dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1910dfe541eSEvan Layton 	    SETATTR3args *, args);
192e1adf50cSahl 
1937c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
1947c478bd9Sstevel@tonic-gate 		error = ESTALE;
1957c478bd9Sstevel@tonic-gate 		goto out;
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	error = sattr3_to_vattr(&args->new_attributes, &ava);
1997c478bd9Sstevel@tonic-gate 	if (error)
2007c478bd9Sstevel@tonic-gate 		goto out;
2017c478bd9Sstevel@tonic-gate 
20203986916Sjarrett 	if (is_system_labeled()) {
20303986916Sjarrett 		bslabel_t *clabel = req->rq_label;
20403986916Sjarrett 
20503986916Sjarrett 		ASSERT(clabel != NULL);
20603986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
20703986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
20803986916Sjarrett 
20903986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
210bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
211bd6f1640SJarrett Lu 			    exi)) {
21203986916Sjarrett 				resp->status = NFS3ERR_ACCES;
21303986916Sjarrett 				goto out1;
21403986916Sjarrett 			}
21503986916Sjarrett 		}
21603986916Sjarrett 	}
21703986916Sjarrett 
2187c478bd9Sstevel@tonic-gate 	/*
2197c478bd9Sstevel@tonic-gate 	 * We need to specially handle size changes because of
2207c478bd9Sstevel@tonic-gate 	 * possible conflicting NBMAND locks. Get into critical
2217c478bd9Sstevel@tonic-gate 	 * region before VOP_GETATTR, so the size attribute is
2227c478bd9Sstevel@tonic-gate 	 * valid when checking conflicts.
2237c478bd9Sstevel@tonic-gate 	 *
2247c478bd9Sstevel@tonic-gate 	 * Also, check to see if the v4 side of the server has
2257c478bd9Sstevel@tonic-gate 	 * delegated this file.  If so, then we return JUKEBOX to
2267c478bd9Sstevel@tonic-gate 	 * allow the client to retrasmit its request.
2277c478bd9Sstevel@tonic-gate 	 */
2287c478bd9Sstevel@tonic-gate 	if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
2297c478bd9Sstevel@tonic-gate 		if (nbl_need_check(vp)) {
2307c478bd9Sstevel@tonic-gate 			nbl_start_crit(vp, RW_READER);
2317c478bd9Sstevel@tonic-gate 			in_crit = 1;
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
2367c478bd9Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &bva, 0, cr);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	/*
2397c478bd9Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
2407c478bd9Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
2417c478bd9Sstevel@tonic-gate 	 */
2427c478bd9Sstevel@tonic-gate 	if (error)
2437c478bd9Sstevel@tonic-gate 		goto out;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	bvap = &bva;
2467c478bd9Sstevel@tonic-gate 
2475cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
2487c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2497c478bd9Sstevel@tonic-gate 		goto out1;
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if (args->guard.check &&
2537c478bd9Sstevel@tonic-gate 	    (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
2547c478bd9Sstevel@tonic-gate 	    args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
2557c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOT_SYNC;
2567c478bd9Sstevel@tonic-gate 		goto out1;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
2607c478bd9Sstevel@tonic-gate 		flag = ATTR_UTIME;
2617c478bd9Sstevel@tonic-gate 	else
2627c478bd9Sstevel@tonic-gate 		flag = 0;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	/*
2657c478bd9Sstevel@tonic-gate 	 * If the filesystem is exported with nosuid, then mask off
2667c478bd9Sstevel@tonic-gate 	 * the setuid and setgid bits.
2677c478bd9Sstevel@tonic-gate 	 */
2687c478bd9Sstevel@tonic-gate 	if ((ava.va_mask & AT_MODE) && vp->v_type == VREG &&
2697c478bd9Sstevel@tonic-gate 	    (exi->exi_export.ex_flags & EX_NOSUID))
2707c478bd9Sstevel@tonic-gate 		ava.va_mode &= ~(VSUID | VSGID);
2717c478bd9Sstevel@tonic-gate 
272cfae96c2Sjwahlig 	ct.cc_sysid = 0;
273cfae96c2Sjwahlig 	ct.cc_pid = 0;
274cfae96c2Sjwahlig 	ct.cc_caller_id = nfs3_srv_caller_id;
275cfae96c2Sjwahlig 	ct.cc_flags = CC_DONTBLOCK;
276cfae96c2Sjwahlig 
2777c478bd9Sstevel@tonic-gate 	/*
2787c478bd9Sstevel@tonic-gate 	 * We need to specially handle size changes because it is
2797c478bd9Sstevel@tonic-gate 	 * possible for the client to create a file with modes
2807c478bd9Sstevel@tonic-gate 	 * which indicate read-only, but with the file opened for
2817c478bd9Sstevel@tonic-gate 	 * writing.  If the client then tries to set the size of
2827c478bd9Sstevel@tonic-gate 	 * the file, then the normal access checking done in
2837c478bd9Sstevel@tonic-gate 	 * VOP_SETATTR would prevent the client from doing so,
2847c478bd9Sstevel@tonic-gate 	 * although it should be legal for it to do so.  To get
2857c478bd9Sstevel@tonic-gate 	 * around this, we do the access checking for ourselves
2867c478bd9Sstevel@tonic-gate 	 * and then use VOP_SPACE which doesn't do the access
2877c478bd9Sstevel@tonic-gate 	 * checking which VOP_SETATTR does. VOP_SPACE can only
2887c478bd9Sstevel@tonic-gate 	 * operate on VREG files, let VOP_SETATTR handle the other
2897c478bd9Sstevel@tonic-gate 	 * extremely rare cases.
2907c478bd9Sstevel@tonic-gate 	 * Also the client should not be allowed to change the
2917c478bd9Sstevel@tonic-gate 	 * size of the file if there is a conflicting non-blocking
2927c478bd9Sstevel@tonic-gate 	 * mandatory lock in the region the change.
2937c478bd9Sstevel@tonic-gate 	 */
2947c478bd9Sstevel@tonic-gate 	if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
2957c478bd9Sstevel@tonic-gate 		if (in_crit) {
2967c478bd9Sstevel@tonic-gate 			u_offset_t offset;
2977c478bd9Sstevel@tonic-gate 			ssize_t length;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 			if (ava.va_size < bva.va_size) {
3007c478bd9Sstevel@tonic-gate 				offset = ava.va_size;
3017c478bd9Sstevel@tonic-gate 				length = bva.va_size - ava.va_size;
3027c478bd9Sstevel@tonic-gate 			} else {
3037c478bd9Sstevel@tonic-gate 				offset = bva.va_size;
3047c478bd9Sstevel@tonic-gate 				length = ava.va_size - bva.va_size;
3057c478bd9Sstevel@tonic-gate 			}
306da6c28aaSamw 			if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
307da6c28aaSamw 			    NULL)) {
3087c478bd9Sstevel@tonic-gate 				error = EACCES;
3097c478bd9Sstevel@tonic-gate 				goto out;
3107c478bd9Sstevel@tonic-gate 			}
3117c478bd9Sstevel@tonic-gate 		}
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 		if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) {
3147c478bd9Sstevel@tonic-gate 			ava.va_mask &= ~AT_SIZE;
3157c478bd9Sstevel@tonic-gate 			bf.l_type = F_WRLCK;
3167c478bd9Sstevel@tonic-gate 			bf.l_whence = 0;
3177c478bd9Sstevel@tonic-gate 			bf.l_start = (off64_t)ava.va_size;
3187c478bd9Sstevel@tonic-gate 			bf.l_len = 0;
3197c478bd9Sstevel@tonic-gate 			bf.l_sysid = 0;
3207c478bd9Sstevel@tonic-gate 			bf.l_pid = 0;
3217c478bd9Sstevel@tonic-gate 			error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
322cfae96c2Sjwahlig 			    (offset_t)ava.va_size, cr, &ct);
3237c478bd9Sstevel@tonic-gate 		}
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	if (!error && ava.va_mask)
327cfae96c2Sjwahlig 		error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
328cfae96c2Sjwahlig 
329cfae96c2Sjwahlig 	/* check if a monitor detected a delegation conflict */
330cfae96c2Sjwahlig 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
331cfae96c2Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
332cfae96c2Sjwahlig 		goto out1;
333cfae96c2Sjwahlig 	}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
3367c478bd9Sstevel@tonic-gate 	avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	/*
3397c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
3407c478bd9Sstevel@tonic-gate 	 */
341cfae96c2Sjwahlig 	(void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	if (error)
3447c478bd9Sstevel@tonic-gate 		goto out;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	if (in_crit)
3477c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
3507c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
351e1adf50cSahl 
3520dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
3530dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3540dfe541eSEvan Layton 	    SETATTR3res *, resp);
355e1adf50cSahl 
356e1adf50cSahl 	VN_RELE(vp);
357e1adf50cSahl 
3587c478bd9Sstevel@tonic-gate 	return;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate out:
3617c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
3627c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
3637c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
3647c478bd9Sstevel@tonic-gate 	} else
3657c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
3667c478bd9Sstevel@tonic-gate out1:
3670dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
3680dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3690dfe541eSEvan Layton 	    SETATTR3res *, resp);
370e1adf50cSahl 
3717c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
3727c478bd9Sstevel@tonic-gate 		if (in_crit)
3737c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
3747c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate 
37927242a7cSthurlow void *
rfs3_setattr_getfh(SETATTR3args * args)3807c478bd9Sstevel@tonic-gate rfs3_setattr_getfh(SETATTR3args *args)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 
38327242a7cSthurlow 	return (&args->object);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate /* ARGSUSED */
3877c478bd9Sstevel@tonic-gate void
rfs3_lookup(LOOKUP3args * args,LOOKUP3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)3887c478bd9Sstevel@tonic-gate rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
3895cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	int error;
3927c478bd9Sstevel@tonic-gate 	vnode_t *vp;
3937c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
3947c478bd9Sstevel@tonic-gate 	struct vattr *vap;
3957c478bd9Sstevel@tonic-gate 	struct vattr va;
3967c478bd9Sstevel@tonic-gate 	struct vattr *dvap;
3977c478bd9Sstevel@tonic-gate 	struct vattr dva;
3987c478bd9Sstevel@tonic-gate 	nfs_fh3 *fhp;
3997c478bd9Sstevel@tonic-gate 	struct sec_ol sec = {0, 0};
4007c478bd9Sstevel@tonic-gate 	bool_t publicfh_flag = FALSE, auth_weak = FALSE;
401b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
402b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	dvap = NULL;
4057c478bd9Sstevel@tonic-gate 
406f7db5903SVitaliy Gusev 	if (exi != NULL)
407f7db5903SVitaliy Gusev 		exi_hold(exi);
408f7db5903SVitaliy Gusev 
4097c478bd9Sstevel@tonic-gate 	/*
4107c478bd9Sstevel@tonic-gate 	 * Allow lookups from the root - the default
4117c478bd9Sstevel@tonic-gate 	 * location of the public filehandle.
4127c478bd9Sstevel@tonic-gate 	 */
4137c478bd9Sstevel@tonic-gate 	if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
4140dfe541eSEvan Layton 		ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
4150dfe541eSEvan Layton 		dvp = ZONE_ROOTVP();
4167c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
417e1adf50cSahl 
4180dfe541eSEvan Layton 		DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
4190dfe541eSEvan Layton 		    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
4200dfe541eSEvan Layton 		    LOOKUP3args *, args);
4217c478bd9Sstevel@tonic-gate 	} else {
42227242a7cSthurlow 		dvp = nfs3_fhtovp(&args->what.dir, exi);
423e1adf50cSahl 
4240dfe541eSEvan Layton 		DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
4250dfe541eSEvan Layton 		    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
4260dfe541eSEvan Layton 		    LOOKUP3args *, args);
427e1adf50cSahl 
4287c478bd9Sstevel@tonic-gate 		if (dvp == NULL) {
4297c478bd9Sstevel@tonic-gate 			error = ESTALE;
4307c478bd9Sstevel@tonic-gate 			goto out;
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	dva.va_mask = AT_ALL;
435da6c28aaSamw 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (args->what.name == nfs3nametoolong) {
4387c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
4397c478bd9Sstevel@tonic-gate 		goto out1;
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	if (args->what.name == NULL || *(args->what.name) == '\0') {
4437c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
4447c478bd9Sstevel@tonic-gate 		goto out1;
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 
44727242a7cSthurlow 	fhp = &args->what.dir;
4480dfe541eSEvan Layton 	ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL */
4497c478bd9Sstevel@tonic-gate 	if (strcmp(args->what.name, "..") == 0 &&
45027242a7cSthurlow 	    EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
451f7db5903SVitaliy Gusev 		if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
4520dfe541eSEvan Layton 		    ((dvp->v_flag & VROOT) || VN_IS_CURZONEROOT(dvp))) {
453f7db5903SVitaliy Gusev 			/*
454f7db5903SVitaliy Gusev 			 * special case for ".." and 'nohide'exported root
455f7db5903SVitaliy Gusev 			 */
456f7db5903SVitaliy Gusev 			if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
457f7db5903SVitaliy Gusev 				resp->status = NFS3ERR_ACCES;
458f7db5903SVitaliy Gusev 				goto out1;
459f7db5903SVitaliy Gusev 			}
460f7db5903SVitaliy Gusev 		} else {
461f7db5903SVitaliy Gusev 			resp->status = NFS3ERR_NOENT;
462f7db5903SVitaliy Gusev 			goto out1;
463f7db5903SVitaliy Gusev 		}
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 
466b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
467b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->what.name,
468b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
469b89a8333Snatalie li - Sun Microsystems - Irvine United States 
470b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
471b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_ACCES;
472b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
473b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
474b89a8333Snatalie li - Sun Microsystems - Irvine United States 
4757c478bd9Sstevel@tonic-gate 	/*
4767c478bd9Sstevel@tonic-gate 	 * If the public filehandle is used then allow
4777c478bd9Sstevel@tonic-gate 	 * a multi-component lookup
4787c478bd9Sstevel@tonic-gate 	 */
47927242a7cSthurlow 	if (PUBLIC_FH3(&args->what.dir)) {
4807c478bd9Sstevel@tonic-gate 		publicfh_flag = TRUE;
481f7db5903SVitaliy Gusev 
482f7db5903SVitaliy Gusev 		exi_rele(exi);
4830dfe541eSEvan Layton 		exi = NULL;
484f7db5903SVitaliy Gusev 
485b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
486596bc239SMarcel Telka 		    &exi, &sec);
487f7db5903SVitaliy Gusev 
48803986916Sjarrett 		/*
48903986916Sjarrett 		 * Since WebNFS may bypass MOUNT, we need to ensure this
49003986916Sjarrett 		 * request didn't come from an unlabeled admin_low client.
49103986916Sjarrett 		 */
49203986916Sjarrett 		if (is_system_labeled() && error == 0) {
49303986916Sjarrett 			int		addr_type;
49403986916Sjarrett 			void		*ipaddr;
49503986916Sjarrett 			tsol_tpc_t	*tp;
49603986916Sjarrett 
49703986916Sjarrett 			if (ca->sa_family == AF_INET) {
49803986916Sjarrett 				addr_type = IPV4_VERSION;
49903986916Sjarrett 				ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
50003986916Sjarrett 			} else if (ca->sa_family == AF_INET6) {
50103986916Sjarrett 				addr_type = IPV6_VERSION;
50203986916Sjarrett 				ipaddr = &((struct sockaddr_in6 *)
50303986916Sjarrett 				    ca)->sin6_addr;
50403986916Sjarrett 			}
50503986916Sjarrett 			tp = find_tpc(ipaddr, addr_type, B_FALSE);
50603986916Sjarrett 			if (tp == NULL || tp->tpc_tp.tp_doi !=
50703986916Sjarrett 			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
50803986916Sjarrett 			    SUN_CIPSO) {
50903986916Sjarrett 				VN_RELE(vp);
510f46abf18SMarcel Telka 				error = EACCES;
51103986916Sjarrett 			}
51203986916Sjarrett 			if (tp != NULL)
51303986916Sjarrett 				TPC_RELE(tp);
51403986916Sjarrett 		}
5157c478bd9Sstevel@tonic-gate 	} else {
516b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = VOP_LOOKUP(dvp, name, &vp,
517cfae96c2Sjwahlig 		    NULL, 0, NULL, cr, NULL, NULL, NULL);
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 
520b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->what.name)
521b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
522b89a8333Snatalie li - Sun Microsystems - Irvine United States 
523f7db5903SVitaliy Gusev 	if (error == 0 && vn_ismntpt(vp)) {
524f7db5903SVitaliy Gusev 		error = rfs_cross_mnt(&vp, &exi);
525f7db5903SVitaliy Gusev 		if (error)
526f7db5903SVitaliy Gusev 			VN_RELE(vp);
527f7db5903SVitaliy Gusev 	}
528f7db5903SVitaliy Gusev 
52903986916Sjarrett 	if (is_system_labeled() && error == 0) {
53003986916Sjarrett 		bslabel_t *clabel = req->rq_label;
53103986916Sjarrett 
53203986916Sjarrett 		ASSERT(clabel != NULL);
53303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
53403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
53503986916Sjarrett 
53603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
53703986916Sjarrett 			if (!do_rfs_label_check(clabel, dvp,
538bd6f1640SJarrett Lu 			    DOMINANCE_CHECK, exi)) {
53903986916Sjarrett 				VN_RELE(vp);
540f46abf18SMarcel Telka 				error = EACCES;
54103986916Sjarrett 			}
54203986916Sjarrett 		}
54303986916Sjarrett 	}
54403986916Sjarrett 
5457c478bd9Sstevel@tonic-gate 	dva.va_mask = AT_ALL;
546da6c28aaSamw 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	if (error)
5497c478bd9Sstevel@tonic-gate 		goto out;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (sec.sec_flags & SEC_QUERY) {
5527c478bd9Sstevel@tonic-gate 		error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
5537c478bd9Sstevel@tonic-gate 	} else {
5547c478bd9Sstevel@tonic-gate 		error = makefh3(&resp->resok.object, vp, exi);
5557c478bd9Sstevel@tonic-gate 		if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
5567c478bd9Sstevel@tonic-gate 			auth_weak = TRUE;
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate 
559fd9d0a82SMarcel Telka 	if (error) {
560fd9d0a82SMarcel Telka 		VN_RELE(vp);
561fd9d0a82SMarcel Telka 		goto out;
562fd9d0a82SMarcel Telka 	}
563fd9d0a82SMarcel Telka 
5647c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
5657c478bd9Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
5707c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
5717c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	/*
5747c478bd9Sstevel@tonic-gate 	 * If it's public fh, no 0x81, and client's flavor is
5757c478bd9Sstevel@tonic-gate 	 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
5767c478bd9Sstevel@tonic-gate 	 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
5777c478bd9Sstevel@tonic-gate 	 */
5787c478bd9Sstevel@tonic-gate 	if (auth_weak)
5797c478bd9Sstevel@tonic-gate 		resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
5807c478bd9Sstevel@tonic-gate 
5810dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
5820dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
5830dfe541eSEvan Layton 	    LOOKUP3res *, resp);
584e1adf50cSahl 	VN_RELE(dvp);
5850dfe541eSEvan Layton 	exi_rele(exi);
586e1adf50cSahl 
5877c478bd9Sstevel@tonic-gate 	return;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate out:
5907c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
5917c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
5927c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
5937c478bd9Sstevel@tonic-gate 	} else
5947c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
5957c478bd9Sstevel@tonic-gate out1:
5960dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
5970dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
5980dfe541eSEvan Layton 	    LOOKUP3res *, resp);
5990dfe541eSEvan Layton 
600f7db5903SVitaliy Gusev 	if (exi != NULL)
601f7db5903SVitaliy Gusev 		exi_rele(exi);
602f7db5903SVitaliy Gusev 
6037c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
6047c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
6057c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate 
60927242a7cSthurlow void *
rfs3_lookup_getfh(LOOKUP3args * args)6107c478bd9Sstevel@tonic-gate rfs3_lookup_getfh(LOOKUP3args *args)
6117c478bd9Sstevel@tonic-gate {
6127c478bd9Sstevel@tonic-gate 
61327242a7cSthurlow 	return (&args->what.dir);
6147c478bd9Sstevel@tonic-gate }
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate /* ARGSUSED */
6177c478bd9Sstevel@tonic-gate void
rfs3_access(ACCESS3args * args,ACCESS3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)6187c478bd9Sstevel@tonic-gate rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
6195cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
6207c478bd9Sstevel@tonic-gate {
6217c478bd9Sstevel@tonic-gate 	int error;
6227c478bd9Sstevel@tonic-gate 	vnode_t *vp;
6237c478bd9Sstevel@tonic-gate 	struct vattr *vap;
6247c478bd9Sstevel@tonic-gate 	struct vattr va;
6257c478bd9Sstevel@tonic-gate 	int checkwriteperm;
62603986916Sjarrett 	boolean_t dominant_label = B_FALSE;
62703986916Sjarrett 	boolean_t equal_label = B_FALSE;
62803986916Sjarrett 	boolean_t admin_low_client;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	vap = NULL;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
633e1adf50cSahl 
6340dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__access__start, struct svc_req *, req,
6350dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
6360dfe541eSEvan Layton 	    ACCESS3args *, args);
637e1adf50cSahl 
6387c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
6397c478bd9Sstevel@tonic-gate 		error = ESTALE;
6407c478bd9Sstevel@tonic-gate 		goto out;
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	/*
6447c478bd9Sstevel@tonic-gate 	 * If the file system is exported read only, it is not appropriate
6457c478bd9Sstevel@tonic-gate 	 * to check write permissions for regular files and directories.
6467c478bd9Sstevel@tonic-gate 	 * Special files are interpreted by the client, so the underlying
6477c478bd9Sstevel@tonic-gate 	 * permissions are sent back to the client for interpretation.
6487c478bd9Sstevel@tonic-gate 	 */
6495cb0d679SMarcel Telka 	if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
6507c478bd9Sstevel@tonic-gate 		checkwriteperm = 0;
6517c478bd9Sstevel@tonic-gate 	else
6527c478bd9Sstevel@tonic-gate 		checkwriteperm = 1;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	/*
6557c478bd9Sstevel@tonic-gate 	 * We need the mode so that we can correctly determine access
6567c478bd9Sstevel@tonic-gate 	 * permissions relative to a mandatory lock file.  Access to
6577c478bd9Sstevel@tonic-gate 	 * mandatory lock files is denied on the server, so it might
6587c478bd9Sstevel@tonic-gate 	 * as well be reflected to the server during the open.
6597c478bd9Sstevel@tonic-gate 	 */
6607c478bd9Sstevel@tonic-gate 	va.va_mask = AT_MODE;
661da6c28aaSamw 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
6627c478bd9Sstevel@tonic-gate 	if (error)
6637c478bd9Sstevel@tonic-gate 		goto out;
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	vap = &va;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	resp->resok.access = 0;
6687c478bd9Sstevel@tonic-gate 
66903986916Sjarrett 	if (is_system_labeled()) {
67003986916Sjarrett 		bslabel_t *clabel = req->rq_label;
67103986916Sjarrett 
67203986916Sjarrett 		ASSERT(clabel != NULL);
67303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
67403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
67503986916Sjarrett 
67603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
67703986916Sjarrett 			if ((equal_label = do_rfs_label_check(clabel, vp,
678bd6f1640SJarrett Lu 			    EQUALITY_CHECK, exi)) == B_FALSE) {
67903986916Sjarrett 				dominant_label = do_rfs_label_check(clabel,
680bd6f1640SJarrett Lu 				    vp, DOMINANCE_CHECK, exi);
68103986916Sjarrett 			} else
68203986916Sjarrett 				dominant_label = B_TRUE;
68303986916Sjarrett 			admin_low_client = B_FALSE;
68403986916Sjarrett 		} else
68503986916Sjarrett 			admin_low_client = B_TRUE;
68603986916Sjarrett 	}
68703986916Sjarrett 
6887c478bd9Sstevel@tonic-gate 	if (args->access & ACCESS3_READ) {
689da6c28aaSamw 		error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
6907c478bd9Sstevel@tonic-gate 		if (error) {
6917c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
6927c478bd9Sstevel@tonic-gate 				goto out;
69303986916Sjarrett 		} else if (!MANDLOCK(vp, va.va_mode) &&
69403986916Sjarrett 		    (!is_system_labeled() || admin_low_client ||
69503986916Sjarrett 		    dominant_label))
6967c478bd9Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_READ;
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 	if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
699da6c28aaSamw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
7007c478bd9Sstevel@tonic-gate 		if (error) {
7017c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
7027c478bd9Sstevel@tonic-gate 				goto out;
70303986916Sjarrett 		} else if (!is_system_labeled() || admin_low_client ||
70403986916Sjarrett 		    dominant_label)
7057c478bd9Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_LOOKUP;
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 	if (checkwriteperm &&
7087c478bd9Sstevel@tonic-gate 	    (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
709da6c28aaSamw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
7107c478bd9Sstevel@tonic-gate 		if (error) {
7117c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
7127c478bd9Sstevel@tonic-gate 				goto out;
71303986916Sjarrett 		} else if (!MANDLOCK(vp, va.va_mode) &&
71403986916Sjarrett 		    (!is_system_labeled() || admin_low_client || equal_label)) {
7157c478bd9Sstevel@tonic-gate 			resp->resok.access |=
7167c478bd9Sstevel@tonic-gate 			    (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND));
7177c478bd9Sstevel@tonic-gate 		}
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 	if (checkwriteperm &&
7207c478bd9Sstevel@tonic-gate 	    (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
721da6c28aaSamw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
7227c478bd9Sstevel@tonic-gate 		if (error) {
7237c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
7247c478bd9Sstevel@tonic-gate 				goto out;
72503986916Sjarrett 		} else if (!is_system_labeled() || admin_low_client ||
72603986916Sjarrett 		    equal_label)
7277c478bd9Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_DELETE;
7287c478bd9Sstevel@tonic-gate 	}
7297c478bd9Sstevel@tonic-gate 	if (args->access & ACCESS3_EXECUTE) {
730da6c28aaSamw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
7317c478bd9Sstevel@tonic-gate 		if (error) {
7327c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
7337c478bd9Sstevel@tonic-gate 				goto out;
73403986916Sjarrett 		} else if (!MANDLOCK(vp, va.va_mode) &&
73503986916Sjarrett 		    (!is_system_labeled() || admin_low_client ||
73603986916Sjarrett 		    dominant_label))
7377c478bd9Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_EXECUTE;
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
7417c478bd9Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
7447c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
745e1adf50cSahl 
7460dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
7470dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
7480dfe541eSEvan Layton 	    ACCESS3res *, resp);
749e1adf50cSahl 
750e1adf50cSahl 	VN_RELE(vp);
751e1adf50cSahl 
7527c478bd9Sstevel@tonic-gate 	return;
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate out:
7557c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
7567c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
7577c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
7587c478bd9Sstevel@tonic-gate 	} else
7597c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
7600dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
7610dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
7620dfe541eSEvan Layton 	    ACCESS3res *, resp);
7637c478bd9Sstevel@tonic-gate 	if (vp != NULL)
7647c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
7657c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
7667c478bd9Sstevel@tonic-gate }
7677c478bd9Sstevel@tonic-gate 
76827242a7cSthurlow void *
rfs3_access_getfh(ACCESS3args * args)7697c478bd9Sstevel@tonic-gate rfs3_access_getfh(ACCESS3args *args)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate 
77227242a7cSthurlow 	return (&args->object);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate /* ARGSUSED */
7767c478bd9Sstevel@tonic-gate void
rfs3_readlink(READLINK3args * args,READLINK3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)7777c478bd9Sstevel@tonic-gate rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
7785cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate 	int error;
7817c478bd9Sstevel@tonic-gate 	vnode_t *vp;
7827c478bd9Sstevel@tonic-gate 	struct vattr *vap;
7837c478bd9Sstevel@tonic-gate 	struct vattr va;
7847c478bd9Sstevel@tonic-gate 	struct iovec iov;
7857c478bd9Sstevel@tonic-gate 	struct uio uio;
7867c478bd9Sstevel@tonic-gate 	char *data;
787b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
788b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
7892f172c55SRobert Thurlow 	int is_referral = 0;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	vap = NULL;
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->symlink, exi);
794e1adf50cSahl 
7950dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req,
7960dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
7970dfe541eSEvan Layton 	    READLINK3args *, args);
798e1adf50cSahl 
7997c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
8007c478bd9Sstevel@tonic-gate 		error = ESTALE;
8017c478bd9Sstevel@tonic-gate 		goto out;
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
805da6c28aaSamw 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
8067c478bd9Sstevel@tonic-gate 	if (error)
8077c478bd9Sstevel@tonic-gate 		goto out;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	vap = &va;
8107c478bd9Sstevel@tonic-gate 
8112f172c55SRobert Thurlow 	/* We lied about the object type for a referral */
8122f172c55SRobert Thurlow 	if (vn_is_nfs_reparse(vp, cr))
8132f172c55SRobert Thurlow 		is_referral = 1;
8142f172c55SRobert Thurlow 
8152f172c55SRobert Thurlow 	if (vp->v_type != VLNK && !is_referral) {
8167c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
8177c478bd9Sstevel@tonic-gate 		goto out1;
8187c478bd9Sstevel@tonic-gate 	}
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	if (MANDLOCK(vp, va.va_mode)) {
8217c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
8227c478bd9Sstevel@tonic-gate 		goto out1;
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 
82503986916Sjarrett 	if (is_system_labeled()) {
82603986916Sjarrett 		bslabel_t *clabel = req->rq_label;
82703986916Sjarrett 
82803986916Sjarrett 		ASSERT(clabel != NULL);
82903986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
83003986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
83103986916Sjarrett 
83203986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
833bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
834bd6f1640SJarrett Lu 			    exi)) {
83503986916Sjarrett 				resp->status = NFS3ERR_ACCES;
83603986916Sjarrett 				goto out1;
83703986916Sjarrett 			}
83803986916Sjarrett 		}
83903986916Sjarrett 	}
84003986916Sjarrett 
8417c478bd9Sstevel@tonic-gate 	data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
8427c478bd9Sstevel@tonic-gate 
8432f172c55SRobert Thurlow 	if (is_referral) {
8442f172c55SRobert Thurlow 		char *s;
8452f172c55SRobert Thurlow 		size_t strsz;
8460dfe541eSEvan Layton 		kstat_named_t *stat = exi->exi_ne->ne_globals->svstat[NFS_V3];
8472f172c55SRobert Thurlow 
8482f172c55SRobert Thurlow 		/* Get an artificial symlink based on a referral */
8492f172c55SRobert Thurlow 		s = build_symlink(vp, cr, &strsz);
8500dfe541eSEvan Layton 		stat[NFS_REFERLINKS].value.ui64++;
8512f172c55SRobert Thurlow 		DTRACE_PROBE2(nfs3serv__func__referral__reflink,
8522f172c55SRobert Thurlow 		    vnode_t *, vp, char *, s);
8532f172c55SRobert Thurlow 		if (s == NULL)
8542f172c55SRobert Thurlow 			error = EINVAL;
8552f172c55SRobert Thurlow 		else {
8562f172c55SRobert Thurlow 			error = 0;
8572f172c55SRobert Thurlow 			(void) strlcpy(data, s, MAXPATHLEN + 1);
8582f172c55SRobert Thurlow 			kmem_free(s, strsz);
8592f172c55SRobert Thurlow 		}
8607c478bd9Sstevel@tonic-gate 
8612f172c55SRobert Thurlow 	} else {
8622f172c55SRobert Thurlow 
8632f172c55SRobert Thurlow 		iov.iov_base = data;
8642f172c55SRobert Thurlow 		iov.iov_len = MAXPATHLEN;
8652f172c55SRobert Thurlow 		uio.uio_iov = &iov;
8662f172c55SRobert Thurlow 		uio.uio_iovcnt = 1;
8672f172c55SRobert Thurlow 		uio.uio_segflg = UIO_SYSSPACE;
8682f172c55SRobert Thurlow 		uio.uio_extflg = UIO_COPY_CACHED;
8692f172c55SRobert Thurlow 		uio.uio_loffset = 0;
8702f172c55SRobert Thurlow 		uio.uio_resid = MAXPATHLEN;
8712f172c55SRobert Thurlow 
8722f172c55SRobert Thurlow 		error = VOP_READLINK(vp, &uio, cr, NULL);
8732f172c55SRobert Thurlow 
8742f172c55SRobert Thurlow 		if (!error)
8752f172c55SRobert Thurlow 			*(data + MAXPATHLEN - uio.uio_resid) = '\0';
8762f172c55SRobert Thurlow 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
879da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
88027246829SVitaliy Gusev 
8812f172c55SRobert Thurlow 	/* Lie about object type again just to be consistent */
8822f172c55SRobert Thurlow 	if (is_referral && vap != NULL)
8832f172c55SRobert Thurlow 		vap->va_type = VLNK;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate #if 0 /* notyet */
8867c478bd9Sstevel@tonic-gate 	/*
8877c478bd9Sstevel@tonic-gate 	 * Don't do this.  It causes local disk writes when just
8887c478bd9Sstevel@tonic-gate 	 * reading the file and the overhead is deemed larger
8897c478bd9Sstevel@tonic-gate 	 * than the benefit.
8907c478bd9Sstevel@tonic-gate 	 */
8917c478bd9Sstevel@tonic-gate 	/*
8927c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
8937c478bd9Sstevel@tonic-gate 	 */
894da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
8957c478bd9Sstevel@tonic-gate #endif
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	if (error) {
8987c478bd9Sstevel@tonic-gate 		kmem_free(data, MAXPATHLEN + 1);
8997c478bd9Sstevel@tonic-gate 		goto out;
9007c478bd9Sstevel@tonic-gate 	}
9017c478bd9Sstevel@tonic-gate 
902b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
903b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
904b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    MAXPATHLEN + 1);
905b89a8333Snatalie li - Sun Microsystems - Irvine United States 
906b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
907b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/*
908b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * Even though the conversion failed, we return
909b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * something. We just don't translate it.
910b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 */
911b89a8333Snatalie li - Sun Microsystems - Irvine United States 		name = data;
912b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
913b89a8333Snatalie li - Sun Microsystems - Irvine United States 
9147c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
9157c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
916b89a8333Snatalie li - Sun Microsystems - Irvine United States 	resp->resok.data = name;
917e1adf50cSahl 
9180dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
9190dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
9200dfe541eSEvan Layton 	    READLINK3res *, resp);
921e1adf50cSahl 	VN_RELE(vp);
922e1adf50cSahl 
923b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != data)
924b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(data, MAXPATHLEN + 1);
925b89a8333Snatalie li - Sun Microsystems - Irvine United States 
9267c478bd9Sstevel@tonic-gate 	return;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate out:
9297c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
9307c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
9317c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
9327c478bd9Sstevel@tonic-gate 	} else
9337c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
9347c478bd9Sstevel@tonic-gate out1:
9350dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
9360dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
9370dfe541eSEvan Layton 	    READLINK3res *, resp);
9387c478bd9Sstevel@tonic-gate 	if (vp != NULL)
9397c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
9407c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate 
94327242a7cSthurlow void *
rfs3_readlink_getfh(READLINK3args * args)9447c478bd9Sstevel@tonic-gate rfs3_readlink_getfh(READLINK3args *args)
9457c478bd9Sstevel@tonic-gate {
9467c478bd9Sstevel@tonic-gate 
94727242a7cSthurlow 	return (&args->symlink);
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate void
rfs3_readlink_free(READLINK3res * resp)9517c478bd9Sstevel@tonic-gate rfs3_readlink_free(READLINK3res *resp)
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	if (resp->status == NFS3_OK)
9557c478bd9Sstevel@tonic-gate 		kmem_free(resp->resok.data, MAXPATHLEN + 1);
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate 
9580a701b1eSRobert Gordon /*
9590a701b1eSRobert Gordon  * Server routine to handle read
9600a701b1eSRobert Gordon  * May handle RDMA data as well as mblks
9610a701b1eSRobert Gordon  */
9627c478bd9Sstevel@tonic-gate /* ARGSUSED */
9637c478bd9Sstevel@tonic-gate void
rfs3_read(READ3args * args,READ3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)9647c478bd9Sstevel@tonic-gate rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
9655cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
9667c478bd9Sstevel@tonic-gate {
9677c478bd9Sstevel@tonic-gate 	int error;
9687c478bd9Sstevel@tonic-gate 	vnode_t *vp;
9697c478bd9Sstevel@tonic-gate 	struct vattr *vap;
9707c478bd9Sstevel@tonic-gate 	struct vattr va;
971e36d7b11SSebastien Roy 	struct iovec iov, *iovp = NULL;
972e36d7b11SSebastien Roy 	int iovcnt;
9737c478bd9Sstevel@tonic-gate 	struct uio uio;
9747c478bd9Sstevel@tonic-gate 	u_offset_t offset;
97541b8345aSchunli zhang - Sun Microsystems - Irvine United States 	mblk_t *mp = NULL;
9767c478bd9Sstevel@tonic-gate 	int in_crit = 0;
9777c478bd9Sstevel@tonic-gate 	int need_rwunlock = 0;
978cfae96c2Sjwahlig 	caller_context_t ct;
979c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	int rdma_used = 0;
980c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	int loaned_buffers;
981c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	struct uio *uiop;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	vap = NULL;
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
986e1adf50cSahl 
9870dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__read__start, struct svc_req *, req,
9880dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
9890dfe541eSEvan Layton 	    READ3args *, args);
9900dfe541eSEvan Layton 
991e1adf50cSahl 
9927c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
9937c478bd9Sstevel@tonic-gate 		error = ESTALE;
9947c478bd9Sstevel@tonic-gate 		goto out;
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate 
99735bbd688SKaren Rochford 	if (args->wlist) {
99835bbd688SKaren Rochford 		if (args->count > clist_len(args->wlist)) {
99935bbd688SKaren Rochford 			error = EINVAL;
100035bbd688SKaren Rochford 			goto out;
100135bbd688SKaren Rochford 		}
1002c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		rdma_used = 1;
100335bbd688SKaren Rochford 	}
1004c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1005c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	/* use loaned buffers for TCP */
1006c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
1007c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
100803986916Sjarrett 	if (is_system_labeled()) {
100903986916Sjarrett 		bslabel_t *clabel = req->rq_label;
101003986916Sjarrett 
101103986916Sjarrett 		ASSERT(clabel != NULL);
101203986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *,
101303986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
101403986916Sjarrett 
101503986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1016bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
1017bd6f1640SJarrett Lu 			    exi)) {
101803986916Sjarrett 				resp->status = NFS3ERR_ACCES;
101903986916Sjarrett 				goto out1;
102003986916Sjarrett 			}
102103986916Sjarrett 		}
102203986916Sjarrett 	}
102303986916Sjarrett 
1024cfae96c2Sjwahlig 	ct.cc_sysid = 0;
1025cfae96c2Sjwahlig 	ct.cc_pid = 0;
1026cfae96c2Sjwahlig 	ct.cc_caller_id = nfs3_srv_caller_id;
1027cfae96c2Sjwahlig 	ct.cc_flags = CC_DONTBLOCK;
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	/*
10307c478bd9Sstevel@tonic-gate 	 * Enter the critical region before calling VOP_RWLOCK
10317c478bd9Sstevel@tonic-gate 	 * to avoid a deadlock with write requests.
10327c478bd9Sstevel@tonic-gate 	 */
10337c478bd9Sstevel@tonic-gate 	if (nbl_need_check(vp)) {
10347c478bd9Sstevel@tonic-gate 		nbl_start_crit(vp, RW_READER);
10357c478bd9Sstevel@tonic-gate 		in_crit = 1;
1036da6c28aaSamw 		if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
1037da6c28aaSamw 		    NULL)) {
10387c478bd9Sstevel@tonic-gate 			error = EACCES;
10397c478bd9Sstevel@tonic-gate 			goto out;
10407c478bd9Sstevel@tonic-gate 		}
10417c478bd9Sstevel@tonic-gate 	}
10427c478bd9Sstevel@tonic-gate 
1043cfae96c2Sjwahlig 	error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
1044cfae96c2Sjwahlig 
1045cfae96c2Sjwahlig 	/* check if a monitor detected a delegation conflict */
1046cfae96c2Sjwahlig 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1047cfae96c2Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
1048cfae96c2Sjwahlig 		goto out1;
1049cfae96c2Sjwahlig 	}
1050cfae96c2Sjwahlig 
10517c478bd9Sstevel@tonic-gate 	need_rwunlock = 1;
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1054cfae96c2Sjwahlig 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	/*
10577c478bd9Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
10587c478bd9Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
10597c478bd9Sstevel@tonic-gate 	 */
10607c478bd9Sstevel@tonic-gate 	if (error)
10617c478bd9Sstevel@tonic-gate 		goto out;
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	vap = &va;
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	if (vp->v_type != VREG) {
10667c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
10677c478bd9Sstevel@tonic-gate 		goto out1;
10687c478bd9Sstevel@tonic-gate 	}
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	if (crgetuid(cr) != va.va_uid) {
1071cfae96c2Sjwahlig 		error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
10727c478bd9Sstevel@tonic-gate 		if (error) {
10737c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
10747c478bd9Sstevel@tonic-gate 				goto out;
1075cfae96c2Sjwahlig 			error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
10767c478bd9Sstevel@tonic-gate 			if (error)
10777c478bd9Sstevel@tonic-gate 				goto out;
10787c478bd9Sstevel@tonic-gate 		}
10797c478bd9Sstevel@tonic-gate 	}
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	if (MANDLOCK(vp, va.va_mode)) {
10827c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
10837c478bd9Sstevel@tonic-gate 		goto out1;
10847c478bd9Sstevel@tonic-gate 	}
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	offset = args->offset;
10877c478bd9Sstevel@tonic-gate 	if (offset >= va.va_size) {
1088cfae96c2Sjwahlig 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
10897c478bd9Sstevel@tonic-gate 		if (in_crit)
10907c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
10917c478bd9Sstevel@tonic-gate 		resp->status = NFS3_OK;
10927c478bd9Sstevel@tonic-gate 		vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
10937c478bd9Sstevel@tonic-gate 		resp->resok.count = 0;
10947c478bd9Sstevel@tonic-gate 		resp->resok.eof = TRUE;
10957c478bd9Sstevel@tonic-gate 		resp->resok.data.data_len = 0;
10967c478bd9Sstevel@tonic-gate 		resp->resok.data.data_val = NULL;
10977c478bd9Sstevel@tonic-gate 		resp->resok.data.mp = NULL;
10980a701b1eSRobert Gordon 		/* RDMA */
10990a701b1eSRobert Gordon 		resp->resok.wlist = args->wlist;
11000a701b1eSRobert Gordon 		resp->resok.wlist_len = resp->resok.count;
1101f837ee4aSSiddheshwar Mahesh 		if (resp->resok.wlist)
1102f837ee4aSSiddheshwar Mahesh 			clist_zero_len(resp->resok.wlist);
1103e1adf50cSahl 		goto done;
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	if (args->count == 0) {
1107cfae96c2Sjwahlig 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
11087c478bd9Sstevel@tonic-gate 		if (in_crit)
11097c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
11107c478bd9Sstevel@tonic-gate 		resp->status = NFS3_OK;
11117c478bd9Sstevel@tonic-gate 		vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
11127c478bd9Sstevel@tonic-gate 		resp->resok.count = 0;
11137c478bd9Sstevel@tonic-gate 		resp->resok.eof = FALSE;
11147c478bd9Sstevel@tonic-gate 		resp->resok.data.data_len = 0;
11157c478bd9Sstevel@tonic-gate 		resp->resok.data.data_val = NULL;
11167c478bd9Sstevel@tonic-gate 		resp->resok.data.mp = NULL;
11170a701b1eSRobert Gordon 		/* RDMA */
11180a701b1eSRobert Gordon 		resp->resok.wlist = args->wlist;
11190a701b1eSRobert Gordon 		resp->resok.wlist_len = resp->resok.count;
1120f837ee4aSSiddheshwar Mahesh 		if (resp->resok.wlist)
1121f837ee4aSSiddheshwar Mahesh 			clist_zero_len(resp->resok.wlist);
1122e1adf50cSahl 		goto done;
11237c478bd9Sstevel@tonic-gate 	}
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	/*
11267c478bd9Sstevel@tonic-gate 	 * do not allocate memory more the max. allowed
11277c478bd9Sstevel@tonic-gate 	 * transfer size
11287c478bd9Sstevel@tonic-gate 	 */
11297c478bd9Sstevel@tonic-gate 	if (args->count > rfs3_tsize(req))
11307c478bd9Sstevel@tonic-gate 		args->count = rfs3_tsize(req);
11317c478bd9Sstevel@tonic-gate 
1132c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (loaned_buffers) {
1133c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop = (uio_t *)rfs_setup_xuio(vp);
1134c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		ASSERT(uiop != NULL);
1135c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop->uio_segflg = UIO_SYSSPACE;
1136c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop->uio_loffset = args->offset;
1137c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop->uio_resid = args->count;
1138c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1139c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		/* Jump to do the read if successful */
1140c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		if (VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cr, &ct) == 0) {
1141c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			/*
1142c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			 * Need to hold the vnode until after VOP_RETZCBUF()
1143c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			 * is called.
1144c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			 */
1145c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			VN_HOLD(vp);
1146c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			goto doio_read;
1147c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		}
1148c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1149c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int,
1150c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		    uiop->uio_loffset, int, uiop->uio_resid);
1151c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1152c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop->uio_extflg = 0;
1153c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		/* failure to setup for zero copy */
1154c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		rfs_free_xuio((void *)uiop);
1155c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		loaned_buffers = 0;
1156c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	}
1157c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
11587c478bd9Sstevel@tonic-gate 	/*
11590a701b1eSRobert Gordon 	 * If returning data via RDMA Write, then grab the chunk list.
11600a701b1eSRobert Gordon 	 * If we aren't returning READ data w/RDMA_WRITE, then grab
11610a701b1eSRobert Gordon 	 * a mblk.
11627c478bd9Sstevel@tonic-gate 	 */
1163c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (rdma_used) {
11640a701b1eSRobert Gordon 		(void) rdma_get_wchunk(req, &iov, args->wlist);
1165e36d7b11SSebastien Roy 		uio.uio_iov = &iov;
1166e36d7b11SSebastien Roy 		uio.uio_iovcnt = 1;
11670a701b1eSRobert Gordon 	} else {
11680a701b1eSRobert Gordon 		/*
11690a701b1eSRobert Gordon 		 * mp will contain the data to be sent out in the read reply.
1170e36d7b11SSebastien Roy 		 * For UDP, this will be freed after the reply has been sent
1171e36d7b11SSebastien Roy 		 * out by the driver.  For TCP, it will be freed after the last
1172e36d7b11SSebastien Roy 		 * segment associated with the reply has been ACKed by the
1173e36d7b11SSebastien Roy 		 * client.
11740a701b1eSRobert Gordon 		 */
1175e36d7b11SSebastien Roy 		mp = rfs_read_alloc(args->count, &iovp, &iovcnt);
1176e36d7b11SSebastien Roy 		uio.uio_iov = iovp;
1177e36d7b11SSebastien Roy 		uio.uio_iovcnt = iovcnt;
11780a701b1eSRobert Gordon 	}
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
11817c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
11827c478bd9Sstevel@tonic-gate 	uio.uio_loffset = args->offset;
11837c478bd9Sstevel@tonic-gate 	uio.uio_resid = args->count;
1184c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	uiop = &uio;
11857c478bd9Sstevel@tonic-gate 
1186c242f9a0Schunli zhang - Sun Microsystems - Irvine United States doio_read:
1187c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	error = VOP_READ(vp, uiop, 0, cr, &ct);
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	if (error) {
1190c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		if (mp)
1191c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			freemsg(mp);
1192cfae96c2Sjwahlig 		/* check if a monitor detected a delegation conflict */
1193cfae96c2Sjwahlig 		if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1194cfae96c2Sjwahlig 			resp->status = NFS3ERR_JUKEBOX;
1195cfae96c2Sjwahlig 			goto out1;
1196cfae96c2Sjwahlig 		}
11977c478bd9Sstevel@tonic-gate 		goto out;
11987c478bd9Sstevel@tonic-gate 	}
11997c478bd9Sstevel@tonic-gate 
1200c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	/* make mblk using zc buffers */
1201c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (loaned_buffers) {
1202c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		mp = uio_to_mblk(uiop);
1203c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		ASSERT(mp != NULL);
1204c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	}
1205c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
12067c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1207cfae96c2Sjwahlig 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	if (error)
12107c478bd9Sstevel@tonic-gate 		vap = NULL;
12117c478bd9Sstevel@tonic-gate 	else
12127c478bd9Sstevel@tonic-gate 		vap = &va;
12137c478bd9Sstevel@tonic-gate 
1214cfae96c2Sjwahlig 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	if (in_crit)
12177c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
12207c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1221c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	resp->resok.count = args->count - uiop->uio_resid;
12227c478bd9Sstevel@tonic-gate 	if (!error && offset + resp->resok.count == va.va_size)
12237c478bd9Sstevel@tonic-gate 		resp->resok.eof = TRUE;
12247c478bd9Sstevel@tonic-gate 	else
12257c478bd9Sstevel@tonic-gate 		resp->resok.eof = FALSE;
12267c478bd9Sstevel@tonic-gate 	resp->resok.data.data_len = resp->resok.count;
1227c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1228c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (mp)
1229c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1230c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
12317c478bd9Sstevel@tonic-gate 	resp->resok.data.mp = mp;
12327c478bd9Sstevel@tonic-gate 	resp->resok.size = (uint_t)args->count;
1233e1adf50cSahl 
1234c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (rdma_used) {
12350a701b1eSRobert Gordon 		resp->resok.data.data_val = (caddr_t)iov.iov_base;
12360a701b1eSRobert Gordon 		if (!rdma_setup_read_data3(args, &(resp->resok))) {
12370a701b1eSRobert Gordon 			resp->status = NFS3ERR_INVAL;
12380a701b1eSRobert Gordon 		}
12390a701b1eSRobert Gordon 	} else {
12400a701b1eSRobert Gordon 		resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
12410a701b1eSRobert Gordon 		(resp->resok).wlist = NULL;
12420a701b1eSRobert Gordon 	}
12430a701b1eSRobert Gordon 
1244e1adf50cSahl done:
12450dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
12460dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
12470dfe541eSEvan Layton 	    READ3res *, resp);
1248e1adf50cSahl 
1249e1adf50cSahl 	VN_RELE(vp);
1250e1adf50cSahl 
1251e36d7b11SSebastien Roy 	if (iovp != NULL)
1252e36d7b11SSebastien Roy 		kmem_free(iovp, iovcnt * sizeof (struct iovec));
1253e36d7b11SSebastien Roy 
12547c478bd9Sstevel@tonic-gate 	return;
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate out:
12577c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
12587c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
12597c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
12607c478bd9Sstevel@tonic-gate 	} else
12617c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
12627c478bd9Sstevel@tonic-gate out1:
12630dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
12640dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
12650dfe541eSEvan Layton 	    READ3res *, resp);
1266e1adf50cSahl 
12677c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
12687c478bd9Sstevel@tonic-gate 		if (need_rwunlock)
1269cfae96c2Sjwahlig 			VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
12707c478bd9Sstevel@tonic-gate 		if (in_crit)
12717c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
12727c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
12737c478bd9Sstevel@tonic-gate 	}
12747c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1275e36d7b11SSebastien Roy 
1276e36d7b11SSebastien Roy 	if (iovp != NULL)
1277e36d7b11SSebastien Roy 		kmem_free(iovp, iovcnt * sizeof (struct iovec));
12787c478bd9Sstevel@tonic-gate }
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate void
rfs3_read_free(READ3res * resp)12817c478bd9Sstevel@tonic-gate rfs3_read_free(READ3res *resp)
12827c478bd9Sstevel@tonic-gate {
12837c478bd9Sstevel@tonic-gate 	mblk_t *mp;
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	if (resp->status == NFS3_OK) {
12867c478bd9Sstevel@tonic-gate 		mp = resp->resok.data.mp;
12877c478bd9Sstevel@tonic-gate 		if (mp != NULL)
1288c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			freemsg(mp);
12897c478bd9Sstevel@tonic-gate 	}
12907c478bd9Sstevel@tonic-gate }
12917c478bd9Sstevel@tonic-gate 
129227242a7cSthurlow void *
rfs3_read_getfh(READ3args * args)12937c478bd9Sstevel@tonic-gate rfs3_read_getfh(READ3args *args)
12947c478bd9Sstevel@tonic-gate {
12957c478bd9Sstevel@tonic-gate 
129627242a7cSthurlow 	return (&args->file);
12977c478bd9Sstevel@tonic-gate }
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate #define	MAX_IOVECS	12
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate #ifdef DEBUG
13027c478bd9Sstevel@tonic-gate static int rfs3_write_hits = 0;
13037c478bd9Sstevel@tonic-gate static int rfs3_write_misses = 0;
13047c478bd9Sstevel@tonic-gate #endif
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate void
rfs3_write(WRITE3args * args,WRITE3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)13077c478bd9Sstevel@tonic-gate rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
13085cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
13097c478bd9Sstevel@tonic-gate {
13100dfe541eSEvan Layton 	nfs3_srv_t *ns;
13117c478bd9Sstevel@tonic-gate 	int error;
13127c478bd9Sstevel@tonic-gate 	vnode_t *vp;
13137c478bd9Sstevel@tonic-gate 	struct vattr *bvap = NULL;
13147c478bd9Sstevel@tonic-gate 	struct vattr bva;
13157c478bd9Sstevel@tonic-gate 	struct vattr *avap = NULL;
13167c478bd9Sstevel@tonic-gate 	struct vattr ava;
13177c478bd9Sstevel@tonic-gate 	u_offset_t rlimit;
13187c478bd9Sstevel@tonic-gate 	struct uio uio;
13197c478bd9Sstevel@tonic-gate 	struct iovec iov[MAX_IOVECS];
13207c478bd9Sstevel@tonic-gate 	mblk_t *m;
13217c478bd9Sstevel@tonic-gate 	struct iovec *iovp;
13227c478bd9Sstevel@tonic-gate 	int iovcnt;
13237c478bd9Sstevel@tonic-gate 	int ioflag;
13247c478bd9Sstevel@tonic-gate 	cred_t *savecred;
13257c478bd9Sstevel@tonic-gate 	int in_crit = 0;
13267c478bd9Sstevel@tonic-gate 	int rwlock_ret = -1;
1327cfae96c2Sjwahlig 	caller_context_t ct;
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
1330e1adf50cSahl 
13310dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__write__start, struct svc_req *, req,
13320dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
13330dfe541eSEvan Layton 	    WRITE3args *, args);
1334e1adf50cSahl 
13357c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
13367c478bd9Sstevel@tonic-gate 		error = ESTALE;
1337e1adf50cSahl 		goto err;
13387c478bd9Sstevel@tonic-gate 	}
13397c478bd9Sstevel@tonic-gate 
13400dfe541eSEvan Layton 	ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
13410dfe541eSEvan Layton 	ns = nfs3_get_srv();
13420dfe541eSEvan Layton 
134303986916Sjarrett 	if (is_system_labeled()) {
134403986916Sjarrett 		bslabel_t *clabel = req->rq_label;
134503986916Sjarrett 
134603986916Sjarrett 		ASSERT(clabel != NULL);
134703986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
134803986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
134903986916Sjarrett 
135003986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1351bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1352bd6f1640SJarrett Lu 			    exi)) {
135303986916Sjarrett 				resp->status = NFS3ERR_ACCES;
1354e1adf50cSahl 				goto err1;
135503986916Sjarrett 			}
135603986916Sjarrett 		}
135703986916Sjarrett 	}
135803986916Sjarrett 
1359cfae96c2Sjwahlig 	ct.cc_sysid = 0;
1360cfae96c2Sjwahlig 	ct.cc_pid = 0;
1361cfae96c2Sjwahlig 	ct.cc_caller_id = nfs3_srv_caller_id;
1362cfae96c2Sjwahlig 	ct.cc_flags = CC_DONTBLOCK;
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	/*
13657c478bd9Sstevel@tonic-gate 	 * We have to enter the critical region before calling VOP_RWLOCK
13667c478bd9Sstevel@tonic-gate 	 * to avoid a deadlock with ufs.
13677c478bd9Sstevel@tonic-gate 	 */
13687c478bd9Sstevel@tonic-gate 	if (nbl_need_check(vp)) {
13697c478bd9Sstevel@tonic-gate 		nbl_start_crit(vp, RW_READER);
13707c478bd9Sstevel@tonic-gate 		in_crit = 1;
1371da6c28aaSamw 		if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
1372da6c28aaSamw 		    NULL)) {
13737c478bd9Sstevel@tonic-gate 			error = EACCES;
1374e1adf50cSahl 			goto err;
13757c478bd9Sstevel@tonic-gate 		}
13767c478bd9Sstevel@tonic-gate 	}
13777c478bd9Sstevel@tonic-gate 
1378cfae96c2Sjwahlig 	rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
1379cfae96c2Sjwahlig 
1380cfae96c2Sjwahlig 	/* check if a monitor detected a delegation conflict */
1381cfae96c2Sjwahlig 	if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1382cfae96c2Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
1383cfae96c2Sjwahlig 		rwlock_ret = -1;
1384e1adf50cSahl 		goto err1;
1385cfae96c2Sjwahlig 	}
1386cfae96c2Sjwahlig 
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
1389cfae96c2Sjwahlig 	error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 	/*
13927c478bd9Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
13937c478bd9Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
13947c478bd9Sstevel@tonic-gate 	 */
13957c478bd9Sstevel@tonic-gate 	if (error)
1396e1adf50cSahl 		goto err;
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	bvap = &bva;
13997c478bd9Sstevel@tonic-gate 	avap = bvap;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	if (args->count != args->data.data_len) {
14027c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
1403e1adf50cSahl 		goto err1;
14047c478bd9Sstevel@tonic-gate 	}
14057c478bd9Sstevel@tonic-gate 
14065cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
14077c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
1408e1adf50cSahl 		goto err1;
14097c478bd9Sstevel@tonic-gate 	}
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	if (vp->v_type != VREG) {
14127c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
1413e1adf50cSahl 		goto err1;
14147c478bd9Sstevel@tonic-gate 	}
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	if (crgetuid(cr) != bva.va_uid &&
1417cfae96c2Sjwahlig 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1418e1adf50cSahl 		goto err;
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	if (MANDLOCK(vp, bva.va_mode)) {
14217c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
1422e1adf50cSahl 		goto err1;
14237c478bd9Sstevel@tonic-gate 	}
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	if (args->count == 0) {
14267c478bd9Sstevel@tonic-gate 		resp->status = NFS3_OK;
14277c478bd9Sstevel@tonic-gate 		vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
14287c478bd9Sstevel@tonic-gate 		resp->resok.count = 0;
14297c478bd9Sstevel@tonic-gate 		resp->resok.committed = args->stable;
14300dfe541eSEvan Layton 		resp->resok.verf = ns->write3verf;
1431e1adf50cSahl 		goto out;
14327c478bd9Sstevel@tonic-gate 	}
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	if (args->mblk != NULL) {
14357c478bd9Sstevel@tonic-gate 		iovcnt = 0;
14367c478bd9Sstevel@tonic-gate 		for (m = args->mblk; m != NULL; m = m->b_cont)
14377c478bd9Sstevel@tonic-gate 			iovcnt++;
14387c478bd9Sstevel@tonic-gate 		if (iovcnt <= MAX_IOVECS) {
14397c478bd9Sstevel@tonic-gate #ifdef DEBUG
14407c478bd9Sstevel@tonic-gate 			rfs3_write_hits++;
14417c478bd9Sstevel@tonic-gate #endif
14427c478bd9Sstevel@tonic-gate 			iovp = iov;
14437c478bd9Sstevel@tonic-gate 		} else {
14447c478bd9Sstevel@tonic-gate #ifdef DEBUG
14457c478bd9Sstevel@tonic-gate 			rfs3_write_misses++;
14467c478bd9Sstevel@tonic-gate #endif
14477c478bd9Sstevel@tonic-gate 			iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
14487c478bd9Sstevel@tonic-gate 		}
14497c478bd9Sstevel@tonic-gate 		mblk_to_iov(args->mblk, iovcnt, iovp);
14500a701b1eSRobert Gordon 
14510a701b1eSRobert Gordon 	} else if (args->rlist != NULL) {
14520a701b1eSRobert Gordon 		iovcnt = 1;
14530a701b1eSRobert Gordon 		iovp = iov;
14540a701b1eSRobert Gordon 		iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
14550a701b1eSRobert Gordon 		iovp->iov_len = args->count;
14567c478bd9Sstevel@tonic-gate 	} else {
14577c478bd9Sstevel@tonic-gate 		iovcnt = 1;
14587c478bd9Sstevel@tonic-gate 		iovp = iov;
14597c478bd9Sstevel@tonic-gate 		iovp->iov_base = args->data.data_val;
14607c478bd9Sstevel@tonic-gate 		iovp->iov_len = args->count;
14617c478bd9Sstevel@tonic-gate 	}
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	uio.uio_iov = iovp;
14647c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = iovcnt;
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
14677c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_DEFAULT;
14687c478bd9Sstevel@tonic-gate 	uio.uio_loffset = args->offset;
14697c478bd9Sstevel@tonic-gate 	uio.uio_resid = args->count;
14707c478bd9Sstevel@tonic-gate 	uio.uio_llimit = curproc->p_fsz_ctl;
14717c478bd9Sstevel@tonic-gate 	rlimit = uio.uio_llimit - args->offset;
14727c478bd9Sstevel@tonic-gate 	if (rlimit < (u_offset_t)uio.uio_resid)
14737c478bd9Sstevel@tonic-gate 		uio.uio_resid = (int)rlimit;
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	if (args->stable == UNSTABLE)
14767c478bd9Sstevel@tonic-gate 		ioflag = 0;
14777c478bd9Sstevel@tonic-gate 	else if (args->stable == FILE_SYNC)
14787c478bd9Sstevel@tonic-gate 		ioflag = FSYNC;
14797c478bd9Sstevel@tonic-gate 	else if (args->stable == DATA_SYNC)
14807c478bd9Sstevel@tonic-gate 		ioflag = FDSYNC;
14817c478bd9Sstevel@tonic-gate 	else {
14827c478bd9Sstevel@tonic-gate 		if (iovp != iov)
14837c478bd9Sstevel@tonic-gate 			kmem_free(iovp, sizeof (*iovp) * iovcnt);
14847c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
1485e1adf50cSahl 		goto err1;
14867c478bd9Sstevel@tonic-gate 	}
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	/*
14897c478bd9Sstevel@tonic-gate 	 * We're changing creds because VM may fault and we need
14907c478bd9Sstevel@tonic-gate 	 * the cred of the current thread to be used if quota
14917c478bd9Sstevel@tonic-gate 	 * checking is enabled.
14927c478bd9Sstevel@tonic-gate 	 */
14937c478bd9Sstevel@tonic-gate 	savecred = curthread->t_cred;
14947c478bd9Sstevel@tonic-gate 	curthread->t_cred = cr;
1495cfae96c2Sjwahlig 	error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
14967c478bd9Sstevel@tonic-gate 	curthread->t_cred = savecred;
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	if (iovp != iov)
14997c478bd9Sstevel@tonic-gate 		kmem_free(iovp, sizeof (*iovp) * iovcnt);
15007c478bd9Sstevel@tonic-gate 
1501cfae96c2Sjwahlig 	/* check if a monitor detected a delegation conflict */
1502cfae96c2Sjwahlig 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1503cfae96c2Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
1504e1adf50cSahl 		goto err1;
1505cfae96c2Sjwahlig 	}
1506cfae96c2Sjwahlig 
15077c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
1508cfae96c2Sjwahlig 	avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	if (error)
1511e1adf50cSahl 		goto err;
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 	/*
15147c478bd9Sstevel@tonic-gate 	 * If we were unable to get the V_WRITELOCK_TRUE, then we
15157c478bd9Sstevel@tonic-gate 	 * may not have accurate after attrs, so check if
15167c478bd9Sstevel@tonic-gate 	 * we have both attributes, they have a non-zero va_seq, and
15177c478bd9Sstevel@tonic-gate 	 * va_seq has changed by exactly one,
15187c478bd9Sstevel@tonic-gate 	 * if not, turn off the before attr.
15197c478bd9Sstevel@tonic-gate 	 */
15207c478bd9Sstevel@tonic-gate 	if (rwlock_ret != V_WRITELOCK_TRUE) {
15217c478bd9Sstevel@tonic-gate 		if (bvap == NULL || avap == NULL ||
1522cfae96c2Sjwahlig 		    bvap->va_seq == 0 || avap->va_seq == 0 ||
1523cfae96c2Sjwahlig 		    avap->va_seq != (bvap->va_seq + 1)) {
15247c478bd9Sstevel@tonic-gate 			bvap = NULL;
15257c478bd9Sstevel@tonic-gate 		}
15267c478bd9Sstevel@tonic-gate 	}
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
15297c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
15307c478bd9Sstevel@tonic-gate 	resp->resok.count = args->count - uio.uio_resid;
15317c478bd9Sstevel@tonic-gate 	resp->resok.committed = args->stable;
15320dfe541eSEvan Layton 	resp->resok.verf = ns->write3verf;
1533e1adf50cSahl 	goto out;
15347c478bd9Sstevel@tonic-gate 
1535e1adf50cSahl err:
15367c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
15377c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
15387c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
15397c478bd9Sstevel@tonic-gate 	} else
15407c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
1541e1adf50cSahl err1:
1542e1adf50cSahl 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1543e1adf50cSahl out:
15440dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__write__done, struct svc_req *, req,
15450dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
15460dfe541eSEvan Layton 	    WRITE3res *, resp);
1547e1adf50cSahl 
15487c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
15497c478bd9Sstevel@tonic-gate 		if (rwlock_ret != -1)
1550cfae96c2Sjwahlig 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
15517c478bd9Sstevel@tonic-gate 		if (in_crit)
15527c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
15537c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
15547c478bd9Sstevel@tonic-gate 	}
15557c478bd9Sstevel@tonic-gate }
15567c478bd9Sstevel@tonic-gate 
155727242a7cSthurlow void *
rfs3_write_getfh(WRITE3args * args)15587c478bd9Sstevel@tonic-gate rfs3_write_getfh(WRITE3args *args)
15597c478bd9Sstevel@tonic-gate {
15607c478bd9Sstevel@tonic-gate 
156127242a7cSthurlow 	return (&args->file);
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate void
rfs3_create(CREATE3args * args,CREATE3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)15657c478bd9Sstevel@tonic-gate rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
15665cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
15677c478bd9Sstevel@tonic-gate {
15687c478bd9Sstevel@tonic-gate 	int error;
15697c478bd9Sstevel@tonic-gate 	int in_crit = 0;
15707c478bd9Sstevel@tonic-gate 	vnode_t *vp;
15717c478bd9Sstevel@tonic-gate 	vnode_t *tvp = NULL;
15727c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
15737c478bd9Sstevel@tonic-gate 	struct vattr *vap;
15747c478bd9Sstevel@tonic-gate 	struct vattr va;
15757c478bd9Sstevel@tonic-gate 	struct vattr *dbvap;
15767c478bd9Sstevel@tonic-gate 	struct vattr dbva;
15777c478bd9Sstevel@tonic-gate 	struct vattr *davap;
15787c478bd9Sstevel@tonic-gate 	struct vattr dava;
15797c478bd9Sstevel@tonic-gate 	enum vcexcl excl;
15807c478bd9Sstevel@tonic-gate 	nfstime3 *mtime;
15817c478bd9Sstevel@tonic-gate 	len_t reqsize;
15827c478bd9Sstevel@tonic-gate 	bool_t trunc;
1583b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
1584b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	dbvap = NULL;
15877c478bd9Sstevel@tonic-gate 	davap = NULL;
15887c478bd9Sstevel@tonic-gate 
158927242a7cSthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
1590e1adf50cSahl 
15910dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__create__start, struct svc_req *, req,
15920dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
15930dfe541eSEvan Layton 	    CREATE3args *, args);
1594e1adf50cSahl 
15957c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
15967c478bd9Sstevel@tonic-gate 		error = ESTALE;
15977c478bd9Sstevel@tonic-gate 		goto out;
15987c478bd9Sstevel@tonic-gate 	}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
1601da6c28aaSamw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
16027c478bd9Sstevel@tonic-gate 	davap = dbvap;
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
16057c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
16067c478bd9Sstevel@tonic-gate 		goto out1;
16077c478bd9Sstevel@tonic-gate 	}
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
16107c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
16117c478bd9Sstevel@tonic-gate 		goto out1;
16127c478bd9Sstevel@tonic-gate 	}
16137c478bd9Sstevel@tonic-gate 
16145cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
16157c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
16167c478bd9Sstevel@tonic-gate 		goto out1;
16177c478bd9Sstevel@tonic-gate 	}
16187c478bd9Sstevel@tonic-gate 
161903986916Sjarrett 	if (is_system_labeled()) {
162003986916Sjarrett 		bslabel_t *clabel = req->rq_label;
162103986916Sjarrett 
162203986916Sjarrett 		ASSERT(clabel != NULL);
162303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
162403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
162503986916Sjarrett 
162603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1627bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1628bd6f1640SJarrett Lu 			    exi)) {
162903986916Sjarrett 				resp->status = NFS3ERR_ACCES;
163003986916Sjarrett 				goto out1;
163103986916Sjarrett 			}
163203986916Sjarrett 		}
163303986916Sjarrett 	}
163403986916Sjarrett 
1635b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1636b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->where.name,
1637b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1638b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1639b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
1640b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/* This is really a Solaris EILSEQ */
1641b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
1642b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
1643b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1644b89a8333Snatalie li - Sun Microsystems - Irvine United States 
16457c478bd9Sstevel@tonic-gate 	if (args->how.mode == EXCLUSIVE) {
16467c478bd9Sstevel@tonic-gate 		va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
16477c478bd9Sstevel@tonic-gate 		va.va_type = VREG;
16487c478bd9Sstevel@tonic-gate 		va.va_mode = (mode_t)0;
16497c478bd9Sstevel@tonic-gate 		/*
16507c478bd9Sstevel@tonic-gate 		 * Ensure no time overflows and that types match
16517c478bd9Sstevel@tonic-gate 		 */
16527c478bd9Sstevel@tonic-gate 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
16537c478bd9Sstevel@tonic-gate 		va.va_mtime.tv_sec = mtime->seconds % INT32_MAX;
16547c478bd9Sstevel@tonic-gate 		va.va_mtime.tv_nsec = mtime->nseconds;
16557c478bd9Sstevel@tonic-gate 		excl = EXCL;
16567c478bd9Sstevel@tonic-gate 	} else {
16577c478bd9Sstevel@tonic-gate 		error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes,
16587c478bd9Sstevel@tonic-gate 		    &va);
16597c478bd9Sstevel@tonic-gate 		if (error)
16607c478bd9Sstevel@tonic-gate 			goto out;
16617c478bd9Sstevel@tonic-gate 		va.va_mask |= AT_TYPE;
16627c478bd9Sstevel@tonic-gate 		va.va_type = VREG;
16637c478bd9Sstevel@tonic-gate 		if (args->how.mode == GUARDED)
16647c478bd9Sstevel@tonic-gate 			excl = EXCL;
16657c478bd9Sstevel@tonic-gate 		else {
16667c478bd9Sstevel@tonic-gate 			excl = NONEXCL;
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 			/*
16697c478bd9Sstevel@tonic-gate 			 * During creation of file in non-exclusive mode
16707c478bd9Sstevel@tonic-gate 			 * if size of file is being set then make sure
16717c478bd9Sstevel@tonic-gate 			 * that if the file already exists that no conflicting
16727c478bd9Sstevel@tonic-gate 			 * non-blocking mandatory locks exists in the region
16737c478bd9Sstevel@tonic-gate 			 * being modified. If there are conflicting locks fail
16747c478bd9Sstevel@tonic-gate 			 * the operation with EACCES.
16757c478bd9Sstevel@tonic-gate 			 */
16767c478bd9Sstevel@tonic-gate 			if (va.va_mask & AT_SIZE) {
16777c478bd9Sstevel@tonic-gate 				struct vattr tva;
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 				/*
16807c478bd9Sstevel@tonic-gate 				 * Does file already exist?
16817c478bd9Sstevel@tonic-gate 				 */
1682b89a8333Snatalie li - Sun Microsystems - Irvine United States 				error = VOP_LOOKUP(dvp, name, &tvp,
1683cfae96c2Sjwahlig 				    NULL, 0, NULL, cr, NULL, NULL, NULL);
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 				/*
16867c478bd9Sstevel@tonic-gate 				 * Check to see if the file has been delegated
16877c478bd9Sstevel@tonic-gate 				 * to a v4 client.  If so, then begin recall of
16887c478bd9Sstevel@tonic-gate 				 * the delegation and return JUKEBOX to allow
16897c478bd9Sstevel@tonic-gate 				 * the client to retrasmit its request.
16907c478bd9Sstevel@tonic-gate 				 */
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 				trunc = va.va_size == 0;
16937c478bd9Sstevel@tonic-gate 				if (!error &&
16947c478bd9Sstevel@tonic-gate 				    rfs4_check_delegated(FWRITE, tvp, trunc)) {
16957c478bd9Sstevel@tonic-gate 					resp->status = NFS3ERR_JUKEBOX;
16967c478bd9Sstevel@tonic-gate 					goto out1;
16977c478bd9Sstevel@tonic-gate 				}
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 				/*
17007c478bd9Sstevel@tonic-gate 				 * Check for NBMAND lock conflicts
17017c478bd9Sstevel@tonic-gate 				 */
17027c478bd9Sstevel@tonic-gate 				if (!error && nbl_need_check(tvp)) {
17037c478bd9Sstevel@tonic-gate 					u_offset_t offset;
17047c478bd9Sstevel@tonic-gate 					ssize_t len;
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate 					nbl_start_crit(tvp, RW_READER);
17077c478bd9Sstevel@tonic-gate 					in_crit = 1;
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 					tva.va_mask = AT_SIZE;
1710da6c28aaSamw 					error = VOP_GETATTR(tvp, &tva, 0, cr,
1711cfae96c2Sjwahlig 					    NULL);
17127c478bd9Sstevel@tonic-gate 					/*
17137c478bd9Sstevel@tonic-gate 					 * Can't check for conflicts, so return
17147c478bd9Sstevel@tonic-gate 					 * error.
17157c478bd9Sstevel@tonic-gate 					 */
17167c478bd9Sstevel@tonic-gate 					if (error)
17177c478bd9Sstevel@tonic-gate 						goto out;
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 					offset = tva.va_size < va.va_size ?
1720cfae96c2Sjwahlig 					    tva.va_size : va.va_size;
17217c478bd9Sstevel@tonic-gate 					len = tva.va_size < va.va_size ?
1722cfae96c2Sjwahlig 					    va.va_size - tva.va_size :
1723cfae96c2Sjwahlig 					    tva.va_size - va.va_size;
17247c478bd9Sstevel@tonic-gate 					if (nbl_conflict(tvp, NBL_WRITE,
1725cfae96c2Sjwahlig 					    offset, len, 0, NULL)) {
17267c478bd9Sstevel@tonic-gate 						error = EACCES;
17277c478bd9Sstevel@tonic-gate 						goto out;
17287c478bd9Sstevel@tonic-gate 					}
17297c478bd9Sstevel@tonic-gate 				} else if (tvp) {
17307c478bd9Sstevel@tonic-gate 					VN_RELE(tvp);
17317c478bd9Sstevel@tonic-gate 					tvp = NULL;
17327c478bd9Sstevel@tonic-gate 				}
17337c478bd9Sstevel@tonic-gate 			}
17347c478bd9Sstevel@tonic-gate 		}
17357c478bd9Sstevel@tonic-gate 		if (va.va_mask & AT_SIZE)
17367c478bd9Sstevel@tonic-gate 			reqsize = va.va_size;
17377c478bd9Sstevel@tonic-gate 	}
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	/*
17407c478bd9Sstevel@tonic-gate 	 * Must specify the mode.
17417c478bd9Sstevel@tonic-gate 	 */
17427c478bd9Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
17437c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
17447c478bd9Sstevel@tonic-gate 		goto out1;
17457c478bd9Sstevel@tonic-gate 	}
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	/*
17487c478bd9Sstevel@tonic-gate 	 * If the filesystem is exported with nosuid, then mask off
17497c478bd9Sstevel@tonic-gate 	 * the setuid and setgid bits.
17507c478bd9Sstevel@tonic-gate 	 */
17517c478bd9Sstevel@tonic-gate 	if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
17527c478bd9Sstevel@tonic-gate 		va.va_mode &= ~(VSUID | VSGID);
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate tryagain:
17557c478bd9Sstevel@tonic-gate 	/*
17567c478bd9Sstevel@tonic-gate 	 * The file open mode used is VWRITE.  If the client needs
17577c478bd9Sstevel@tonic-gate 	 * some other semantic, then it should do the access checking
17587c478bd9Sstevel@tonic-gate 	 * itself.  It would have been nice to have the file open mode
17597c478bd9Sstevel@tonic-gate 	 * passed as part of the arguments.
17607c478bd9Sstevel@tonic-gate 	 */
1761b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
1762da6c28aaSamw 	    &vp, cr, 0, NULL, NULL);
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
1765da6c28aaSamw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	if (error) {
17687c478bd9Sstevel@tonic-gate 		/*
17697c478bd9Sstevel@tonic-gate 		 * If we got something other than file already exists
17707c478bd9Sstevel@tonic-gate 		 * then just return this error.  Otherwise, we got
17717c478bd9Sstevel@tonic-gate 		 * EEXIST.  If we were doing a GUARDED create, then
17727c478bd9Sstevel@tonic-gate 		 * just return this error.  Otherwise, we need to
17737c478bd9Sstevel@tonic-gate 		 * make sure that this wasn't a duplicate of an
17747c478bd9Sstevel@tonic-gate 		 * exclusive create request.
17757c478bd9Sstevel@tonic-gate 		 *
17767c478bd9Sstevel@tonic-gate 		 * The assumption is made that a non-exclusive create
17777c478bd9Sstevel@tonic-gate 		 * request will never return EEXIST.
17787c478bd9Sstevel@tonic-gate 		 */
17797c478bd9Sstevel@tonic-gate 		if (error != EEXIST || args->how.mode == GUARDED)
17807c478bd9Sstevel@tonic-gate 			goto out;
17817c478bd9Sstevel@tonic-gate 		/*
17827c478bd9Sstevel@tonic-gate 		 * Lookup the file so that we can get a vnode for it.
17837c478bd9Sstevel@tonic-gate 		 */
1784b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
1785da6c28aaSamw 		    NULL, cr, NULL, NULL, NULL);
17867c478bd9Sstevel@tonic-gate 		if (error) {
17877c478bd9Sstevel@tonic-gate 			/*
17887c478bd9Sstevel@tonic-gate 			 * We couldn't find the file that we thought that
17897c478bd9Sstevel@tonic-gate 			 * we just created.  So, we'll just try creating
17907c478bd9Sstevel@tonic-gate 			 * it again.
17917c478bd9Sstevel@tonic-gate 			 */
17927c478bd9Sstevel@tonic-gate 			if (error == ENOENT)
17937c478bd9Sstevel@tonic-gate 				goto tryagain;
17947c478bd9Sstevel@tonic-gate 			goto out;
17957c478bd9Sstevel@tonic-gate 		}
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 		/*
17987c478bd9Sstevel@tonic-gate 		 * If the file is delegated to a v4 client, go ahead
17997c478bd9Sstevel@tonic-gate 		 * and initiate recall, this create is a hint that a
18007c478bd9Sstevel@tonic-gate 		 * conflicting v3 open has occurred.
18017c478bd9Sstevel@tonic-gate 		 */
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 		if (rfs4_check_delegated(FWRITE, vp, FALSE)) {
18047c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
18057c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
18067c478bd9Sstevel@tonic-gate 			goto out1;
18077c478bd9Sstevel@tonic-gate 		}
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 		va.va_mask = AT_ALL;
1810da6c28aaSamw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
18137c478bd9Sstevel@tonic-gate 		/* % with INT32_MAX to prevent overflows */
18147c478bd9Sstevel@tonic-gate 		if (args->how.mode == EXCLUSIVE && (vap == NULL ||
18157c478bd9Sstevel@tonic-gate 		    vap->va_mtime.tv_sec !=
18167c478bd9Sstevel@tonic-gate 		    (mtime->seconds % INT32_MAX) ||
18177c478bd9Sstevel@tonic-gate 		    vap->va_mtime.tv_nsec != mtime->nseconds)) {
18187c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
18197c478bd9Sstevel@tonic-gate 			error = EEXIST;
18207c478bd9Sstevel@tonic-gate 			goto out;
18217c478bd9Sstevel@tonic-gate 		}
18227c478bd9Sstevel@tonic-gate 	} else {
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 		if ((args->how.mode == UNCHECKED ||
18257c478bd9Sstevel@tonic-gate 		    args->how.mode == GUARDED) &&
18267c478bd9Sstevel@tonic-gate 		    args->how.createhow3_u.obj_attributes.size.set_it &&
18277c478bd9Sstevel@tonic-gate 		    va.va_size == 0)
18287c478bd9Sstevel@tonic-gate 			trunc = TRUE;
18297c478bd9Sstevel@tonic-gate 		else
18307c478bd9Sstevel@tonic-gate 			trunc = FALSE;
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 		if (rfs4_check_delegated(FWRITE, vp, trunc)) {
18337c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
18347c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
18357c478bd9Sstevel@tonic-gate 			goto out1;
18367c478bd9Sstevel@tonic-gate 		}
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 		va.va_mask = AT_ALL;
1839da6c28aaSamw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 		/*
18427c478bd9Sstevel@tonic-gate 		 * We need to check to make sure that the file got
18437c478bd9Sstevel@tonic-gate 		 * created to the indicated size.  If not, we do a
18447c478bd9Sstevel@tonic-gate 		 * setattr to try to change the size, but we don't
18457c478bd9Sstevel@tonic-gate 		 * try too hard.  This shouldn't a problem as most
18467c478bd9Sstevel@tonic-gate 		 * clients will only specifiy a size of zero which
18477c478bd9Sstevel@tonic-gate 		 * local file systems handle.  However, even if
18487c478bd9Sstevel@tonic-gate 		 * the client does specify a non-zero size, it can
18497c478bd9Sstevel@tonic-gate 		 * still recover by checking the size of the file
18507c478bd9Sstevel@tonic-gate 		 * after it has created it and then issue a setattr
18517c478bd9Sstevel@tonic-gate 		 * request of its own to set the size of the file.
18527c478bd9Sstevel@tonic-gate 		 */
18537c478bd9Sstevel@tonic-gate 		if (vap != NULL &&
18547c478bd9Sstevel@tonic-gate 		    (args->how.mode == UNCHECKED ||
18557c478bd9Sstevel@tonic-gate 		    args->how.mode == GUARDED) &&
18567c478bd9Sstevel@tonic-gate 		    args->how.createhow3_u.obj_attributes.size.set_it &&
18577c478bd9Sstevel@tonic-gate 		    vap->va_size != reqsize) {
18587c478bd9Sstevel@tonic-gate 			va.va_mask = AT_SIZE;
18597c478bd9Sstevel@tonic-gate 			va.va_size = reqsize;
18607c478bd9Sstevel@tonic-gate 			(void) VOP_SETATTR(vp, &va, 0, cr, NULL);
18617c478bd9Sstevel@tonic-gate 			va.va_mask = AT_ALL;
1862da6c28aaSamw 			vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
18637c478bd9Sstevel@tonic-gate 		}
18647c478bd9Sstevel@tonic-gate 	}
18657c478bd9Sstevel@tonic-gate 
1866b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->where.name)
1867b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
1868b89a8333Snatalie li - Sun Microsystems - Irvine United States 
18697c478bd9Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
18707c478bd9Sstevel@tonic-gate 	if (error)
18717c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
18727c478bd9Sstevel@tonic-gate 	else
18737c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	/*
18767c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
18777c478bd9Sstevel@tonic-gate 	 */
1878da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1879da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
18827c478bd9Sstevel@tonic-gate 	if (tvp != NULL) {
18837c478bd9Sstevel@tonic-gate 		if (in_crit)
18847c478bd9Sstevel@tonic-gate 			nbl_end_crit(tvp);
18857c478bd9Sstevel@tonic-gate 		VN_RELE(tvp);
18867c478bd9Sstevel@tonic-gate 	}
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
18897c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
18907c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1891e1adf50cSahl 
18920dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
18930dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
18940dfe541eSEvan Layton 	    CREATE3res *, resp);
1895e1adf50cSahl 
1896e1adf50cSahl 	VN_RELE(dvp);
18977c478bd9Sstevel@tonic-gate 	return;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate out:
19007c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
19017c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
19027c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
19037c478bd9Sstevel@tonic-gate 	} else
19047c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
19057c478bd9Sstevel@tonic-gate out1:
19060dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
19070dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
19080dfe541eSEvan Layton 	    CREATE3res *, resp);
1909e1adf50cSahl 
1910b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->where.name)
1911b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
1912b89a8333Snatalie li - Sun Microsystems - Irvine United States 
19137c478bd9Sstevel@tonic-gate 	if (tvp != NULL) {
19147c478bd9Sstevel@tonic-gate 		if (in_crit)
19157c478bd9Sstevel@tonic-gate 			nbl_end_crit(tvp);
19167c478bd9Sstevel@tonic-gate 		VN_RELE(tvp);
19177c478bd9Sstevel@tonic-gate 	}
19187c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
19197c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
19207c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
19217c478bd9Sstevel@tonic-gate }
19227c478bd9Sstevel@tonic-gate 
192327242a7cSthurlow void *
rfs3_create_getfh(CREATE3args * args)19247c478bd9Sstevel@tonic-gate rfs3_create_getfh(CREATE3args *args)
19257c478bd9Sstevel@tonic-gate {
19267c478bd9Sstevel@tonic-gate 
192727242a7cSthurlow 	return (&args->where.dir);
19287c478bd9Sstevel@tonic-gate }
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate void
rfs3_mkdir(MKDIR3args * args,MKDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)19317c478bd9Sstevel@tonic-gate rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
19325cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
19337c478bd9Sstevel@tonic-gate {
19347c478bd9Sstevel@tonic-gate 	int error;
19357c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
19367c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
19377c478bd9Sstevel@tonic-gate 	struct vattr *vap;
19387c478bd9Sstevel@tonic-gate 	struct vattr va;
19397c478bd9Sstevel@tonic-gate 	struct vattr *dbvap;
19407c478bd9Sstevel@tonic-gate 	struct vattr dbva;
19417c478bd9Sstevel@tonic-gate 	struct vattr *davap;
19427c478bd9Sstevel@tonic-gate 	struct vattr dava;
1943b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
1944b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	dbvap = NULL;
19477c478bd9Sstevel@tonic-gate 	davap = NULL;
19487c478bd9Sstevel@tonic-gate 
194927242a7cSthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
1950e1adf50cSahl 
19510dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req,
19520dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
19530dfe541eSEvan Layton 	    MKDIR3args *, args);
1954e1adf50cSahl 
19557c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
19567c478bd9Sstevel@tonic-gate 		error = ESTALE;
19577c478bd9Sstevel@tonic-gate 		goto out;
19587c478bd9Sstevel@tonic-gate 	}
19597c478bd9Sstevel@tonic-gate 
19607c478bd9Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
1961da6c28aaSamw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
19627c478bd9Sstevel@tonic-gate 	davap = dbvap;
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
19657c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
19667c478bd9Sstevel@tonic-gate 		goto out1;
19677c478bd9Sstevel@tonic-gate 	}
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
19707c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
19717c478bd9Sstevel@tonic-gate 		goto out1;
19727c478bd9Sstevel@tonic-gate 	}
19737c478bd9Sstevel@tonic-gate 
19745cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
19757c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
19767c478bd9Sstevel@tonic-gate 		goto out1;
19777c478bd9Sstevel@tonic-gate 	}
19787c478bd9Sstevel@tonic-gate 
197903986916Sjarrett 	if (is_system_labeled()) {
198003986916Sjarrett 		bslabel_t *clabel = req->rq_label;
198103986916Sjarrett 
198203986916Sjarrett 		ASSERT(clabel != NULL);
198303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
198403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
198503986916Sjarrett 
198603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1987bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1988bd6f1640SJarrett Lu 			    exi)) {
198903986916Sjarrett 				resp->status = NFS3ERR_ACCES;
199003986916Sjarrett 				goto out1;
199103986916Sjarrett 			}
199203986916Sjarrett 		}
199303986916Sjarrett 	}
199403986916Sjarrett 
19957c478bd9Sstevel@tonic-gate 	error = sattr3_to_vattr(&args->attributes, &va);
19967c478bd9Sstevel@tonic-gate 	if (error)
19977c478bd9Sstevel@tonic-gate 		goto out;
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
20007c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
20017c478bd9Sstevel@tonic-gate 		goto out1;
20027c478bd9Sstevel@tonic-gate 	}
20037c478bd9Sstevel@tonic-gate 
2004b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2005b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->where.name,
2006b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2007b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2008b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2009b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2010b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
2011b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2012b89a8333Snatalie li - Sun Microsystems - Irvine United States 
20137c478bd9Sstevel@tonic-gate 	va.va_mask |= AT_TYPE;
20147c478bd9Sstevel@tonic-gate 	va.va_type = VDIR;
20157c478bd9Sstevel@tonic-gate 
2016b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
2017b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2018b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->where.name)
2019b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
2022da6c28aaSamw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	/*
20257c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
20267c478bd9Sstevel@tonic-gate 	 */
2027da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
20287c478bd9Sstevel@tonic-gate 
20297c478bd9Sstevel@tonic-gate 	if (error)
20307c478bd9Sstevel@tonic-gate 		goto out;
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
20337c478bd9Sstevel@tonic-gate 	if (error)
20347c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
20357c478bd9Sstevel@tonic-gate 	else
20367c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2039da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate 	/*
20427c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
20437c478bd9Sstevel@tonic-gate 	 */
2044da6c28aaSamw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
20497c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
20507c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2051e1adf50cSahl 
20520dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
20530dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
20540dfe541eSEvan Layton 	    MKDIR3res *, resp);
2055e1adf50cSahl 	VN_RELE(dvp);
2056e1adf50cSahl 
20577c478bd9Sstevel@tonic-gate 	return;
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate out:
20607c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
20617c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
20627c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
20637c478bd9Sstevel@tonic-gate 	} else
20647c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
20657c478bd9Sstevel@tonic-gate out1:
20660dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
20670dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
20680dfe541eSEvan Layton 	    MKDIR3res *, resp);
20697c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
20707c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
20717c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate 
207427242a7cSthurlow void *
rfs3_mkdir_getfh(MKDIR3args * args)20757c478bd9Sstevel@tonic-gate rfs3_mkdir_getfh(MKDIR3args *args)
20767c478bd9Sstevel@tonic-gate {
20777c478bd9Sstevel@tonic-gate 
207827242a7cSthurlow 	return (&args->where.dir);
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate void
rfs3_symlink(SYMLINK3args * args,SYMLINK3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)20827c478bd9Sstevel@tonic-gate rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
20835cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
20847c478bd9Sstevel@tonic-gate {
20857c478bd9Sstevel@tonic-gate 	int error;
20867c478bd9Sstevel@tonic-gate 	vnode_t *vp;
20877c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
20887c478bd9Sstevel@tonic-gate 	struct vattr *vap;
20897c478bd9Sstevel@tonic-gate 	struct vattr va;
20907c478bd9Sstevel@tonic-gate 	struct vattr *dbvap;
20917c478bd9Sstevel@tonic-gate 	struct vattr dbva;
20927c478bd9Sstevel@tonic-gate 	struct vattr *davap;
20937c478bd9Sstevel@tonic-gate 	struct vattr dava;
2094b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2095b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
2096b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *symdata = NULL;
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate 	dbvap = NULL;
20997c478bd9Sstevel@tonic-gate 	davap = NULL;
21007c478bd9Sstevel@tonic-gate 
210127242a7cSthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
2102e1adf50cSahl 
21030dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req,
21040dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
21050dfe541eSEvan Layton 	    SYMLINK3args *, args);
2106e1adf50cSahl 
21077c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
21087c478bd9Sstevel@tonic-gate 		error = ESTALE;
2109e1adf50cSahl 		goto err;
21107c478bd9Sstevel@tonic-gate 	}
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
2113da6c28aaSamw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
21147c478bd9Sstevel@tonic-gate 	davap = dbvap;
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
21177c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2118e1adf50cSahl 		goto err1;
21197c478bd9Sstevel@tonic-gate 	}
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
21227c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2123e1adf50cSahl 		goto err1;
21247c478bd9Sstevel@tonic-gate 	}
21257c478bd9Sstevel@tonic-gate 
21265cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
21277c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2128e1adf50cSahl 		goto err1;
21297c478bd9Sstevel@tonic-gate 	}
21307c478bd9Sstevel@tonic-gate 
213103986916Sjarrett 	if (is_system_labeled()) {
213203986916Sjarrett 		bslabel_t *clabel = req->rq_label;
213303986916Sjarrett 
213403986916Sjarrett 		ASSERT(clabel != NULL);
213503986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
213603986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
213703986916Sjarrett 
213803986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2139bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2140bd6f1640SJarrett Lu 			    exi)) {
214103986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2142e1adf50cSahl 				goto err1;
214303986916Sjarrett 			}
214403986916Sjarrett 		}
214503986916Sjarrett 	}
214603986916Sjarrett 
21477c478bd9Sstevel@tonic-gate 	error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
21487c478bd9Sstevel@tonic-gate 	if (error)
2149e1adf50cSahl 		goto err;
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
21527c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
2153e1adf50cSahl 		goto err1;
21547c478bd9Sstevel@tonic-gate 	}
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 	if (args->symlink.symlink_data == nfs3nametoolong) {
21577c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2158e1adf50cSahl 		goto err1;
21597c478bd9Sstevel@tonic-gate 	}
21607c478bd9Sstevel@tonic-gate 
2161b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2162b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->where.name,
2163b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2164b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2165b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2166b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/* This is really a Solaris EILSEQ */
2167b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2168b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2169b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2170b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2171b89a8333Snatalie li - Sun Microsystems - Irvine United States 	symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
2172b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2173b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (symdata == NULL) {
2174b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/* This is really a Solaris EILSEQ */
2175b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2176b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2177b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2178b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2179b89a8333Snatalie li - Sun Microsystems - Irvine United States 
21807c478bd9Sstevel@tonic-gate 	va.va_mask |= AT_TYPE;
21817c478bd9Sstevel@tonic-gate 	va.va_type = VLNK;
21827c478bd9Sstevel@tonic-gate 
2183b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
2186da6c28aaSamw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 	if (error)
2189e1adf50cSahl 		goto err;
21907c478bd9Sstevel@tonic-gate 
2191b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
2192cfae96c2Sjwahlig 	    NULL, NULL, NULL);
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate 	/*
21957c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
21967c478bd9Sstevel@tonic-gate 	 */
2197da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
22017c478bd9Sstevel@tonic-gate 	if (error) {
22027c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
22037c478bd9Sstevel@tonic-gate 		vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
22047c478bd9Sstevel@tonic-gate 		vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2205e1adf50cSahl 		goto out;
22067c478bd9Sstevel@tonic-gate 	}
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
22097c478bd9Sstevel@tonic-gate 	if (error)
22107c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
22117c478bd9Sstevel@tonic-gate 	else
22127c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2215da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	/*
22187c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
22197c478bd9Sstevel@tonic-gate 	 */
2220da6c28aaSamw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
22257c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2226e1adf50cSahl 	goto out;
22277c478bd9Sstevel@tonic-gate 
2228e1adf50cSahl err:
22297c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
22307c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
22317c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
22327c478bd9Sstevel@tonic-gate 	} else
22337c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
2234e1adf50cSahl err1:
2235e1adf50cSahl 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2236e1adf50cSahl out:
2237b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->where.name)
2238b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
2239b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (symdata != NULL && symdata != args->symlink.symlink_data)
2240b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(symdata, MAXPATHLEN + 1);
2241b89a8333Snatalie li - Sun Microsystems - Irvine United States 
22420dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req,
22430dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
22440dfe541eSEvan Layton 	    SYMLINK3res *, resp);
2245e1adf50cSahl 
22467c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
22477c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
22487c478bd9Sstevel@tonic-gate }
22497c478bd9Sstevel@tonic-gate 
225027242a7cSthurlow void *
rfs3_symlink_getfh(SYMLINK3args * args)22517c478bd9Sstevel@tonic-gate rfs3_symlink_getfh(SYMLINK3args *args)
22527c478bd9Sstevel@tonic-gate {
22537c478bd9Sstevel@tonic-gate 
225427242a7cSthurlow 	return (&args->where.dir);
22557c478bd9Sstevel@tonic-gate }
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate void
rfs3_mknod(MKNOD3args * args,MKNOD3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)22587c478bd9Sstevel@tonic-gate rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
22595cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
22607c478bd9Sstevel@tonic-gate {
22617c478bd9Sstevel@tonic-gate 	int error;
22627c478bd9Sstevel@tonic-gate 	vnode_t *vp;
2263fd7da618Sgt 	vnode_t *realvp;
22647c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
22657c478bd9Sstevel@tonic-gate 	struct vattr *vap;
22667c478bd9Sstevel@tonic-gate 	struct vattr va;
22677c478bd9Sstevel@tonic-gate 	struct vattr *dbvap;
22687c478bd9Sstevel@tonic-gate 	struct vattr dbva;
22697c478bd9Sstevel@tonic-gate 	struct vattr *davap;
22707c478bd9Sstevel@tonic-gate 	struct vattr dava;
22717c478bd9Sstevel@tonic-gate 	int mode;
22727c478bd9Sstevel@tonic-gate 	enum vcexcl excl;
2273b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2274b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate 	dbvap = NULL;
22777c478bd9Sstevel@tonic-gate 	davap = NULL;
22787c478bd9Sstevel@tonic-gate 
227927242a7cSthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
2280e1adf50cSahl 
22810dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req,
22820dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
22830dfe541eSEvan Layton 	    MKNOD3args *, args);
2284e1adf50cSahl 
22857c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
22867c478bd9Sstevel@tonic-gate 		error = ESTALE;
22877c478bd9Sstevel@tonic-gate 		goto out;
22887c478bd9Sstevel@tonic-gate 	}
22897c478bd9Sstevel@tonic-gate 
22907c478bd9Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
2291da6c28aaSamw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
22927c478bd9Sstevel@tonic-gate 	davap = dbvap;
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
22957c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
22967c478bd9Sstevel@tonic-gate 		goto out1;
22977c478bd9Sstevel@tonic-gate 	}
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
23007c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
23017c478bd9Sstevel@tonic-gate 		goto out1;
23027c478bd9Sstevel@tonic-gate 	}
23037c478bd9Sstevel@tonic-gate 
23045cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
23057c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
23067c478bd9Sstevel@tonic-gate 		goto out1;
23077c478bd9Sstevel@tonic-gate 	}
23087c478bd9Sstevel@tonic-gate 
230903986916Sjarrett 	if (is_system_labeled()) {
231003986916Sjarrett 		bslabel_t *clabel = req->rq_label;
231103986916Sjarrett 
231203986916Sjarrett 		ASSERT(clabel != NULL);
231303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
231403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
231503986916Sjarrett 
231603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2317bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2318bd6f1640SJarrett Lu 			    exi)) {
231903986916Sjarrett 				resp->status = NFS3ERR_ACCES;
232003986916Sjarrett 				goto out1;
232103986916Sjarrett 			}
232203986916Sjarrett 		}
232303986916Sjarrett 	}
232403986916Sjarrett 
23257c478bd9Sstevel@tonic-gate 	switch (args->what.type) {
23267c478bd9Sstevel@tonic-gate 	case NF3CHR:
23277c478bd9Sstevel@tonic-gate 	case NF3BLK:
23287c478bd9Sstevel@tonic-gate 		error = sattr3_to_vattr(
23297c478bd9Sstevel@tonic-gate 		    &args->what.mknoddata3_u.device.dev_attributes, &va);
23307c478bd9Sstevel@tonic-gate 		if (error)
23317c478bd9Sstevel@tonic-gate 			goto out;
23327c478bd9Sstevel@tonic-gate 		if (secpolicy_sys_devices(cr) != 0) {
23337c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_PERM;
23347c478bd9Sstevel@tonic-gate 			goto out1;
23357c478bd9Sstevel@tonic-gate 		}
23367c478bd9Sstevel@tonic-gate 		if (args->what.type == NF3CHR)
23377c478bd9Sstevel@tonic-gate 			va.va_type = VCHR;
23387c478bd9Sstevel@tonic-gate 		else
23397c478bd9Sstevel@tonic-gate 			va.va_type = VBLK;
23407c478bd9Sstevel@tonic-gate 		va.va_rdev = makedevice(
23417c478bd9Sstevel@tonic-gate 		    args->what.mknoddata3_u.device.spec.specdata1,
23427c478bd9Sstevel@tonic-gate 		    args->what.mknoddata3_u.device.spec.specdata2);
23437c478bd9Sstevel@tonic-gate 		va.va_mask |= AT_TYPE | AT_RDEV;
23447c478bd9Sstevel@tonic-gate 		break;
23457c478bd9Sstevel@tonic-gate 	case NF3SOCK:
23467c478bd9Sstevel@tonic-gate 		error = sattr3_to_vattr(
23477c478bd9Sstevel@tonic-gate 		    &args->what.mknoddata3_u.pipe_attributes, &va);
23487c478bd9Sstevel@tonic-gate 		if (error)
23497c478bd9Sstevel@tonic-gate 			goto out;
23507c478bd9Sstevel@tonic-gate 		va.va_type = VSOCK;
23517c478bd9Sstevel@tonic-gate 		va.va_mask |= AT_TYPE;
23527c478bd9Sstevel@tonic-gate 		break;
23537c478bd9Sstevel@tonic-gate 	case NF3FIFO:
23547c478bd9Sstevel@tonic-gate 		error = sattr3_to_vattr(
23557c478bd9Sstevel@tonic-gate 		    &args->what.mknoddata3_u.pipe_attributes, &va);
23567c478bd9Sstevel@tonic-gate 		if (error)
23577c478bd9Sstevel@tonic-gate 			goto out;
23587c478bd9Sstevel@tonic-gate 		va.va_type = VFIFO;
23597c478bd9Sstevel@tonic-gate 		va.va_mask |= AT_TYPE;
23607c478bd9Sstevel@tonic-gate 		break;
23617c478bd9Sstevel@tonic-gate 	default:
23627c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_BADTYPE;
23637c478bd9Sstevel@tonic-gate 		goto out1;
23647c478bd9Sstevel@tonic-gate 	}
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate 	/*
23677c478bd9Sstevel@tonic-gate 	 * Must specify the mode.
23687c478bd9Sstevel@tonic-gate 	 */
23697c478bd9Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
23707c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
23717c478bd9Sstevel@tonic-gate 		goto out1;
23727c478bd9Sstevel@tonic-gate 	}
23737c478bd9Sstevel@tonic-gate 
2374b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2375b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->where.name,
2376b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2377b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2378b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2379b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2380b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
2381b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2382b89a8333Snatalie li - Sun Microsystems - Irvine United States 
23837c478bd9Sstevel@tonic-gate 	excl = EXCL;
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 	mode = 0;
23867c478bd9Sstevel@tonic-gate 
2387b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_CREATE(dvp, name, &va, excl, mode,
2388da6c28aaSamw 	    &vp, cr, 0, NULL, NULL);
23897c478bd9Sstevel@tonic-gate 
2390b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->where.name)
2391b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
2392b89a8333Snatalie li - Sun Microsystems - Irvine United States 
23937c478bd9Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
2394da6c28aaSamw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate 	/*
23977c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
23987c478bd9Sstevel@tonic-gate 	 */
2399da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate 	if (error)
24027c478bd9Sstevel@tonic-gate 		goto out;
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
24077c478bd9Sstevel@tonic-gate 	if (error)
24087c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
24097c478bd9Sstevel@tonic-gate 	else
24107c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2413da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate 	/*
24167c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
2417fd7da618Sgt 	 *
2418fd7da618Sgt 	 * if a underlying vp exists, pass it to VOP_FSYNC
24197c478bd9Sstevel@tonic-gate 	 */
2420fd7da618Sgt 	if (VOP_REALVP(vp, &realvp, NULL) == 0)
2421fd7da618Sgt 		(void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2422fd7da618Sgt 	else
2423fd7da618Sgt 		(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
24287c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
24290dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
24300dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
24310dfe541eSEvan Layton 	    MKNOD3res *, resp);
2432e1adf50cSahl 	VN_RELE(dvp);
24337c478bd9Sstevel@tonic-gate 	return;
24347c478bd9Sstevel@tonic-gate 
24357c478bd9Sstevel@tonic-gate out:
24367c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
24377c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
24387c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
24397c478bd9Sstevel@tonic-gate 	} else
24407c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
24417c478bd9Sstevel@tonic-gate out1:
24420dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
24430dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
24440dfe541eSEvan Layton 	    MKNOD3res *, resp);
24457c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
24467c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
24477c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
24487c478bd9Sstevel@tonic-gate }
24497c478bd9Sstevel@tonic-gate 
245027242a7cSthurlow void *
rfs3_mknod_getfh(MKNOD3args * args)24517c478bd9Sstevel@tonic-gate rfs3_mknod_getfh(MKNOD3args *args)
24527c478bd9Sstevel@tonic-gate {
24537c478bd9Sstevel@tonic-gate 
245427242a7cSthurlow 	return (&args->where.dir);
24557c478bd9Sstevel@tonic-gate }
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate void
rfs3_remove(REMOVE3args * args,REMOVE3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)24587c478bd9Sstevel@tonic-gate rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
24595cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
24607c478bd9Sstevel@tonic-gate {
24617c478bd9Sstevel@tonic-gate 	int error = 0;
24627c478bd9Sstevel@tonic-gate 	vnode_t *vp;
24637c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
24647c478bd9Sstevel@tonic-gate 	struct vattr bva;
24657c478bd9Sstevel@tonic-gate 	struct vattr *avap;
24667c478bd9Sstevel@tonic-gate 	struct vattr ava;
24677c478bd9Sstevel@tonic-gate 	vnode_t *targvp = NULL;
2468b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2469b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate 	bvap = NULL;
24727c478bd9Sstevel@tonic-gate 	avap = NULL;
24737c478bd9Sstevel@tonic-gate 
247427242a7cSthurlow 	vp = nfs3_fhtovp(&args->object.dir, exi);
2475e1adf50cSahl 
24760dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req,
24770dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
24780dfe541eSEvan Layton 	    REMOVE3args *, args);
2479e1adf50cSahl 
24807c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
24817c478bd9Sstevel@tonic-gate 		error = ESTALE;
2482e1adf50cSahl 		goto err;
24837c478bd9Sstevel@tonic-gate 	}
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
2486da6c28aaSamw 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
24877c478bd9Sstevel@tonic-gate 	avap = bvap;
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
24907c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
2491e1adf50cSahl 		goto err1;
24927c478bd9Sstevel@tonic-gate 	}
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate 	if (args->object.name == nfs3nametoolong) {
24957c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2496e1adf50cSahl 		goto err1;
24977c478bd9Sstevel@tonic-gate 	}
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 	if (args->object.name == NULL || *(args->object.name) == '\0') {
25007c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2501e1adf50cSahl 		goto err1;
25027c478bd9Sstevel@tonic-gate 	}
25037c478bd9Sstevel@tonic-gate 
25045cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
25057c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2506e1adf50cSahl 		goto err1;
25077c478bd9Sstevel@tonic-gate 	}
25087c478bd9Sstevel@tonic-gate 
250903986916Sjarrett 	if (is_system_labeled()) {
251003986916Sjarrett 		bslabel_t *clabel = req->rq_label;
251103986916Sjarrett 
251203986916Sjarrett 		ASSERT(clabel != NULL);
251303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *,
251403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
251503986916Sjarrett 
251603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2517bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2518bd6f1640SJarrett Lu 			    exi)) {
251903986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2520e1adf50cSahl 				goto err1;
252103986916Sjarrett 			}
252203986916Sjarrett 		}
252303986916Sjarrett 	}
252403986916Sjarrett 
2525b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2526b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->object.name,
2527b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2528b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2529b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2530b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2531b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2532b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2533b89a8333Snatalie li - Sun Microsystems - Irvine United States 
25347c478bd9Sstevel@tonic-gate 	/*
25357c478bd9Sstevel@tonic-gate 	 * Check for a conflict with a non-blocking mandatory share
25367c478bd9Sstevel@tonic-gate 	 * reservation and V4 delegations
25377c478bd9Sstevel@tonic-gate 	 */
2538b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_LOOKUP(vp, name, &targvp, NULL, 0,
2539cfae96c2Sjwahlig 	    NULL, cr, NULL, NULL, NULL);
25407c478bd9Sstevel@tonic-gate 	if (error != 0)
2541e1adf50cSahl 		goto err;
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 	if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
25447c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
2545e1adf50cSahl 		goto err1;
25467c478bd9Sstevel@tonic-gate 	}
25477c478bd9Sstevel@tonic-gate 
25487c478bd9Sstevel@tonic-gate 	if (!nbl_need_check(targvp)) {
2549b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = VOP_REMOVE(vp, name, cr, NULL, 0);
25507c478bd9Sstevel@tonic-gate 	} else {
25517c478bd9Sstevel@tonic-gate 		nbl_start_crit(targvp, RW_READER);
2552da6c28aaSamw 		if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
25537c478bd9Sstevel@tonic-gate 			error = EACCES;
25547c478bd9Sstevel@tonic-gate 		} else {
2555b89a8333Snatalie li - Sun Microsystems - Irvine United States 			error = VOP_REMOVE(vp, name, cr, NULL, 0);
25567c478bd9Sstevel@tonic-gate 		}
25577c478bd9Sstevel@tonic-gate 		nbl_end_crit(targvp);
25587c478bd9Sstevel@tonic-gate 	}
25597c478bd9Sstevel@tonic-gate 	VN_RELE(targvp);
25607c478bd9Sstevel@tonic-gate 	targvp = NULL;
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
2563da6c28aaSamw 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 	/*
25667c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
25677c478bd9Sstevel@tonic-gate 	 */
2568da6c28aaSamw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	if (error)
2571e1adf50cSahl 		goto err;
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
25747c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2575e1adf50cSahl 	goto out;
25767c478bd9Sstevel@tonic-gate 
2577e1adf50cSahl err:
25787c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
25797c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
25807c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
25817c478bd9Sstevel@tonic-gate 	} else
25827c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
2583e1adf50cSahl err1:
2584e1adf50cSahl 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2585e1adf50cSahl out:
25860dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req,
25870dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
25880dfe541eSEvan Layton 	    REMOVE3res *, resp);
2589b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2590b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->object.name)
2591b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
2592b89a8333Snatalie li - Sun Microsystems - Irvine United States 
25937c478bd9Sstevel@tonic-gate 	if (vp != NULL)
25947c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
25957c478bd9Sstevel@tonic-gate }
25967c478bd9Sstevel@tonic-gate 
259727242a7cSthurlow void *
rfs3_remove_getfh(REMOVE3args * args)25987c478bd9Sstevel@tonic-gate rfs3_remove_getfh(REMOVE3args *args)
25997c478bd9Sstevel@tonic-gate {
26007c478bd9Sstevel@tonic-gate 
260127242a7cSthurlow 	return (&args->object.dir);
26027c478bd9Sstevel@tonic-gate }
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate void
rfs3_rmdir(RMDIR3args * args,RMDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)26057c478bd9Sstevel@tonic-gate rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
26065cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
26077c478bd9Sstevel@tonic-gate {
26087c478bd9Sstevel@tonic-gate 	int error;
26097c478bd9Sstevel@tonic-gate 	vnode_t *vp;
26107c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
26117c478bd9Sstevel@tonic-gate 	struct vattr bva;
26127c478bd9Sstevel@tonic-gate 	struct vattr *avap;
26137c478bd9Sstevel@tonic-gate 	struct vattr ava;
2614b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2615b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	bvap = NULL;
26187c478bd9Sstevel@tonic-gate 	avap = NULL;
26197c478bd9Sstevel@tonic-gate 
262027242a7cSthurlow 	vp = nfs3_fhtovp(&args->object.dir, exi);
2621e1adf50cSahl 
26220dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req,
26230dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
26240dfe541eSEvan Layton 	    RMDIR3args *, args);
2625e1adf50cSahl 
26267c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
26277c478bd9Sstevel@tonic-gate 		error = ESTALE;
2628e1adf50cSahl 		goto err;
26297c478bd9Sstevel@tonic-gate 	}
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
2632da6c28aaSamw 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
26337c478bd9Sstevel@tonic-gate 	avap = bvap;
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
26367c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
2637e1adf50cSahl 		goto err1;
26387c478bd9Sstevel@tonic-gate 	}
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate 	if (args->object.name == nfs3nametoolong) {
26417c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2642e1adf50cSahl 		goto err1;
26437c478bd9Sstevel@tonic-gate 	}
26447c478bd9Sstevel@tonic-gate 
26457c478bd9Sstevel@tonic-gate 	if (args->object.name == NULL || *(args->object.name) == '\0') {
26467c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2647e1adf50cSahl 		goto err1;
26487c478bd9Sstevel@tonic-gate 	}
26497c478bd9Sstevel@tonic-gate 
26505cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
26517c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2652e1adf50cSahl 		goto err1;
26537c478bd9Sstevel@tonic-gate 	}
26547c478bd9Sstevel@tonic-gate 
265503986916Sjarrett 	if (is_system_labeled()) {
265603986916Sjarrett 		bslabel_t *clabel = req->rq_label;
265703986916Sjarrett 
265803986916Sjarrett 		ASSERT(clabel != NULL);
265903986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *,
266003986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
266103986916Sjarrett 
266203986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2663bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2664bd6f1640SJarrett Lu 			    exi)) {
266503986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2666e1adf50cSahl 				goto err1;
266703986916Sjarrett 			}
266803986916Sjarrett 		}
266903986916Sjarrett 	}
267003986916Sjarrett 
2671b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2672b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->object.name,
2673b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2674b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2675b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2676b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2677b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2678b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2679b89a8333Snatalie li - Sun Microsystems - Irvine United States 
26800dfe541eSEvan Layton 	ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
26810dfe541eSEvan Layton 	error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
2682b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2683b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->object.name)
2684b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
26857c478bd9Sstevel@tonic-gate 
26867c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
2687da6c28aaSamw 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
26887c478bd9Sstevel@tonic-gate 
26897c478bd9Sstevel@tonic-gate 	/*
26907c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
26917c478bd9Sstevel@tonic-gate 	 */
2692da6c28aaSamw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate 	if (error) {
26957c478bd9Sstevel@tonic-gate 		/*
26967c478bd9Sstevel@tonic-gate 		 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
26977c478bd9Sstevel@tonic-gate 		 * if the directory is not empty.  A System V NFS server
26987c478bd9Sstevel@tonic-gate 		 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
26997c478bd9Sstevel@tonic-gate 		 * over the wire.
27007c478bd9Sstevel@tonic-gate 		 */
27017c478bd9Sstevel@tonic-gate 		if (error == EEXIST)
27027c478bd9Sstevel@tonic-gate 			error = ENOTEMPTY;
2703e1adf50cSahl 		goto err;
27047c478bd9Sstevel@tonic-gate 	}
27057c478bd9Sstevel@tonic-gate 
27067c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
27077c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2708e1adf50cSahl 	goto out;
27097c478bd9Sstevel@tonic-gate 
2710e1adf50cSahl err:
27117c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
27127c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
27137c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
27147c478bd9Sstevel@tonic-gate 	} else
27157c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
2716e1adf50cSahl err1:
2717e1adf50cSahl 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2718e1adf50cSahl out:
27190dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req,
27200dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
27210dfe541eSEvan Layton 	    RMDIR3res *, resp);
27227c478bd9Sstevel@tonic-gate 	if (vp != NULL)
27237c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
2724e1adf50cSahl 
27257c478bd9Sstevel@tonic-gate }
27267c478bd9Sstevel@tonic-gate 
272727242a7cSthurlow void *
rfs3_rmdir_getfh(RMDIR3args * args)27287c478bd9Sstevel@tonic-gate rfs3_rmdir_getfh(RMDIR3args *args)
27297c478bd9Sstevel@tonic-gate {
27307c478bd9Sstevel@tonic-gate 
273127242a7cSthurlow 	return (&args->object.dir);
27327c478bd9Sstevel@tonic-gate }
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate void
rfs3_rename(RENAME3args * args,RENAME3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)27357c478bd9Sstevel@tonic-gate rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
27365cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
27377c478bd9Sstevel@tonic-gate {
27387c478bd9Sstevel@tonic-gate 	int error = 0;
27397c478bd9Sstevel@tonic-gate 	vnode_t *fvp;
27407c478bd9Sstevel@tonic-gate 	vnode_t *tvp;
27417c478bd9Sstevel@tonic-gate 	vnode_t *targvp;
27427c478bd9Sstevel@tonic-gate 	struct vattr *fbvap;
27437c478bd9Sstevel@tonic-gate 	struct vattr fbva;
27447c478bd9Sstevel@tonic-gate 	struct vattr *favap;
27457c478bd9Sstevel@tonic-gate 	struct vattr fava;
27467c478bd9Sstevel@tonic-gate 	struct vattr *tbvap;
27477c478bd9Sstevel@tonic-gate 	struct vattr tbva;
27487c478bd9Sstevel@tonic-gate 	struct vattr *tavap;
27497c478bd9Sstevel@tonic-gate 	struct vattr tava;
275027242a7cSthurlow 	nfs_fh3 *fh3;
27517c478bd9Sstevel@tonic-gate 	struct exportinfo *to_exi;
27527c478bd9Sstevel@tonic-gate 	vnode_t *srcvp = NULL;
275303986916Sjarrett 	bslabel_t *clabel;
2754b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2755b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
2756b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *toname = NULL;
27577c478bd9Sstevel@tonic-gate 
27587c478bd9Sstevel@tonic-gate 	fbvap = NULL;
27597c478bd9Sstevel@tonic-gate 	favap = NULL;
27607c478bd9Sstevel@tonic-gate 	tbvap = NULL;
27617c478bd9Sstevel@tonic-gate 	tavap = NULL;
27627c478bd9Sstevel@tonic-gate 	tvp = NULL;
27637c478bd9Sstevel@tonic-gate 
276427242a7cSthurlow 	fvp = nfs3_fhtovp(&args->from.dir, exi);
2765e1adf50cSahl 
27660dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req,
27670dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
27680dfe541eSEvan Layton 	    RENAME3args *, args);
2769e1adf50cSahl 
27707c478bd9Sstevel@tonic-gate 	if (fvp == NULL) {
27717c478bd9Sstevel@tonic-gate 		error = ESTALE;
2772e1adf50cSahl 		goto err;
27737c478bd9Sstevel@tonic-gate 	}
27747c478bd9Sstevel@tonic-gate 
277503986916Sjarrett 	if (is_system_labeled()) {
277603986916Sjarrett 		clabel = req->rq_label;
277703986916Sjarrett 		ASSERT(clabel != NULL);
277803986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
277903986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
278003986916Sjarrett 
278103986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2782bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2783bd6f1640SJarrett Lu 			    exi)) {
278403986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2785e1adf50cSahl 				goto err1;
278603986916Sjarrett 			}
278703986916Sjarrett 		}
278803986916Sjarrett 	}
278903986916Sjarrett 
27907c478bd9Sstevel@tonic-gate 	fbva.va_mask = AT_ALL;
2791da6c28aaSamw 	fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
27927c478bd9Sstevel@tonic-gate 	favap = fbvap;
27937c478bd9Sstevel@tonic-gate 
279427242a7cSthurlow 	fh3 = &args->to.dir;
279527242a7cSthurlow 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
27967c478bd9Sstevel@tonic-gate 	if (to_exi == NULL) {
27977c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2798e1adf50cSahl 		goto err1;
27997c478bd9Sstevel@tonic-gate 	}
28007c478bd9Sstevel@tonic-gate 	exi_rele(to_exi);
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate 	if (to_exi != exi) {
28037c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_XDEV;
2804e1adf50cSahl 		goto err1;
28057c478bd9Sstevel@tonic-gate 	}
28067c478bd9Sstevel@tonic-gate 
280727242a7cSthurlow 	tvp = nfs3_fhtovp(&args->to.dir, exi);
28087c478bd9Sstevel@tonic-gate 	if (tvp == NULL) {
28097c478bd9Sstevel@tonic-gate 		error = ESTALE;
2810e1adf50cSahl 		goto err;
28117c478bd9Sstevel@tonic-gate 	}
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 	tbva.va_mask = AT_ALL;
2814da6c28aaSamw 	tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
28157c478bd9Sstevel@tonic-gate 	tavap = tbvap;
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 	if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
28187c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
2819e1adf50cSahl 		goto err1;
28207c478bd9Sstevel@tonic-gate 	}
28217c478bd9Sstevel@tonic-gate 
28227c478bd9Sstevel@tonic-gate 	if (args->from.name == nfs3nametoolong ||
28237c478bd9Sstevel@tonic-gate 	    args->to.name == nfs3nametoolong) {
28247c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2825e1adf50cSahl 		goto err1;
28267c478bd9Sstevel@tonic-gate 	}
28277c478bd9Sstevel@tonic-gate 	if (args->from.name == NULL || *(args->from.name) == '\0' ||
28287c478bd9Sstevel@tonic-gate 	    args->to.name == NULL || *(args->to.name) == '\0') {
28297c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2830e1adf50cSahl 		goto err1;
28317c478bd9Sstevel@tonic-gate 	}
28327c478bd9Sstevel@tonic-gate 
28335cb0d679SMarcel Telka 	if (rdonly(ro, tvp)) {
28347c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2835e1adf50cSahl 		goto err1;
28367c478bd9Sstevel@tonic-gate 	}
28377c478bd9Sstevel@tonic-gate 
283803986916Sjarrett 	if (is_system_labeled()) {
283903986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2840bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2841bd6f1640SJarrett Lu 			    exi)) {
284203986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2843e1adf50cSahl 				goto err1;
284403986916Sjarrett 			}
284503986916Sjarrett 		}
284603986916Sjarrett 	}
284703986916Sjarrett 
2848b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2849b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->from.name,
2850b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2851b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2852b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2853b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2854b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2855b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2856b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2857b89a8333Snatalie li - Sun Microsystems - Irvine United States 	toname = nfscmd_convname(ca, exi, args->to.name,
2858b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2859b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2860b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (toname == NULL) {
2861b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2862b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2863b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2864b89a8333Snatalie li - Sun Microsystems - Irvine United States 
28657c478bd9Sstevel@tonic-gate 	/*
28667c478bd9Sstevel@tonic-gate 	 * Check for a conflict with a non-blocking mandatory share
28677c478bd9Sstevel@tonic-gate 	 * reservation or V4 delegations.
28687c478bd9Sstevel@tonic-gate 	 */
2869b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2870cfae96c2Sjwahlig 	    NULL, cr, NULL, NULL, NULL);
28717c478bd9Sstevel@tonic-gate 	if (error != 0)
2872e1adf50cSahl 		goto err;
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate 	/*
28757c478bd9Sstevel@tonic-gate 	 * If we rename a delegated file we should recall the
28767c478bd9Sstevel@tonic-gate 	 * delegation, since future opens should fail or would
28777c478bd9Sstevel@tonic-gate 	 * refer to a new file.
28787c478bd9Sstevel@tonic-gate 	 */
28797c478bd9Sstevel@tonic-gate 	if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
28807c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
2881e1adf50cSahl 		goto err1;
28827c478bd9Sstevel@tonic-gate 	}
28837c478bd9Sstevel@tonic-gate 
28847c478bd9Sstevel@tonic-gate 	/*
28850dfe541eSEvan Layton 	 * Check for renaming over a delegated file.  Check nfs4_deleg_policy
28867c478bd9Sstevel@tonic-gate 	 * first to avoid VOP_LOOKUP if possible.
28877c478bd9Sstevel@tonic-gate 	 */
28880dfe541eSEvan Layton 	if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE &&
2889b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2890da6c28aaSamw 	    NULL, NULL, NULL) == 0) {
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate 		if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
28937c478bd9Sstevel@tonic-gate 			VN_RELE(targvp);
28947c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
2895e1adf50cSahl 			goto err1;
28967c478bd9Sstevel@tonic-gate 		}
28977c478bd9Sstevel@tonic-gate 		VN_RELE(targvp);
28987c478bd9Sstevel@tonic-gate 	}
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 	if (!nbl_need_check(srcvp)) {
2901b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
29027c478bd9Sstevel@tonic-gate 	} else {
29037c478bd9Sstevel@tonic-gate 		nbl_start_crit(srcvp, RW_READER);
2904b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
29057c478bd9Sstevel@tonic-gate 			error = EACCES;
2906b89a8333Snatalie li - Sun Microsystems - Irvine United States 		else
2907b89a8333Snatalie li - Sun Microsystems - Irvine United States 			error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
29087c478bd9Sstevel@tonic-gate 		nbl_end_crit(srcvp);
29097c478bd9Sstevel@tonic-gate 	}
291051ece835Seschrock 	if (error == 0)
291151ece835Seschrock 		vn_renamepath(tvp, srcvp, args->to.name,
2912cfae96c2Sjwahlig 		    strlen(args->to.name));
29137c478bd9Sstevel@tonic-gate 	VN_RELE(srcvp);
29147c478bd9Sstevel@tonic-gate 	srcvp = NULL;
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate 	fava.va_mask = AT_ALL;
2917da6c28aaSamw 	favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
29187c478bd9Sstevel@tonic-gate 	tava.va_mask = AT_ALL;
2919da6c28aaSamw 	tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
29207c478bd9Sstevel@tonic-gate 
29217c478bd9Sstevel@tonic-gate 	/*
29227c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
29237c478bd9Sstevel@tonic-gate 	 */
2924da6c28aaSamw 	(void) VOP_FSYNC(fvp, 0, cr, NULL);
2925da6c28aaSamw 	(void) VOP_FSYNC(tvp, 0, cr, NULL);
29267c478bd9Sstevel@tonic-gate 
29277c478bd9Sstevel@tonic-gate 	if (error)
2928e1adf50cSahl 		goto err;
29297c478bd9Sstevel@tonic-gate 
29307c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
29317c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
29327c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2933e1adf50cSahl 	goto out;
29347c478bd9Sstevel@tonic-gate 
2935e1adf50cSahl err:
29367c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
29377c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
29387c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
2939b89a8333Snatalie li - Sun Microsystems - Irvine United States 	} else {
29407c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
2941b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2942e1adf50cSahl err1:
2943e1adf50cSahl 	vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2944e1adf50cSahl 	vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2945b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2946e1adf50cSahl out:
2947b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->from.name)
2948b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
2949b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (toname != NULL && toname != args->to.name)
2950b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(toname, MAXPATHLEN + 1);
2951b89a8333Snatalie li - Sun Microsystems - Irvine United States 
29520dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req,
29530dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
29540dfe541eSEvan Layton 	    RENAME3res *, resp);
29557c478bd9Sstevel@tonic-gate 	if (fvp != NULL)
29567c478bd9Sstevel@tonic-gate 		VN_RELE(fvp);
29577c478bd9Sstevel@tonic-gate 	if (tvp != NULL)
29587c478bd9Sstevel@tonic-gate 		VN_RELE(tvp);
29597c478bd9Sstevel@tonic-gate }
29607c478bd9Sstevel@tonic-gate 
296127242a7cSthurlow void *
rfs3_rename_getfh(RENAME3args * args)29627c478bd9Sstevel@tonic-gate rfs3_rename_getfh(RENAME3args *args)
29637c478bd9Sstevel@tonic-gate {
29647c478bd9Sstevel@tonic-gate 
296527242a7cSthurlow 	return (&args->from.dir);
29667c478bd9Sstevel@tonic-gate }
29677c478bd9Sstevel@tonic-gate 
29687c478bd9Sstevel@tonic-gate void
rfs3_link(LINK3args * args,LINK3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)29697c478bd9Sstevel@tonic-gate rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
29705cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
29717c478bd9Sstevel@tonic-gate {
29727c478bd9Sstevel@tonic-gate 	int error;
29737c478bd9Sstevel@tonic-gate 	vnode_t *vp;
29747c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
29757c478bd9Sstevel@tonic-gate 	struct vattr *vap;
29767c478bd9Sstevel@tonic-gate 	struct vattr va;
29777c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
29787c478bd9Sstevel@tonic-gate 	struct vattr bva;
29797c478bd9Sstevel@tonic-gate 	struct vattr *avap;
29807c478bd9Sstevel@tonic-gate 	struct vattr ava;
29817c478bd9Sstevel@tonic-gate 	nfs_fh3	*fh3;
29827c478bd9Sstevel@tonic-gate 	struct exportinfo *to_exi;
298303986916Sjarrett 	bslabel_t *clabel;
2984b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2985b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
29867c478bd9Sstevel@tonic-gate 
29877c478bd9Sstevel@tonic-gate 	vap = NULL;
29887c478bd9Sstevel@tonic-gate 	bvap = NULL;
29897c478bd9Sstevel@tonic-gate 	avap = NULL;
29907c478bd9Sstevel@tonic-gate 	dvp = NULL;
29917c478bd9Sstevel@tonic-gate 
29927c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
2993e1adf50cSahl 
29940dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__link__start, struct svc_req *, req,
29950dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
29960dfe541eSEvan Layton 	    LINK3args *, args);
2997e1adf50cSahl 
29987c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
29997c478bd9Sstevel@tonic-gate 		error = ESTALE;
30007c478bd9Sstevel@tonic-gate 		goto out;
30017c478bd9Sstevel@tonic-gate 	}
30027c478bd9Sstevel@tonic-gate 
30037c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3004da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
30057c478bd9Sstevel@tonic-gate 
300627242a7cSthurlow 	fh3 = &args->link.dir;
300727242a7cSthurlow 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
30087c478bd9Sstevel@tonic-gate 	if (to_exi == NULL) {
30097c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
30107c478bd9Sstevel@tonic-gate 		goto out1;
30117c478bd9Sstevel@tonic-gate 	}
30127c478bd9Sstevel@tonic-gate 	exi_rele(to_exi);
30137c478bd9Sstevel@tonic-gate 
30147c478bd9Sstevel@tonic-gate 	if (to_exi != exi) {
30157c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_XDEV;
30167c478bd9Sstevel@tonic-gate 		goto out1;
30177c478bd9Sstevel@tonic-gate 	}
30187c478bd9Sstevel@tonic-gate 
301903986916Sjarrett 	if (is_system_labeled()) {
302003986916Sjarrett 		clabel = req->rq_label;
302103986916Sjarrett 
302203986916Sjarrett 		ASSERT(clabel != NULL);
302303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
302403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
302503986916Sjarrett 
302603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3027bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3028bd6f1640SJarrett Lu 			    exi)) {
302903986916Sjarrett 				resp->status = NFS3ERR_ACCES;
303003986916Sjarrett 				goto out1;
303103986916Sjarrett 			}
303203986916Sjarrett 		}
303303986916Sjarrett 	}
303403986916Sjarrett 
303527242a7cSthurlow 	dvp = nfs3_fhtovp(&args->link.dir, exi);
30367c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
30377c478bd9Sstevel@tonic-gate 		error = ESTALE;
30387c478bd9Sstevel@tonic-gate 		goto out;
30397c478bd9Sstevel@tonic-gate 	}
30407c478bd9Sstevel@tonic-gate 
30417c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
3042da6c28aaSamw 	bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
30437c478bd9Sstevel@tonic-gate 
30447c478bd9Sstevel@tonic-gate 	if (dvp->v_type != VDIR) {
30457c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
30467c478bd9Sstevel@tonic-gate 		goto out1;
30477c478bd9Sstevel@tonic-gate 	}
30487c478bd9Sstevel@tonic-gate 
30497c478bd9Sstevel@tonic-gate 	if (args->link.name == nfs3nametoolong) {
30507c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
30517c478bd9Sstevel@tonic-gate 		goto out1;
30527c478bd9Sstevel@tonic-gate 	}
30537c478bd9Sstevel@tonic-gate 
30547c478bd9Sstevel@tonic-gate 	if (args->link.name == NULL || *(args->link.name) == '\0') {
30557c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
30567c478bd9Sstevel@tonic-gate 		goto out1;
30577c478bd9Sstevel@tonic-gate 	}
30587c478bd9Sstevel@tonic-gate 
30595cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
30607c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
30617c478bd9Sstevel@tonic-gate 		goto out1;
30627c478bd9Sstevel@tonic-gate 	}
30637c478bd9Sstevel@tonic-gate 
306403986916Sjarrett 	if (is_system_labeled()) {
306503986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
306603986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
306703986916Sjarrett 
306803986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3069bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
3070bd6f1640SJarrett Lu 			    exi)) {
307103986916Sjarrett 				resp->status = NFS3ERR_ACCES;
307203986916Sjarrett 				goto out1;
307303986916Sjarrett 			}
307403986916Sjarrett 		}
307503986916Sjarrett 	}
307603986916Sjarrett 
3077b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3078b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->link.name,
3079b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3080b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3081b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
3082b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_SERVERFAULT;
3083b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
3084b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
3085b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3086b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
30877c478bd9Sstevel@tonic-gate 
30887c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3089da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
30907c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
3091da6c28aaSamw 	avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
30927c478bd9Sstevel@tonic-gate 
30937c478bd9Sstevel@tonic-gate 	/*
30947c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
30957c478bd9Sstevel@tonic-gate 	 */
3096da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3097da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
30987c478bd9Sstevel@tonic-gate 
30997c478bd9Sstevel@tonic-gate 	if (error)
31007c478bd9Sstevel@tonic-gate 		goto out;
31017c478bd9Sstevel@tonic-gate 
31027c478bd9Sstevel@tonic-gate 	VN_RELE(dvp);
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
31057c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
31067c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3107e1adf50cSahl 
31080dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
31090dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
31100dfe541eSEvan Layton 	    LINK3res *, resp);
3111e1adf50cSahl 
3112e1adf50cSahl 	VN_RELE(vp);
3113e1adf50cSahl 
31147c478bd9Sstevel@tonic-gate 	return;
31157c478bd9Sstevel@tonic-gate 
31167c478bd9Sstevel@tonic-gate out:
31177c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
31187c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
31197c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
31207c478bd9Sstevel@tonic-gate 	} else
31217c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
31227c478bd9Sstevel@tonic-gate out1:
3123b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->link.name)
3124b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
3125b89a8333Snatalie li - Sun Microsystems - Irvine United States 
31260dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
31270dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
31280dfe541eSEvan Layton 	    LINK3res *, resp);
3129e1adf50cSahl 
31307c478bd9Sstevel@tonic-gate 	if (vp != NULL)
31317c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
31327c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
31337c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
31347c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
31357c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
31367c478bd9Sstevel@tonic-gate }
31377c478bd9Sstevel@tonic-gate 
313827242a7cSthurlow void *
rfs3_link_getfh(LINK3args * args)31397c478bd9Sstevel@tonic-gate rfs3_link_getfh(LINK3args *args)
31407c478bd9Sstevel@tonic-gate {
31417c478bd9Sstevel@tonic-gate 
314227242a7cSthurlow 	return (&args->file);
31437c478bd9Sstevel@tonic-gate }
31447c478bd9Sstevel@tonic-gate 
31457c478bd9Sstevel@tonic-gate /*
31467c478bd9Sstevel@tonic-gate  * This macro defines the size of a response which contains attribute
31477c478bd9Sstevel@tonic-gate  * information and one directory entry (whose length is specified by
31487c478bd9Sstevel@tonic-gate  * the macro parameter).  If the incoming request is larger than this,
31497c478bd9Sstevel@tonic-gate  * then we are guaranteed to be able to return at one directory entry
31507c478bd9Sstevel@tonic-gate  * if one exists.  Therefore, we do not need to check for
31517c478bd9Sstevel@tonic-gate  * NFS3ERR_TOOSMALL if the requested size is larger then this.  If it
31527c478bd9Sstevel@tonic-gate  * is not, then we need to check to make sure that this error does not
31537c478bd9Sstevel@tonic-gate  * need to be returned.
31547c478bd9Sstevel@tonic-gate  *
31557c478bd9Sstevel@tonic-gate  * NFS3_READDIR_MIN_COUNT is comprised of following :
31567c478bd9Sstevel@tonic-gate  *
31577c478bd9Sstevel@tonic-gate  * status - 1 * BYTES_PER_XDR_UNIT
31587c478bd9Sstevel@tonic-gate  * attr. flag - 1 * BYTES_PER_XDR_UNIT
31597c478bd9Sstevel@tonic-gate  * cookie verifier - 2 * BYTES_PER_XDR_UNIT
31607c478bd9Sstevel@tonic-gate  * attributes  - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
31617c478bd9Sstevel@tonic-gate  * boolean - 1 * BYTES_PER_XDR_UNIT
31627c478bd9Sstevel@tonic-gate  * file id - 2 * BYTES_PER_XDR_UNIT
3163da6c28aaSamw  * directory name length - 1 * BYTES_PER_XDR_UNIT
31647c478bd9Sstevel@tonic-gate  * cookie - 2 * BYTES_PER_XDR_UNIT
31657c478bd9Sstevel@tonic-gate  * end of list - 1 * BYTES_PER_XDR_UNIT
31667c478bd9Sstevel@tonic-gate  * end of file - 1 * BYTES_PER_XDR_UNIT
31677c478bd9Sstevel@tonic-gate  * Name length of directory to the nearest byte
31687c478bd9Sstevel@tonic-gate  */
31697c478bd9Sstevel@tonic-gate 
31707c478bd9Sstevel@tonic-gate #define	NFS3_READDIR_MIN_COUNT(length)	\
31717c478bd9Sstevel@tonic-gate 	((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
31727c478bd9Sstevel@tonic-gate 		BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
31737c478bd9Sstevel@tonic-gate 
31747c478bd9Sstevel@tonic-gate /* ARGSUSED */
31757c478bd9Sstevel@tonic-gate void
rfs3_readdir(READDIR3args * args,READDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)31767c478bd9Sstevel@tonic-gate rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
31775cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
31787c478bd9Sstevel@tonic-gate {
31797c478bd9Sstevel@tonic-gate 	int error;
31807c478bd9Sstevel@tonic-gate 	vnode_t *vp;
31817c478bd9Sstevel@tonic-gate 	struct vattr *vap;
31827c478bd9Sstevel@tonic-gate 	struct vattr va;
31837c478bd9Sstevel@tonic-gate 	struct iovec iov;
31847c478bd9Sstevel@tonic-gate 	struct uio uio;
31857c478bd9Sstevel@tonic-gate 	char *data;
31867c478bd9Sstevel@tonic-gate 	int iseof;
31877c478bd9Sstevel@tonic-gate 	int bufsize;
31887c478bd9Sstevel@tonic-gate 	int namlen;
31897c478bd9Sstevel@tonic-gate 	uint_t count;
3190b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
31917c478bd9Sstevel@tonic-gate 
31927c478bd9Sstevel@tonic-gate 	vap = NULL;
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->dir, exi);
3195e1adf50cSahl 
31960dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req,
31970dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
31980dfe541eSEvan Layton 	    READDIR3args *, args);
3199e1adf50cSahl 
32007c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
32017c478bd9Sstevel@tonic-gate 		error = ESTALE;
32027c478bd9Sstevel@tonic-gate 		goto out;
32037c478bd9Sstevel@tonic-gate 	}
32047c478bd9Sstevel@tonic-gate 
320503986916Sjarrett 	if (is_system_labeled()) {
320603986916Sjarrett 		bslabel_t *clabel = req->rq_label;
320703986916Sjarrett 
320803986916Sjarrett 		ASSERT(clabel != NULL);
320903986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
321003986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
321103986916Sjarrett 
321203986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3213bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3214bd6f1640SJarrett Lu 			    exi)) {
321503986916Sjarrett 				resp->status = NFS3ERR_ACCES;
321603986916Sjarrett 				goto out1;
321703986916Sjarrett 			}
321803986916Sjarrett 		}
321903986916Sjarrett 	}
322003986916Sjarrett 
32217c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
32227c478bd9Sstevel@tonic-gate 
32237c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3224da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
32257c478bd9Sstevel@tonic-gate 
32267c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
32277c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
32287c478bd9Sstevel@tonic-gate 		goto out1;
32297c478bd9Sstevel@tonic-gate 	}
32307c478bd9Sstevel@tonic-gate 
3231da6c28aaSamw 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
32327c478bd9Sstevel@tonic-gate 	if (error)
32337c478bd9Sstevel@tonic-gate 		goto out;
32347c478bd9Sstevel@tonic-gate 
32357c478bd9Sstevel@tonic-gate 	/*
32367c478bd9Sstevel@tonic-gate 	 * Now don't allow arbitrary count to alloc;
32377c478bd9Sstevel@tonic-gate 	 * allow the maximum not to exceed rfs3_tsize()
32387c478bd9Sstevel@tonic-gate 	 */
32397c478bd9Sstevel@tonic-gate 	if (args->count > rfs3_tsize(req))
32407c478bd9Sstevel@tonic-gate 		args->count = rfs3_tsize(req);
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate 	/*
32437c478bd9Sstevel@tonic-gate 	 * Make sure that there is room to read at least one entry
32447c478bd9Sstevel@tonic-gate 	 * if any are available.
32457c478bd9Sstevel@tonic-gate 	 */
32467c478bd9Sstevel@tonic-gate 	if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
32477c478bd9Sstevel@tonic-gate 		count = DIRENT64_RECLEN(MAXNAMELEN);
32487c478bd9Sstevel@tonic-gate 	else
32497c478bd9Sstevel@tonic-gate 		count = args->count;
32507c478bd9Sstevel@tonic-gate 
32517c478bd9Sstevel@tonic-gate 	data = kmem_alloc(count, KM_SLEEP);
32527c478bd9Sstevel@tonic-gate 
32537c478bd9Sstevel@tonic-gate 	iov.iov_base = data;
32547c478bd9Sstevel@tonic-gate 	iov.iov_len = count;
32557c478bd9Sstevel@tonic-gate 	uio.uio_iov = &iov;
32567c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
32577c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
32587c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
32597c478bd9Sstevel@tonic-gate 	uio.uio_loffset = (offset_t)args->cookie;
32607c478bd9Sstevel@tonic-gate 	uio.uio_resid = count;
32617c478bd9Sstevel@tonic-gate 
3262da6c28aaSamw 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
32637c478bd9Sstevel@tonic-gate 
32647c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3265da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
32667c478bd9Sstevel@tonic-gate 
32677c478bd9Sstevel@tonic-gate 	if (error) {
32687c478bd9Sstevel@tonic-gate 		kmem_free(data, count);
32697c478bd9Sstevel@tonic-gate 		goto out;
32707c478bd9Sstevel@tonic-gate 	}
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate 	/*
32737c478bd9Sstevel@tonic-gate 	 * If the count was not large enough to be able to guarantee
32747c478bd9Sstevel@tonic-gate 	 * to be able to return at least one entry, then need to
32757c478bd9Sstevel@tonic-gate 	 * check to see if NFS3ERR_TOOSMALL should be returned.
32767c478bd9Sstevel@tonic-gate 	 */
32777c478bd9Sstevel@tonic-gate 	if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
32787c478bd9Sstevel@tonic-gate 		/*
32797c478bd9Sstevel@tonic-gate 		 * bufsize is used to keep track of the size of the response.
32807c478bd9Sstevel@tonic-gate 		 * It is primed with:
32817c478bd9Sstevel@tonic-gate 		 *	1 for the status +
32827c478bd9Sstevel@tonic-gate 		 *	1 for the dir_attributes.attributes boolean +
32837c478bd9Sstevel@tonic-gate 		 *	2 for the cookie verifier
32847c478bd9Sstevel@tonic-gate 		 * all times BYTES_PER_XDR_UNIT to convert from XDR units
32857c478bd9Sstevel@tonic-gate 		 * to bytes.  If there are directory attributes to be
32867c478bd9Sstevel@tonic-gate 		 * returned, then:
32877c478bd9Sstevel@tonic-gate 		 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
32887c478bd9Sstevel@tonic-gate 		 * time BYTES_PER_XDR_UNIT is added to account for them.
32897c478bd9Sstevel@tonic-gate 		 */
32907c478bd9Sstevel@tonic-gate 		bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
32917c478bd9Sstevel@tonic-gate 		if (vap != NULL)
32927c478bd9Sstevel@tonic-gate 			bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
32937c478bd9Sstevel@tonic-gate 		/*
32947c478bd9Sstevel@tonic-gate 		 * An entry is composed of:
32957c478bd9Sstevel@tonic-gate 		 *	1 for the true/false list indicator +
32967c478bd9Sstevel@tonic-gate 		 *	2 for the fileid +
32977c478bd9Sstevel@tonic-gate 		 *	1 for the length of the name +
32987c478bd9Sstevel@tonic-gate 		 *	2 for the cookie +
32997c478bd9Sstevel@tonic-gate 		 * all times BYTES_PER_XDR_UNIT to convert from
33007c478bd9Sstevel@tonic-gate 		 * XDR units to bytes, plus the length of the name
33017c478bd9Sstevel@tonic-gate 		 * rounded up to the nearest BYTES_PER_XDR_UNIT.
33027c478bd9Sstevel@tonic-gate 		 */
33037c478bd9Sstevel@tonic-gate 		if (count != uio.uio_resid) {
33047c478bd9Sstevel@tonic-gate 			namlen = strlen(((struct dirent64 *)data)->d_name);
33057c478bd9Sstevel@tonic-gate 			bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3306cfae96c2Sjwahlig 			    roundup(namlen, BYTES_PER_XDR_UNIT);
33077c478bd9Sstevel@tonic-gate 		}
33087c478bd9Sstevel@tonic-gate 		/*
33097c478bd9Sstevel@tonic-gate 		 * We need to check to see if the number of bytes left
33107c478bd9Sstevel@tonic-gate 		 * to go into the buffer will actually fit into the
33117c478bd9Sstevel@tonic-gate 		 * buffer.  This is calculated as the size of this
33127c478bd9Sstevel@tonic-gate 		 * entry plus:
33137c478bd9Sstevel@tonic-gate 		 *	1 for the true/false list indicator +
33147c478bd9Sstevel@tonic-gate 		 *	1 for the eof indicator
33157c478bd9Sstevel@tonic-gate 		 * times BYTES_PER_XDR_UNIT to convert from from
33167c478bd9Sstevel@tonic-gate 		 * XDR units to bytes.
33177c478bd9Sstevel@tonic-gate 		 */
33187c478bd9Sstevel@tonic-gate 		bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
33197c478bd9Sstevel@tonic-gate 		if (bufsize > args->count) {
33207c478bd9Sstevel@tonic-gate 			kmem_free(data, count);
33217c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_TOOSMALL;
33227c478bd9Sstevel@tonic-gate 			goto out1;
33237c478bd9Sstevel@tonic-gate 		}
33247c478bd9Sstevel@tonic-gate 	}
33257c478bd9Sstevel@tonic-gate 
3326b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*
3327b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * Have a valid readir buffer for the native character
3328b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * set. Need to check if a conversion is necessary and
3329b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * potentially rewrite the whole buffer. Note that if the
3330b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * conversion expands names enough, the structure may not
3331b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * fit. In this case, we need to drop entries until if fits
3332b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * and patch the counts in order that the next readdir will
3333b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * get the correct entries.
3334b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 */
3335b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3336b89a8333Snatalie li - Sun Microsystems - Irvine United States 	data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
3337b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3338b89a8333Snatalie li - Sun Microsystems - Irvine United States 
33397c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
33407c478bd9Sstevel@tonic-gate 
33417c478bd9Sstevel@tonic-gate #if 0 /* notyet */
33427c478bd9Sstevel@tonic-gate 	/*
33437c478bd9Sstevel@tonic-gate 	 * Don't do this.  It causes local disk writes when just
33447c478bd9Sstevel@tonic-gate 	 * reading the file and the overhead is deemed larger
33457c478bd9Sstevel@tonic-gate 	 * than the benefit.
33467c478bd9Sstevel@tonic-gate 	 */
33477c478bd9Sstevel@tonic-gate 	/*
33487c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
33497c478bd9Sstevel@tonic-gate 	 */
3350da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
33517c478bd9Sstevel@tonic-gate #endif
33527c478bd9Sstevel@tonic-gate 
33537c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
33547c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
33557c478bd9Sstevel@tonic-gate 	resp->resok.cookieverf = 0;
33567c478bd9Sstevel@tonic-gate 	resp->resok.reply.entries = (entry3 *)data;
33577c478bd9Sstevel@tonic-gate 	resp->resok.reply.eof = iseof;
33587c478bd9Sstevel@tonic-gate 	resp->resok.size = count - uio.uio_resid;
33597c478bd9Sstevel@tonic-gate 	resp->resok.count = args->count;
33607c478bd9Sstevel@tonic-gate 	resp->resok.freecount = count;
3361e1adf50cSahl 
33620dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
33630dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
33640dfe541eSEvan Layton 	    READDIR3res *, resp);
3365e1adf50cSahl 
3366e1adf50cSahl 	VN_RELE(vp);
3367e1adf50cSahl 
33687c478bd9Sstevel@tonic-gate 	return;
33697c478bd9Sstevel@tonic-gate 
33707c478bd9Sstevel@tonic-gate out:
33717c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
33727c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
33737c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
33747c478bd9Sstevel@tonic-gate 	} else
33757c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
33767c478bd9Sstevel@tonic-gate out1:
33770dfe541eSEvan Layton 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
33780dfe541eSEvan Layton 
33790dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
33800dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
33810dfe541eSEvan Layton 	    READDIR3res *, resp);
3382e1adf50cSahl 
33837c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
33847c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
33857c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
33867c478bd9Sstevel@tonic-gate 	}
33877c478bd9Sstevel@tonic-gate }
33887c478bd9Sstevel@tonic-gate 
338927242a7cSthurlow void *
rfs3_readdir_getfh(READDIR3args * args)33907c478bd9Sstevel@tonic-gate rfs3_readdir_getfh(READDIR3args *args)
33917c478bd9Sstevel@tonic-gate {
33927c478bd9Sstevel@tonic-gate 
339327242a7cSthurlow 	return (&args->dir);
33947c478bd9Sstevel@tonic-gate }
33957c478bd9Sstevel@tonic-gate 
33967c478bd9Sstevel@tonic-gate void
rfs3_readdir_free(READDIR3res * resp)33977c478bd9Sstevel@tonic-gate rfs3_readdir_free(READDIR3res *resp)
33987c478bd9Sstevel@tonic-gate {
33997c478bd9Sstevel@tonic-gate 
34007c478bd9Sstevel@tonic-gate 	if (resp->status == NFS3_OK)
34017c478bd9Sstevel@tonic-gate 		kmem_free(resp->resok.reply.entries, resp->resok.freecount);
34027c478bd9Sstevel@tonic-gate }
34037c478bd9Sstevel@tonic-gate 
34047c478bd9Sstevel@tonic-gate #ifdef nextdp
34057c478bd9Sstevel@tonic-gate #undef nextdp
34067c478bd9Sstevel@tonic-gate #endif
34077c478bd9Sstevel@tonic-gate #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
34087c478bd9Sstevel@tonic-gate 
34097c478bd9Sstevel@tonic-gate /*
34107c478bd9Sstevel@tonic-gate  * This macro computes the size of a response which contains
34117c478bd9Sstevel@tonic-gate  * one directory entry including the attributes as well as file handle.
34127c478bd9Sstevel@tonic-gate  * If the incoming request is larger than this, then we are guaranteed to be
34137c478bd9Sstevel@tonic-gate  * able to return at least one more directory entry if one exists.
34147c478bd9Sstevel@tonic-gate  *
34157c478bd9Sstevel@tonic-gate  * NFS3_READDIRPLUS_ENTRY is made up of the following:
34167c478bd9Sstevel@tonic-gate  *
34177c478bd9Sstevel@tonic-gate  * boolean - 1 * BYTES_PER_XDR_UNIT
34187c478bd9Sstevel@tonic-gate  * file id - 2 * BYTES_PER_XDR_UNIT
34197c478bd9Sstevel@tonic-gate  * directory name length - 1 * BYTES_PER_XDR_UNIT
34207c478bd9Sstevel@tonic-gate  * cookie - 2 * BYTES_PER_XDR_UNIT
34217c478bd9Sstevel@tonic-gate  * attribute flag - 1 * BYTES_PER_XDR_UNIT
34227c478bd9Sstevel@tonic-gate  * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
34237c478bd9Sstevel@tonic-gate  * status byte for file handle - 1 *  BYTES_PER_XDR_UNIT
34247c478bd9Sstevel@tonic-gate  * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3425da6c28aaSamw  * Maximum length of a file handle (NFS3_MAXFHSIZE)
34267c478bd9Sstevel@tonic-gate  * name length of the entry to the nearest bytes
34277c478bd9Sstevel@tonic-gate  */
34287c478bd9Sstevel@tonic-gate #define	NFS3_READDIRPLUS_ENTRY(namelen)	\
34297c478bd9Sstevel@tonic-gate 	((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
34307c478bd9Sstevel@tonic-gate 		BYTES_PER_XDR_UNIT + \
343127242a7cSthurlow 	NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
34327c478bd9Sstevel@tonic-gate 
34337c478bd9Sstevel@tonic-gate static int rfs3_readdir_unit = MAXBSIZE;
34347c478bd9Sstevel@tonic-gate 
34357c478bd9Sstevel@tonic-gate /* ARGSUSED */
34367c478bd9Sstevel@tonic-gate void
rfs3_readdirplus(READDIRPLUS3args * args,READDIRPLUS3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)34377c478bd9Sstevel@tonic-gate rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
34385cb0d679SMarcel Telka     struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
34397c478bd9Sstevel@tonic-gate {
34407c478bd9Sstevel@tonic-gate 	int error;
34417c478bd9Sstevel@tonic-gate 	vnode_t *vp;
34427c478bd9Sstevel@tonic-gate 	struct vattr *vap;
34437c478bd9Sstevel@tonic-gate 	struct vattr va;
34447c478bd9Sstevel@tonic-gate 	struct iovec iov;
34457c478bd9Sstevel@tonic-gate 	struct uio uio;
34467c478bd9Sstevel@tonic-gate 	char *data;
34477c478bd9Sstevel@tonic-gate 	int iseof;
34487c478bd9Sstevel@tonic-gate 	struct dirent64 *dp;
34497c478bd9Sstevel@tonic-gate 	vnode_t *nvp;
34507c478bd9Sstevel@tonic-gate 	struct vattr *nvap;
34517c478bd9Sstevel@tonic-gate 	struct vattr nva;
34527c478bd9Sstevel@tonic-gate 	entryplus3_info *infop = NULL;
34537c478bd9Sstevel@tonic-gate 	int size = 0;
34547c478bd9Sstevel@tonic-gate 	int nents = 0;
34557c478bd9Sstevel@tonic-gate 	int bufsize = 0;
34567c478bd9Sstevel@tonic-gate 	int entrysize = 0;
34577c478bd9Sstevel@tonic-gate 	int tofit = 0;
34587c478bd9Sstevel@tonic-gate 	int rd_unit = rfs3_readdir_unit;
34597c478bd9Sstevel@tonic-gate 	int prev_len;
34607c478bd9Sstevel@tonic-gate 	int space_left;
34617c478bd9Sstevel@tonic-gate 	int i;
34627c478bd9Sstevel@tonic-gate 	uint_t *namlen = NULL;
3463b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *ndata = NULL;
3464b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
3465b89a8333Snatalie li - Sun Microsystems - Irvine United States 	size_t ret;
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate 	vap = NULL;
34687c478bd9Sstevel@tonic-gate 
34697c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->dir, exi);
3470e1adf50cSahl 
34710dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req,
34720dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
34730dfe541eSEvan Layton 	    READDIRPLUS3args *, args);
3474e1adf50cSahl 
34757c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
34767c478bd9Sstevel@tonic-gate 		error = ESTALE;
34777c478bd9Sstevel@tonic-gate 		goto out;
34787c478bd9Sstevel@tonic-gate 	}
34797c478bd9Sstevel@tonic-gate 
348003986916Sjarrett 	if (is_system_labeled()) {
348103986916Sjarrett 		bslabel_t *clabel = req->rq_label;
348203986916Sjarrett 
348303986916Sjarrett 		ASSERT(clabel != NULL);
348403986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
348503986916Sjarrett 		    char *, "got client label from request(1)",
348603986916Sjarrett 		    struct svc_req *, req);
348703986916Sjarrett 
348803986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3489bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3490bd6f1640SJarrett Lu 			    exi)) {
349103986916Sjarrett 				resp->status = NFS3ERR_ACCES;
349203986916Sjarrett 				goto out1;
349303986916Sjarrett 			}
349403986916Sjarrett 		}
349503986916Sjarrett 	}
349603986916Sjarrett 
34977c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
34987c478bd9Sstevel@tonic-gate 
34997c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3500da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
35037c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
35047c478bd9Sstevel@tonic-gate 		goto out;
35057c478bd9Sstevel@tonic-gate 	}
35067c478bd9Sstevel@tonic-gate 
3507da6c28aaSamw 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
35087c478bd9Sstevel@tonic-gate 	if (error)
35097c478bd9Sstevel@tonic-gate 		goto out;
35107c478bd9Sstevel@tonic-gate 
35117c478bd9Sstevel@tonic-gate 	/*
35127c478bd9Sstevel@tonic-gate 	 * Don't allow arbitrary counts for allocation
35137c478bd9Sstevel@tonic-gate 	 */
35147c478bd9Sstevel@tonic-gate 	if (args->maxcount > rfs3_tsize(req))
35157c478bd9Sstevel@tonic-gate 		args->maxcount = rfs3_tsize(req);
35167c478bd9Sstevel@tonic-gate 
35177c478bd9Sstevel@tonic-gate 	/*
35187c478bd9Sstevel@tonic-gate 	 * Make sure that there is room to read at least one entry
35197c478bd9Sstevel@tonic-gate 	 * if any are available
35207c478bd9Sstevel@tonic-gate 	 */
35217c478bd9Sstevel@tonic-gate 	args->dircount = MIN(args->dircount, args->maxcount);
35227c478bd9Sstevel@tonic-gate 
35237c478bd9Sstevel@tonic-gate 	if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
35247c478bd9Sstevel@tonic-gate 		args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
35257c478bd9Sstevel@tonic-gate 
35267c478bd9Sstevel@tonic-gate 	/*
35277c478bd9Sstevel@tonic-gate 	 * This allocation relies on a minimum directory entry
35287c478bd9Sstevel@tonic-gate 	 * being roughly 24 bytes.  Therefore, the namlen array
35297c478bd9Sstevel@tonic-gate 	 * will have enough space based on the maximum number of
35307c478bd9Sstevel@tonic-gate 	 * entries to read.
35317c478bd9Sstevel@tonic-gate 	 */
35327c478bd9Sstevel@tonic-gate 	namlen = kmem_alloc(args->dircount, KM_SLEEP);
35337c478bd9Sstevel@tonic-gate 
35347c478bd9Sstevel@tonic-gate 	space_left = args->dircount;
35357c478bd9Sstevel@tonic-gate 	data = kmem_alloc(args->dircount, KM_SLEEP);
35367c478bd9Sstevel@tonic-gate 	dp = (struct dirent64 *)data;
35377c478bd9Sstevel@tonic-gate 	uio.uio_iov = &iov;
35387c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
35397c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
35407c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
35417c478bd9Sstevel@tonic-gate 	uio.uio_loffset = (offset_t)args->cookie;
35427c478bd9Sstevel@tonic-gate 
35437c478bd9Sstevel@tonic-gate 	/*
35447c478bd9Sstevel@tonic-gate 	 * bufsize is used to keep track of the size of the response as we
35457c478bd9Sstevel@tonic-gate 	 * get post op attributes and filehandles for each entry.  This is
35467c478bd9Sstevel@tonic-gate 	 * an optimization as the server may have read more entries than will
35477c478bd9Sstevel@tonic-gate 	 * fit in the buffer specified by maxcount.  We stop calculating
35487c478bd9Sstevel@tonic-gate 	 * post op attributes and filehandles once we have exceeded maxcount.
35497c478bd9Sstevel@tonic-gate 	 * This will minimize the effect of truncation.
35507c478bd9Sstevel@tonic-gate 	 *
35517c478bd9Sstevel@tonic-gate 	 * It is primed with:
35527c478bd9Sstevel@tonic-gate 	 *	1 for the status +
35537c478bd9Sstevel@tonic-gate 	 *	1 for the dir_attributes.attributes boolean +
35547c478bd9Sstevel@tonic-gate 	 *	2 for the cookie verifier
35557c478bd9Sstevel@tonic-gate 	 * all times BYTES_PER_XDR_UNIT to convert from XDR units
35567c478bd9Sstevel@tonic-gate 	 * to bytes.  If there are directory attributes to be
35577c478bd9Sstevel@tonic-gate 	 * returned, then:
35587c478bd9Sstevel@tonic-gate 	 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
35597c478bd9Sstevel@tonic-gate 	 * time BYTES_PER_XDR_UNIT is added to account for them.
35607c478bd9Sstevel@tonic-gate 	 */
35617c478bd9Sstevel@tonic-gate 	bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
35627c478bd9Sstevel@tonic-gate 	if (vap != NULL)
35637c478bd9Sstevel@tonic-gate 		bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
35647c478bd9Sstevel@tonic-gate 
35657c478bd9Sstevel@tonic-gate getmoredents:
35667c478bd9Sstevel@tonic-gate 	/*
35677c478bd9Sstevel@tonic-gate 	 * Here we make a check so that our read unit is not larger than
35687c478bd9Sstevel@tonic-gate 	 * the space left in the buffer.
35697c478bd9Sstevel@tonic-gate 	 */
35707c478bd9Sstevel@tonic-gate 	rd_unit = MIN(rd_unit, space_left);
35717c478bd9Sstevel@tonic-gate 	iov.iov_base = (char *)dp;
35727c478bd9Sstevel@tonic-gate 	iov.iov_len = rd_unit;
35737c478bd9Sstevel@tonic-gate 	uio.uio_resid = rd_unit;
35747c478bd9Sstevel@tonic-gate 	prev_len = rd_unit;
35757c478bd9Sstevel@tonic-gate 
3576da6c28aaSamw 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
35777c478bd9Sstevel@tonic-gate 
35787c478bd9Sstevel@tonic-gate 	if (error) {
35797c478bd9Sstevel@tonic-gate 		kmem_free(data, args->dircount);
35807c478bd9Sstevel@tonic-gate 		goto out;
35817c478bd9Sstevel@tonic-gate 	}
35827c478bd9Sstevel@tonic-gate 
35837c478bd9Sstevel@tonic-gate 	if (uio.uio_resid == prev_len && !iseof) {
35847c478bd9Sstevel@tonic-gate 		if (nents == 0) {
35857c478bd9Sstevel@tonic-gate 			kmem_free(data, args->dircount);
35867c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_TOOSMALL;
35877c478bd9Sstevel@tonic-gate 			goto out1;
35887c478bd9Sstevel@tonic-gate 		}
35897c478bd9Sstevel@tonic-gate 
35907c478bd9Sstevel@tonic-gate 		/*
35917c478bd9Sstevel@tonic-gate 		 * We could not get any more entries, so get the attributes
35927c478bd9Sstevel@tonic-gate 		 * and filehandle for the entries already obtained.
35937c478bd9Sstevel@tonic-gate 		 */
35947c478bd9Sstevel@tonic-gate 		goto good;
35957c478bd9Sstevel@tonic-gate 	}
35967c478bd9Sstevel@tonic-gate 
35977c478bd9Sstevel@tonic-gate 	/*
35987c478bd9Sstevel@tonic-gate 	 * We estimate the size of the response by assuming the
35997c478bd9Sstevel@tonic-gate 	 * entry exists and attributes and filehandle are also valid
36007c478bd9Sstevel@tonic-gate 	 */
36017c478bd9Sstevel@tonic-gate 	for (size = prev_len - uio.uio_resid;
3602cfae96c2Sjwahlig 	    size > 0;
3603cfae96c2Sjwahlig 	    size -= dp->d_reclen, dp = nextdp(dp)) {
36047c478bd9Sstevel@tonic-gate 
36057c478bd9Sstevel@tonic-gate 		if (dp->d_ino == 0) {
36067c478bd9Sstevel@tonic-gate 			nents++;
36077c478bd9Sstevel@tonic-gate 			continue;
36087c478bd9Sstevel@tonic-gate 		}
36097c478bd9Sstevel@tonic-gate 
36107c478bd9Sstevel@tonic-gate 		namlen[nents] = strlen(dp->d_name);
36117c478bd9Sstevel@tonic-gate 		entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
36127c478bd9Sstevel@tonic-gate 
36137c478bd9Sstevel@tonic-gate 		/*
36147c478bd9Sstevel@tonic-gate 		 * We need to check to see if the number of bytes left
36157c478bd9Sstevel@tonic-gate 		 * to go into the buffer will actually fit into the
36167c478bd9Sstevel@tonic-gate 		 * buffer.  This is calculated as the size of this
36177c478bd9Sstevel@tonic-gate 		 * entry plus:
36187c478bd9Sstevel@tonic-gate 		 *	1 for the true/false list indicator +
36197c478bd9Sstevel@tonic-gate 		 *	1 for the eof indicator
36207c478bd9Sstevel@tonic-gate 		 * times BYTES_PER_XDR_UNIT to convert from XDR units
36217c478bd9Sstevel@tonic-gate 		 * to bytes.
36227c478bd9Sstevel@tonic-gate 		 *
36237c478bd9Sstevel@tonic-gate 		 * Also check the dircount limit against the first entry read
36247c478bd9Sstevel@tonic-gate 		 *
36257c478bd9Sstevel@tonic-gate 		 */
36267c478bd9Sstevel@tonic-gate 		tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
36277c478bd9Sstevel@tonic-gate 		if (bufsize + tofit > args->maxcount) {
36287c478bd9Sstevel@tonic-gate 			/*
36297c478bd9Sstevel@tonic-gate 			 * We make a check here to see if this was the
36307c478bd9Sstevel@tonic-gate 			 * first entry being measured.  If so, then maxcount
36317c478bd9Sstevel@tonic-gate 			 * was too small to begin with and so we need to
36327c478bd9Sstevel@tonic-gate 			 * return with NFS3ERR_TOOSMALL.
36337c478bd9Sstevel@tonic-gate 			 */
36347c478bd9Sstevel@tonic-gate 			if (nents == 0) {
36357c478bd9Sstevel@tonic-gate 				kmem_free(data, args->dircount);
36367c478bd9Sstevel@tonic-gate 				resp->status = NFS3ERR_TOOSMALL;
36377c478bd9Sstevel@tonic-gate 				goto out1;
36387c478bd9Sstevel@tonic-gate 			}
36397c478bd9Sstevel@tonic-gate 			iseof = FALSE;
36407c478bd9Sstevel@tonic-gate 			goto good;
36417c478bd9Sstevel@tonic-gate 		}
36427c478bd9Sstevel@tonic-gate 		bufsize += entrysize;
36437c478bd9Sstevel@tonic-gate 		nents++;
36447c478bd9Sstevel@tonic-gate 	}
36457c478bd9Sstevel@tonic-gate 
36467c478bd9Sstevel@tonic-gate 	/*
36477c478bd9Sstevel@tonic-gate 	 * If there is enough room to fit at least 1 more entry including
36487c478bd9Sstevel@tonic-gate 	 * post op attributes and filehandle in the buffer AND that we haven't
36497c478bd9Sstevel@tonic-gate 	 * exceeded dircount then go back and get some more.
36507c478bd9Sstevel@tonic-gate 	 */
36517c478bd9Sstevel@tonic-gate 	if (!iseof &&
36527c478bd9Sstevel@tonic-gate 	    (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
36537c478bd9Sstevel@tonic-gate 		space_left -= (prev_len - uio.uio_resid);
36547c478bd9Sstevel@tonic-gate 		if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
36557c478bd9Sstevel@tonic-gate 			goto getmoredents;
36567c478bd9Sstevel@tonic-gate 
36577c478bd9Sstevel@tonic-gate 		/* else, fall through */
36587c478bd9Sstevel@tonic-gate 	}
36597c478bd9Sstevel@tonic-gate good:
36607c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3661da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
36627c478bd9Sstevel@tonic-gate 
36637c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
36647c478bd9Sstevel@tonic-gate 
36657c478bd9Sstevel@tonic-gate 	infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
36667c478bd9Sstevel@tonic-gate 	resp->resok.infop = infop;
36677c478bd9Sstevel@tonic-gate 
36687c478bd9Sstevel@tonic-gate 	dp = (struct dirent64 *)data;
36697c478bd9Sstevel@tonic-gate 	for (i = 0; i < nents; i++) {
36707c478bd9Sstevel@tonic-gate 
36717c478bd9Sstevel@tonic-gate 		if (dp->d_ino == 0) {
36727c478bd9Sstevel@tonic-gate 			infop[i].attr.attributes = FALSE;
36737c478bd9Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
36747c478bd9Sstevel@tonic-gate 			dp = nextdp(dp);
36757c478bd9Sstevel@tonic-gate 			continue;
36767c478bd9Sstevel@tonic-gate 		}
36777c478bd9Sstevel@tonic-gate 
36787c478bd9Sstevel@tonic-gate 		infop[i].namelen = namlen[i];
36797c478bd9Sstevel@tonic-gate 
3680da6c28aaSamw 		error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3681cfae96c2Sjwahlig 		    NULL, NULL, NULL);
36827c478bd9Sstevel@tonic-gate 		if (error) {
36837c478bd9Sstevel@tonic-gate 			infop[i].attr.attributes = FALSE;
36847c478bd9Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
36857c478bd9Sstevel@tonic-gate 			dp = nextdp(dp);
36867c478bd9Sstevel@tonic-gate 			continue;
36877c478bd9Sstevel@tonic-gate 		}
36887c478bd9Sstevel@tonic-gate 
36897c478bd9Sstevel@tonic-gate 		nva.va_mask = AT_ALL;
36907c478bd9Sstevel@tonic-gate 		nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
369127246829SVitaliy Gusev 
36922f172c55SRobert Thurlow 		/* Lie about the object type for a referral */
36932f172c55SRobert Thurlow 		if (vn_is_nfs_reparse(nvp, cr))
36942f172c55SRobert Thurlow 			nvap->va_type = VLNK;
36952f172c55SRobert Thurlow 
3696f7db5903SVitaliy Gusev 		if (vn_ismntpt(nvp)) {
3697f7db5903SVitaliy Gusev 			infop[i].attr.attributes = FALSE;
36987c478bd9Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
3699f7db5903SVitaliy Gusev 		} else {
3700f7db5903SVitaliy Gusev 			vattr_to_post_op_attr(nvap, &infop[i].attr);
3701f7db5903SVitaliy Gusev 
3702f7db5903SVitaliy Gusev 			error = makefh3(&infop[i].fh.handle, nvp, exi);
3703f7db5903SVitaliy Gusev 			if (!error)
3704f7db5903SVitaliy Gusev 				infop[i].fh.handle_follows = TRUE;
3705f7db5903SVitaliy Gusev 			else
3706f7db5903SVitaliy Gusev 				infop[i].fh.handle_follows = FALSE;
3707f7db5903SVitaliy Gusev 		}
37087c478bd9Sstevel@tonic-gate 
37097c478bd9Sstevel@tonic-gate 		VN_RELE(nvp);
37107c478bd9Sstevel@tonic-gate 		dp = nextdp(dp);
37117c478bd9Sstevel@tonic-gate 	}
37127c478bd9Sstevel@tonic-gate 
3713b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3714b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3715b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ndata == NULL)
3716b89a8333Snatalie li - Sun Microsystems - Irvine United States 		ndata = data;
3717b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3718b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ret > 0) {
3719b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/*
3720b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * We had to drop one or more entries in order to fit
3721b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * during the character conversion.  We need to patch
3722b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * up the size and eof info.
3723b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 */
3724b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (iseof)
3725b89a8333Snatalie li - Sun Microsystems - Irvine United States 			iseof = FALSE;
3726b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3727b89a8333Snatalie li - Sun Microsystems - Irvine United States 		ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3728b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    nents, ret);
3729b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
3730b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3731b89a8333Snatalie li - Sun Microsystems - Irvine United States 
37327c478bd9Sstevel@tonic-gate #if 0 /* notyet */
37337c478bd9Sstevel@tonic-gate 	/*
37347c478bd9Sstevel@tonic-gate 	 * Don't do this.  It causes local disk writes when just
37357c478bd9Sstevel@tonic-gate 	 * reading the file and the overhead is deemed larger
37367c478bd9Sstevel@tonic-gate 	 * than the benefit.
37377c478bd9Sstevel@tonic-gate 	 */
37387c478bd9Sstevel@tonic-gate 	/*
37397c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
37407c478bd9Sstevel@tonic-gate 	 */
3741da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
37427c478bd9Sstevel@tonic-gate #endif
37437c478bd9Sstevel@tonic-gate 
37447c478bd9Sstevel@tonic-gate 	kmem_free(namlen, args->dircount);
3745*dfdcac05SMarcel Telka 	if (ndata != data)
3746*dfdcac05SMarcel Telka 		kmem_free(data, args->dircount);
37477c478bd9Sstevel@tonic-gate 
37487c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
37497c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
37507c478bd9Sstevel@tonic-gate 	resp->resok.cookieverf = 0;
3751b89a8333Snatalie li - Sun Microsystems - Irvine United States 	resp->resok.reply.entries = (entryplus3 *)ndata;
37527c478bd9Sstevel@tonic-gate 	resp->resok.reply.eof = iseof;
37537c478bd9Sstevel@tonic-gate 	resp->resok.size = nents;
3754b89a8333Snatalie li - Sun Microsystems - Irvine United States 	resp->resok.count = args->dircount - ret;
37557c478bd9Sstevel@tonic-gate 	resp->resok.maxcount = args->maxcount;
3756e1adf50cSahl 
37570dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
37580dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
37590dfe541eSEvan Layton 	    READDIRPLUS3res *, resp);
3760e1adf50cSahl 
3761e1adf50cSahl 	VN_RELE(vp);
3762e1adf50cSahl 
37637c478bd9Sstevel@tonic-gate 	return;
37647c478bd9Sstevel@tonic-gate 
37657c478bd9Sstevel@tonic-gate out:
37667c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
37677c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
37687c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
3769b89a8333Snatalie li - Sun Microsystems - Irvine United States 	} else {
37707c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
3771b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
37727c478bd9Sstevel@tonic-gate out1:
37730dfe541eSEvan Layton 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
37740dfe541eSEvan Layton 
37750dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
37760dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
37770dfe541eSEvan Layton 	    READDIRPLUS3res *, resp);
3778e1adf50cSahl 
37797c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
37807c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
37817c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
37827c478bd9Sstevel@tonic-gate 	}
37837c478bd9Sstevel@tonic-gate 
37847c478bd9Sstevel@tonic-gate 	if (namlen != NULL)
37857c478bd9Sstevel@tonic-gate 		kmem_free(namlen, args->dircount);
37867c478bd9Sstevel@tonic-gate }
37877c478bd9Sstevel@tonic-gate 
378827242a7cSthurlow void *
rfs3_readdirplus_getfh(READDIRPLUS3args * args)37897c478bd9Sstevel@tonic-gate rfs3_readdirplus_getfh(READDIRPLUS3args *args)
37907c478bd9Sstevel@tonic-gate {
37917c478bd9Sstevel@tonic-gate 
379227242a7cSthurlow 	return (&args->dir);
37937c478bd9Sstevel@tonic-gate }
37947c478bd9Sstevel@tonic-gate 
37957c478bd9Sstevel@tonic-gate void
rfs3_readdirplus_free(READDIRPLUS3res * resp)37967c478bd9Sstevel@tonic-gate rfs3_readdirplus_free(READDIRPLUS3res *resp)
37977c478bd9Sstevel@tonic-gate {
37987c478bd9Sstevel@tonic-gate 
37997c478bd9Sstevel@tonic-gate 	if (resp->status == NFS3_OK) {
38007c478bd9Sstevel@tonic-gate 		kmem_free(resp->resok.reply.entries, resp->resok.count);
38017c478bd9Sstevel@tonic-gate 		kmem_free(resp->resok.infop,
3802cfae96c2Sjwahlig 		    resp->resok.size * sizeof (struct entryplus3_info));
38037c478bd9Sstevel@tonic-gate 	}
38047c478bd9Sstevel@tonic-gate }
38057c478bd9Sstevel@tonic-gate 
38067c478bd9Sstevel@tonic-gate /* ARGSUSED */
38077c478bd9Sstevel@tonic-gate void
rfs3_fsstat(FSSTAT3args * args,FSSTAT3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)38087c478bd9Sstevel@tonic-gate rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
38095cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
38107c478bd9Sstevel@tonic-gate {
38117c478bd9Sstevel@tonic-gate 	int error;
38127c478bd9Sstevel@tonic-gate 	vnode_t *vp;
38137c478bd9Sstevel@tonic-gate 	struct vattr *vap;
38147c478bd9Sstevel@tonic-gate 	struct vattr va;
38157c478bd9Sstevel@tonic-gate 	struct statvfs64 sb;
38167c478bd9Sstevel@tonic-gate 
38177c478bd9Sstevel@tonic-gate 	vap = NULL;
38187c478bd9Sstevel@tonic-gate 
38197c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->fsroot, exi);
3820e1adf50cSahl 
38210dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req,
38220dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
38230dfe541eSEvan Layton 	    FSSTAT3args *, args);
3824e1adf50cSahl 
38257c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
38267c478bd9Sstevel@tonic-gate 		error = ESTALE;
38277c478bd9Sstevel@tonic-gate 		goto out;
38287c478bd9Sstevel@tonic-gate 	}
38297c478bd9Sstevel@tonic-gate 
383003986916Sjarrett 	if (is_system_labeled()) {
383103986916Sjarrett 		bslabel_t *clabel = req->rq_label;
383203986916Sjarrett 
383303986916Sjarrett 		ASSERT(clabel != NULL);
383403986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
383503986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
383603986916Sjarrett 
383703986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3838bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3839bd6f1640SJarrett Lu 			    exi)) {
384003986916Sjarrett 				resp->status = NFS3ERR_ACCES;
384103986916Sjarrett 				goto out1;
384203986916Sjarrett 			}
384303986916Sjarrett 		}
384403986916Sjarrett 	}
384503986916Sjarrett 
38467c478bd9Sstevel@tonic-gate 	error = VFS_STATVFS(vp->v_vfsp, &sb);
38477c478bd9Sstevel@tonic-gate 
38487c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3849da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
38507c478bd9Sstevel@tonic-gate 
38517c478bd9Sstevel@tonic-gate 	if (error)
38527c478bd9Sstevel@tonic-gate 		goto out;
38537c478bd9Sstevel@tonic-gate 
38547c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
38557c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
38567c478bd9Sstevel@tonic-gate 	if (sb.f_blocks != (fsblkcnt64_t)-1)
38577c478bd9Sstevel@tonic-gate 		resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
38587c478bd9Sstevel@tonic-gate 	else
38597c478bd9Sstevel@tonic-gate 		resp->resok.tbytes = (size3)sb.f_blocks;
38607c478bd9Sstevel@tonic-gate 	if (sb.f_bfree != (fsblkcnt64_t)-1)
38617c478bd9Sstevel@tonic-gate 		resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
38627c478bd9Sstevel@tonic-gate 	else
38637c478bd9Sstevel@tonic-gate 		resp->resok.fbytes = (size3)sb.f_bfree;
38647c478bd9Sstevel@tonic-gate 	if (sb.f_bavail != (fsblkcnt64_t)-1)
38657c478bd9Sstevel@tonic-gate 		resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
38667c478bd9Sstevel@tonic-gate 	else
38677c478bd9Sstevel@tonic-gate 		resp->resok.abytes = (size3)sb.f_bavail;
38687c478bd9Sstevel@tonic-gate 	resp->resok.tfiles = (size3)sb.f_files;
38697c478bd9Sstevel@tonic-gate 	resp->resok.ffiles = (size3)sb.f_ffree;
38707c478bd9Sstevel@tonic-gate 	resp->resok.afiles = (size3)sb.f_favail;
38717c478bd9Sstevel@tonic-gate 	resp->resok.invarsec = 0;
3872e1adf50cSahl 
38730dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
38740dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
38750dfe541eSEvan Layton 	    FSSTAT3res *, resp);
3876e1adf50cSahl 	VN_RELE(vp);
3877e1adf50cSahl 
38787c478bd9Sstevel@tonic-gate 	return;
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate out:
38817c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
38827c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
38837c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
38847c478bd9Sstevel@tonic-gate 	} else
38857c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
388603986916Sjarrett out1:
38870dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
38880dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
38890dfe541eSEvan Layton 	    FSSTAT3res *, resp);
3890e1adf50cSahl 
389103986916Sjarrett 	if (vp != NULL)
389203986916Sjarrett 		VN_RELE(vp);
38937c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
38947c478bd9Sstevel@tonic-gate }
38957c478bd9Sstevel@tonic-gate 
389627242a7cSthurlow void *
rfs3_fsstat_getfh(FSSTAT3args * args)38977c478bd9Sstevel@tonic-gate rfs3_fsstat_getfh(FSSTAT3args *args)
38987c478bd9Sstevel@tonic-gate {
38997c478bd9Sstevel@tonic-gate 
390027242a7cSthurlow 	return (&args->fsroot);
39017c478bd9Sstevel@tonic-gate }
39027c478bd9Sstevel@tonic-gate 
39035cb0d679SMarcel Telka /* ARGSUSED */
39047c478bd9Sstevel@tonic-gate void
rfs3_fsinfo(FSINFO3args * args,FSINFO3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)39057c478bd9Sstevel@tonic-gate rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
39065cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
39077c478bd9Sstevel@tonic-gate {
39087c478bd9Sstevel@tonic-gate 	vnode_t *vp;
39097c478bd9Sstevel@tonic-gate 	struct vattr *vap;
39107c478bd9Sstevel@tonic-gate 	struct vattr va;
39117c478bd9Sstevel@tonic-gate 	uint32_t xfer_size;
39127c478bd9Sstevel@tonic-gate 	ulong_t l = 0;
39137c478bd9Sstevel@tonic-gate 	int error;
39147c478bd9Sstevel@tonic-gate 
39157c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->fsroot, exi);
3916e1adf50cSahl 
39170dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req,
39180dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
39190dfe541eSEvan Layton 	    FSINFO3args *, args);
3920e1adf50cSahl 
39217c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
39227c478bd9Sstevel@tonic-gate 		if (curthread->t_flag & T_WOULDBLOCK) {
39237c478bd9Sstevel@tonic-gate 			curthread->t_flag &= ~T_WOULDBLOCK;
39247c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
39257c478bd9Sstevel@tonic-gate 		} else
39267c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_STALE;
39277c478bd9Sstevel@tonic-gate 		vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3928e1adf50cSahl 		goto out;
39297c478bd9Sstevel@tonic-gate 	}
39307c478bd9Sstevel@tonic-gate 
393103986916Sjarrett 	if (is_system_labeled()) {
393203986916Sjarrett 		bslabel_t *clabel = req->rq_label;
393303986916Sjarrett 
393403986916Sjarrett 		ASSERT(clabel != NULL);
393503986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
393603986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
393703986916Sjarrett 
393803986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3939bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3940bd6f1640SJarrett Lu 			    exi)) {
394103986916Sjarrett 				resp->status = NFS3ERR_STALE;
394203986916Sjarrett 				vattr_to_post_op_attr(NULL,
394303986916Sjarrett 				    &resp->resfail.obj_attributes);
3944e1adf50cSahl 				goto out;
394503986916Sjarrett 			}
394603986916Sjarrett 		}
394703986916Sjarrett 	}
394803986916Sjarrett 
39497c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3950da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
39517c478bd9Sstevel@tonic-gate 
39527c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
39537c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
39547c478bd9Sstevel@tonic-gate 	xfer_size = rfs3_tsize(req);
39557c478bd9Sstevel@tonic-gate 	resp->resok.rtmax = xfer_size;
39567c478bd9Sstevel@tonic-gate 	resp->resok.rtpref = xfer_size;
39577c478bd9Sstevel@tonic-gate 	resp->resok.rtmult = DEV_BSIZE;
39587c478bd9Sstevel@tonic-gate 	resp->resok.wtmax = xfer_size;
39597c478bd9Sstevel@tonic-gate 	resp->resok.wtpref = xfer_size;
39607c478bd9Sstevel@tonic-gate 	resp->resok.wtmult = DEV_BSIZE;
39617c478bd9Sstevel@tonic-gate 	resp->resok.dtpref = MAXBSIZE;
39627c478bd9Sstevel@tonic-gate 
39637c478bd9Sstevel@tonic-gate 	/*
39647c478bd9Sstevel@tonic-gate 	 * Large file spec: want maxfilesize based on limit of
39657c478bd9Sstevel@tonic-gate 	 * underlying filesystem.  We can guess 2^31-1 if need be.
39667c478bd9Sstevel@tonic-gate 	 */
3967da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
3968710f82c5SPiyush Shivam 	if (error) {
3969710f82c5SPiyush Shivam 		resp->status = puterrno3(error);
3970710f82c5SPiyush Shivam 		goto out;
3971710f82c5SPiyush Shivam 	}
39727c478bd9Sstevel@tonic-gate 
3973710f82c5SPiyush Shivam 	/*
3974710f82c5SPiyush Shivam 	 * If the underlying file system does not support _PC_FILESIZEBITS,
3975710f82c5SPiyush Shivam 	 * return a reasonable default. Note that error code on VOP_PATHCONF
3976710f82c5SPiyush Shivam 	 * will be 0, even if the underlying file system does not support
3977710f82c5SPiyush Shivam 	 * _PC_FILESIZEBITS.
3978710f82c5SPiyush Shivam 	 */
3979710f82c5SPiyush Shivam 	if (l == (ulong_t)-1) {
39807c478bd9Sstevel@tonic-gate 		resp->resok.maxfilesize = MAXOFF32_T;
3981710f82c5SPiyush Shivam 	} else {
3982710f82c5SPiyush Shivam 		if (l >= (sizeof (uint64_t) * 8))
3983710f82c5SPiyush Shivam 			resp->resok.maxfilesize = INT64_MAX;
3984710f82c5SPiyush Shivam 		else
3985710f82c5SPiyush Shivam 			resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3986710f82c5SPiyush Shivam 	}
39877c478bd9Sstevel@tonic-gate 
39887c478bd9Sstevel@tonic-gate 	resp->resok.time_delta.seconds = 0;
39897c478bd9Sstevel@tonic-gate 	resp->resok.time_delta.nseconds = 1000;
39907c478bd9Sstevel@tonic-gate 	resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
39917c478bd9Sstevel@tonic-gate 	    FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3992e1adf50cSahl 
39930dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
39940dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
39950dfe541eSEvan Layton 	    FSINFO3res *, resp);
3996e1adf50cSahl 
3997e1adf50cSahl 	VN_RELE(vp);
3998e1adf50cSahl 
3999e1adf50cSahl 	return;
4000e1adf50cSahl 
4001e1adf50cSahl out:
40020dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
40030dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi,
40040dfe541eSEvan Layton 	    FSINFO3res *, resp);
4005e1adf50cSahl 	if (vp != NULL)
4006e1adf50cSahl 		VN_RELE(vp);
40077c478bd9Sstevel@tonic-gate }
40087c478bd9Sstevel@tonic-gate 
400927242a7cSthurlow void *
rfs3_fsinfo_getfh(FSINFO3args * args)40107c478bd9Sstevel@tonic-gate rfs3_fsinfo_getfh(FSINFO3args *args)
40117c478bd9Sstevel@tonic-gate {
401227242a7cSthurlow 	return (&args->fsroot);
40137c478bd9Sstevel@tonic-gate }
40147c478bd9Sstevel@tonic-gate 
40157c478bd9Sstevel@tonic-gate /* ARGSUSED */
40167c478bd9Sstevel@tonic-gate void
rfs3_pathconf(PATHCONF3args * args,PATHCONF3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)40177c478bd9Sstevel@tonic-gate rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
40185cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
40197c478bd9Sstevel@tonic-gate {
40207c478bd9Sstevel@tonic-gate 	int error;
40217c478bd9Sstevel@tonic-gate 	vnode_t *vp;
40227c478bd9Sstevel@tonic-gate 	struct vattr *vap;
40237c478bd9Sstevel@tonic-gate 	struct vattr va;
40247c478bd9Sstevel@tonic-gate 	ulong_t val;
40257c478bd9Sstevel@tonic-gate 
40267c478bd9Sstevel@tonic-gate 	vap = NULL;
40277c478bd9Sstevel@tonic-gate 
40287c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
4029e1adf50cSahl 
40300dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req,
40310dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
40320dfe541eSEvan Layton 	    PATHCONF3args *, args);
4033e1adf50cSahl 
40347c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
40357c478bd9Sstevel@tonic-gate 		error = ESTALE;
40367c478bd9Sstevel@tonic-gate 		goto out;
40377c478bd9Sstevel@tonic-gate 	}
40387c478bd9Sstevel@tonic-gate 
403903986916Sjarrett 	if (is_system_labeled()) {
404003986916Sjarrett 		bslabel_t *clabel = req->rq_label;
404103986916Sjarrett 
404203986916Sjarrett 		ASSERT(clabel != NULL);
404303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
404403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
404503986916Sjarrett 
404603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
4047bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4048bd6f1640SJarrett Lu 			    exi)) {
404903986916Sjarrett 				resp->status = NFS3ERR_ACCES;
405003986916Sjarrett 				goto out1;
405103986916Sjarrett 			}
405203986916Sjarrett 		}
405303986916Sjarrett 	}
405403986916Sjarrett 
40557c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
4056da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
40577c478bd9Sstevel@tonic-gate 
4058da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
40597c478bd9Sstevel@tonic-gate 	if (error)
40607c478bd9Sstevel@tonic-gate 		goto out;
40617c478bd9Sstevel@tonic-gate 	resp->resok.info.link_max = (uint32)val;
40627c478bd9Sstevel@tonic-gate 
4063da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
40647c478bd9Sstevel@tonic-gate 	if (error)
40657c478bd9Sstevel@tonic-gate 		goto out;
40667c478bd9Sstevel@tonic-gate 	resp->resok.info.name_max = (uint32)val;
40677c478bd9Sstevel@tonic-gate 
4068da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
40697c478bd9Sstevel@tonic-gate 	if (error)
40707c478bd9Sstevel@tonic-gate 		goto out;
40717c478bd9Sstevel@tonic-gate 	if (val == 1)
40727c478bd9Sstevel@tonic-gate 		resp->resok.info.no_trunc = TRUE;
40737c478bd9Sstevel@tonic-gate 	else
40747c478bd9Sstevel@tonic-gate 		resp->resok.info.no_trunc = FALSE;
40757c478bd9Sstevel@tonic-gate 
4076da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
40777c478bd9Sstevel@tonic-gate 	if (error)
40787c478bd9Sstevel@tonic-gate 		goto out;
40797c478bd9Sstevel@tonic-gate 	if (val == 1)
40807c478bd9Sstevel@tonic-gate 		resp->resok.info.chown_restricted = TRUE;
40817c478bd9Sstevel@tonic-gate 	else
40827c478bd9Sstevel@tonic-gate 		resp->resok.info.chown_restricted = FALSE;
40837c478bd9Sstevel@tonic-gate 
40847c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
40857c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
40867c478bd9Sstevel@tonic-gate 	resp->resok.info.case_insensitive = FALSE;
40877c478bd9Sstevel@tonic-gate 	resp->resok.info.case_preserving = TRUE;
40880dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
40890dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
40900dfe541eSEvan Layton 	    PATHCONF3res *, resp);
4091e1adf50cSahl 	VN_RELE(vp);
40927c478bd9Sstevel@tonic-gate 	return;
40937c478bd9Sstevel@tonic-gate 
40947c478bd9Sstevel@tonic-gate out:
40957c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
40967c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
40977c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
40987c478bd9Sstevel@tonic-gate 	} else
40997c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
410003986916Sjarrett out1:
41010dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
41020dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
41030dfe541eSEvan Layton 	    PATHCONF3res *, resp);
41047c478bd9Sstevel@tonic-gate 	if (vp != NULL)
41057c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
41067c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
41077c478bd9Sstevel@tonic-gate }
41087c478bd9Sstevel@tonic-gate 
410927242a7cSthurlow void *
rfs3_pathconf_getfh(PATHCONF3args * args)41107c478bd9Sstevel@tonic-gate rfs3_pathconf_getfh(PATHCONF3args *args)
41117c478bd9Sstevel@tonic-gate {
41127c478bd9Sstevel@tonic-gate 
411327242a7cSthurlow 	return (&args->object);
41147c478bd9Sstevel@tonic-gate }
41157c478bd9Sstevel@tonic-gate 
41167c478bd9Sstevel@tonic-gate void
rfs3_commit(COMMIT3args * args,COMMIT3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)41177c478bd9Sstevel@tonic-gate rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
41185cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
41197c478bd9Sstevel@tonic-gate {
41200dfe541eSEvan Layton 	nfs3_srv_t *ns;
41217c478bd9Sstevel@tonic-gate 	int error;
41227c478bd9Sstevel@tonic-gate 	vnode_t *vp;
41237c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
41247c478bd9Sstevel@tonic-gate 	struct vattr bva;
41257c478bd9Sstevel@tonic-gate 	struct vattr *avap;
41267c478bd9Sstevel@tonic-gate 	struct vattr ava;
41277c478bd9Sstevel@tonic-gate 
41287c478bd9Sstevel@tonic-gate 	bvap = NULL;
41297c478bd9Sstevel@tonic-gate 	avap = NULL;
41307c478bd9Sstevel@tonic-gate 
41317c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
4132e1adf50cSahl 
41330dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req,
41340dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
41350dfe541eSEvan Layton 	    COMMIT3args *, args);
4136e1adf50cSahl 
41377c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
41387c478bd9Sstevel@tonic-gate 		error = ESTALE;
41397c478bd9Sstevel@tonic-gate 		goto out;
41407c478bd9Sstevel@tonic-gate 	}
41417c478bd9Sstevel@tonic-gate 
41420dfe541eSEvan Layton 	ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
41430dfe541eSEvan Layton 	ns = nfs3_get_srv();
41447c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
4145da6c28aaSamw 	error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
41467c478bd9Sstevel@tonic-gate 
41477c478bd9Sstevel@tonic-gate 	/*
41487c478bd9Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
41497c478bd9Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
41507c478bd9Sstevel@tonic-gate 	 */
41517c478bd9Sstevel@tonic-gate 	if (error)
41527c478bd9Sstevel@tonic-gate 		goto out;
41537c478bd9Sstevel@tonic-gate 
41547c478bd9Sstevel@tonic-gate 	bvap = &bva;
41557c478bd9Sstevel@tonic-gate 
41565cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
41577c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
41587c478bd9Sstevel@tonic-gate 		goto out1;
41597c478bd9Sstevel@tonic-gate 	}
41607c478bd9Sstevel@tonic-gate 
41617c478bd9Sstevel@tonic-gate 	if (vp->v_type != VREG) {
41627c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
41637c478bd9Sstevel@tonic-gate 		goto out1;
41647c478bd9Sstevel@tonic-gate 	}
41657c478bd9Sstevel@tonic-gate 
416603986916Sjarrett 	if (is_system_labeled()) {
416703986916Sjarrett 		bslabel_t *clabel = req->rq_label;
416803986916Sjarrett 
416903986916Sjarrett 		ASSERT(clabel != NULL);
417003986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
417103986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
417203986916Sjarrett 
417303986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
4174bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
4175bd6f1640SJarrett Lu 			    exi)) {
417603986916Sjarrett 				resp->status = NFS3ERR_ACCES;
417703986916Sjarrett 				goto out1;
417803986916Sjarrett 			}
417903986916Sjarrett 		}
418003986916Sjarrett 	}
418103986916Sjarrett 
41827c478bd9Sstevel@tonic-gate 	if (crgetuid(cr) != bva.va_uid &&
4183da6c28aaSamw 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
41847c478bd9Sstevel@tonic-gate 		goto out;
41857c478bd9Sstevel@tonic-gate 
4186f63200e6SJeff A. Smith 	error = VOP_FSYNC(vp, FSYNC, cr, NULL);
41877c478bd9Sstevel@tonic-gate 
41887c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
4189da6c28aaSamw 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
41907c478bd9Sstevel@tonic-gate 
41917c478bd9Sstevel@tonic-gate 	if (error)
41927c478bd9Sstevel@tonic-gate 		goto out;
41937c478bd9Sstevel@tonic-gate 
41947c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
41957c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
41960dfe541eSEvan Layton 	resp->resok.verf = ns->write3verf;
4197e1adf50cSahl 
41980dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
41990dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
42000dfe541eSEvan Layton 	    COMMIT3res *, resp);
4201e1adf50cSahl 
4202e1adf50cSahl 	VN_RELE(vp);
4203e1adf50cSahl 
42047c478bd9Sstevel@tonic-gate 	return;
42057c478bd9Sstevel@tonic-gate 
42067c478bd9Sstevel@tonic-gate out:
42077c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
42087c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
42097c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
42107c478bd9Sstevel@tonic-gate 	} else
42117c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
42127c478bd9Sstevel@tonic-gate out1:
42130dfe541eSEvan Layton 	DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
42140dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
42150dfe541eSEvan Layton 	    COMMIT3res *, resp);
4216e1adf50cSahl 
42177c478bd9Sstevel@tonic-gate 	if (vp != NULL)
42187c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
42197c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
42207c478bd9Sstevel@tonic-gate }
42217c478bd9Sstevel@tonic-gate 
422227242a7cSthurlow void *
rfs3_commit_getfh(COMMIT3args * args)42237c478bd9Sstevel@tonic-gate rfs3_commit_getfh(COMMIT3args *args)
42247c478bd9Sstevel@tonic-gate {
42257c478bd9Sstevel@tonic-gate 
422627242a7cSthurlow 	return (&args->file);
42277c478bd9Sstevel@tonic-gate }
42287c478bd9Sstevel@tonic-gate 
42297c478bd9Sstevel@tonic-gate static int
sattr3_to_vattr(sattr3 * sap,struct vattr * vap)42307c478bd9Sstevel@tonic-gate sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
42317c478bd9Sstevel@tonic-gate {
42327c478bd9Sstevel@tonic-gate 
42337c478bd9Sstevel@tonic-gate 	vap->va_mask = 0;
42347c478bd9Sstevel@tonic-gate 
42357c478bd9Sstevel@tonic-gate 	if (sap->mode.set_it) {
42367c478bd9Sstevel@tonic-gate 		vap->va_mode = (mode_t)sap->mode.mode;
42377c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_MODE;
42387c478bd9Sstevel@tonic-gate 	}
42397c478bd9Sstevel@tonic-gate 	if (sap->uid.set_it) {
42407c478bd9Sstevel@tonic-gate 		vap->va_uid = (uid_t)sap->uid.uid;
42417c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_UID;
42427c478bd9Sstevel@tonic-gate 	}
42437c478bd9Sstevel@tonic-gate 	if (sap->gid.set_it) {
42447c478bd9Sstevel@tonic-gate 		vap->va_gid = (gid_t)sap->gid.gid;
42457c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_GID;
42467c478bd9Sstevel@tonic-gate 	}
42477c478bd9Sstevel@tonic-gate 	if (sap->size.set_it) {
42487c478bd9Sstevel@tonic-gate 		if (sap->size.size > (size3)((u_longlong_t)-1))
42497c478bd9Sstevel@tonic-gate 			return (EINVAL);
42507c478bd9Sstevel@tonic-gate 		vap->va_size = sap->size.size;
42517c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_SIZE;
42527c478bd9Sstevel@tonic-gate 	}
42537c478bd9Sstevel@tonic-gate 	if (sap->atime.set_it == SET_TO_CLIENT_TIME) {
42547c478bd9Sstevel@tonic-gate #ifndef _LP64
42557c478bd9Sstevel@tonic-gate 		/* check time validity */
42567c478bd9Sstevel@tonic-gate 		if (!NFS3_TIME_OK(sap->atime.atime.seconds))
42577c478bd9Sstevel@tonic-gate 			return (EOVERFLOW);
42587c478bd9Sstevel@tonic-gate #endif
42597c478bd9Sstevel@tonic-gate 		/*
42607c478bd9Sstevel@tonic-gate 		 * nfs protocol defines times as unsigned so don't extend sign,
42617c478bd9Sstevel@tonic-gate 		 * unless sysadmin set nfs_allow_preepoch_time.
42627c478bd9Sstevel@tonic-gate 		 */
42637c478bd9Sstevel@tonic-gate 		NFS_TIME_T_CONVERT(vap->va_atime.tv_sec,
4264cfae96c2Sjwahlig 		    sap->atime.atime.seconds);
42657c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds;
42667c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_ATIME;
42677c478bd9Sstevel@tonic-gate 	} else if (sap->atime.set_it == SET_TO_SERVER_TIME) {
42687c478bd9Sstevel@tonic-gate 		gethrestime(&vap->va_atime);
42697c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_ATIME;
42707c478bd9Sstevel@tonic-gate 	}
42717c478bd9Sstevel@tonic-gate 	if (sap->mtime.set_it == SET_TO_CLIENT_TIME) {
42727c478bd9Sstevel@tonic-gate #ifndef _LP64
42737c478bd9Sstevel@tonic-gate 		/* check time validity */
42747c478bd9Sstevel@tonic-gate 		if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
42757c478bd9Sstevel@tonic-gate 			return (EOVERFLOW);
42767c478bd9Sstevel@tonic-gate #endif
42777c478bd9Sstevel@tonic-gate 		/*
42787c478bd9Sstevel@tonic-gate 		 * nfs protocol defines times as unsigned so don't extend sign,
42797c478bd9Sstevel@tonic-gate 		 * unless sysadmin set nfs_allow_preepoch_time.
42807c478bd9Sstevel@tonic-gate 		 */
42817c478bd9Sstevel@tonic-gate 		NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4282cfae96c2Sjwahlig 		    sap->mtime.mtime.seconds);
42837c478bd9Sstevel@tonic-gate 		vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
42847c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_MTIME;
42857c478bd9Sstevel@tonic-gate 	} else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
42867c478bd9Sstevel@tonic-gate 		gethrestime(&vap->va_mtime);
42877c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_MTIME;
42887c478bd9Sstevel@tonic-gate 	}
42897c478bd9Sstevel@tonic-gate 
42907c478bd9Sstevel@tonic-gate 	return (0);
42917c478bd9Sstevel@tonic-gate }
42927c478bd9Sstevel@tonic-gate 
42930dfe541eSEvan Layton static const ftype3 vt_to_nf3[] = {
42947c478bd9Sstevel@tonic-gate 	0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
42957c478bd9Sstevel@tonic-gate };
42967c478bd9Sstevel@tonic-gate 
42977c478bd9Sstevel@tonic-gate static int
vattr_to_fattr3(struct vattr * vap,fattr3 * fap)42987c478bd9Sstevel@tonic-gate vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
42997c478bd9Sstevel@tonic-gate {
43007c478bd9Sstevel@tonic-gate 
43017c478bd9Sstevel@tonic-gate 	ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
43027c478bd9Sstevel@tonic-gate 	/* Return error if time or size overflow */
43037c478bd9Sstevel@tonic-gate 	if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
43047c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
43057c478bd9Sstevel@tonic-gate 	}
43067c478bd9Sstevel@tonic-gate 	fap->type = vt_to_nf3[vap->va_type];
43077c478bd9Sstevel@tonic-gate 	fap->mode = (mode3)(vap->va_mode & MODEMASK);
43087c478bd9Sstevel@tonic-gate 	fap->nlink = (uint32)vap->va_nlink;
43097c478bd9Sstevel@tonic-gate 	if (vap->va_uid == UID_NOBODY)
43107c478bd9Sstevel@tonic-gate 		fap->uid = (uid3)NFS_UID_NOBODY;
43117c478bd9Sstevel@tonic-gate 	else
43127c478bd9Sstevel@tonic-gate 		fap->uid = (uid3)vap->va_uid;
43137c478bd9Sstevel@tonic-gate 	if (vap->va_gid == GID_NOBODY)
43147c478bd9Sstevel@tonic-gate 		fap->gid = (gid3)NFS_GID_NOBODY;
43157c478bd9Sstevel@tonic-gate 	else
43167c478bd9Sstevel@tonic-gate 		fap->gid = (gid3)vap->va_gid;
43177c478bd9Sstevel@tonic-gate 	fap->size = (size3)vap->va_size;
43187c478bd9Sstevel@tonic-gate 	fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks;
43197c478bd9Sstevel@tonic-gate 	fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev);
43207c478bd9Sstevel@tonic-gate 	fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev);
43217c478bd9Sstevel@tonic-gate 	fap->fsid = (uint64)vap->va_fsid;
43227c478bd9Sstevel@tonic-gate 	fap->fileid = (fileid3)vap->va_nodeid;
43237c478bd9Sstevel@tonic-gate 	fap->atime.seconds = vap->va_atime.tv_sec;
43247c478bd9Sstevel@tonic-gate 	fap->atime.nseconds = vap->va_atime.tv_nsec;
43257c478bd9Sstevel@tonic-gate 	fap->mtime.seconds = vap->va_mtime.tv_sec;
43267c478bd9Sstevel@tonic-gate 	fap->mtime.nseconds = vap->va_mtime.tv_nsec;
43277c478bd9Sstevel@tonic-gate 	fap->ctime.seconds = vap->va_ctime.tv_sec;
43287c478bd9Sstevel@tonic-gate 	fap->ctime.nseconds = vap->va_ctime.tv_nsec;
43297c478bd9Sstevel@tonic-gate 	return (0);
43307c478bd9Sstevel@tonic-gate }
43317c478bd9Sstevel@tonic-gate 
43327c478bd9Sstevel@tonic-gate static int
vattr_to_wcc_attr(struct vattr * vap,wcc_attr * wccap)43337c478bd9Sstevel@tonic-gate vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap)
43347c478bd9Sstevel@tonic-gate {
43357c478bd9Sstevel@tonic-gate 
43367c478bd9Sstevel@tonic-gate 	/* Return error if time or size overflow */
43370a701b1eSRobert Gordon 	if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) &&
4338cfae96c2Sjwahlig 	    NFS_TIME_T_OK(vap->va_ctime.tv_sec) &&
4339cfae96c2Sjwahlig 	    NFS3_SIZE_OK(vap->va_size))) {
43407c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
43417c478bd9Sstevel@tonic-gate 	}
43427c478bd9Sstevel@tonic-gate 	wccap->size = (size3)vap->va_size;
43437c478bd9Sstevel@tonic-gate 	wccap->mtime.seconds = vap->va_mtime.tv_sec;
43447c478bd9Sstevel@tonic-gate 	wccap->mtime.nseconds = vap->va_mtime.tv_nsec;
43457c478bd9Sstevel@tonic-gate 	wccap->ctime.seconds = vap->va_ctime.tv_sec;
43467c478bd9Sstevel@tonic-gate 	wccap->ctime.nseconds = vap->va_ctime.tv_nsec;
43477c478bd9Sstevel@tonic-gate 	return (0);
43487c478bd9Sstevel@tonic-gate }
43497c478bd9Sstevel@tonic-gate 
43507c478bd9Sstevel@tonic-gate static void
vattr_to_pre_op_attr(struct vattr * vap,pre_op_attr * poap)43517c478bd9Sstevel@tonic-gate vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap)
43527c478bd9Sstevel@tonic-gate {
43537c478bd9Sstevel@tonic-gate 
43547c478bd9Sstevel@tonic-gate 	/* don't return attrs if time overflow */
43557c478bd9Sstevel@tonic-gate 	if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
43567c478bd9Sstevel@tonic-gate 		poap->attributes = TRUE;
43577c478bd9Sstevel@tonic-gate 	} else
43587c478bd9Sstevel@tonic-gate 		poap->attributes = FALSE;
43597c478bd9Sstevel@tonic-gate }
43607c478bd9Sstevel@tonic-gate 
43617c478bd9Sstevel@tonic-gate void
vattr_to_post_op_attr(struct vattr * vap,post_op_attr * poap)43627c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
43637c478bd9Sstevel@tonic-gate {
43647c478bd9Sstevel@tonic-gate 
43657c478bd9Sstevel@tonic-gate 	/* don't return attrs if time overflow */
43667c478bd9Sstevel@tonic-gate 	if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
43677c478bd9Sstevel@tonic-gate 		poap->attributes = TRUE;
43687c478bd9Sstevel@tonic-gate 	} else
43697c478bd9Sstevel@tonic-gate 		poap->attributes = FALSE;
43707c478bd9Sstevel@tonic-gate }
43717c478bd9Sstevel@tonic-gate 
43727c478bd9Sstevel@tonic-gate static void
vattr_to_wcc_data(struct vattr * bvap,struct vattr * avap,wcc_data * wccp)43737c478bd9Sstevel@tonic-gate vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
43747c478bd9Sstevel@tonic-gate {
43757c478bd9Sstevel@tonic-gate 	vattr_to_pre_op_attr(bvap, &wccp->before);
43767c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(avap, &wccp->after);
43777c478bd9Sstevel@tonic-gate }
43787c478bd9Sstevel@tonic-gate 
43790dfe541eSEvan Layton static int
rdma_setup_read_data3(READ3args * args,READ3resok * rok)43800dfe541eSEvan Layton rdma_setup_read_data3(READ3args *args, READ3resok *rok)
43810dfe541eSEvan Layton {
43820dfe541eSEvan Layton 	struct clist	*wcl;
43830dfe541eSEvan Layton 	int		wlist_len;
43840dfe541eSEvan Layton 	count3		count = rok->count;
43850dfe541eSEvan Layton 
43860dfe541eSEvan Layton 	wcl = args->wlist;
43870dfe541eSEvan Layton 	if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE)
43880dfe541eSEvan Layton 		return (FALSE);
43890dfe541eSEvan Layton 
43900dfe541eSEvan Layton 	wcl = args->wlist;
43910dfe541eSEvan Layton 	rok->wlist_len = wlist_len;
43920dfe541eSEvan Layton 	rok->wlist = wcl;
43930dfe541eSEvan Layton 	return (TRUE);
43940dfe541eSEvan Layton }
43950dfe541eSEvan Layton 
43967c478bd9Sstevel@tonic-gate void
rfs3_srv_zone_init(nfs_globals_t * ng)43970dfe541eSEvan Layton rfs3_srv_zone_init(nfs_globals_t *ng)
43987c478bd9Sstevel@tonic-gate {
43990dfe541eSEvan Layton 	nfs3_srv_t *ns;
44007c478bd9Sstevel@tonic-gate 	struct rfs3_verf_overlay {
44017c478bd9Sstevel@tonic-gate 		uint_t id; /* a "unique" identifier */
44027c478bd9Sstevel@tonic-gate 		int ts; /* a unique timestamp */
44037c478bd9Sstevel@tonic-gate 	} *verfp;
44047c478bd9Sstevel@tonic-gate 	timestruc_t now;
44057c478bd9Sstevel@tonic-gate 
44060dfe541eSEvan Layton 	ns = kmem_zalloc(sizeof (*ns), KM_SLEEP);
44070dfe541eSEvan Layton 
44087c478bd9Sstevel@tonic-gate 	/*
44097c478bd9Sstevel@tonic-gate 	 * The following algorithm attempts to find a unique verifier
44107c478bd9Sstevel@tonic-gate 	 * to be used as the write verifier returned from the server
44117c478bd9Sstevel@tonic-gate 	 * to the client.  It is important that this verifier change
44127c478bd9Sstevel@tonic-gate 	 * whenever the server reboots.  Of secondary importance, it
44137c478bd9Sstevel@tonic-gate 	 * is important for the verifier to be unique between two
44147c478bd9Sstevel@tonic-gate 	 * different servers.
44157c478bd9Sstevel@tonic-gate 	 *
44167c478bd9Sstevel@tonic-gate 	 * Thus, an attempt is made to use the system hostid and the
44177c478bd9Sstevel@tonic-gate 	 * current time in seconds when the nfssrv kernel module is
44187c478bd9Sstevel@tonic-gate 	 * loaded.  It is assumed that an NFS server will not be able
44197c478bd9Sstevel@tonic-gate 	 * to boot and then to reboot in less than a second.  If the
44207c478bd9Sstevel@tonic-gate 	 * hostid has not been set, then the current high resolution
44217c478bd9Sstevel@tonic-gate 	 * time is used.  This will ensure different verifiers each
44227c478bd9Sstevel@tonic-gate 	 * time the server reboots and minimize the chances that two
44237c478bd9Sstevel@tonic-gate 	 * different servers will have the same verifier.
44247c478bd9Sstevel@tonic-gate 	 */
44257c478bd9Sstevel@tonic-gate 
44267c478bd9Sstevel@tonic-gate #ifndef	lint
44277c478bd9Sstevel@tonic-gate 	/*
44287c478bd9Sstevel@tonic-gate 	 * We ASSERT that this constant logic expression is
44297c478bd9Sstevel@tonic-gate 	 * always true because in the past, it wasn't.
44307c478bd9Sstevel@tonic-gate 	 */
44310dfe541eSEvan Layton 	ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf));
44327c478bd9Sstevel@tonic-gate #endif
44337c478bd9Sstevel@tonic-gate 
44347c478bd9Sstevel@tonic-gate 	gethrestime(&now);
44350dfe541eSEvan Layton 	verfp = (struct rfs3_verf_overlay *)&ns->write3verf;
44367c478bd9Sstevel@tonic-gate 	verfp->ts = (int)now.tv_sec;
44375679c89fSjv 	verfp->id = zone_get_hostid(NULL);
44387c478bd9Sstevel@tonic-gate 
44397c478bd9Sstevel@tonic-gate 	if (verfp->id == 0)
44407c478bd9Sstevel@tonic-gate 		verfp->id = (uint_t)now.tv_nsec;
44417c478bd9Sstevel@tonic-gate 
44420dfe541eSEvan Layton 	ng->nfs3_srv = ns;
44437c478bd9Sstevel@tonic-gate }
44447c478bd9Sstevel@tonic-gate 
44450dfe541eSEvan Layton void
rfs3_srv_zone_fini(nfs_globals_t * ng)44460dfe541eSEvan Layton rfs3_srv_zone_fini(nfs_globals_t *ng)
44470a701b1eSRobert Gordon {
44480dfe541eSEvan Layton 	nfs3_srv_t *ns = ng->nfs3_srv;
44490a701b1eSRobert Gordon 
44500dfe541eSEvan Layton 	ng->nfs3_srv = NULL;
44510a701b1eSRobert Gordon 
44520dfe541eSEvan Layton 	kmem_free(ns, sizeof (*ns));
44530dfe541eSEvan Layton }
44540dfe541eSEvan Layton 
44550dfe541eSEvan Layton void
rfs3_srvrinit(void)44560dfe541eSEvan Layton rfs3_srvrinit(void)
44570dfe541eSEvan Layton {
44580dfe541eSEvan Layton 	nfs3_srv_caller_id = fs_new_caller_id();
44590a701b1eSRobert Gordon }
44600a701b1eSRobert Gordon 
44617c478bd9Sstevel@tonic-gate void
rfs3_srvrfini(void)44627c478bd9Sstevel@tonic-gate rfs3_srvrfini(void)
44637c478bd9Sstevel@tonic-gate {
44647c478bd9Sstevel@tonic-gate 	/* Nothing to do */
44657c478bd9Sstevel@tonic-gate }
4466