xref: /titanic_51/usr/src/uts/common/fs/nfs/nfs3_srv.c (revision fbd2e8e189c52419d4ad4d1ebec410789b38c84c)
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 /*
23f46abf18SMarcel Telka  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
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 
317c478bd9Sstevel@tonic-gate #include <sys/param.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/cred.h>
357c478bd9Sstevel@tonic-gate #include <sys/buf.h>
367c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
377c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
387c478bd9Sstevel@tonic-gate #include <sys/uio.h>
397c478bd9Sstevel@tonic-gate #include <sys/errno.h>
407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
417c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
427c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
437c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
447c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
457c478bd9Sstevel@tonic-gate #include <sys/debug.h>
467c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
477c478bd9Sstevel@tonic-gate #include <sys/flock.h>
487c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h>
497c478bd9Sstevel@tonic-gate #include <sys/policy.h>
5003986916Sjarrett #include <sys/sdt.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include <rpc/types.h>
537c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
547c478bd9Sstevel@tonic-gate #include <rpc/svc.h>
550a701b1eSRobert Gordon #include <rpc/rpc_rdma.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
587c478bd9Sstevel@tonic-gate #include <nfs/export.h>
59b89a8333Snatalie li - Sun Microsystems - Irvine United States #include <nfs/nfs_cmd.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
6203986916Sjarrett #include <sys/tsol/label.h>
6303986916Sjarrett #include <sys/tsol/tndb.h>
6403986916Sjarrett 
655679c89fSjv227347 #include <sys/zone.h>
665679c89fSjv227347 
6703986916Sjarrett #include <inet/ip.h>
6803986916Sjarrett #include <inet/ip6.h>
6903986916Sjarrett 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * These are the interface routines for the server side of the
727c478bd9Sstevel@tonic-gate  * Network File System.  See the NFS version 3 protocol specification
737c478bd9Sstevel@tonic-gate  * for a description of this interface.
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static writeverf3 write3verf;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static int	sattr3_to_vattr(sattr3 *, struct vattr *);
797c478bd9Sstevel@tonic-gate static int	vattr_to_fattr3(struct vattr *, fattr3 *);
807c478bd9Sstevel@tonic-gate static int	vattr_to_wcc_attr(struct vattr *, wcc_attr *);
817c478bd9Sstevel@tonic-gate static void	vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
827c478bd9Sstevel@tonic-gate static void	vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
830a701b1eSRobert Gordon static int	rdma_setup_read_data3(READ3args *, READ3resok *);
847c478bd9Sstevel@tonic-gate 
85c242f9a0Schunli zhang - Sun Microsystems - Irvine United States extern int nfs_loaned_buffers;
86c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
87cfae96c2Sjwahlig u_longlong_t nfs3_srv_caller_id;
88cfae96c2Sjwahlig 
897c478bd9Sstevel@tonic-gate /* ARGSUSED */
907c478bd9Sstevel@tonic-gate void
917c478bd9Sstevel@tonic-gate rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
925cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	int error;
957c478bd9Sstevel@tonic-gate 	vnode_t *vp;
967c478bd9Sstevel@tonic-gate 	struct vattr va;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
99e1adf50cSahl 
100e1adf50cSahl 	DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req,
101e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, GETATTR3args *, args);
102e1adf50cSahl 
1037c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
1047c478bd9Sstevel@tonic-gate 		error = ESTALE;
1057c478bd9Sstevel@tonic-gate 		goto out;
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1097c478bd9Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &va, 0, cr);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	if (!error) {
1122f172c55SRobert Thurlow 		/* Lie about the object type for a referral */
1132f172c55SRobert Thurlow 		if (vn_is_nfs_reparse(vp, cr))
1142f172c55SRobert Thurlow 			va.va_type = VLNK;
1152f172c55SRobert Thurlow 
1167c478bd9Sstevel@tonic-gate 		/* overflow error if time or size is out of range */
1177c478bd9Sstevel@tonic-gate 		error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
1187c478bd9Sstevel@tonic-gate 		if (error)
1197c478bd9Sstevel@tonic-gate 			goto out;
1207c478bd9Sstevel@tonic-gate 		resp->status = NFS3_OK;
121e1adf50cSahl 
122e1adf50cSahl 		DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
123e1adf50cSahl 		    cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
124e1adf50cSahl 
125e1adf50cSahl 		VN_RELE(vp);
126e1adf50cSahl 
1277c478bd9Sstevel@tonic-gate 		return;
1287c478bd9Sstevel@tonic-gate 	}
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate out:
1317c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
1327c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
1337c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
1347c478bd9Sstevel@tonic-gate 	} else
1357c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
136e1adf50cSahl 
137e1adf50cSahl 	DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
138e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
139e1adf50cSahl 
140e1adf50cSahl 	if (vp != NULL)
141e1adf50cSahl 		VN_RELE(vp);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
14427242a7cSthurlow void *
1457c478bd9Sstevel@tonic-gate rfs3_getattr_getfh(GETATTR3args *args)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 
14827242a7cSthurlow 	return (&args->object);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate void
1527c478bd9Sstevel@tonic-gate rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
1535cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	int error;
1567c478bd9Sstevel@tonic-gate 	vnode_t *vp;
1577c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
1587c478bd9Sstevel@tonic-gate 	struct vattr bva;
1597c478bd9Sstevel@tonic-gate 	struct vattr *avap;
1607c478bd9Sstevel@tonic-gate 	struct vattr ava;
1617c478bd9Sstevel@tonic-gate 	int flag;
1627c478bd9Sstevel@tonic-gate 	int in_crit = 0;
1637c478bd9Sstevel@tonic-gate 	struct flock64 bf;
164cfae96c2Sjwahlig 	caller_context_t ct;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	bvap = NULL;
1677c478bd9Sstevel@tonic-gate 	avap = NULL;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
170e1adf50cSahl 
171e1adf50cSahl 	DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req,
172e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, SETATTR3args *, args);
173e1adf50cSahl 
1747c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
1757c478bd9Sstevel@tonic-gate 		error = ESTALE;
1767c478bd9Sstevel@tonic-gate 		goto out;
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	error = sattr3_to_vattr(&args->new_attributes, &ava);
1807c478bd9Sstevel@tonic-gate 	if (error)
1817c478bd9Sstevel@tonic-gate 		goto out;
1827c478bd9Sstevel@tonic-gate 
18303986916Sjarrett 	if (is_system_labeled()) {
18403986916Sjarrett 		bslabel_t *clabel = req->rq_label;
18503986916Sjarrett 
18603986916Sjarrett 		ASSERT(clabel != NULL);
18703986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
18803986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
18903986916Sjarrett 
19003986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
191bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
192bd6f1640SJarrett Lu 			    exi)) {
19303986916Sjarrett 				resp->status = NFS3ERR_ACCES;
19403986916Sjarrett 				goto out1;
19503986916Sjarrett 			}
19603986916Sjarrett 		}
19703986916Sjarrett 	}
19803986916Sjarrett 
1997c478bd9Sstevel@tonic-gate 	/*
2007c478bd9Sstevel@tonic-gate 	 * We need to specially handle size changes because of
2017c478bd9Sstevel@tonic-gate 	 * possible conflicting NBMAND locks. Get into critical
2027c478bd9Sstevel@tonic-gate 	 * region before VOP_GETATTR, so the size attribute is
2037c478bd9Sstevel@tonic-gate 	 * valid when checking conflicts.
2047c478bd9Sstevel@tonic-gate 	 *
2057c478bd9Sstevel@tonic-gate 	 * Also, check to see if the v4 side of the server has
2067c478bd9Sstevel@tonic-gate 	 * delegated this file.  If so, then we return JUKEBOX to
2077c478bd9Sstevel@tonic-gate 	 * allow the client to retrasmit its request.
2087c478bd9Sstevel@tonic-gate 	 */
2097c478bd9Sstevel@tonic-gate 	if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
2107c478bd9Sstevel@tonic-gate 		if (nbl_need_check(vp)) {
2117c478bd9Sstevel@tonic-gate 			nbl_start_crit(vp, RW_READER);
2127c478bd9Sstevel@tonic-gate 			in_crit = 1;
2137c478bd9Sstevel@tonic-gate 		}
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
2177c478bd9Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &bva, 0, cr);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
2217c478bd9Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
2227c478bd9Sstevel@tonic-gate 	 */
2237c478bd9Sstevel@tonic-gate 	if (error)
2247c478bd9Sstevel@tonic-gate 		goto out;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	bvap = &bva;
2277c478bd9Sstevel@tonic-gate 
2285cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
2297c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2307c478bd9Sstevel@tonic-gate 		goto out1;
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	if (args->guard.check &&
2347c478bd9Sstevel@tonic-gate 	    (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
2357c478bd9Sstevel@tonic-gate 	    args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
2367c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOT_SYNC;
2377c478bd9Sstevel@tonic-gate 		goto out1;
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
2417c478bd9Sstevel@tonic-gate 		flag = ATTR_UTIME;
2427c478bd9Sstevel@tonic-gate 	else
2437c478bd9Sstevel@tonic-gate 		flag = 0;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/*
2467c478bd9Sstevel@tonic-gate 	 * If the filesystem is exported with nosuid, then mask off
2477c478bd9Sstevel@tonic-gate 	 * the setuid and setgid bits.
2487c478bd9Sstevel@tonic-gate 	 */
2497c478bd9Sstevel@tonic-gate 	if ((ava.va_mask & AT_MODE) && vp->v_type == VREG &&
2507c478bd9Sstevel@tonic-gate 	    (exi->exi_export.ex_flags & EX_NOSUID))
2517c478bd9Sstevel@tonic-gate 		ava.va_mode &= ~(VSUID | VSGID);
2527c478bd9Sstevel@tonic-gate 
253cfae96c2Sjwahlig 	ct.cc_sysid = 0;
254cfae96c2Sjwahlig 	ct.cc_pid = 0;
255cfae96c2Sjwahlig 	ct.cc_caller_id = nfs3_srv_caller_id;
256cfae96c2Sjwahlig 	ct.cc_flags = CC_DONTBLOCK;
257cfae96c2Sjwahlig 
2587c478bd9Sstevel@tonic-gate 	/*
2597c478bd9Sstevel@tonic-gate 	 * We need to specially handle size changes because it is
2607c478bd9Sstevel@tonic-gate 	 * possible for the client to create a file with modes
2617c478bd9Sstevel@tonic-gate 	 * which indicate read-only, but with the file opened for
2627c478bd9Sstevel@tonic-gate 	 * writing.  If the client then tries to set the size of
2637c478bd9Sstevel@tonic-gate 	 * the file, then the normal access checking done in
2647c478bd9Sstevel@tonic-gate 	 * VOP_SETATTR would prevent the client from doing so,
2657c478bd9Sstevel@tonic-gate 	 * although it should be legal for it to do so.  To get
2667c478bd9Sstevel@tonic-gate 	 * around this, we do the access checking for ourselves
2677c478bd9Sstevel@tonic-gate 	 * and then use VOP_SPACE which doesn't do the access
2687c478bd9Sstevel@tonic-gate 	 * checking which VOP_SETATTR does. VOP_SPACE can only
2697c478bd9Sstevel@tonic-gate 	 * operate on VREG files, let VOP_SETATTR handle the other
2707c478bd9Sstevel@tonic-gate 	 * extremely rare cases.
2717c478bd9Sstevel@tonic-gate 	 * Also the client should not be allowed to change the
2727c478bd9Sstevel@tonic-gate 	 * size of the file if there is a conflicting non-blocking
2737c478bd9Sstevel@tonic-gate 	 * mandatory lock in the region the change.
2747c478bd9Sstevel@tonic-gate 	 */
2757c478bd9Sstevel@tonic-gate 	if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
2767c478bd9Sstevel@tonic-gate 		if (in_crit) {
2777c478bd9Sstevel@tonic-gate 			u_offset_t offset;
2787c478bd9Sstevel@tonic-gate 			ssize_t length;
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 			if (ava.va_size < bva.va_size) {
2817c478bd9Sstevel@tonic-gate 				offset = ava.va_size;
2827c478bd9Sstevel@tonic-gate 				length = bva.va_size - ava.va_size;
2837c478bd9Sstevel@tonic-gate 			} else {
2847c478bd9Sstevel@tonic-gate 				offset = bva.va_size;
2857c478bd9Sstevel@tonic-gate 				length = ava.va_size - bva.va_size;
2867c478bd9Sstevel@tonic-gate 			}
287da6c28aaSamw 			if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
288da6c28aaSamw 			    NULL)) {
2897c478bd9Sstevel@tonic-gate 				error = EACCES;
2907c478bd9Sstevel@tonic-gate 				goto out;
2917c478bd9Sstevel@tonic-gate 			}
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 		if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) {
2957c478bd9Sstevel@tonic-gate 			ava.va_mask &= ~AT_SIZE;
2967c478bd9Sstevel@tonic-gate 			bf.l_type = F_WRLCK;
2977c478bd9Sstevel@tonic-gate 			bf.l_whence = 0;
2987c478bd9Sstevel@tonic-gate 			bf.l_start = (off64_t)ava.va_size;
2997c478bd9Sstevel@tonic-gate 			bf.l_len = 0;
3007c478bd9Sstevel@tonic-gate 			bf.l_sysid = 0;
3017c478bd9Sstevel@tonic-gate 			bf.l_pid = 0;
3027c478bd9Sstevel@tonic-gate 			error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
303cfae96c2Sjwahlig 			    (offset_t)ava.va_size, cr, &ct);
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if (!error && ava.va_mask)
308cfae96c2Sjwahlig 		error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
309cfae96c2Sjwahlig 
310cfae96c2Sjwahlig 	/* check if a monitor detected a delegation conflict */
311cfae96c2Sjwahlig 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
312cfae96c2Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
313cfae96c2Sjwahlig 		goto out1;
314cfae96c2Sjwahlig 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
3177c478bd9Sstevel@tonic-gate 	avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
3217c478bd9Sstevel@tonic-gate 	 */
322cfae96c2Sjwahlig 	(void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	if (error)
3257c478bd9Sstevel@tonic-gate 		goto out;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	if (in_crit)
3287c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
3317c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
332e1adf50cSahl 
333e1adf50cSahl 	DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
334e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
335e1adf50cSahl 
336e1adf50cSahl 	VN_RELE(vp);
337e1adf50cSahl 
3387c478bd9Sstevel@tonic-gate 	return;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate out:
3417c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
3427c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
3437c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
3447c478bd9Sstevel@tonic-gate 	} else
3457c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
3467c478bd9Sstevel@tonic-gate out1:
347e1adf50cSahl 	DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
348e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
349e1adf50cSahl 
3507c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
3517c478bd9Sstevel@tonic-gate 		if (in_crit)
3527c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
3537c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
35827242a7cSthurlow void *
3597c478bd9Sstevel@tonic-gate rfs3_setattr_getfh(SETATTR3args *args)
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 
36227242a7cSthurlow 	return (&args->object);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate /* ARGSUSED */
3667c478bd9Sstevel@tonic-gate void
3677c478bd9Sstevel@tonic-gate rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
3685cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate 	int error;
3717c478bd9Sstevel@tonic-gate 	vnode_t *vp;
3727c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
3737c478bd9Sstevel@tonic-gate 	struct vattr *vap;
3747c478bd9Sstevel@tonic-gate 	struct vattr va;
3757c478bd9Sstevel@tonic-gate 	struct vattr *dvap;
3767c478bd9Sstevel@tonic-gate 	struct vattr dva;
3777c478bd9Sstevel@tonic-gate 	nfs_fh3 *fhp;
3787c478bd9Sstevel@tonic-gate 	struct sec_ol sec = {0, 0};
3797c478bd9Sstevel@tonic-gate 	bool_t publicfh_flag = FALSE, auth_weak = FALSE;
380b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
381b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	dvap = NULL;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	/*
3867c478bd9Sstevel@tonic-gate 	 * Allow lookups from the root - the default
3877c478bd9Sstevel@tonic-gate 	 * location of the public filehandle.
3887c478bd9Sstevel@tonic-gate 	 */
3897c478bd9Sstevel@tonic-gate 	if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
3907c478bd9Sstevel@tonic-gate 		dvp = rootdir;
3917c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
392e1adf50cSahl 
393e1adf50cSahl 		DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
394e1adf50cSahl 		    cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
3957c478bd9Sstevel@tonic-gate 	} else {
39627242a7cSthurlow 		dvp = nfs3_fhtovp(&args->what.dir, exi);
397e1adf50cSahl 
398e1adf50cSahl 		DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
399e1adf50cSahl 		    cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
400e1adf50cSahl 
4017c478bd9Sstevel@tonic-gate 		if (dvp == NULL) {
4027c478bd9Sstevel@tonic-gate 			error = ESTALE;
4037c478bd9Sstevel@tonic-gate 			goto out;
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	dva.va_mask = AT_ALL;
408da6c28aaSamw 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	if (args->what.name == nfs3nametoolong) {
4117c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
4127c478bd9Sstevel@tonic-gate 		goto out1;
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	if (args->what.name == NULL || *(args->what.name) == '\0') {
4167c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
4177c478bd9Sstevel@tonic-gate 		goto out1;
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
42027242a7cSthurlow 	fhp = &args->what.dir;
4217c478bd9Sstevel@tonic-gate 	if (strcmp(args->what.name, "..") == 0 &&
42227242a7cSthurlow 	    EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
4237c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOENT;
4247c478bd9Sstevel@tonic-gate 		goto out1;
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
427b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
428b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->what.name,
429b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
430b89a8333Snatalie li - Sun Microsystems - Irvine United States 
431b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
432b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_ACCES;
433b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
434b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
435b89a8333Snatalie li - Sun Microsystems - Irvine United States 
4367c478bd9Sstevel@tonic-gate 	/*
4377c478bd9Sstevel@tonic-gate 	 * If the public filehandle is used then allow
4387c478bd9Sstevel@tonic-gate 	 * a multi-component lookup
4397c478bd9Sstevel@tonic-gate 	 */
44027242a7cSthurlow 	if (PUBLIC_FH3(&args->what.dir)) {
4417c478bd9Sstevel@tonic-gate 		publicfh_flag = TRUE;
442b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
443596bc239SMarcel Telka 		    &exi, &sec);
444596bc239SMarcel Telka 		if (error && exi != NULL)
445596bc239SMarcel Telka 			exi_rele(exi); /* See comment below Re: publicfh_flag */
44603986916Sjarrett 		/*
44703986916Sjarrett 		 * Since WebNFS may bypass MOUNT, we need to ensure this
44803986916Sjarrett 		 * request didn't come from an unlabeled admin_low client.
44903986916Sjarrett 		 */
45003986916Sjarrett 		if (is_system_labeled() && error == 0) {
45103986916Sjarrett 			int		addr_type;
45203986916Sjarrett 			void		*ipaddr;
45303986916Sjarrett 			tsol_tpc_t	*tp;
45403986916Sjarrett 
45503986916Sjarrett 			if (ca->sa_family == AF_INET) {
45603986916Sjarrett 				addr_type = IPV4_VERSION;
45703986916Sjarrett 				ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
45803986916Sjarrett 			} else if (ca->sa_family == AF_INET6) {
45903986916Sjarrett 				addr_type = IPV6_VERSION;
46003986916Sjarrett 				ipaddr = &((struct sockaddr_in6 *)
46103986916Sjarrett 				    ca)->sin6_addr;
46203986916Sjarrett 			}
46303986916Sjarrett 			tp = find_tpc(ipaddr, addr_type, B_FALSE);
46403986916Sjarrett 			if (tp == NULL || tp->tpc_tp.tp_doi !=
46503986916Sjarrett 			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
46603986916Sjarrett 			    SUN_CIPSO) {
467596bc239SMarcel Telka 				if (exi != NULL)
468596bc239SMarcel Telka 					exi_rele(exi);
46903986916Sjarrett 				VN_RELE(vp);
470f46abf18SMarcel Telka 				error = EACCES;
47103986916Sjarrett 			}
47203986916Sjarrett 			if (tp != NULL)
47303986916Sjarrett 				TPC_RELE(tp);
47403986916Sjarrett 		}
4757c478bd9Sstevel@tonic-gate 	} else {
476b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = VOP_LOOKUP(dvp, name, &vp,
477da6c28aaSamw 		    NULL, 0, NULL, cr, NULL, NULL, NULL);
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate 
480b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->what.name)
481b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
482b89a8333Snatalie li - Sun Microsystems - Irvine United States 
48303986916Sjarrett 	if (is_system_labeled() && error == 0) {
48403986916Sjarrett 		bslabel_t *clabel = req->rq_label;
48503986916Sjarrett 
48603986916Sjarrett 		ASSERT(clabel != NULL);
48703986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
48803986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
48903986916Sjarrett 
49003986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
49103986916Sjarrett 			if (!do_rfs_label_check(clabel, dvp,
492bd6f1640SJarrett Lu 			    DOMINANCE_CHECK, exi)) {
493596bc239SMarcel Telka 				if (publicfh_flag && exi != NULL)
494596bc239SMarcel Telka 					exi_rele(exi);
49503986916Sjarrett 				VN_RELE(vp);
496f46abf18SMarcel Telka 				error = EACCES;
49703986916Sjarrett 			}
49803986916Sjarrett 		}
49903986916Sjarrett 	}
50003986916Sjarrett 
5017c478bd9Sstevel@tonic-gate 	dva.va_mask = AT_ALL;
502da6c28aaSamw 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	if (error)
5057c478bd9Sstevel@tonic-gate 		goto out;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	if (sec.sec_flags & SEC_QUERY) {
5087c478bd9Sstevel@tonic-gate 		error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
5097c478bd9Sstevel@tonic-gate 	} else {
5107c478bd9Sstevel@tonic-gate 		error = makefh3(&resp->resok.object, vp, exi);
5117c478bd9Sstevel@tonic-gate 		if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
5127c478bd9Sstevel@tonic-gate 			auth_weak = TRUE;
5137c478bd9Sstevel@tonic-gate 	}
5147c478bd9Sstevel@tonic-gate 
515596bc239SMarcel Telka 	/*
516596bc239SMarcel Telka 	 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
517596bc239SMarcel Telka 	 * and have obtained a new exportinfo in exi which needs to be
518fd9d0a82SMarcel Telka 	 * released. Note that the original exportinfo pointed to by exi
519596bc239SMarcel Telka 	 * will be released by the caller, common_dispatch.
520596bc239SMarcel Telka 	 */
521596bc239SMarcel Telka 	if (publicfh_flag)
522596bc239SMarcel Telka 		exi_rele(exi);
523596bc239SMarcel Telka 
524fd9d0a82SMarcel Telka 	if (error) {
525fd9d0a82SMarcel Telka 		VN_RELE(vp);
526fd9d0a82SMarcel Telka 		goto out;
527fd9d0a82SMarcel Telka 	}
528fd9d0a82SMarcel Telka 
5297c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
5307c478bd9Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
5357c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
5367c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	/*
5397c478bd9Sstevel@tonic-gate 	 * If it's public fh, no 0x81, and client's flavor is
5407c478bd9Sstevel@tonic-gate 	 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
5417c478bd9Sstevel@tonic-gate 	 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
5427c478bd9Sstevel@tonic-gate 	 */
5437c478bd9Sstevel@tonic-gate 	if (auth_weak)
5447c478bd9Sstevel@tonic-gate 		resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
5457c478bd9Sstevel@tonic-gate 
546e1adf50cSahl 	DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
547e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
548e1adf50cSahl 	VN_RELE(dvp);
549e1adf50cSahl 
5507c478bd9Sstevel@tonic-gate 	return;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate out:
5537c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
5547c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
5557c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
5567c478bd9Sstevel@tonic-gate 	} else
5577c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
5587c478bd9Sstevel@tonic-gate out1:
559e1adf50cSahl 	DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
560e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
561e1adf50cSahl 
5627c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
5637c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
5647c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
56827242a7cSthurlow void *
5697c478bd9Sstevel@tonic-gate rfs3_lookup_getfh(LOOKUP3args *args)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 
57227242a7cSthurlow 	return (&args->what.dir);
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate /* ARGSUSED */
5767c478bd9Sstevel@tonic-gate void
5777c478bd9Sstevel@tonic-gate rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
5785cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate 	int error;
5817c478bd9Sstevel@tonic-gate 	vnode_t *vp;
5827c478bd9Sstevel@tonic-gate 	struct vattr *vap;
5837c478bd9Sstevel@tonic-gate 	struct vattr va;
5847c478bd9Sstevel@tonic-gate 	int checkwriteperm;
58503986916Sjarrett 	boolean_t dominant_label = B_FALSE;
58603986916Sjarrett 	boolean_t equal_label = B_FALSE;
58703986916Sjarrett 	boolean_t admin_low_client;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	vap = NULL;
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
592e1adf50cSahl 
593e1adf50cSahl 	DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
594e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
595e1adf50cSahl 
5967c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
5977c478bd9Sstevel@tonic-gate 		error = ESTALE;
5987c478bd9Sstevel@tonic-gate 		goto out;
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	/*
6027c478bd9Sstevel@tonic-gate 	 * If the file system is exported read only, it is not appropriate
6037c478bd9Sstevel@tonic-gate 	 * to check write permissions for regular files and directories.
6047c478bd9Sstevel@tonic-gate 	 * Special files are interpreted by the client, so the underlying
6057c478bd9Sstevel@tonic-gate 	 * permissions are sent back to the client for interpretation.
6067c478bd9Sstevel@tonic-gate 	 */
6075cb0d679SMarcel Telka 	if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
6087c478bd9Sstevel@tonic-gate 		checkwriteperm = 0;
6097c478bd9Sstevel@tonic-gate 	else
6107c478bd9Sstevel@tonic-gate 		checkwriteperm = 1;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	/*
6137c478bd9Sstevel@tonic-gate 	 * We need the mode so that we can correctly determine access
6147c478bd9Sstevel@tonic-gate 	 * permissions relative to a mandatory lock file.  Access to
6157c478bd9Sstevel@tonic-gate 	 * mandatory lock files is denied on the server, so it might
6167c478bd9Sstevel@tonic-gate 	 * as well be reflected to the server during the open.
6177c478bd9Sstevel@tonic-gate 	 */
6187c478bd9Sstevel@tonic-gate 	va.va_mask = AT_MODE;
619da6c28aaSamw 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
6207c478bd9Sstevel@tonic-gate 	if (error)
6217c478bd9Sstevel@tonic-gate 		goto out;
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	vap = &va;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	resp->resok.access = 0;
6267c478bd9Sstevel@tonic-gate 
62703986916Sjarrett 	if (is_system_labeled()) {
62803986916Sjarrett 		bslabel_t *clabel = req->rq_label;
62903986916Sjarrett 
63003986916Sjarrett 		ASSERT(clabel != NULL);
63103986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
63203986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
63303986916Sjarrett 
63403986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
63503986916Sjarrett 			if ((equal_label = do_rfs_label_check(clabel, vp,
636bd6f1640SJarrett Lu 			    EQUALITY_CHECK, exi)) == B_FALSE) {
63703986916Sjarrett 				dominant_label = do_rfs_label_check(clabel,
638bd6f1640SJarrett Lu 				    vp, DOMINANCE_CHECK, exi);
63903986916Sjarrett 			} else
64003986916Sjarrett 				dominant_label = B_TRUE;
64103986916Sjarrett 			admin_low_client = B_FALSE;
64203986916Sjarrett 		} else
64303986916Sjarrett 			admin_low_client = B_TRUE;
64403986916Sjarrett 	}
64503986916Sjarrett 
6467c478bd9Sstevel@tonic-gate 	if (args->access & ACCESS3_READ) {
647da6c28aaSamw 		error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
6487c478bd9Sstevel@tonic-gate 		if (error) {
6497c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
6507c478bd9Sstevel@tonic-gate 				goto out;
65103986916Sjarrett 		} else if (!MANDLOCK(vp, va.va_mode) &&
65203986916Sjarrett 		    (!is_system_labeled() || admin_low_client ||
65303986916Sjarrett 		    dominant_label))
6547c478bd9Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_READ;
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 	if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
657da6c28aaSamw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
6587c478bd9Sstevel@tonic-gate 		if (error) {
6597c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
6607c478bd9Sstevel@tonic-gate 				goto out;
66103986916Sjarrett 		} else if (!is_system_labeled() || admin_low_client ||
66203986916Sjarrett 		    dominant_label)
6637c478bd9Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_LOOKUP;
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 	if (checkwriteperm &&
6667c478bd9Sstevel@tonic-gate 	    (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
667da6c28aaSamw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
6687c478bd9Sstevel@tonic-gate 		if (error) {
6697c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
6707c478bd9Sstevel@tonic-gate 				goto out;
67103986916Sjarrett 		} else if (!MANDLOCK(vp, va.va_mode) &&
67203986916Sjarrett 		    (!is_system_labeled() || admin_low_client || equal_label)) {
6737c478bd9Sstevel@tonic-gate 			resp->resok.access |=
6747c478bd9Sstevel@tonic-gate 			    (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND));
6757c478bd9Sstevel@tonic-gate 		}
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 	if (checkwriteperm &&
6787c478bd9Sstevel@tonic-gate 	    (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
679da6c28aaSamw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
6807c478bd9Sstevel@tonic-gate 		if (error) {
6817c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
6827c478bd9Sstevel@tonic-gate 				goto out;
68303986916Sjarrett 		} else if (!is_system_labeled() || admin_low_client ||
68403986916Sjarrett 		    equal_label)
6857c478bd9Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_DELETE;
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate 	if (args->access & ACCESS3_EXECUTE) {
688da6c28aaSamw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
6897c478bd9Sstevel@tonic-gate 		if (error) {
6907c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
6917c478bd9Sstevel@tonic-gate 				goto out;
69203986916Sjarrett 		} else if (!MANDLOCK(vp, va.va_mode) &&
69303986916Sjarrett 		    (!is_system_labeled() || admin_low_client ||
69403986916Sjarrett 		    dominant_label))
6957c478bd9Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_EXECUTE;
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
6997c478bd9Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
7027c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
703e1adf50cSahl 
704e1adf50cSahl 	DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
705e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
706e1adf50cSahl 
707e1adf50cSahl 	VN_RELE(vp);
708e1adf50cSahl 
7097c478bd9Sstevel@tonic-gate 	return;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate out:
7127c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
7137c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
7147c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
7157c478bd9Sstevel@tonic-gate 	} else
7167c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
717e1adf50cSahl 	DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
718e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
7197c478bd9Sstevel@tonic-gate 	if (vp != NULL)
7207c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
7217c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
7227c478bd9Sstevel@tonic-gate }
7237c478bd9Sstevel@tonic-gate 
72427242a7cSthurlow void *
7257c478bd9Sstevel@tonic-gate rfs3_access_getfh(ACCESS3args *args)
7267c478bd9Sstevel@tonic-gate {
7277c478bd9Sstevel@tonic-gate 
72827242a7cSthurlow 	return (&args->object);
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate /* ARGSUSED */
7327c478bd9Sstevel@tonic-gate void
7337c478bd9Sstevel@tonic-gate rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
7345cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
7357c478bd9Sstevel@tonic-gate {
7367c478bd9Sstevel@tonic-gate 	int error;
7377c478bd9Sstevel@tonic-gate 	vnode_t *vp;
7387c478bd9Sstevel@tonic-gate 	struct vattr *vap;
7397c478bd9Sstevel@tonic-gate 	struct vattr va;
7407c478bd9Sstevel@tonic-gate 	struct iovec iov;
7417c478bd9Sstevel@tonic-gate 	struct uio uio;
7427c478bd9Sstevel@tonic-gate 	char *data;
743b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
744b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
7452f172c55SRobert Thurlow 	int is_referral = 0;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	vap = NULL;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->symlink, exi);
750e1adf50cSahl 
751e1adf50cSahl 	DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
752e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
753e1adf50cSahl 
7547c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
7557c478bd9Sstevel@tonic-gate 		error = ESTALE;
7567c478bd9Sstevel@tonic-gate 		goto out;
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
760da6c28aaSamw 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
7617c478bd9Sstevel@tonic-gate 	if (error)
7627c478bd9Sstevel@tonic-gate 		goto out;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	vap = &va;
7657c478bd9Sstevel@tonic-gate 
7662f172c55SRobert Thurlow 	/* We lied about the object type for a referral */
7672f172c55SRobert Thurlow 	if (vn_is_nfs_reparse(vp, cr))
7682f172c55SRobert Thurlow 		is_referral = 1;
7692f172c55SRobert Thurlow 
7702f172c55SRobert Thurlow 	if (vp->v_type != VLNK && !is_referral) {
7717c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
7727c478bd9Sstevel@tonic-gate 		goto out1;
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	if (MANDLOCK(vp, va.va_mode)) {
7767c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
7777c478bd9Sstevel@tonic-gate 		goto out1;
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 
78003986916Sjarrett 	if (is_system_labeled()) {
78103986916Sjarrett 		bslabel_t *clabel = req->rq_label;
78203986916Sjarrett 
78303986916Sjarrett 		ASSERT(clabel != NULL);
78403986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
78503986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
78603986916Sjarrett 
78703986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
788bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
789bd6f1640SJarrett Lu 			    exi)) {
79003986916Sjarrett 				resp->status = NFS3ERR_ACCES;
79103986916Sjarrett 				goto out1;
79203986916Sjarrett 			}
79303986916Sjarrett 		}
79403986916Sjarrett 	}
79503986916Sjarrett 
7967c478bd9Sstevel@tonic-gate 	data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
7977c478bd9Sstevel@tonic-gate 
7982f172c55SRobert Thurlow 	if (is_referral) {
7992f172c55SRobert Thurlow 		char *s;
8002f172c55SRobert Thurlow 		size_t strsz;
8012f172c55SRobert Thurlow 
8022f172c55SRobert Thurlow 		/* Get an artificial symlink based on a referral */
8032f172c55SRobert Thurlow 		s = build_symlink(vp, cr, &strsz);
8042f172c55SRobert Thurlow 		global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
8052f172c55SRobert Thurlow 		DTRACE_PROBE2(nfs3serv__func__referral__reflink,
8062f172c55SRobert Thurlow 		    vnode_t *, vp, char *, s);
8072f172c55SRobert Thurlow 		if (s == NULL)
8082f172c55SRobert Thurlow 			error = EINVAL;
8092f172c55SRobert Thurlow 		else {
8102f172c55SRobert Thurlow 			error = 0;
8112f172c55SRobert Thurlow 			(void) strlcpy(data, s, MAXPATHLEN + 1);
8122f172c55SRobert Thurlow 			kmem_free(s, strsz);
8132f172c55SRobert Thurlow 		}
8142f172c55SRobert Thurlow 
8152f172c55SRobert Thurlow 	} else {
8162f172c55SRobert Thurlow 
8177c478bd9Sstevel@tonic-gate 		iov.iov_base = data;
8187c478bd9Sstevel@tonic-gate 		iov.iov_len = MAXPATHLEN;
8197c478bd9Sstevel@tonic-gate 		uio.uio_iov = &iov;
8207c478bd9Sstevel@tonic-gate 		uio.uio_iovcnt = 1;
8217c478bd9Sstevel@tonic-gate 		uio.uio_segflg = UIO_SYSSPACE;
8227c478bd9Sstevel@tonic-gate 		uio.uio_extflg = UIO_COPY_CACHED;
8237c478bd9Sstevel@tonic-gate 		uio.uio_loffset = 0;
8247c478bd9Sstevel@tonic-gate 		uio.uio_resid = MAXPATHLEN;
8257c478bd9Sstevel@tonic-gate 
826da6c28aaSamw 		error = VOP_READLINK(vp, &uio, cr, NULL);
8277c478bd9Sstevel@tonic-gate 
8282f172c55SRobert Thurlow 		if (!error)
8292f172c55SRobert Thurlow 			*(data + MAXPATHLEN - uio.uio_resid) = '\0';
8302f172c55SRobert Thurlow 	}
8312f172c55SRobert Thurlow 
8327c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
833da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
83427246829SVitaliy Gusev 
8352f172c55SRobert Thurlow 	/* Lie about object type again just to be consistent */
8362f172c55SRobert Thurlow 	if (is_referral && vap != NULL)
8372f172c55SRobert Thurlow 		vap->va_type = VLNK;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate #if 0 /* notyet */
8407c478bd9Sstevel@tonic-gate 	/*
8417c478bd9Sstevel@tonic-gate 	 * Don't do this.  It causes local disk writes when just
8427c478bd9Sstevel@tonic-gate 	 * reading the file and the overhead is deemed larger
8437c478bd9Sstevel@tonic-gate 	 * than the benefit.
8447c478bd9Sstevel@tonic-gate 	 */
8457c478bd9Sstevel@tonic-gate 	/*
8467c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
8477c478bd9Sstevel@tonic-gate 	 */
848da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
8497c478bd9Sstevel@tonic-gate #endif
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	if (error) {
8527c478bd9Sstevel@tonic-gate 		kmem_free(data, MAXPATHLEN + 1);
8537c478bd9Sstevel@tonic-gate 		goto out;
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 
856b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
857b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
858b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    MAXPATHLEN + 1);
859b89a8333Snatalie li - Sun Microsystems - Irvine United States 
860b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
861b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/*
862b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * Even though the conversion failed, we return
863b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * something. We just don't translate it.
864b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 */
865b89a8333Snatalie li - Sun Microsystems - Irvine United States 		name = data;
866b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
867b89a8333Snatalie li - Sun Microsystems - Irvine United States 
8687c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
8697c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
870b89a8333Snatalie li - Sun Microsystems - Irvine United States 	resp->resok.data = name;
871e1adf50cSahl 
872e1adf50cSahl 	DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
873e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
874e1adf50cSahl 	VN_RELE(vp);
875e1adf50cSahl 
876b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != data)
877b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(data, MAXPATHLEN + 1);
878b89a8333Snatalie li - Sun Microsystems - Irvine United States 
8797c478bd9Sstevel@tonic-gate 	return;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate out:
8827c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
8837c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
8847c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
8857c478bd9Sstevel@tonic-gate 	} else
8867c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
8877c478bd9Sstevel@tonic-gate out1:
888e1adf50cSahl 	DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
889e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
8907c478bd9Sstevel@tonic-gate 	if (vp != NULL)
8917c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
8927c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
8937c478bd9Sstevel@tonic-gate }
8947c478bd9Sstevel@tonic-gate 
89527242a7cSthurlow void *
8967c478bd9Sstevel@tonic-gate rfs3_readlink_getfh(READLINK3args *args)
8977c478bd9Sstevel@tonic-gate {
8987c478bd9Sstevel@tonic-gate 
89927242a7cSthurlow 	return (&args->symlink);
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate void
9037c478bd9Sstevel@tonic-gate rfs3_readlink_free(READLINK3res *resp)
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	if (resp->status == NFS3_OK)
9077c478bd9Sstevel@tonic-gate 		kmem_free(resp->resok.data, MAXPATHLEN + 1);
9087c478bd9Sstevel@tonic-gate }
9097c478bd9Sstevel@tonic-gate 
9100a701b1eSRobert Gordon /*
9110a701b1eSRobert Gordon  * Server routine to handle read
9120a701b1eSRobert Gordon  * May handle RDMA data as well as mblks
9130a701b1eSRobert Gordon  */
9147c478bd9Sstevel@tonic-gate /* ARGSUSED */
9157c478bd9Sstevel@tonic-gate void
9167c478bd9Sstevel@tonic-gate rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
9175cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate 	int error;
9207c478bd9Sstevel@tonic-gate 	vnode_t *vp;
9217c478bd9Sstevel@tonic-gate 	struct vattr *vap;
9227c478bd9Sstevel@tonic-gate 	struct vattr va;
923e36d7b11SSebastien Roy 	struct iovec iov, *iovp = NULL;
924e36d7b11SSebastien Roy 	int iovcnt;
9257c478bd9Sstevel@tonic-gate 	struct uio uio;
9267c478bd9Sstevel@tonic-gate 	u_offset_t offset;
92741b8345aSchunli zhang - Sun Microsystems - Irvine United States 	mblk_t *mp = NULL;
9287c478bd9Sstevel@tonic-gate 	int in_crit = 0;
9297c478bd9Sstevel@tonic-gate 	int need_rwunlock = 0;
930cfae96c2Sjwahlig 	caller_context_t ct;
931c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	int rdma_used = 0;
932c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	int loaned_buffers;
933c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	struct uio *uiop;
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	vap = NULL;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
938e1adf50cSahl 
939e1adf50cSahl 	DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
940e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READ3args *, args);
941e1adf50cSahl 
9427c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
9437c478bd9Sstevel@tonic-gate 		error = ESTALE;
9447c478bd9Sstevel@tonic-gate 		goto out;
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 
94735bbd688SKaren Rochford 	if (args->wlist) {
94835bbd688SKaren Rochford 		if (args->count > clist_len(args->wlist)) {
94935bbd688SKaren Rochford 			error = EINVAL;
95035bbd688SKaren Rochford 			goto out;
95135bbd688SKaren Rochford 		}
952c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		rdma_used = 1;
95335bbd688SKaren Rochford 	}
954c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
955c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	/* use loaned buffers for TCP */
956c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
957c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
95803986916Sjarrett 	if (is_system_labeled()) {
95903986916Sjarrett 		bslabel_t *clabel = req->rq_label;
96003986916Sjarrett 
96103986916Sjarrett 		ASSERT(clabel != NULL);
96203986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *,
96303986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
96403986916Sjarrett 
96503986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
966bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
967bd6f1640SJarrett Lu 			    exi)) {
96803986916Sjarrett 				resp->status = NFS3ERR_ACCES;
96903986916Sjarrett 				goto out1;
97003986916Sjarrett 			}
97103986916Sjarrett 		}
97203986916Sjarrett 	}
97303986916Sjarrett 
974cfae96c2Sjwahlig 	ct.cc_sysid = 0;
975cfae96c2Sjwahlig 	ct.cc_pid = 0;
976cfae96c2Sjwahlig 	ct.cc_caller_id = nfs3_srv_caller_id;
977cfae96c2Sjwahlig 	ct.cc_flags = CC_DONTBLOCK;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/*
9807c478bd9Sstevel@tonic-gate 	 * Enter the critical region before calling VOP_RWLOCK
9817c478bd9Sstevel@tonic-gate 	 * to avoid a deadlock with write requests.
9827c478bd9Sstevel@tonic-gate 	 */
9837c478bd9Sstevel@tonic-gate 	if (nbl_need_check(vp)) {
9847c478bd9Sstevel@tonic-gate 		nbl_start_crit(vp, RW_READER);
9857c478bd9Sstevel@tonic-gate 		in_crit = 1;
986da6c28aaSamw 		if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
987da6c28aaSamw 		    NULL)) {
9887c478bd9Sstevel@tonic-gate 			error = EACCES;
9897c478bd9Sstevel@tonic-gate 			goto out;
9907c478bd9Sstevel@tonic-gate 		}
9917c478bd9Sstevel@tonic-gate 	}
9927c478bd9Sstevel@tonic-gate 
993cfae96c2Sjwahlig 	error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
994cfae96c2Sjwahlig 
995cfae96c2Sjwahlig 	/* check if a monitor detected a delegation conflict */
996cfae96c2Sjwahlig 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
997cfae96c2Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
998cfae96c2Sjwahlig 		goto out1;
999cfae96c2Sjwahlig 	}
1000cfae96c2Sjwahlig 
10017c478bd9Sstevel@tonic-gate 	need_rwunlock = 1;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1004cfae96c2Sjwahlig 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	/*
10077c478bd9Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
10087c478bd9Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
10097c478bd9Sstevel@tonic-gate 	 */
10107c478bd9Sstevel@tonic-gate 	if (error)
10117c478bd9Sstevel@tonic-gate 		goto out;
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	vap = &va;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	if (vp->v_type != VREG) {
10167c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
10177c478bd9Sstevel@tonic-gate 		goto out1;
10187c478bd9Sstevel@tonic-gate 	}
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	if (crgetuid(cr) != va.va_uid) {
1021cfae96c2Sjwahlig 		error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
10227c478bd9Sstevel@tonic-gate 		if (error) {
10237c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
10247c478bd9Sstevel@tonic-gate 				goto out;
1025cfae96c2Sjwahlig 			error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
10267c478bd9Sstevel@tonic-gate 			if (error)
10277c478bd9Sstevel@tonic-gate 				goto out;
10287c478bd9Sstevel@tonic-gate 		}
10297c478bd9Sstevel@tonic-gate 	}
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	if (MANDLOCK(vp, va.va_mode)) {
10327c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
10337c478bd9Sstevel@tonic-gate 		goto out1;
10347c478bd9Sstevel@tonic-gate 	}
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	offset = args->offset;
10377c478bd9Sstevel@tonic-gate 	if (offset >= va.va_size) {
1038cfae96c2Sjwahlig 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
10397c478bd9Sstevel@tonic-gate 		if (in_crit)
10407c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
10417c478bd9Sstevel@tonic-gate 		resp->status = NFS3_OK;
10427c478bd9Sstevel@tonic-gate 		vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
10437c478bd9Sstevel@tonic-gate 		resp->resok.count = 0;
10447c478bd9Sstevel@tonic-gate 		resp->resok.eof = TRUE;
10457c478bd9Sstevel@tonic-gate 		resp->resok.data.data_len = 0;
10467c478bd9Sstevel@tonic-gate 		resp->resok.data.data_val = NULL;
10477c478bd9Sstevel@tonic-gate 		resp->resok.data.mp = NULL;
10480a701b1eSRobert Gordon 		/* RDMA */
10490a701b1eSRobert Gordon 		resp->resok.wlist = args->wlist;
10500a701b1eSRobert Gordon 		resp->resok.wlist_len = resp->resok.count;
1051f837ee4aSSiddheshwar Mahesh 		if (resp->resok.wlist)
1052f837ee4aSSiddheshwar Mahesh 			clist_zero_len(resp->resok.wlist);
1053e1adf50cSahl 		goto done;
10547c478bd9Sstevel@tonic-gate 	}
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	if (args->count == 0) {
1057cfae96c2Sjwahlig 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
10587c478bd9Sstevel@tonic-gate 		if (in_crit)
10597c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
10607c478bd9Sstevel@tonic-gate 		resp->status = NFS3_OK;
10617c478bd9Sstevel@tonic-gate 		vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
10627c478bd9Sstevel@tonic-gate 		resp->resok.count = 0;
10637c478bd9Sstevel@tonic-gate 		resp->resok.eof = FALSE;
10647c478bd9Sstevel@tonic-gate 		resp->resok.data.data_len = 0;
10657c478bd9Sstevel@tonic-gate 		resp->resok.data.data_val = NULL;
10667c478bd9Sstevel@tonic-gate 		resp->resok.data.mp = NULL;
10670a701b1eSRobert Gordon 		/* RDMA */
10680a701b1eSRobert Gordon 		resp->resok.wlist = args->wlist;
10690a701b1eSRobert Gordon 		resp->resok.wlist_len = resp->resok.count;
1070f837ee4aSSiddheshwar Mahesh 		if (resp->resok.wlist)
1071f837ee4aSSiddheshwar Mahesh 			clist_zero_len(resp->resok.wlist);
1072e1adf50cSahl 		goto done;
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	/*
10767c478bd9Sstevel@tonic-gate 	 * do not allocate memory more the max. allowed
10777c478bd9Sstevel@tonic-gate 	 * transfer size
10787c478bd9Sstevel@tonic-gate 	 */
10797c478bd9Sstevel@tonic-gate 	if (args->count > rfs3_tsize(req))
10807c478bd9Sstevel@tonic-gate 		args->count = rfs3_tsize(req);
10817c478bd9Sstevel@tonic-gate 
1082c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (loaned_buffers) {
1083c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop = (uio_t *)rfs_setup_xuio(vp);
1084c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		ASSERT(uiop != NULL);
1085c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop->uio_segflg = UIO_SYSSPACE;
1086c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop->uio_loffset = args->offset;
1087c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop->uio_resid = args->count;
1088c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1089c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		/* Jump to do the read if successful */
1090c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		if (VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cr, &ct) == 0) {
1091c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			/*
1092c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			 * Need to hold the vnode until after VOP_RETZCBUF()
1093c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			 * is called.
1094c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			 */
1095c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			VN_HOLD(vp);
1096c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			goto doio_read;
1097c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		}
1098c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1099c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int,
1100c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		    uiop->uio_loffset, int, uiop->uio_resid);
1101c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1102c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		uiop->uio_extflg = 0;
1103c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		/* failure to setup for zero copy */
1104c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		rfs_free_xuio((void *)uiop);
1105c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		loaned_buffers = 0;
1106c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	}
1107c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
11087c478bd9Sstevel@tonic-gate 	/*
11090a701b1eSRobert Gordon 	 * If returning data via RDMA Write, then grab the chunk list.
11100a701b1eSRobert Gordon 	 * If we aren't returning READ data w/RDMA_WRITE, then grab
11110a701b1eSRobert Gordon 	 * a mblk.
11120a701b1eSRobert Gordon 	 */
1113c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (rdma_used) {
11140a701b1eSRobert Gordon 		(void) rdma_get_wchunk(req, &iov, args->wlist);
1115e36d7b11SSebastien Roy 		uio.uio_iov = &iov;
1116e36d7b11SSebastien Roy 		uio.uio_iovcnt = 1;
11170a701b1eSRobert Gordon 	} else {
11180a701b1eSRobert Gordon 		/*
11197c478bd9Sstevel@tonic-gate 		 * mp will contain the data to be sent out in the read reply.
1120e36d7b11SSebastien Roy 		 * For UDP, this will be freed after the reply has been sent
1121e36d7b11SSebastien Roy 		 * out by the driver.  For TCP, it will be freed after the last
1122e36d7b11SSebastien Roy 		 * segment associated with the reply has been ACKed by the
1123e36d7b11SSebastien Roy 		 * client.
11247c478bd9Sstevel@tonic-gate 		 */
1125e36d7b11SSebastien Roy 		mp = rfs_read_alloc(args->count, &iovp, &iovcnt);
1126e36d7b11SSebastien Roy 		uio.uio_iov = iovp;
1127e36d7b11SSebastien Roy 		uio.uio_iovcnt = iovcnt;
11280a701b1eSRobert Gordon 	}
11290a701b1eSRobert Gordon 
11307c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
11317c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
11327c478bd9Sstevel@tonic-gate 	uio.uio_loffset = args->offset;
11337c478bd9Sstevel@tonic-gate 	uio.uio_resid = args->count;
1134c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	uiop = &uio;
11357c478bd9Sstevel@tonic-gate 
1136c242f9a0Schunli zhang - Sun Microsystems - Irvine United States doio_read:
1137c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	error = VOP_READ(vp, uiop, 0, cr, &ct);
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	if (error) {
1140c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		if (mp)
1141c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			freemsg(mp);
1142cfae96c2Sjwahlig 		/* check if a monitor detected a delegation conflict */
1143cfae96c2Sjwahlig 		if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1144cfae96c2Sjwahlig 			resp->status = NFS3ERR_JUKEBOX;
1145cfae96c2Sjwahlig 			goto out1;
1146cfae96c2Sjwahlig 		}
11477c478bd9Sstevel@tonic-gate 		goto out;
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 
1150c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	/* make mblk using zc buffers */
1151c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (loaned_buffers) {
1152c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		mp = uio_to_mblk(uiop);
1153c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		ASSERT(mp != NULL);
1154c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	}
1155c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
11567c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1157cfae96c2Sjwahlig 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	if (error)
11607c478bd9Sstevel@tonic-gate 		vap = NULL;
11617c478bd9Sstevel@tonic-gate 	else
11627c478bd9Sstevel@tonic-gate 		vap = &va;
11637c478bd9Sstevel@tonic-gate 
1164cfae96c2Sjwahlig 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	if (in_crit)
11677c478bd9Sstevel@tonic-gate 		nbl_end_crit(vp);
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
11707c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1171c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	resp->resok.count = args->count - uiop->uio_resid;
11727c478bd9Sstevel@tonic-gate 	if (!error && offset + resp->resok.count == va.va_size)
11737c478bd9Sstevel@tonic-gate 		resp->resok.eof = TRUE;
11747c478bd9Sstevel@tonic-gate 	else
11757c478bd9Sstevel@tonic-gate 		resp->resok.eof = FALSE;
11767c478bd9Sstevel@tonic-gate 	resp->resok.data.data_len = resp->resok.count;
1177c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1178c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (mp)
1179c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1180c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
11817c478bd9Sstevel@tonic-gate 	resp->resok.data.mp = mp;
11827c478bd9Sstevel@tonic-gate 	resp->resok.size = (uint_t)args->count;
1183e1adf50cSahl 
1184c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (rdma_used) {
11850a701b1eSRobert Gordon 		resp->resok.data.data_val = (caddr_t)iov.iov_base;
11860a701b1eSRobert Gordon 		if (!rdma_setup_read_data3(args, &(resp->resok))) {
11870a701b1eSRobert Gordon 			resp->status = NFS3ERR_INVAL;
11880a701b1eSRobert Gordon 		}
11890a701b1eSRobert Gordon 	} else {
11900a701b1eSRobert Gordon 		resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
11910a701b1eSRobert Gordon 		(resp->resok).wlist = NULL;
11920a701b1eSRobert Gordon 	}
11930a701b1eSRobert Gordon 
1194e1adf50cSahl done:
1195e1adf50cSahl 	DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1196e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1197e1adf50cSahl 
1198e1adf50cSahl 	VN_RELE(vp);
1199e1adf50cSahl 
1200e36d7b11SSebastien Roy 	if (iovp != NULL)
1201e36d7b11SSebastien Roy 		kmem_free(iovp, iovcnt * sizeof (struct iovec));
1202e36d7b11SSebastien Roy 
12037c478bd9Sstevel@tonic-gate 	return;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate out:
12067c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
12077c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
12087c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
12097c478bd9Sstevel@tonic-gate 	} else
12107c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
12117c478bd9Sstevel@tonic-gate out1:
1212e1adf50cSahl 	DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1213e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1214e1adf50cSahl 
12157c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
12167c478bd9Sstevel@tonic-gate 		if (need_rwunlock)
1217cfae96c2Sjwahlig 			VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
12187c478bd9Sstevel@tonic-gate 		if (in_crit)
12197c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
12207c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1223e36d7b11SSebastien Roy 
1224e36d7b11SSebastien Roy 	if (iovp != NULL)
1225e36d7b11SSebastien Roy 		kmem_free(iovp, iovcnt * sizeof (struct iovec));
12267c478bd9Sstevel@tonic-gate }
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate void
12297c478bd9Sstevel@tonic-gate rfs3_read_free(READ3res *resp)
12307c478bd9Sstevel@tonic-gate {
12317c478bd9Sstevel@tonic-gate 	mblk_t *mp;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	if (resp->status == NFS3_OK) {
12347c478bd9Sstevel@tonic-gate 		mp = resp->resok.data.mp;
12357c478bd9Sstevel@tonic-gate 		if (mp != NULL)
1236c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 			freemsg(mp);
12377c478bd9Sstevel@tonic-gate 	}
12387c478bd9Sstevel@tonic-gate }
12397c478bd9Sstevel@tonic-gate 
124027242a7cSthurlow void *
12417c478bd9Sstevel@tonic-gate rfs3_read_getfh(READ3args *args)
12427c478bd9Sstevel@tonic-gate {
12437c478bd9Sstevel@tonic-gate 
124427242a7cSthurlow 	return (&args->file);
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate #define	MAX_IOVECS	12
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate #ifdef DEBUG
12507c478bd9Sstevel@tonic-gate static int rfs3_write_hits = 0;
12517c478bd9Sstevel@tonic-gate static int rfs3_write_misses = 0;
12527c478bd9Sstevel@tonic-gate #endif
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate void
12557c478bd9Sstevel@tonic-gate rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
12565cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate 	int error;
12597c478bd9Sstevel@tonic-gate 	vnode_t *vp;
12607c478bd9Sstevel@tonic-gate 	struct vattr *bvap = NULL;
12617c478bd9Sstevel@tonic-gate 	struct vattr bva;
12627c478bd9Sstevel@tonic-gate 	struct vattr *avap = NULL;
12637c478bd9Sstevel@tonic-gate 	struct vattr ava;
12647c478bd9Sstevel@tonic-gate 	u_offset_t rlimit;
12657c478bd9Sstevel@tonic-gate 	struct uio uio;
12667c478bd9Sstevel@tonic-gate 	struct iovec iov[MAX_IOVECS];
12677c478bd9Sstevel@tonic-gate 	mblk_t *m;
12687c478bd9Sstevel@tonic-gate 	struct iovec *iovp;
12697c478bd9Sstevel@tonic-gate 	int iovcnt;
12707c478bd9Sstevel@tonic-gate 	int ioflag;
12717c478bd9Sstevel@tonic-gate 	cred_t *savecred;
12727c478bd9Sstevel@tonic-gate 	int in_crit = 0;
12737c478bd9Sstevel@tonic-gate 	int rwlock_ret = -1;
1274cfae96c2Sjwahlig 	caller_context_t ct;
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
1277e1adf50cSahl 
1278e1adf50cSahl 	DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
1279e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
1280e1adf50cSahl 
12817c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
12827c478bd9Sstevel@tonic-gate 		error = ESTALE;
1283e1adf50cSahl 		goto err;
12847c478bd9Sstevel@tonic-gate 	}
12857c478bd9Sstevel@tonic-gate 
128603986916Sjarrett 	if (is_system_labeled()) {
128703986916Sjarrett 		bslabel_t *clabel = req->rq_label;
128803986916Sjarrett 
128903986916Sjarrett 		ASSERT(clabel != NULL);
129003986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
129103986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
129203986916Sjarrett 
129303986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1294bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1295bd6f1640SJarrett Lu 			    exi)) {
129603986916Sjarrett 				resp->status = NFS3ERR_ACCES;
1297e1adf50cSahl 				goto err1;
129803986916Sjarrett 			}
129903986916Sjarrett 		}
130003986916Sjarrett 	}
130103986916Sjarrett 
1302cfae96c2Sjwahlig 	ct.cc_sysid = 0;
1303cfae96c2Sjwahlig 	ct.cc_pid = 0;
1304cfae96c2Sjwahlig 	ct.cc_caller_id = nfs3_srv_caller_id;
1305cfae96c2Sjwahlig 	ct.cc_flags = CC_DONTBLOCK;
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	/*
13087c478bd9Sstevel@tonic-gate 	 * We have to enter the critical region before calling VOP_RWLOCK
13097c478bd9Sstevel@tonic-gate 	 * to avoid a deadlock with ufs.
13107c478bd9Sstevel@tonic-gate 	 */
13117c478bd9Sstevel@tonic-gate 	if (nbl_need_check(vp)) {
13127c478bd9Sstevel@tonic-gate 		nbl_start_crit(vp, RW_READER);
13137c478bd9Sstevel@tonic-gate 		in_crit = 1;
1314da6c28aaSamw 		if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
1315da6c28aaSamw 		    NULL)) {
13167c478bd9Sstevel@tonic-gate 			error = EACCES;
1317e1adf50cSahl 			goto err;
13187c478bd9Sstevel@tonic-gate 		}
13197c478bd9Sstevel@tonic-gate 	}
13207c478bd9Sstevel@tonic-gate 
1321cfae96c2Sjwahlig 	rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
1322cfae96c2Sjwahlig 
1323cfae96c2Sjwahlig 	/* check if a monitor detected a delegation conflict */
1324cfae96c2Sjwahlig 	if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1325cfae96c2Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
1326cfae96c2Sjwahlig 		rwlock_ret = -1;
1327e1adf50cSahl 		goto err1;
1328cfae96c2Sjwahlig 	}
1329cfae96c2Sjwahlig 
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
1332cfae96c2Sjwahlig 	error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	/*
13357c478bd9Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
13367c478bd9Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
13377c478bd9Sstevel@tonic-gate 	 */
13387c478bd9Sstevel@tonic-gate 	if (error)
1339e1adf50cSahl 		goto err;
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 	bvap = &bva;
13427c478bd9Sstevel@tonic-gate 	avap = bvap;
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	if (args->count != args->data.data_len) {
13457c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
1346e1adf50cSahl 		goto err1;
13477c478bd9Sstevel@tonic-gate 	}
13487c478bd9Sstevel@tonic-gate 
13495cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
13507c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
1351e1adf50cSahl 		goto err1;
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	if (vp->v_type != VREG) {
13557c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
1356e1adf50cSahl 		goto err1;
13577c478bd9Sstevel@tonic-gate 	}
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 	if (crgetuid(cr) != bva.va_uid &&
1360cfae96c2Sjwahlig 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1361e1adf50cSahl 		goto err;
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	if (MANDLOCK(vp, bva.va_mode)) {
13647c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
1365e1adf50cSahl 		goto err1;
13667c478bd9Sstevel@tonic-gate 	}
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	if (args->count == 0) {
13697c478bd9Sstevel@tonic-gate 		resp->status = NFS3_OK;
13707c478bd9Sstevel@tonic-gate 		vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
13717c478bd9Sstevel@tonic-gate 		resp->resok.count = 0;
13727c478bd9Sstevel@tonic-gate 		resp->resok.committed = args->stable;
13737c478bd9Sstevel@tonic-gate 		resp->resok.verf = write3verf;
1374e1adf50cSahl 		goto out;
13757c478bd9Sstevel@tonic-gate 	}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	if (args->mblk != NULL) {
13787c478bd9Sstevel@tonic-gate 		iovcnt = 0;
13797c478bd9Sstevel@tonic-gate 		for (m = args->mblk; m != NULL; m = m->b_cont)
13807c478bd9Sstevel@tonic-gate 			iovcnt++;
13817c478bd9Sstevel@tonic-gate 		if (iovcnt <= MAX_IOVECS) {
13827c478bd9Sstevel@tonic-gate #ifdef DEBUG
13837c478bd9Sstevel@tonic-gate 			rfs3_write_hits++;
13847c478bd9Sstevel@tonic-gate #endif
13857c478bd9Sstevel@tonic-gate 			iovp = iov;
13867c478bd9Sstevel@tonic-gate 		} else {
13877c478bd9Sstevel@tonic-gate #ifdef DEBUG
13887c478bd9Sstevel@tonic-gate 			rfs3_write_misses++;
13897c478bd9Sstevel@tonic-gate #endif
13907c478bd9Sstevel@tonic-gate 			iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
13917c478bd9Sstevel@tonic-gate 		}
13927c478bd9Sstevel@tonic-gate 		mblk_to_iov(args->mblk, iovcnt, iovp);
13930a701b1eSRobert Gordon 
13940a701b1eSRobert Gordon 	} else if (args->rlist != NULL) {
13950a701b1eSRobert Gordon 		iovcnt = 1;
13960a701b1eSRobert Gordon 		iovp = iov;
13970a701b1eSRobert Gordon 		iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
13980a701b1eSRobert Gordon 		iovp->iov_len = args->count;
13997c478bd9Sstevel@tonic-gate 	} else {
14007c478bd9Sstevel@tonic-gate 		iovcnt = 1;
14017c478bd9Sstevel@tonic-gate 		iovp = iov;
14027c478bd9Sstevel@tonic-gate 		iovp->iov_base = args->data.data_val;
14037c478bd9Sstevel@tonic-gate 		iovp->iov_len = args->count;
14047c478bd9Sstevel@tonic-gate 	}
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	uio.uio_iov = iovp;
14077c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = iovcnt;
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
14107c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_DEFAULT;
14117c478bd9Sstevel@tonic-gate 	uio.uio_loffset = args->offset;
14127c478bd9Sstevel@tonic-gate 	uio.uio_resid = args->count;
14137c478bd9Sstevel@tonic-gate 	uio.uio_llimit = curproc->p_fsz_ctl;
14147c478bd9Sstevel@tonic-gate 	rlimit = uio.uio_llimit - args->offset;
14157c478bd9Sstevel@tonic-gate 	if (rlimit < (u_offset_t)uio.uio_resid)
14167c478bd9Sstevel@tonic-gate 		uio.uio_resid = (int)rlimit;
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	if (args->stable == UNSTABLE)
14197c478bd9Sstevel@tonic-gate 		ioflag = 0;
14207c478bd9Sstevel@tonic-gate 	else if (args->stable == FILE_SYNC)
14217c478bd9Sstevel@tonic-gate 		ioflag = FSYNC;
14227c478bd9Sstevel@tonic-gate 	else if (args->stable == DATA_SYNC)
14237c478bd9Sstevel@tonic-gate 		ioflag = FDSYNC;
14247c478bd9Sstevel@tonic-gate 	else {
14257c478bd9Sstevel@tonic-gate 		if (iovp != iov)
14267c478bd9Sstevel@tonic-gate 			kmem_free(iovp, sizeof (*iovp) * iovcnt);
14277c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
1428e1adf50cSahl 		goto err1;
14297c478bd9Sstevel@tonic-gate 	}
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	/*
14327c478bd9Sstevel@tonic-gate 	 * We're changing creds because VM may fault and we need
14337c478bd9Sstevel@tonic-gate 	 * the cred of the current thread to be used if quota
14347c478bd9Sstevel@tonic-gate 	 * checking is enabled.
14357c478bd9Sstevel@tonic-gate 	 */
14367c478bd9Sstevel@tonic-gate 	savecred = curthread->t_cred;
14377c478bd9Sstevel@tonic-gate 	curthread->t_cred = cr;
1438cfae96c2Sjwahlig 	error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
14397c478bd9Sstevel@tonic-gate 	curthread->t_cred = savecred;
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	if (iovp != iov)
14427c478bd9Sstevel@tonic-gate 		kmem_free(iovp, sizeof (*iovp) * iovcnt);
14437c478bd9Sstevel@tonic-gate 
1444cfae96c2Sjwahlig 	/* check if a monitor detected a delegation conflict */
1445cfae96c2Sjwahlig 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1446cfae96c2Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
1447e1adf50cSahl 		goto err1;
1448cfae96c2Sjwahlig 	}
1449cfae96c2Sjwahlig 
14507c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
1451cfae96c2Sjwahlig 	avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	if (error)
1454e1adf50cSahl 		goto err;
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	/*
14577c478bd9Sstevel@tonic-gate 	 * If we were unable to get the V_WRITELOCK_TRUE, then we
14587c478bd9Sstevel@tonic-gate 	 * may not have accurate after attrs, so check if
14597c478bd9Sstevel@tonic-gate 	 * we have both attributes, they have a non-zero va_seq, and
14607c478bd9Sstevel@tonic-gate 	 * va_seq has changed by exactly one,
14617c478bd9Sstevel@tonic-gate 	 * if not, turn off the before attr.
14627c478bd9Sstevel@tonic-gate 	 */
14637c478bd9Sstevel@tonic-gate 	if (rwlock_ret != V_WRITELOCK_TRUE) {
14647c478bd9Sstevel@tonic-gate 		if (bvap == NULL || avap == NULL ||
14657c478bd9Sstevel@tonic-gate 		    bvap->va_seq == 0 || avap->va_seq == 0 ||
14667c478bd9Sstevel@tonic-gate 		    avap->va_seq != (bvap->va_seq + 1)) {
14677c478bd9Sstevel@tonic-gate 			bvap = NULL;
14687c478bd9Sstevel@tonic-gate 		}
14697c478bd9Sstevel@tonic-gate 	}
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
14727c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
14737c478bd9Sstevel@tonic-gate 	resp->resok.count = args->count - uio.uio_resid;
14747c478bd9Sstevel@tonic-gate 	resp->resok.committed = args->stable;
14757c478bd9Sstevel@tonic-gate 	resp->resok.verf = write3verf;
1476e1adf50cSahl 	goto out;
14777c478bd9Sstevel@tonic-gate 
1478e1adf50cSahl err:
14797c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
14807c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
14817c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
14827c478bd9Sstevel@tonic-gate 	} else
14837c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
1484e1adf50cSahl err1:
1485e1adf50cSahl 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1486e1adf50cSahl out:
1487e1adf50cSahl 	DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
1488e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
1489e1adf50cSahl 
14907c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
14917c478bd9Sstevel@tonic-gate 		if (rwlock_ret != -1)
1492cfae96c2Sjwahlig 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
14937c478bd9Sstevel@tonic-gate 		if (in_crit)
14947c478bd9Sstevel@tonic-gate 			nbl_end_crit(vp);
14957c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
14967c478bd9Sstevel@tonic-gate 	}
14977c478bd9Sstevel@tonic-gate }
14987c478bd9Sstevel@tonic-gate 
149927242a7cSthurlow void *
15007c478bd9Sstevel@tonic-gate rfs3_write_getfh(WRITE3args *args)
15017c478bd9Sstevel@tonic-gate {
15027c478bd9Sstevel@tonic-gate 
150327242a7cSthurlow 	return (&args->file);
15047c478bd9Sstevel@tonic-gate }
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate void
15077c478bd9Sstevel@tonic-gate rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
15085cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
15097c478bd9Sstevel@tonic-gate {
15107c478bd9Sstevel@tonic-gate 	int error;
15117c478bd9Sstevel@tonic-gate 	int in_crit = 0;
15127c478bd9Sstevel@tonic-gate 	vnode_t *vp;
15137c478bd9Sstevel@tonic-gate 	vnode_t *tvp = NULL;
15147c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
15157c478bd9Sstevel@tonic-gate 	struct vattr *vap;
15167c478bd9Sstevel@tonic-gate 	struct vattr va;
15177c478bd9Sstevel@tonic-gate 	struct vattr *dbvap;
15187c478bd9Sstevel@tonic-gate 	struct vattr dbva;
15197c478bd9Sstevel@tonic-gate 	struct vattr *davap;
15207c478bd9Sstevel@tonic-gate 	struct vattr dava;
15217c478bd9Sstevel@tonic-gate 	enum vcexcl excl;
15227c478bd9Sstevel@tonic-gate 	nfstime3 *mtime;
15237c478bd9Sstevel@tonic-gate 	len_t reqsize;
15247c478bd9Sstevel@tonic-gate 	bool_t trunc;
1525b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
1526b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	dbvap = NULL;
15297c478bd9Sstevel@tonic-gate 	davap = NULL;
15307c478bd9Sstevel@tonic-gate 
153127242a7cSthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
1532e1adf50cSahl 
1533e1adf50cSahl 	DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1534e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
1535e1adf50cSahl 
15367c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
15377c478bd9Sstevel@tonic-gate 		error = ESTALE;
15387c478bd9Sstevel@tonic-gate 		goto out;
15397c478bd9Sstevel@tonic-gate 	}
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
1542da6c28aaSamw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
15437c478bd9Sstevel@tonic-gate 	davap = dbvap;
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
15467c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
15477c478bd9Sstevel@tonic-gate 		goto out1;
15487c478bd9Sstevel@tonic-gate 	}
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
15517c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
15527c478bd9Sstevel@tonic-gate 		goto out1;
15537c478bd9Sstevel@tonic-gate 	}
15547c478bd9Sstevel@tonic-gate 
15555cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
15567c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
15577c478bd9Sstevel@tonic-gate 		goto out1;
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 
156003986916Sjarrett 	if (is_system_labeled()) {
156103986916Sjarrett 		bslabel_t *clabel = req->rq_label;
156203986916Sjarrett 
156303986916Sjarrett 		ASSERT(clabel != NULL);
156403986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
156503986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
156603986916Sjarrett 
156703986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1568bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1569bd6f1640SJarrett Lu 			    exi)) {
157003986916Sjarrett 				resp->status = NFS3ERR_ACCES;
157103986916Sjarrett 				goto out1;
157203986916Sjarrett 			}
157303986916Sjarrett 		}
157403986916Sjarrett 	}
157503986916Sjarrett 
1576b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1577b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->where.name,
1578b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1579b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1580b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
1581b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/* This is really a Solaris EILSEQ */
1582b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
1583b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
1584b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1585b89a8333Snatalie li - Sun Microsystems - Irvine United States 
15867c478bd9Sstevel@tonic-gate 	if (args->how.mode == EXCLUSIVE) {
15877c478bd9Sstevel@tonic-gate 		va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
15887c478bd9Sstevel@tonic-gate 		va.va_type = VREG;
15897c478bd9Sstevel@tonic-gate 		va.va_mode = (mode_t)0;
15907c478bd9Sstevel@tonic-gate 		/*
15917c478bd9Sstevel@tonic-gate 		 * Ensure no time overflows and that types match
15927c478bd9Sstevel@tonic-gate 		 */
15937c478bd9Sstevel@tonic-gate 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
15947c478bd9Sstevel@tonic-gate 		va.va_mtime.tv_sec = mtime->seconds % INT32_MAX;
15957c478bd9Sstevel@tonic-gate 		va.va_mtime.tv_nsec = mtime->nseconds;
15967c478bd9Sstevel@tonic-gate 		excl = EXCL;
15977c478bd9Sstevel@tonic-gate 	} else {
15987c478bd9Sstevel@tonic-gate 		error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes,
15997c478bd9Sstevel@tonic-gate 		    &va);
16007c478bd9Sstevel@tonic-gate 		if (error)
16017c478bd9Sstevel@tonic-gate 			goto out;
16027c478bd9Sstevel@tonic-gate 		va.va_mask |= AT_TYPE;
16037c478bd9Sstevel@tonic-gate 		va.va_type = VREG;
16047c478bd9Sstevel@tonic-gate 		if (args->how.mode == GUARDED)
16057c478bd9Sstevel@tonic-gate 			excl = EXCL;
16067c478bd9Sstevel@tonic-gate 		else {
16077c478bd9Sstevel@tonic-gate 			excl = NONEXCL;
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 			/*
16107c478bd9Sstevel@tonic-gate 			 * During creation of file in non-exclusive mode
16117c478bd9Sstevel@tonic-gate 			 * if size of file is being set then make sure
16127c478bd9Sstevel@tonic-gate 			 * that if the file already exists that no conflicting
16137c478bd9Sstevel@tonic-gate 			 * non-blocking mandatory locks exists in the region
16147c478bd9Sstevel@tonic-gate 			 * being modified. If there are conflicting locks fail
16157c478bd9Sstevel@tonic-gate 			 * the operation with EACCES.
16167c478bd9Sstevel@tonic-gate 			 */
16177c478bd9Sstevel@tonic-gate 			if (va.va_mask & AT_SIZE) {
16187c478bd9Sstevel@tonic-gate 				struct vattr tva;
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate 				/*
16217c478bd9Sstevel@tonic-gate 				 * Does file already exist?
16227c478bd9Sstevel@tonic-gate 				 */
1623b89a8333Snatalie li - Sun Microsystems - Irvine United States 				error = VOP_LOOKUP(dvp, name, &tvp,
1624da6c28aaSamw 				    NULL, 0, NULL, cr, NULL, NULL, NULL);
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 				/*
16277c478bd9Sstevel@tonic-gate 				 * Check to see if the file has been delegated
16287c478bd9Sstevel@tonic-gate 				 * to a v4 client.  If so, then begin recall of
16297c478bd9Sstevel@tonic-gate 				 * the delegation and return JUKEBOX to allow
16307c478bd9Sstevel@tonic-gate 				 * the client to retrasmit its request.
16317c478bd9Sstevel@tonic-gate 				 */
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 				trunc = va.va_size == 0;
16347c478bd9Sstevel@tonic-gate 				if (!error &&
16357c478bd9Sstevel@tonic-gate 				    rfs4_check_delegated(FWRITE, tvp, trunc)) {
16367c478bd9Sstevel@tonic-gate 					resp->status = NFS3ERR_JUKEBOX;
16377c478bd9Sstevel@tonic-gate 					goto out1;
16387c478bd9Sstevel@tonic-gate 				}
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 				/*
16417c478bd9Sstevel@tonic-gate 				 * Check for NBMAND lock conflicts
16427c478bd9Sstevel@tonic-gate 				 */
16437c478bd9Sstevel@tonic-gate 				if (!error && nbl_need_check(tvp)) {
16447c478bd9Sstevel@tonic-gate 					u_offset_t offset;
16457c478bd9Sstevel@tonic-gate 					ssize_t len;
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 					nbl_start_crit(tvp, RW_READER);
16487c478bd9Sstevel@tonic-gate 					in_crit = 1;
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 					tva.va_mask = AT_SIZE;
1651da6c28aaSamw 					error = VOP_GETATTR(tvp, &tva, 0, cr,
1652da6c28aaSamw 					    NULL);
16537c478bd9Sstevel@tonic-gate 					/*
16547c478bd9Sstevel@tonic-gate 					 * Can't check for conflicts, so return
16557c478bd9Sstevel@tonic-gate 					 * error.
16567c478bd9Sstevel@tonic-gate 					 */
16577c478bd9Sstevel@tonic-gate 					if (error)
16587c478bd9Sstevel@tonic-gate 						goto out;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 					offset = tva.va_size < va.va_size ?
16617c478bd9Sstevel@tonic-gate 					    tva.va_size : va.va_size;
16627c478bd9Sstevel@tonic-gate 					len = tva.va_size < va.va_size ?
16637c478bd9Sstevel@tonic-gate 					    va.va_size - tva.va_size :
16647c478bd9Sstevel@tonic-gate 					    tva.va_size - va.va_size;
16657c478bd9Sstevel@tonic-gate 					if (nbl_conflict(tvp, NBL_WRITE,
1666da6c28aaSamw 					    offset, len, 0, NULL)) {
16677c478bd9Sstevel@tonic-gate 						error = EACCES;
16687c478bd9Sstevel@tonic-gate 						goto out;
16697c478bd9Sstevel@tonic-gate 					}
16707c478bd9Sstevel@tonic-gate 				} else if (tvp) {
16717c478bd9Sstevel@tonic-gate 					VN_RELE(tvp);
16727c478bd9Sstevel@tonic-gate 					tvp = NULL;
16737c478bd9Sstevel@tonic-gate 				}
16747c478bd9Sstevel@tonic-gate 			}
16757c478bd9Sstevel@tonic-gate 		}
16767c478bd9Sstevel@tonic-gate 		if (va.va_mask & AT_SIZE)
16777c478bd9Sstevel@tonic-gate 			reqsize = va.va_size;
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	/*
16817c478bd9Sstevel@tonic-gate 	 * Must specify the mode.
16827c478bd9Sstevel@tonic-gate 	 */
16837c478bd9Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
16847c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
16857c478bd9Sstevel@tonic-gate 		goto out1;
16867c478bd9Sstevel@tonic-gate 	}
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	/*
16897c478bd9Sstevel@tonic-gate 	 * If the filesystem is exported with nosuid, then mask off
16907c478bd9Sstevel@tonic-gate 	 * the setuid and setgid bits.
16917c478bd9Sstevel@tonic-gate 	 */
16927c478bd9Sstevel@tonic-gate 	if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
16937c478bd9Sstevel@tonic-gate 		va.va_mode &= ~(VSUID | VSGID);
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate tryagain:
16967c478bd9Sstevel@tonic-gate 	/*
16977c478bd9Sstevel@tonic-gate 	 * The file open mode used is VWRITE.  If the client needs
16987c478bd9Sstevel@tonic-gate 	 * some other semantic, then it should do the access checking
16997c478bd9Sstevel@tonic-gate 	 * itself.  It would have been nice to have the file open mode
17007c478bd9Sstevel@tonic-gate 	 * passed as part of the arguments.
17017c478bd9Sstevel@tonic-gate 	 */
1702b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
1703da6c28aaSamw 	    &vp, cr, 0, NULL, NULL);
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
1706da6c28aaSamw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	if (error) {
17097c478bd9Sstevel@tonic-gate 		/*
17107c478bd9Sstevel@tonic-gate 		 * If we got something other than file already exists
17117c478bd9Sstevel@tonic-gate 		 * then just return this error.  Otherwise, we got
17127c478bd9Sstevel@tonic-gate 		 * EEXIST.  If we were doing a GUARDED create, then
17137c478bd9Sstevel@tonic-gate 		 * just return this error.  Otherwise, we need to
17147c478bd9Sstevel@tonic-gate 		 * make sure that this wasn't a duplicate of an
17157c478bd9Sstevel@tonic-gate 		 * exclusive create request.
17167c478bd9Sstevel@tonic-gate 		 *
17177c478bd9Sstevel@tonic-gate 		 * The assumption is made that a non-exclusive create
17187c478bd9Sstevel@tonic-gate 		 * request will never return EEXIST.
17197c478bd9Sstevel@tonic-gate 		 */
17207c478bd9Sstevel@tonic-gate 		if (error != EEXIST || args->how.mode == GUARDED)
17217c478bd9Sstevel@tonic-gate 			goto out;
17227c478bd9Sstevel@tonic-gate 		/*
17237c478bd9Sstevel@tonic-gate 		 * Lookup the file so that we can get a vnode for it.
17247c478bd9Sstevel@tonic-gate 		 */
1725b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
1726da6c28aaSamw 		    NULL, cr, NULL, NULL, NULL);
17277c478bd9Sstevel@tonic-gate 		if (error) {
17287c478bd9Sstevel@tonic-gate 			/*
17297c478bd9Sstevel@tonic-gate 			 * We couldn't find the file that we thought that
17307c478bd9Sstevel@tonic-gate 			 * we just created.  So, we'll just try creating
17317c478bd9Sstevel@tonic-gate 			 * it again.
17327c478bd9Sstevel@tonic-gate 			 */
17337c478bd9Sstevel@tonic-gate 			if (error == ENOENT)
17347c478bd9Sstevel@tonic-gate 				goto tryagain;
17357c478bd9Sstevel@tonic-gate 			goto out;
17367c478bd9Sstevel@tonic-gate 		}
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 		/*
17397c478bd9Sstevel@tonic-gate 		 * If the file is delegated to a v4 client, go ahead
17407c478bd9Sstevel@tonic-gate 		 * and initiate recall, this create is a hint that a
17417c478bd9Sstevel@tonic-gate 		 * conflicting v3 open has occurred.
17427c478bd9Sstevel@tonic-gate 		 */
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 		if (rfs4_check_delegated(FWRITE, vp, FALSE)) {
17457c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
17467c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
17477c478bd9Sstevel@tonic-gate 			goto out1;
17487c478bd9Sstevel@tonic-gate 		}
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 		va.va_mask = AT_ALL;
1751da6c28aaSamw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
17547c478bd9Sstevel@tonic-gate 		/* % with INT32_MAX to prevent overflows */
17557c478bd9Sstevel@tonic-gate 		if (args->how.mode == EXCLUSIVE && (vap == NULL ||
17567c478bd9Sstevel@tonic-gate 		    vap->va_mtime.tv_sec !=
17577c478bd9Sstevel@tonic-gate 		    (mtime->seconds % INT32_MAX) ||
17587c478bd9Sstevel@tonic-gate 		    vap->va_mtime.tv_nsec != mtime->nseconds)) {
17597c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
17607c478bd9Sstevel@tonic-gate 			error = EEXIST;
17617c478bd9Sstevel@tonic-gate 			goto out;
17627c478bd9Sstevel@tonic-gate 		}
17637c478bd9Sstevel@tonic-gate 	} else {
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 		if ((args->how.mode == UNCHECKED ||
17667c478bd9Sstevel@tonic-gate 		    args->how.mode == GUARDED) &&
17677c478bd9Sstevel@tonic-gate 		    args->how.createhow3_u.obj_attributes.size.set_it &&
17687c478bd9Sstevel@tonic-gate 		    va.va_size == 0)
17697c478bd9Sstevel@tonic-gate 			trunc = TRUE;
17707c478bd9Sstevel@tonic-gate 		else
17717c478bd9Sstevel@tonic-gate 			trunc = FALSE;
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 		if (rfs4_check_delegated(FWRITE, vp, trunc)) {
17747c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
17757c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
17767c478bd9Sstevel@tonic-gate 			goto out1;
17777c478bd9Sstevel@tonic-gate 		}
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 		va.va_mask = AT_ALL;
1780da6c28aaSamw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 		/*
17837c478bd9Sstevel@tonic-gate 		 * We need to check to make sure that the file got
17847c478bd9Sstevel@tonic-gate 		 * created to the indicated size.  If not, we do a
17857c478bd9Sstevel@tonic-gate 		 * setattr to try to change the size, but we don't
17867c478bd9Sstevel@tonic-gate 		 * try too hard.  This shouldn't a problem as most
17877c478bd9Sstevel@tonic-gate 		 * clients will only specifiy a size of zero which
17887c478bd9Sstevel@tonic-gate 		 * local file systems handle.  However, even if
17897c478bd9Sstevel@tonic-gate 		 * the client does specify a non-zero size, it can
17907c478bd9Sstevel@tonic-gate 		 * still recover by checking the size of the file
17917c478bd9Sstevel@tonic-gate 		 * after it has created it and then issue a setattr
17927c478bd9Sstevel@tonic-gate 		 * request of its own to set the size of the file.
17937c478bd9Sstevel@tonic-gate 		 */
17947c478bd9Sstevel@tonic-gate 		if (vap != NULL &&
17957c478bd9Sstevel@tonic-gate 		    (args->how.mode == UNCHECKED ||
17967c478bd9Sstevel@tonic-gate 		    args->how.mode == GUARDED) &&
17977c478bd9Sstevel@tonic-gate 		    args->how.createhow3_u.obj_attributes.size.set_it &&
17987c478bd9Sstevel@tonic-gate 		    vap->va_size != reqsize) {
17997c478bd9Sstevel@tonic-gate 			va.va_mask = AT_SIZE;
18007c478bd9Sstevel@tonic-gate 			va.va_size = reqsize;
18017c478bd9Sstevel@tonic-gate 			(void) VOP_SETATTR(vp, &va, 0, cr, NULL);
18027c478bd9Sstevel@tonic-gate 			va.va_mask = AT_ALL;
1803da6c28aaSamw 			vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
18047c478bd9Sstevel@tonic-gate 		}
18057c478bd9Sstevel@tonic-gate 	}
18067c478bd9Sstevel@tonic-gate 
1807b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->where.name)
1808b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
1809b89a8333Snatalie li - Sun Microsystems - Irvine United States 
18107c478bd9Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
18117c478bd9Sstevel@tonic-gate 	if (error)
18127c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
18137c478bd9Sstevel@tonic-gate 	else
18147c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 	/*
18177c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
18187c478bd9Sstevel@tonic-gate 	 */
1819da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1820da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
18237c478bd9Sstevel@tonic-gate 	if (tvp != NULL) {
18247c478bd9Sstevel@tonic-gate 		if (in_crit)
18257c478bd9Sstevel@tonic-gate 			nbl_end_crit(tvp);
18267c478bd9Sstevel@tonic-gate 		VN_RELE(tvp);
18277c478bd9Sstevel@tonic-gate 	}
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
18307c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
18317c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1832e1adf50cSahl 
1833e1adf50cSahl 	DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1834e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1835e1adf50cSahl 
1836e1adf50cSahl 	VN_RELE(dvp);
18377c478bd9Sstevel@tonic-gate 	return;
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate out:
18407c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
18417c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
18427c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
18437c478bd9Sstevel@tonic-gate 	} else
18447c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
18457c478bd9Sstevel@tonic-gate out1:
1846e1adf50cSahl 	DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1847e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1848e1adf50cSahl 
1849b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->where.name)
1850b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
1851b89a8333Snatalie li - Sun Microsystems - Irvine United States 
18527c478bd9Sstevel@tonic-gate 	if (tvp != NULL) {
18537c478bd9Sstevel@tonic-gate 		if (in_crit)
18547c478bd9Sstevel@tonic-gate 			nbl_end_crit(tvp);
18557c478bd9Sstevel@tonic-gate 		VN_RELE(tvp);
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
18587c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
18597c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate 
186227242a7cSthurlow void *
18637c478bd9Sstevel@tonic-gate rfs3_create_getfh(CREATE3args *args)
18647c478bd9Sstevel@tonic-gate {
18657c478bd9Sstevel@tonic-gate 
186627242a7cSthurlow 	return (&args->where.dir);
18677c478bd9Sstevel@tonic-gate }
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate void
18707c478bd9Sstevel@tonic-gate rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
18715cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
18727c478bd9Sstevel@tonic-gate {
18737c478bd9Sstevel@tonic-gate 	int error;
18747c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
18757c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
18767c478bd9Sstevel@tonic-gate 	struct vattr *vap;
18777c478bd9Sstevel@tonic-gate 	struct vattr va;
18787c478bd9Sstevel@tonic-gate 	struct vattr *dbvap;
18797c478bd9Sstevel@tonic-gate 	struct vattr dbva;
18807c478bd9Sstevel@tonic-gate 	struct vattr *davap;
18817c478bd9Sstevel@tonic-gate 	struct vattr dava;
1882b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
1883b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	dbvap = NULL;
18867c478bd9Sstevel@tonic-gate 	davap = NULL;
18877c478bd9Sstevel@tonic-gate 
188827242a7cSthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
1889e1adf50cSahl 
1890e1adf50cSahl 	DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
1891e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
1892e1adf50cSahl 
18937c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
18947c478bd9Sstevel@tonic-gate 		error = ESTALE;
18957c478bd9Sstevel@tonic-gate 		goto out;
18967c478bd9Sstevel@tonic-gate 	}
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
1899da6c28aaSamw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
19007c478bd9Sstevel@tonic-gate 	davap = dbvap;
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
19037c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
19047c478bd9Sstevel@tonic-gate 		goto out1;
19057c478bd9Sstevel@tonic-gate 	}
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
19087c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
19097c478bd9Sstevel@tonic-gate 		goto out1;
19107c478bd9Sstevel@tonic-gate 	}
19117c478bd9Sstevel@tonic-gate 
19125cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
19137c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
19147c478bd9Sstevel@tonic-gate 		goto out1;
19157c478bd9Sstevel@tonic-gate 	}
19167c478bd9Sstevel@tonic-gate 
191703986916Sjarrett 	if (is_system_labeled()) {
191803986916Sjarrett 		bslabel_t *clabel = req->rq_label;
191903986916Sjarrett 
192003986916Sjarrett 		ASSERT(clabel != NULL);
192103986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
192203986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
192303986916Sjarrett 
192403986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1925bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1926bd6f1640SJarrett Lu 			    exi)) {
192703986916Sjarrett 				resp->status = NFS3ERR_ACCES;
192803986916Sjarrett 				goto out1;
192903986916Sjarrett 			}
193003986916Sjarrett 		}
193103986916Sjarrett 	}
193203986916Sjarrett 
19337c478bd9Sstevel@tonic-gate 	error = sattr3_to_vattr(&args->attributes, &va);
19347c478bd9Sstevel@tonic-gate 	if (error)
19357c478bd9Sstevel@tonic-gate 		goto out;
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
19387c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
19397c478bd9Sstevel@tonic-gate 		goto out1;
19407c478bd9Sstevel@tonic-gate 	}
19417c478bd9Sstevel@tonic-gate 
1942b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1943b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->where.name,
1944b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1945b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1946b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
1947b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
1948b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
1949b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1950b89a8333Snatalie li - Sun Microsystems - Irvine United States 
19517c478bd9Sstevel@tonic-gate 	va.va_mask |= AT_TYPE;
19527c478bd9Sstevel@tonic-gate 	va.va_type = VDIR;
19537c478bd9Sstevel@tonic-gate 
1954b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
1955b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1956b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->where.name)
1957b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
1960da6c28aaSamw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	/*
19637c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
19647c478bd9Sstevel@tonic-gate 	 */
1965da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	if (error)
19687c478bd9Sstevel@tonic-gate 		goto out;
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
19717c478bd9Sstevel@tonic-gate 	if (error)
19727c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
19737c478bd9Sstevel@tonic-gate 	else
19747c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1977da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	/*
19807c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
19817c478bd9Sstevel@tonic-gate 	 */
1982da6c28aaSamw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
19877c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
19887c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1989e1adf50cSahl 
1990e1adf50cSahl 	DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
1991e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
1992e1adf50cSahl 	VN_RELE(dvp);
1993e1adf50cSahl 
19947c478bd9Sstevel@tonic-gate 	return;
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate out:
19977c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
19987c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
19997c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
20007c478bd9Sstevel@tonic-gate 	} else
20017c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
20027c478bd9Sstevel@tonic-gate out1:
2003e1adf50cSahl 	DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2004e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
20057c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
20067c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
20077c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
20087c478bd9Sstevel@tonic-gate }
20097c478bd9Sstevel@tonic-gate 
201027242a7cSthurlow void *
20117c478bd9Sstevel@tonic-gate rfs3_mkdir_getfh(MKDIR3args *args)
20127c478bd9Sstevel@tonic-gate {
20137c478bd9Sstevel@tonic-gate 
201427242a7cSthurlow 	return (&args->where.dir);
20157c478bd9Sstevel@tonic-gate }
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate void
20187c478bd9Sstevel@tonic-gate rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
20195cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
20207c478bd9Sstevel@tonic-gate {
20217c478bd9Sstevel@tonic-gate 	int error;
20227c478bd9Sstevel@tonic-gate 	vnode_t *vp;
20237c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
20247c478bd9Sstevel@tonic-gate 	struct vattr *vap;
20257c478bd9Sstevel@tonic-gate 	struct vattr va;
20267c478bd9Sstevel@tonic-gate 	struct vattr *dbvap;
20277c478bd9Sstevel@tonic-gate 	struct vattr dbva;
20287c478bd9Sstevel@tonic-gate 	struct vattr *davap;
20297c478bd9Sstevel@tonic-gate 	struct vattr dava;
2030b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2031b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
2032b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *symdata = NULL;
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 	dbvap = NULL;
20357c478bd9Sstevel@tonic-gate 	davap = NULL;
20367c478bd9Sstevel@tonic-gate 
203727242a7cSthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
2038e1adf50cSahl 
2039e1adf50cSahl 	DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2040e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
2041e1adf50cSahl 
20427c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
20437c478bd9Sstevel@tonic-gate 		error = ESTALE;
2044e1adf50cSahl 		goto err;
20457c478bd9Sstevel@tonic-gate 	}
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
2048da6c28aaSamw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
20497c478bd9Sstevel@tonic-gate 	davap = dbvap;
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
20527c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2053e1adf50cSahl 		goto err1;
20547c478bd9Sstevel@tonic-gate 	}
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
20577c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2058e1adf50cSahl 		goto err1;
20597c478bd9Sstevel@tonic-gate 	}
20607c478bd9Sstevel@tonic-gate 
20615cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
20627c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2063e1adf50cSahl 		goto err1;
20647c478bd9Sstevel@tonic-gate 	}
20657c478bd9Sstevel@tonic-gate 
206603986916Sjarrett 	if (is_system_labeled()) {
206703986916Sjarrett 		bslabel_t *clabel = req->rq_label;
206803986916Sjarrett 
206903986916Sjarrett 		ASSERT(clabel != NULL);
207003986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
207103986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
207203986916Sjarrett 
207303986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2074bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2075bd6f1640SJarrett Lu 			    exi)) {
207603986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2077e1adf50cSahl 				goto err1;
207803986916Sjarrett 			}
207903986916Sjarrett 		}
208003986916Sjarrett 	}
208103986916Sjarrett 
20827c478bd9Sstevel@tonic-gate 	error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
20837c478bd9Sstevel@tonic-gate 	if (error)
2084e1adf50cSahl 		goto err;
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
20877c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
2088e1adf50cSahl 		goto err1;
20897c478bd9Sstevel@tonic-gate 	}
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 	if (args->symlink.symlink_data == nfs3nametoolong) {
20927c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2093e1adf50cSahl 		goto err1;
20947c478bd9Sstevel@tonic-gate 	}
20957c478bd9Sstevel@tonic-gate 
2096b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2097b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->where.name,
2098b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2099b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2100b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2101b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/* This is really a Solaris EILSEQ */
2102b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2103b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2104b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2105b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2106b89a8333Snatalie li - Sun Microsystems - Irvine United States 	symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
2107b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2108b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (symdata == NULL) {
2109b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/* This is really a Solaris EILSEQ */
2110b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2111b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2112b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2113b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2114b89a8333Snatalie li - Sun Microsystems - Irvine United States 
21157c478bd9Sstevel@tonic-gate 	va.va_mask |= AT_TYPE;
21167c478bd9Sstevel@tonic-gate 	va.va_type = VLNK;
21177c478bd9Sstevel@tonic-gate 
2118b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
2121da6c28aaSamw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 	if (error)
2124e1adf50cSahl 		goto err;
21257c478bd9Sstevel@tonic-gate 
2126b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
2127da6c28aaSamw 	    NULL, NULL, NULL);
21287c478bd9Sstevel@tonic-gate 
21297c478bd9Sstevel@tonic-gate 	/*
21307c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
21317c478bd9Sstevel@tonic-gate 	 */
2132da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
21367c478bd9Sstevel@tonic-gate 	if (error) {
21377c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
21387c478bd9Sstevel@tonic-gate 		vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
21397c478bd9Sstevel@tonic-gate 		vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2140e1adf50cSahl 		goto out;
21417c478bd9Sstevel@tonic-gate 	}
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
21447c478bd9Sstevel@tonic-gate 	if (error)
21457c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
21467c478bd9Sstevel@tonic-gate 	else
21477c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2150da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 	/*
21537c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
21547c478bd9Sstevel@tonic-gate 	 */
2155da6c28aaSamw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
21607c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2161e1adf50cSahl 	goto out;
21627c478bd9Sstevel@tonic-gate 
2163e1adf50cSahl err:
21647c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
21657c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
21667c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
21677c478bd9Sstevel@tonic-gate 	} else
21687c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
2169e1adf50cSahl err1:
2170e1adf50cSahl 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2171e1adf50cSahl out:
2172b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->where.name)
2173b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
2174b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (symdata != NULL && symdata != args->symlink.symlink_data)
2175b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(symdata, MAXPATHLEN + 1);
2176b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2177e1adf50cSahl 	DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
2178e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
2179e1adf50cSahl 
21807c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
21817c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
21827c478bd9Sstevel@tonic-gate }
21837c478bd9Sstevel@tonic-gate 
218427242a7cSthurlow void *
21857c478bd9Sstevel@tonic-gate rfs3_symlink_getfh(SYMLINK3args *args)
21867c478bd9Sstevel@tonic-gate {
21877c478bd9Sstevel@tonic-gate 
218827242a7cSthurlow 	return (&args->where.dir);
21897c478bd9Sstevel@tonic-gate }
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate void
21927c478bd9Sstevel@tonic-gate rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
21935cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
21947c478bd9Sstevel@tonic-gate {
21957c478bd9Sstevel@tonic-gate 	int error;
21967c478bd9Sstevel@tonic-gate 	vnode_t *vp;
2197fd7da618Sgt29601 	vnode_t *realvp;
21987c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
21997c478bd9Sstevel@tonic-gate 	struct vattr *vap;
22007c478bd9Sstevel@tonic-gate 	struct vattr va;
22017c478bd9Sstevel@tonic-gate 	struct vattr *dbvap;
22027c478bd9Sstevel@tonic-gate 	struct vattr dbva;
22037c478bd9Sstevel@tonic-gate 	struct vattr *davap;
22047c478bd9Sstevel@tonic-gate 	struct vattr dava;
22057c478bd9Sstevel@tonic-gate 	int mode;
22067c478bd9Sstevel@tonic-gate 	enum vcexcl excl;
2207b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2208b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate 	dbvap = NULL;
22117c478bd9Sstevel@tonic-gate 	davap = NULL;
22127c478bd9Sstevel@tonic-gate 
221327242a7cSthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
2214e1adf50cSahl 
2215e1adf50cSahl 	DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2216e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
2217e1adf50cSahl 
22187c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
22197c478bd9Sstevel@tonic-gate 		error = ESTALE;
22207c478bd9Sstevel@tonic-gate 		goto out;
22217c478bd9Sstevel@tonic-gate 	}
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
2224da6c28aaSamw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
22257c478bd9Sstevel@tonic-gate 	davap = dbvap;
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
22287c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
22297c478bd9Sstevel@tonic-gate 		goto out1;
22307c478bd9Sstevel@tonic-gate 	}
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
22337c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
22347c478bd9Sstevel@tonic-gate 		goto out1;
22357c478bd9Sstevel@tonic-gate 	}
22367c478bd9Sstevel@tonic-gate 
22375cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
22387c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
22397c478bd9Sstevel@tonic-gate 		goto out1;
22407c478bd9Sstevel@tonic-gate 	}
22417c478bd9Sstevel@tonic-gate 
224203986916Sjarrett 	if (is_system_labeled()) {
224303986916Sjarrett 		bslabel_t *clabel = req->rq_label;
224403986916Sjarrett 
224503986916Sjarrett 		ASSERT(clabel != NULL);
224603986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
224703986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
224803986916Sjarrett 
224903986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2250bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2251bd6f1640SJarrett Lu 			    exi)) {
225203986916Sjarrett 				resp->status = NFS3ERR_ACCES;
225303986916Sjarrett 				goto out1;
225403986916Sjarrett 			}
225503986916Sjarrett 		}
225603986916Sjarrett 	}
225703986916Sjarrett 
22587c478bd9Sstevel@tonic-gate 	switch (args->what.type) {
22597c478bd9Sstevel@tonic-gate 	case NF3CHR:
22607c478bd9Sstevel@tonic-gate 	case NF3BLK:
22617c478bd9Sstevel@tonic-gate 		error = sattr3_to_vattr(
22627c478bd9Sstevel@tonic-gate 		    &args->what.mknoddata3_u.device.dev_attributes, &va);
22637c478bd9Sstevel@tonic-gate 		if (error)
22647c478bd9Sstevel@tonic-gate 			goto out;
22657c478bd9Sstevel@tonic-gate 		if (secpolicy_sys_devices(cr) != 0) {
22667c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_PERM;
22677c478bd9Sstevel@tonic-gate 			goto out1;
22687c478bd9Sstevel@tonic-gate 		}
22697c478bd9Sstevel@tonic-gate 		if (args->what.type == NF3CHR)
22707c478bd9Sstevel@tonic-gate 			va.va_type = VCHR;
22717c478bd9Sstevel@tonic-gate 		else
22727c478bd9Sstevel@tonic-gate 			va.va_type = VBLK;
22737c478bd9Sstevel@tonic-gate 		va.va_rdev = makedevice(
22747c478bd9Sstevel@tonic-gate 		    args->what.mknoddata3_u.device.spec.specdata1,
22757c478bd9Sstevel@tonic-gate 		    args->what.mknoddata3_u.device.spec.specdata2);
22767c478bd9Sstevel@tonic-gate 		va.va_mask |= AT_TYPE | AT_RDEV;
22777c478bd9Sstevel@tonic-gate 		break;
22787c478bd9Sstevel@tonic-gate 	case NF3SOCK:
22797c478bd9Sstevel@tonic-gate 		error = sattr3_to_vattr(
22807c478bd9Sstevel@tonic-gate 		    &args->what.mknoddata3_u.pipe_attributes, &va);
22817c478bd9Sstevel@tonic-gate 		if (error)
22827c478bd9Sstevel@tonic-gate 			goto out;
22837c478bd9Sstevel@tonic-gate 		va.va_type = VSOCK;
22847c478bd9Sstevel@tonic-gate 		va.va_mask |= AT_TYPE;
22857c478bd9Sstevel@tonic-gate 		break;
22867c478bd9Sstevel@tonic-gate 	case NF3FIFO:
22877c478bd9Sstevel@tonic-gate 		error = sattr3_to_vattr(
22887c478bd9Sstevel@tonic-gate 		    &args->what.mknoddata3_u.pipe_attributes, &va);
22897c478bd9Sstevel@tonic-gate 		if (error)
22907c478bd9Sstevel@tonic-gate 			goto out;
22917c478bd9Sstevel@tonic-gate 		va.va_type = VFIFO;
22927c478bd9Sstevel@tonic-gate 		va.va_mask |= AT_TYPE;
22937c478bd9Sstevel@tonic-gate 		break;
22947c478bd9Sstevel@tonic-gate 	default:
22957c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_BADTYPE;
22967c478bd9Sstevel@tonic-gate 		goto out1;
22977c478bd9Sstevel@tonic-gate 	}
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 	/*
23007c478bd9Sstevel@tonic-gate 	 * Must specify the mode.
23017c478bd9Sstevel@tonic-gate 	 */
23027c478bd9Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
23037c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
23047c478bd9Sstevel@tonic-gate 		goto out1;
23057c478bd9Sstevel@tonic-gate 	}
23067c478bd9Sstevel@tonic-gate 
2307b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2308b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->where.name,
2309b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2310b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2311b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2312b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2313b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
2314b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2315b89a8333Snatalie li - Sun Microsystems - Irvine United States 
23167c478bd9Sstevel@tonic-gate 	excl = EXCL;
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 	mode = 0;
23197c478bd9Sstevel@tonic-gate 
2320b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_CREATE(dvp, name, &va, excl, mode,
2321da6c28aaSamw 	    &vp, cr, 0, NULL, NULL);
23227c478bd9Sstevel@tonic-gate 
2323b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->where.name)
2324b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
2325b89a8333Snatalie li - Sun Microsystems - Irvine United States 
23267c478bd9Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
2327da6c28aaSamw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate 	/*
23307c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
23317c478bd9Sstevel@tonic-gate 	 */
2332da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
23337c478bd9Sstevel@tonic-gate 
23347c478bd9Sstevel@tonic-gate 	if (error)
23357c478bd9Sstevel@tonic-gate 		goto out;
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
23407c478bd9Sstevel@tonic-gate 	if (error)
23417c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
23427c478bd9Sstevel@tonic-gate 	else
23437c478bd9Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2346da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 	/*
23497c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
2350fd7da618Sgt29601 	 *
2351fd7da618Sgt29601 	 * if a underlying vp exists, pass it to VOP_FSYNC
23527c478bd9Sstevel@tonic-gate 	 */
2353fd7da618Sgt29601 	if (VOP_REALVP(vp, &realvp, NULL) == 0)
2354fd7da618Sgt29601 		(void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2355fd7da618Sgt29601 	else
2356da6c28aaSamw 		(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
23597c478bd9Sstevel@tonic-gate 
23607c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
23617c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2362e1adf50cSahl 	DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2363e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2364e1adf50cSahl 	VN_RELE(dvp);
23657c478bd9Sstevel@tonic-gate 	return;
23667c478bd9Sstevel@tonic-gate 
23677c478bd9Sstevel@tonic-gate out:
23687c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
23697c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
23707c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
23717c478bd9Sstevel@tonic-gate 	} else
23727c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
23737c478bd9Sstevel@tonic-gate out1:
2374e1adf50cSahl 	DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2375e1adf50cSahl 	    cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
23767c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
23777c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
23787c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
23797c478bd9Sstevel@tonic-gate }
23807c478bd9Sstevel@tonic-gate 
238127242a7cSthurlow void *
23827c478bd9Sstevel@tonic-gate rfs3_mknod_getfh(MKNOD3args *args)
23837c478bd9Sstevel@tonic-gate {
23847c478bd9Sstevel@tonic-gate 
238527242a7cSthurlow 	return (&args->where.dir);
23867c478bd9Sstevel@tonic-gate }
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate void
23897c478bd9Sstevel@tonic-gate rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
23905cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
23917c478bd9Sstevel@tonic-gate {
23927c478bd9Sstevel@tonic-gate 	int error = 0;
23937c478bd9Sstevel@tonic-gate 	vnode_t *vp;
23947c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
23957c478bd9Sstevel@tonic-gate 	struct vattr bva;
23967c478bd9Sstevel@tonic-gate 	struct vattr *avap;
23977c478bd9Sstevel@tonic-gate 	struct vattr ava;
23987c478bd9Sstevel@tonic-gate 	vnode_t *targvp = NULL;
2399b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2400b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate 	bvap = NULL;
24037c478bd9Sstevel@tonic-gate 	avap = NULL;
24047c478bd9Sstevel@tonic-gate 
240527242a7cSthurlow 	vp = nfs3_fhtovp(&args->object.dir, exi);
2406e1adf50cSahl 
2407e1adf50cSahl 	DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2408e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
2409e1adf50cSahl 
24107c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
24117c478bd9Sstevel@tonic-gate 		error = ESTALE;
2412e1adf50cSahl 		goto err;
24137c478bd9Sstevel@tonic-gate 	}
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
2416da6c28aaSamw 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
24177c478bd9Sstevel@tonic-gate 	avap = bvap;
24187c478bd9Sstevel@tonic-gate 
24197c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
24207c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
2421e1adf50cSahl 		goto err1;
24227c478bd9Sstevel@tonic-gate 	}
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate 	if (args->object.name == nfs3nametoolong) {
24257c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2426e1adf50cSahl 		goto err1;
24277c478bd9Sstevel@tonic-gate 	}
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate 	if (args->object.name == NULL || *(args->object.name) == '\0') {
24307c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2431e1adf50cSahl 		goto err1;
24327c478bd9Sstevel@tonic-gate 	}
24337c478bd9Sstevel@tonic-gate 
24345cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
24357c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2436e1adf50cSahl 		goto err1;
24377c478bd9Sstevel@tonic-gate 	}
24387c478bd9Sstevel@tonic-gate 
243903986916Sjarrett 	if (is_system_labeled()) {
244003986916Sjarrett 		bslabel_t *clabel = req->rq_label;
244103986916Sjarrett 
244203986916Sjarrett 		ASSERT(clabel != NULL);
244303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *,
244403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
244503986916Sjarrett 
244603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2447bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2448bd6f1640SJarrett Lu 			    exi)) {
244903986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2450e1adf50cSahl 				goto err1;
245103986916Sjarrett 			}
245203986916Sjarrett 		}
245303986916Sjarrett 	}
245403986916Sjarrett 
2455b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2456b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->object.name,
2457b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2458b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2459b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2460b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2461b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2462b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2463b89a8333Snatalie li - Sun Microsystems - Irvine United States 
24647c478bd9Sstevel@tonic-gate 	/*
24657c478bd9Sstevel@tonic-gate 	 * Check for a conflict with a non-blocking mandatory share
24667c478bd9Sstevel@tonic-gate 	 * reservation and V4 delegations
24677c478bd9Sstevel@tonic-gate 	 */
2468b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_LOOKUP(vp, name, &targvp, NULL, 0,
2469da6c28aaSamw 	    NULL, cr, NULL, NULL, NULL);
24707c478bd9Sstevel@tonic-gate 	if (error != 0)
2471e1adf50cSahl 		goto err;
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 	if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
24747c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
2475e1adf50cSahl 		goto err1;
24767c478bd9Sstevel@tonic-gate 	}
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 	if (!nbl_need_check(targvp)) {
2479b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = VOP_REMOVE(vp, name, cr, NULL, 0);
24807c478bd9Sstevel@tonic-gate 	} else {
24817c478bd9Sstevel@tonic-gate 		nbl_start_crit(targvp, RW_READER);
2482da6c28aaSamw 		if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
24837c478bd9Sstevel@tonic-gate 			error = EACCES;
24847c478bd9Sstevel@tonic-gate 		} else {
2485b89a8333Snatalie li - Sun Microsystems - Irvine United States 			error = VOP_REMOVE(vp, name, cr, NULL, 0);
24867c478bd9Sstevel@tonic-gate 		}
24877c478bd9Sstevel@tonic-gate 		nbl_end_crit(targvp);
24887c478bd9Sstevel@tonic-gate 	}
24897c478bd9Sstevel@tonic-gate 	VN_RELE(targvp);
24907c478bd9Sstevel@tonic-gate 	targvp = NULL;
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
2493da6c28aaSamw 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
24947c478bd9Sstevel@tonic-gate 
24957c478bd9Sstevel@tonic-gate 	/*
24967c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
24977c478bd9Sstevel@tonic-gate 	 */
2498da6c28aaSamw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate 	if (error)
2501e1adf50cSahl 		goto err;
25027c478bd9Sstevel@tonic-gate 
25037c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
25047c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2505e1adf50cSahl 	goto out;
25067c478bd9Sstevel@tonic-gate 
2507e1adf50cSahl err:
25087c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
25097c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
25107c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
25117c478bd9Sstevel@tonic-gate 	} else
25127c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
2513e1adf50cSahl err1:
2514e1adf50cSahl 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2515e1adf50cSahl out:
2516e1adf50cSahl 	DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
2517e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
2518b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2519b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->object.name)
2520b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
2521b89a8333Snatalie li - Sun Microsystems - Irvine United States 
25227c478bd9Sstevel@tonic-gate 	if (vp != NULL)
25237c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
25247c478bd9Sstevel@tonic-gate }
25257c478bd9Sstevel@tonic-gate 
252627242a7cSthurlow void *
25277c478bd9Sstevel@tonic-gate rfs3_remove_getfh(REMOVE3args *args)
25287c478bd9Sstevel@tonic-gate {
25297c478bd9Sstevel@tonic-gate 
253027242a7cSthurlow 	return (&args->object.dir);
25317c478bd9Sstevel@tonic-gate }
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate void
25347c478bd9Sstevel@tonic-gate rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
25355cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
25367c478bd9Sstevel@tonic-gate {
25377c478bd9Sstevel@tonic-gate 	int error;
25387c478bd9Sstevel@tonic-gate 	vnode_t *vp;
25397c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
25407c478bd9Sstevel@tonic-gate 	struct vattr bva;
25417c478bd9Sstevel@tonic-gate 	struct vattr *avap;
25427c478bd9Sstevel@tonic-gate 	struct vattr ava;
2543b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2544b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
25457c478bd9Sstevel@tonic-gate 
25467c478bd9Sstevel@tonic-gate 	bvap = NULL;
25477c478bd9Sstevel@tonic-gate 	avap = NULL;
25487c478bd9Sstevel@tonic-gate 
254927242a7cSthurlow 	vp = nfs3_fhtovp(&args->object.dir, exi);
2550e1adf50cSahl 
2551e1adf50cSahl 	DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2552e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
2553e1adf50cSahl 
25547c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
25557c478bd9Sstevel@tonic-gate 		error = ESTALE;
2556e1adf50cSahl 		goto err;
25577c478bd9Sstevel@tonic-gate 	}
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
2560da6c28aaSamw 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
25617c478bd9Sstevel@tonic-gate 	avap = bvap;
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
25647c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
2565e1adf50cSahl 		goto err1;
25667c478bd9Sstevel@tonic-gate 	}
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate 	if (args->object.name == nfs3nametoolong) {
25697c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2570e1adf50cSahl 		goto err1;
25717c478bd9Sstevel@tonic-gate 	}
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 	if (args->object.name == NULL || *(args->object.name) == '\0') {
25747c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2575e1adf50cSahl 		goto err1;
25767c478bd9Sstevel@tonic-gate 	}
25777c478bd9Sstevel@tonic-gate 
25785cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
25797c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2580e1adf50cSahl 		goto err1;
25817c478bd9Sstevel@tonic-gate 	}
25827c478bd9Sstevel@tonic-gate 
258303986916Sjarrett 	if (is_system_labeled()) {
258403986916Sjarrett 		bslabel_t *clabel = req->rq_label;
258503986916Sjarrett 
258603986916Sjarrett 		ASSERT(clabel != NULL);
258703986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *,
258803986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
258903986916Sjarrett 
259003986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2591bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2592bd6f1640SJarrett Lu 			    exi)) {
259303986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2594e1adf50cSahl 				goto err1;
259503986916Sjarrett 			}
259603986916Sjarrett 		}
259703986916Sjarrett 	}
259803986916Sjarrett 
2599b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2600b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->object.name,
2601b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2602b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2603b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2604b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2605b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2606b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2607b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2608b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
2609b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2610b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != args->object.name)
2611b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
2614da6c28aaSamw 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	/*
26177c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
26187c478bd9Sstevel@tonic-gate 	 */
2619da6c28aaSamw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
26207c478bd9Sstevel@tonic-gate 
26217c478bd9Sstevel@tonic-gate 	if (error) {
26227c478bd9Sstevel@tonic-gate 		/*
26237c478bd9Sstevel@tonic-gate 		 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
26247c478bd9Sstevel@tonic-gate 		 * if the directory is not empty.  A System V NFS server
26257c478bd9Sstevel@tonic-gate 		 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
26267c478bd9Sstevel@tonic-gate 		 * over the wire.
26277c478bd9Sstevel@tonic-gate 		 */
26287c478bd9Sstevel@tonic-gate 		if (error == EEXIST)
26297c478bd9Sstevel@tonic-gate 			error = ENOTEMPTY;
2630e1adf50cSahl 		goto err;
26317c478bd9Sstevel@tonic-gate 	}
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
26347c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2635e1adf50cSahl 	goto out;
26367c478bd9Sstevel@tonic-gate 
2637e1adf50cSahl err:
26387c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
26397c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
26407c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
26417c478bd9Sstevel@tonic-gate 	} else
26427c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
2643e1adf50cSahl err1:
2644e1adf50cSahl 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2645e1adf50cSahl out:
2646e1adf50cSahl 	DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
2647e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
26487c478bd9Sstevel@tonic-gate 	if (vp != NULL)
26497c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
2650e1adf50cSahl 
26517c478bd9Sstevel@tonic-gate }
26527c478bd9Sstevel@tonic-gate 
265327242a7cSthurlow void *
26547c478bd9Sstevel@tonic-gate rfs3_rmdir_getfh(RMDIR3args *args)
26557c478bd9Sstevel@tonic-gate {
26567c478bd9Sstevel@tonic-gate 
265727242a7cSthurlow 	return (&args->object.dir);
26587c478bd9Sstevel@tonic-gate }
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate void
26617c478bd9Sstevel@tonic-gate rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
26625cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
26637c478bd9Sstevel@tonic-gate {
26647c478bd9Sstevel@tonic-gate 	int error = 0;
26657c478bd9Sstevel@tonic-gate 	vnode_t *fvp;
26667c478bd9Sstevel@tonic-gate 	vnode_t *tvp;
26677c478bd9Sstevel@tonic-gate 	vnode_t *targvp;
26687c478bd9Sstevel@tonic-gate 	struct vattr *fbvap;
26697c478bd9Sstevel@tonic-gate 	struct vattr fbva;
26707c478bd9Sstevel@tonic-gate 	struct vattr *favap;
26717c478bd9Sstevel@tonic-gate 	struct vattr fava;
26727c478bd9Sstevel@tonic-gate 	struct vattr *tbvap;
26737c478bd9Sstevel@tonic-gate 	struct vattr tbva;
26747c478bd9Sstevel@tonic-gate 	struct vattr *tavap;
26757c478bd9Sstevel@tonic-gate 	struct vattr tava;
26767c478bd9Sstevel@tonic-gate 	nfs_fh3 *fh3;
26777c478bd9Sstevel@tonic-gate 	struct exportinfo *to_exi;
26787c478bd9Sstevel@tonic-gate 	vnode_t *srcvp = NULL;
267903986916Sjarrett 	bslabel_t *clabel;
2680b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2681b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
2682b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *toname = NULL;
26837c478bd9Sstevel@tonic-gate 
26847c478bd9Sstevel@tonic-gate 	fbvap = NULL;
26857c478bd9Sstevel@tonic-gate 	favap = NULL;
26867c478bd9Sstevel@tonic-gate 	tbvap = NULL;
26877c478bd9Sstevel@tonic-gate 	tavap = NULL;
26887c478bd9Sstevel@tonic-gate 	tvp = NULL;
26897c478bd9Sstevel@tonic-gate 
269027242a7cSthurlow 	fvp = nfs3_fhtovp(&args->from.dir, exi);
2691e1adf50cSahl 
2692e1adf50cSahl 	DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
2693e1adf50cSahl 	    cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
2694e1adf50cSahl 
26957c478bd9Sstevel@tonic-gate 	if (fvp == NULL) {
26967c478bd9Sstevel@tonic-gate 		error = ESTALE;
2697e1adf50cSahl 		goto err;
26987c478bd9Sstevel@tonic-gate 	}
26997c478bd9Sstevel@tonic-gate 
270003986916Sjarrett 	if (is_system_labeled()) {
270103986916Sjarrett 		clabel = req->rq_label;
270203986916Sjarrett 		ASSERT(clabel != NULL);
270303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
270403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
270503986916Sjarrett 
270603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2707bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2708bd6f1640SJarrett Lu 			    exi)) {
270903986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2710e1adf50cSahl 				goto err1;
271103986916Sjarrett 			}
271203986916Sjarrett 		}
271303986916Sjarrett 	}
271403986916Sjarrett 
27157c478bd9Sstevel@tonic-gate 	fbva.va_mask = AT_ALL;
2716da6c28aaSamw 	fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
27177c478bd9Sstevel@tonic-gate 	favap = fbvap;
27187c478bd9Sstevel@tonic-gate 
271927242a7cSthurlow 	fh3 = &args->to.dir;
2720*fbd2e8e1SArne Jansen 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3), NULL);
27217c478bd9Sstevel@tonic-gate 	if (to_exi == NULL) {
27227c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2723e1adf50cSahl 		goto err1;
27247c478bd9Sstevel@tonic-gate 	}
27257c478bd9Sstevel@tonic-gate 	exi_rele(to_exi);
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 	if (to_exi != exi) {
27287c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_XDEV;
2729e1adf50cSahl 		goto err1;
27307c478bd9Sstevel@tonic-gate 	}
27317c478bd9Sstevel@tonic-gate 
273227242a7cSthurlow 	tvp = nfs3_fhtovp(&args->to.dir, exi);
27337c478bd9Sstevel@tonic-gate 	if (tvp == NULL) {
27347c478bd9Sstevel@tonic-gate 		error = ESTALE;
2735e1adf50cSahl 		goto err;
27367c478bd9Sstevel@tonic-gate 	}
27377c478bd9Sstevel@tonic-gate 
27387c478bd9Sstevel@tonic-gate 	tbva.va_mask = AT_ALL;
2739da6c28aaSamw 	tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
27407c478bd9Sstevel@tonic-gate 	tavap = tbvap;
27417c478bd9Sstevel@tonic-gate 
27427c478bd9Sstevel@tonic-gate 	if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
27437c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
2744e1adf50cSahl 		goto err1;
27457c478bd9Sstevel@tonic-gate 	}
27467c478bd9Sstevel@tonic-gate 
27477c478bd9Sstevel@tonic-gate 	if (args->from.name == nfs3nametoolong ||
27487c478bd9Sstevel@tonic-gate 	    args->to.name == nfs3nametoolong) {
27497c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
2750e1adf50cSahl 		goto err1;
27517c478bd9Sstevel@tonic-gate 	}
27527c478bd9Sstevel@tonic-gate 	if (args->from.name == NULL || *(args->from.name) == '\0' ||
27537c478bd9Sstevel@tonic-gate 	    args->to.name == NULL || *(args->to.name) == '\0') {
27547c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
2755e1adf50cSahl 		goto err1;
27567c478bd9Sstevel@tonic-gate 	}
27577c478bd9Sstevel@tonic-gate 
27585cb0d679SMarcel Telka 	if (rdonly(ro, tvp)) {
27597c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2760e1adf50cSahl 		goto err1;
27617c478bd9Sstevel@tonic-gate 	}
27627c478bd9Sstevel@tonic-gate 
276303986916Sjarrett 	if (is_system_labeled()) {
276403986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2765bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2766bd6f1640SJarrett Lu 			    exi)) {
276703986916Sjarrett 				resp->status = NFS3ERR_ACCES;
2768e1adf50cSahl 				goto err1;
276903986916Sjarrett 			}
277003986916Sjarrett 		}
277103986916Sjarrett 	}
277203986916Sjarrett 
2773b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2774b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->from.name,
2775b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2776b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2777b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
2778b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2779b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2780b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2781b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2782b89a8333Snatalie li - Sun Microsystems - Irvine United States 	toname = nfscmd_convname(ca, exi, args->to.name,
2783b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2784b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2785b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (toname == NULL) {
2786b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_INVAL;
2787b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto err1;
2788b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2789b89a8333Snatalie li - Sun Microsystems - Irvine United States 
27907c478bd9Sstevel@tonic-gate 	/*
27917c478bd9Sstevel@tonic-gate 	 * Check for a conflict with a non-blocking mandatory share
27927c478bd9Sstevel@tonic-gate 	 * reservation or V4 delegations.
27937c478bd9Sstevel@tonic-gate 	 */
2794b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2795da6c28aaSamw 	    NULL, cr, NULL, NULL, NULL);
27967c478bd9Sstevel@tonic-gate 	if (error != 0)
2797e1adf50cSahl 		goto err;
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate 	/*
28007c478bd9Sstevel@tonic-gate 	 * If we rename a delegated file we should recall the
28017c478bd9Sstevel@tonic-gate 	 * delegation, since future opens should fail or would
28027c478bd9Sstevel@tonic-gate 	 * refer to a new file.
28037c478bd9Sstevel@tonic-gate 	 */
28047c478bd9Sstevel@tonic-gate 	if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
28057c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
2806e1adf50cSahl 		goto err1;
28077c478bd9Sstevel@tonic-gate 	}
28087c478bd9Sstevel@tonic-gate 
28097c478bd9Sstevel@tonic-gate 	/*
28107c478bd9Sstevel@tonic-gate 	 * Check for renaming over a delegated file.  Check rfs4_deleg_policy
28117c478bd9Sstevel@tonic-gate 	 * first to avoid VOP_LOOKUP if possible.
28127c478bd9Sstevel@tonic-gate 	 */
28137c478bd9Sstevel@tonic-gate 	if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
2814b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2815da6c28aaSamw 	    NULL, NULL, NULL) == 0) {
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 		if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
28187c478bd9Sstevel@tonic-gate 			VN_RELE(targvp);
28197c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
2820e1adf50cSahl 			goto err1;
28217c478bd9Sstevel@tonic-gate 		}
28227c478bd9Sstevel@tonic-gate 		VN_RELE(targvp);
28237c478bd9Sstevel@tonic-gate 	}
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate 	if (!nbl_need_check(srcvp)) {
2826b89a8333Snatalie li - Sun Microsystems - Irvine United States 		error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
28277c478bd9Sstevel@tonic-gate 	} else {
28287c478bd9Sstevel@tonic-gate 		nbl_start_crit(srcvp, RW_READER);
2829b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
28307c478bd9Sstevel@tonic-gate 			error = EACCES;
2831b89a8333Snatalie li - Sun Microsystems - Irvine United States 		else
2832b89a8333Snatalie li - Sun Microsystems - Irvine United States 			error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
28337c478bd9Sstevel@tonic-gate 		nbl_end_crit(srcvp);
28347c478bd9Sstevel@tonic-gate 	}
283551ece835Seschrock 	if (error == 0)
283651ece835Seschrock 		vn_renamepath(tvp, srcvp, args->to.name,
2837c9264041Sjwahlig 		    strlen(args->to.name));
28387c478bd9Sstevel@tonic-gate 	VN_RELE(srcvp);
28397c478bd9Sstevel@tonic-gate 	srcvp = NULL;
28407c478bd9Sstevel@tonic-gate 
28417c478bd9Sstevel@tonic-gate 	fava.va_mask = AT_ALL;
2842da6c28aaSamw 	favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
28437c478bd9Sstevel@tonic-gate 	tava.va_mask = AT_ALL;
2844da6c28aaSamw 	tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 	/*
28477c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
28487c478bd9Sstevel@tonic-gate 	 */
2849da6c28aaSamw 	(void) VOP_FSYNC(fvp, 0, cr, NULL);
2850da6c28aaSamw 	(void) VOP_FSYNC(tvp, 0, cr, NULL);
28517c478bd9Sstevel@tonic-gate 
28527c478bd9Sstevel@tonic-gate 	if (error)
2853e1adf50cSahl 		goto err;
28547c478bd9Sstevel@tonic-gate 
28557c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
28567c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
28577c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2858e1adf50cSahl 	goto out;
28597c478bd9Sstevel@tonic-gate 
2860e1adf50cSahl err:
28617c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
28627c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
28637c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
2864b89a8333Snatalie li - Sun Microsystems - Irvine United States 	} else {
28657c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
2866b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2867e1adf50cSahl err1:
2868e1adf50cSahl 	vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2869e1adf50cSahl 	vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2870b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2871e1adf50cSahl out:
2872b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->from.name)
2873b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
2874b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (toname != NULL && toname != args->to.name)
2875b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(toname, MAXPATHLEN + 1);
2876b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2877e1adf50cSahl 	DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
2878e1adf50cSahl 	    cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
28797c478bd9Sstevel@tonic-gate 	if (fvp != NULL)
28807c478bd9Sstevel@tonic-gate 		VN_RELE(fvp);
28817c478bd9Sstevel@tonic-gate 	if (tvp != NULL)
28827c478bd9Sstevel@tonic-gate 		VN_RELE(tvp);
28837c478bd9Sstevel@tonic-gate }
28847c478bd9Sstevel@tonic-gate 
288527242a7cSthurlow void *
28867c478bd9Sstevel@tonic-gate rfs3_rename_getfh(RENAME3args *args)
28877c478bd9Sstevel@tonic-gate {
28887c478bd9Sstevel@tonic-gate 
288927242a7cSthurlow 	return (&args->from.dir);
28907c478bd9Sstevel@tonic-gate }
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate void
28937c478bd9Sstevel@tonic-gate rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
28945cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
28957c478bd9Sstevel@tonic-gate {
28967c478bd9Sstevel@tonic-gate 	int error;
28977c478bd9Sstevel@tonic-gate 	vnode_t *vp;
28987c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
28997c478bd9Sstevel@tonic-gate 	struct vattr *vap;
29007c478bd9Sstevel@tonic-gate 	struct vattr va;
29017c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
29027c478bd9Sstevel@tonic-gate 	struct vattr bva;
29037c478bd9Sstevel@tonic-gate 	struct vattr *avap;
29047c478bd9Sstevel@tonic-gate 	struct vattr ava;
29057c478bd9Sstevel@tonic-gate 	nfs_fh3	*fh3;
29067c478bd9Sstevel@tonic-gate 	struct exportinfo *to_exi;
290703986916Sjarrett 	bslabel_t *clabel;
2908b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
2909b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name = NULL;
29107c478bd9Sstevel@tonic-gate 
29117c478bd9Sstevel@tonic-gate 	vap = NULL;
29127c478bd9Sstevel@tonic-gate 	bvap = NULL;
29137c478bd9Sstevel@tonic-gate 	avap = NULL;
29147c478bd9Sstevel@tonic-gate 	dvp = NULL;
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
2917e1adf50cSahl 
2918e1adf50cSahl 	DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
2919e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, LINK3args *, args);
2920e1adf50cSahl 
29217c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
29227c478bd9Sstevel@tonic-gate 		error = ESTALE;
29237c478bd9Sstevel@tonic-gate 		goto out;
29247c478bd9Sstevel@tonic-gate 	}
29257c478bd9Sstevel@tonic-gate 
29267c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2927da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
29287c478bd9Sstevel@tonic-gate 
292927242a7cSthurlow 	fh3 = &args->link.dir;
2930*fbd2e8e1SArne Jansen 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3), NULL);
29317c478bd9Sstevel@tonic-gate 	if (to_exi == NULL) {
29327c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
29337c478bd9Sstevel@tonic-gate 		goto out1;
29347c478bd9Sstevel@tonic-gate 	}
29357c478bd9Sstevel@tonic-gate 	exi_rele(to_exi);
29367c478bd9Sstevel@tonic-gate 
29377c478bd9Sstevel@tonic-gate 	if (to_exi != exi) {
29387c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_XDEV;
29397c478bd9Sstevel@tonic-gate 		goto out1;
29407c478bd9Sstevel@tonic-gate 	}
29417c478bd9Sstevel@tonic-gate 
294203986916Sjarrett 	if (is_system_labeled()) {
294303986916Sjarrett 		clabel = req->rq_label;
294403986916Sjarrett 
294503986916Sjarrett 		ASSERT(clabel != NULL);
294603986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
294703986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
294803986916Sjarrett 
294903986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2950bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
2951bd6f1640SJarrett Lu 			    exi)) {
295203986916Sjarrett 				resp->status = NFS3ERR_ACCES;
295303986916Sjarrett 				goto out1;
295403986916Sjarrett 			}
295503986916Sjarrett 		}
295603986916Sjarrett 	}
295703986916Sjarrett 
295827242a7cSthurlow 	dvp = nfs3_fhtovp(&args->link.dir, exi);
29597c478bd9Sstevel@tonic-gate 	if (dvp == NULL) {
29607c478bd9Sstevel@tonic-gate 		error = ESTALE;
29617c478bd9Sstevel@tonic-gate 		goto out;
29627c478bd9Sstevel@tonic-gate 	}
29637c478bd9Sstevel@tonic-gate 
29647c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
2965da6c28aaSamw 	bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
29667c478bd9Sstevel@tonic-gate 
29677c478bd9Sstevel@tonic-gate 	if (dvp->v_type != VDIR) {
29687c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
29697c478bd9Sstevel@tonic-gate 		goto out1;
29707c478bd9Sstevel@tonic-gate 	}
29717c478bd9Sstevel@tonic-gate 
29727c478bd9Sstevel@tonic-gate 	if (args->link.name == nfs3nametoolong) {
29737c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
29747c478bd9Sstevel@tonic-gate 		goto out1;
29757c478bd9Sstevel@tonic-gate 	}
29767c478bd9Sstevel@tonic-gate 
29777c478bd9Sstevel@tonic-gate 	if (args->link.name == NULL || *(args->link.name) == '\0') {
29787c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
29797c478bd9Sstevel@tonic-gate 		goto out1;
29807c478bd9Sstevel@tonic-gate 	}
29817c478bd9Sstevel@tonic-gate 
29825cb0d679SMarcel Telka 	if (rdonly(ro, dvp)) {
29837c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
29847c478bd9Sstevel@tonic-gate 		goto out1;
29857c478bd9Sstevel@tonic-gate 	}
29867c478bd9Sstevel@tonic-gate 
298703986916Sjarrett 	if (is_system_labeled()) {
298803986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
298903986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
299003986916Sjarrett 
299103986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
2992bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2993bd6f1640SJarrett Lu 			    exi)) {
299403986916Sjarrett 				resp->status = NFS3ERR_ACCES;
299503986916Sjarrett 				goto out1;
299603986916Sjarrett 			}
299703986916Sjarrett 		}
299803986916Sjarrett 	}
299903986916Sjarrett 
3000b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3001b89a8333Snatalie li - Sun Microsystems - Irvine United States 	name = nfscmd_convname(ca, exi, args->link.name,
3002b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3003b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3004b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name == NULL) {
3005b89a8333Snatalie li - Sun Microsystems - Irvine United States 		resp->status = NFS3ERR_SERVERFAULT;
3006b89a8333Snatalie li - Sun Microsystems - Irvine United States 		goto out1;
3007b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
3008b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3009b89a8333Snatalie li - Sun Microsystems - Irvine United States 	error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3012da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
30137c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
3014da6c28aaSamw 	avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
30157c478bd9Sstevel@tonic-gate 
30167c478bd9Sstevel@tonic-gate 	/*
30177c478bd9Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
30187c478bd9Sstevel@tonic-gate 	 */
3019da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3020da6c28aaSamw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
30217c478bd9Sstevel@tonic-gate 
30227c478bd9Sstevel@tonic-gate 	if (error)
30237c478bd9Sstevel@tonic-gate 		goto out;
30247c478bd9Sstevel@tonic-gate 
30257c478bd9Sstevel@tonic-gate 	VN_RELE(dvp);
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
30287c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
30297c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3030e1adf50cSahl 
3031e1adf50cSahl 	DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3032e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3033e1adf50cSahl 
3034e1adf50cSahl 	VN_RELE(vp);
3035e1adf50cSahl 
30367c478bd9Sstevel@tonic-gate 	return;
30377c478bd9Sstevel@tonic-gate 
30387c478bd9Sstevel@tonic-gate out:
30397c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
30407c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
30417c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
30427c478bd9Sstevel@tonic-gate 	} else
30437c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
30447c478bd9Sstevel@tonic-gate out1:
3045b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (name != NULL && name != args->link.name)
3046b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(name, MAXPATHLEN + 1);
3047b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3048e1adf50cSahl 	DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3049e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3050e1adf50cSahl 
30517c478bd9Sstevel@tonic-gate 	if (vp != NULL)
30527c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
30537c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
30547c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
30557c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
30567c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
30577c478bd9Sstevel@tonic-gate }
30587c478bd9Sstevel@tonic-gate 
305927242a7cSthurlow void *
30607c478bd9Sstevel@tonic-gate rfs3_link_getfh(LINK3args *args)
30617c478bd9Sstevel@tonic-gate {
30627c478bd9Sstevel@tonic-gate 
306327242a7cSthurlow 	return (&args->file);
30647c478bd9Sstevel@tonic-gate }
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate /*
30677c478bd9Sstevel@tonic-gate  * This macro defines the size of a response which contains attribute
30687c478bd9Sstevel@tonic-gate  * information and one directory entry (whose length is specified by
30697c478bd9Sstevel@tonic-gate  * the macro parameter).  If the incoming request is larger than this,
30707c478bd9Sstevel@tonic-gate  * then we are guaranteed to be able to return at one directory entry
30717c478bd9Sstevel@tonic-gate  * if one exists.  Therefore, we do not need to check for
30727c478bd9Sstevel@tonic-gate  * NFS3ERR_TOOSMALL if the requested size is larger then this.  If it
30737c478bd9Sstevel@tonic-gate  * is not, then we need to check to make sure that this error does not
30747c478bd9Sstevel@tonic-gate  * need to be returned.
30757c478bd9Sstevel@tonic-gate  *
30767c478bd9Sstevel@tonic-gate  * NFS3_READDIR_MIN_COUNT is comprised of following :
30777c478bd9Sstevel@tonic-gate  *
30787c478bd9Sstevel@tonic-gate  * status - 1 * BYTES_PER_XDR_UNIT
30797c478bd9Sstevel@tonic-gate  * attr. flag - 1 * BYTES_PER_XDR_UNIT
30807c478bd9Sstevel@tonic-gate  * cookie verifier - 2 * BYTES_PER_XDR_UNIT
30817c478bd9Sstevel@tonic-gate  * attributes  - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
30827c478bd9Sstevel@tonic-gate  * boolean - 1 * BYTES_PER_XDR_UNIT
30837c478bd9Sstevel@tonic-gate  * file id - 2 * BYTES_PER_XDR_UNIT
3084da6c28aaSamw  * directory name length - 1 * BYTES_PER_XDR_UNIT
30857c478bd9Sstevel@tonic-gate  * cookie - 2 * BYTES_PER_XDR_UNIT
30867c478bd9Sstevel@tonic-gate  * end of list - 1 * BYTES_PER_XDR_UNIT
30877c478bd9Sstevel@tonic-gate  * end of file - 1 * BYTES_PER_XDR_UNIT
30887c478bd9Sstevel@tonic-gate  * Name length of directory to the nearest byte
30897c478bd9Sstevel@tonic-gate  */
30907c478bd9Sstevel@tonic-gate 
30917c478bd9Sstevel@tonic-gate #define	NFS3_READDIR_MIN_COUNT(length)	\
30927c478bd9Sstevel@tonic-gate 	((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
30937c478bd9Sstevel@tonic-gate 		BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
30947c478bd9Sstevel@tonic-gate 
30957c478bd9Sstevel@tonic-gate /* ARGSUSED */
30967c478bd9Sstevel@tonic-gate void
30977c478bd9Sstevel@tonic-gate rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
30985cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
30997c478bd9Sstevel@tonic-gate {
31007c478bd9Sstevel@tonic-gate 	int error;
31017c478bd9Sstevel@tonic-gate 	vnode_t *vp;
31027c478bd9Sstevel@tonic-gate 	struct vattr *vap;
31037c478bd9Sstevel@tonic-gate 	struct vattr va;
31047c478bd9Sstevel@tonic-gate 	struct iovec iov;
31057c478bd9Sstevel@tonic-gate 	struct uio uio;
31067c478bd9Sstevel@tonic-gate 	char *data;
31077c478bd9Sstevel@tonic-gate 	int iseof;
31087c478bd9Sstevel@tonic-gate 	int bufsize;
31097c478bd9Sstevel@tonic-gate 	int namlen;
31107c478bd9Sstevel@tonic-gate 	uint_t count;
3111b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
31127c478bd9Sstevel@tonic-gate 
31137c478bd9Sstevel@tonic-gate 	vap = NULL;
31147c478bd9Sstevel@tonic-gate 
31157c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->dir, exi);
3116e1adf50cSahl 
3117e1adf50cSahl 	DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
3118e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
3119e1adf50cSahl 
31207c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
31217c478bd9Sstevel@tonic-gate 		error = ESTALE;
31227c478bd9Sstevel@tonic-gate 		goto out;
31237c478bd9Sstevel@tonic-gate 	}
31247c478bd9Sstevel@tonic-gate 
312503986916Sjarrett 	if (is_system_labeled()) {
312603986916Sjarrett 		bslabel_t *clabel = req->rq_label;
312703986916Sjarrett 
312803986916Sjarrett 		ASSERT(clabel != NULL);
312903986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
313003986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
313103986916Sjarrett 
313203986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3133bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3134bd6f1640SJarrett Lu 			    exi)) {
313503986916Sjarrett 				resp->status = NFS3ERR_ACCES;
313603986916Sjarrett 				goto out1;
313703986916Sjarrett 			}
313803986916Sjarrett 		}
313903986916Sjarrett 	}
314003986916Sjarrett 
31417c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3144da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
31457c478bd9Sstevel@tonic-gate 
31467c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
31477c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
31487c478bd9Sstevel@tonic-gate 		goto out1;
31497c478bd9Sstevel@tonic-gate 	}
31507c478bd9Sstevel@tonic-gate 
3151da6c28aaSamw 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
31527c478bd9Sstevel@tonic-gate 	if (error)
31537c478bd9Sstevel@tonic-gate 		goto out;
31547c478bd9Sstevel@tonic-gate 
31557c478bd9Sstevel@tonic-gate 	/*
31567c478bd9Sstevel@tonic-gate 	 * Now don't allow arbitrary count to alloc;
31577c478bd9Sstevel@tonic-gate 	 * allow the maximum not to exceed rfs3_tsize()
31587c478bd9Sstevel@tonic-gate 	 */
31597c478bd9Sstevel@tonic-gate 	if (args->count > rfs3_tsize(req))
31607c478bd9Sstevel@tonic-gate 		args->count = rfs3_tsize(req);
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate 	/*
31637c478bd9Sstevel@tonic-gate 	 * Make sure that there is room to read at least one entry
31647c478bd9Sstevel@tonic-gate 	 * if any are available.
31657c478bd9Sstevel@tonic-gate 	 */
31667c478bd9Sstevel@tonic-gate 	if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
31677c478bd9Sstevel@tonic-gate 		count = DIRENT64_RECLEN(MAXNAMELEN);
31687c478bd9Sstevel@tonic-gate 	else
31697c478bd9Sstevel@tonic-gate 		count = args->count;
31707c478bd9Sstevel@tonic-gate 
31717c478bd9Sstevel@tonic-gate 	data = kmem_alloc(count, KM_SLEEP);
31727c478bd9Sstevel@tonic-gate 
31737c478bd9Sstevel@tonic-gate 	iov.iov_base = data;
31747c478bd9Sstevel@tonic-gate 	iov.iov_len = count;
31757c478bd9Sstevel@tonic-gate 	uio.uio_iov = &iov;
31767c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
31777c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
31787c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
31797c478bd9Sstevel@tonic-gate 	uio.uio_loffset = (offset_t)args->cookie;
31807c478bd9Sstevel@tonic-gate 	uio.uio_resid = count;
31817c478bd9Sstevel@tonic-gate 
3182da6c28aaSamw 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
31837c478bd9Sstevel@tonic-gate 
31847c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3185da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
31867c478bd9Sstevel@tonic-gate 
31877c478bd9Sstevel@tonic-gate 	if (error) {
31887c478bd9Sstevel@tonic-gate 		kmem_free(data, count);
31897c478bd9Sstevel@tonic-gate 		goto out;
31907c478bd9Sstevel@tonic-gate 	}
31917c478bd9Sstevel@tonic-gate 
31927c478bd9Sstevel@tonic-gate 	/*
31937c478bd9Sstevel@tonic-gate 	 * If the count was not large enough to be able to guarantee
31947c478bd9Sstevel@tonic-gate 	 * to be able to return at least one entry, then need to
31957c478bd9Sstevel@tonic-gate 	 * check to see if NFS3ERR_TOOSMALL should be returned.
31967c478bd9Sstevel@tonic-gate 	 */
31977c478bd9Sstevel@tonic-gate 	if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
31987c478bd9Sstevel@tonic-gate 		/*
31997c478bd9Sstevel@tonic-gate 		 * bufsize is used to keep track of the size of the response.
32007c478bd9Sstevel@tonic-gate 		 * It is primed with:
32017c478bd9Sstevel@tonic-gate 		 *	1 for the status +
32027c478bd9Sstevel@tonic-gate 		 *	1 for the dir_attributes.attributes boolean +
32037c478bd9Sstevel@tonic-gate 		 *	2 for the cookie verifier
32047c478bd9Sstevel@tonic-gate 		 * all times BYTES_PER_XDR_UNIT to convert from XDR units
32057c478bd9Sstevel@tonic-gate 		 * to bytes.  If there are directory attributes to be
32067c478bd9Sstevel@tonic-gate 		 * returned, then:
32077c478bd9Sstevel@tonic-gate 		 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
32087c478bd9Sstevel@tonic-gate 		 * time BYTES_PER_XDR_UNIT is added to account for them.
32097c478bd9Sstevel@tonic-gate 		 */
32107c478bd9Sstevel@tonic-gate 		bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
32117c478bd9Sstevel@tonic-gate 		if (vap != NULL)
32127c478bd9Sstevel@tonic-gate 			bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
32137c478bd9Sstevel@tonic-gate 		/*
32147c478bd9Sstevel@tonic-gate 		 * An entry is composed of:
32157c478bd9Sstevel@tonic-gate 		 *	1 for the true/false list indicator +
32167c478bd9Sstevel@tonic-gate 		 *	2 for the fileid +
32177c478bd9Sstevel@tonic-gate 		 *	1 for the length of the name +
32187c478bd9Sstevel@tonic-gate 		 *	2 for the cookie +
32197c478bd9Sstevel@tonic-gate 		 * all times BYTES_PER_XDR_UNIT to convert from
32207c478bd9Sstevel@tonic-gate 		 * XDR units to bytes, plus the length of the name
32217c478bd9Sstevel@tonic-gate 		 * rounded up to the nearest BYTES_PER_XDR_UNIT.
32227c478bd9Sstevel@tonic-gate 		 */
32237c478bd9Sstevel@tonic-gate 		if (count != uio.uio_resid) {
32247c478bd9Sstevel@tonic-gate 			namlen = strlen(((struct dirent64 *)data)->d_name);
32257c478bd9Sstevel@tonic-gate 			bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
32267c478bd9Sstevel@tonic-gate 			    roundup(namlen, BYTES_PER_XDR_UNIT);
32277c478bd9Sstevel@tonic-gate 		}
32287c478bd9Sstevel@tonic-gate 		/*
32297c478bd9Sstevel@tonic-gate 		 * We need to check to see if the number of bytes left
32307c478bd9Sstevel@tonic-gate 		 * to go into the buffer will actually fit into the
32317c478bd9Sstevel@tonic-gate 		 * buffer.  This is calculated as the size of this
32327c478bd9Sstevel@tonic-gate 		 * entry plus:
32337c478bd9Sstevel@tonic-gate 		 *	1 for the true/false list indicator +
32347c478bd9Sstevel@tonic-gate 		 *	1 for the eof indicator
32357c478bd9Sstevel@tonic-gate 		 * times BYTES_PER_XDR_UNIT to convert from from
32367c478bd9Sstevel@tonic-gate 		 * XDR units to bytes.
32377c478bd9Sstevel@tonic-gate 		 */
32387c478bd9Sstevel@tonic-gate 		bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
32397c478bd9Sstevel@tonic-gate 		if (bufsize > args->count) {
32407c478bd9Sstevel@tonic-gate 			kmem_free(data, count);
32417c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_TOOSMALL;
32427c478bd9Sstevel@tonic-gate 			goto out1;
32437c478bd9Sstevel@tonic-gate 		}
32447c478bd9Sstevel@tonic-gate 	}
32457c478bd9Sstevel@tonic-gate 
3246b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*
3247b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * Have a valid readir buffer for the native character
3248b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * set. Need to check if a conversion is necessary and
3249b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * potentially rewrite the whole buffer. Note that if the
3250b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * conversion expands names enough, the structure may not
3251b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * fit. In this case, we need to drop entries until if fits
3252b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * and patch the counts in order that the next readdir will
3253b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * get the correct entries.
3254b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 */
3255b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3256b89a8333Snatalie li - Sun Microsystems - Irvine United States 	data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
3257b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3258b89a8333Snatalie li - Sun Microsystems - Irvine United States 
32597c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
32607c478bd9Sstevel@tonic-gate 
32617c478bd9Sstevel@tonic-gate #if 0 /* notyet */
32627c478bd9Sstevel@tonic-gate 	/*
32637c478bd9Sstevel@tonic-gate 	 * Don't do this.  It causes local disk writes when just
32647c478bd9Sstevel@tonic-gate 	 * reading the file and the overhead is deemed larger
32657c478bd9Sstevel@tonic-gate 	 * than the benefit.
32667c478bd9Sstevel@tonic-gate 	 */
32677c478bd9Sstevel@tonic-gate 	/*
32687c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
32697c478bd9Sstevel@tonic-gate 	 */
3270da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
32717c478bd9Sstevel@tonic-gate #endif
32727c478bd9Sstevel@tonic-gate 
32737c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
32747c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
32757c478bd9Sstevel@tonic-gate 	resp->resok.cookieverf = 0;
32767c478bd9Sstevel@tonic-gate 	resp->resok.reply.entries = (entry3 *)data;
32777c478bd9Sstevel@tonic-gate 	resp->resok.reply.eof = iseof;
32787c478bd9Sstevel@tonic-gate 	resp->resok.size = count - uio.uio_resid;
32797c478bd9Sstevel@tonic-gate 	resp->resok.count = args->count;
32807c478bd9Sstevel@tonic-gate 	resp->resok.freecount = count;
3281e1adf50cSahl 
3282e1adf50cSahl 	DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3283e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3284e1adf50cSahl 
3285e1adf50cSahl 	VN_RELE(vp);
3286e1adf50cSahl 
32877c478bd9Sstevel@tonic-gate 	return;
32887c478bd9Sstevel@tonic-gate 
32897c478bd9Sstevel@tonic-gate out:
32907c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
32917c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
32927c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
32937c478bd9Sstevel@tonic-gate 	} else
32947c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
32957c478bd9Sstevel@tonic-gate out1:
3296e1adf50cSahl 	DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3297e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3298e1adf50cSahl 
32997c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
33007c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
33017c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
33027c478bd9Sstevel@tonic-gate 	}
33037c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
33047c478bd9Sstevel@tonic-gate }
33057c478bd9Sstevel@tonic-gate 
330627242a7cSthurlow void *
33077c478bd9Sstevel@tonic-gate rfs3_readdir_getfh(READDIR3args *args)
33087c478bd9Sstevel@tonic-gate {
33097c478bd9Sstevel@tonic-gate 
331027242a7cSthurlow 	return (&args->dir);
33117c478bd9Sstevel@tonic-gate }
33127c478bd9Sstevel@tonic-gate 
33137c478bd9Sstevel@tonic-gate void
33147c478bd9Sstevel@tonic-gate rfs3_readdir_free(READDIR3res *resp)
33157c478bd9Sstevel@tonic-gate {
33167c478bd9Sstevel@tonic-gate 
33177c478bd9Sstevel@tonic-gate 	if (resp->status == NFS3_OK)
33187c478bd9Sstevel@tonic-gate 		kmem_free(resp->resok.reply.entries, resp->resok.freecount);
33197c478bd9Sstevel@tonic-gate }
33207c478bd9Sstevel@tonic-gate 
33217c478bd9Sstevel@tonic-gate #ifdef nextdp
33227c478bd9Sstevel@tonic-gate #undef nextdp
33237c478bd9Sstevel@tonic-gate #endif
33247c478bd9Sstevel@tonic-gate #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
33257c478bd9Sstevel@tonic-gate 
33267c478bd9Sstevel@tonic-gate /*
33277c478bd9Sstevel@tonic-gate  * This macro computes the size of a response which contains
33287c478bd9Sstevel@tonic-gate  * one directory entry including the attributes as well as file handle.
33297c478bd9Sstevel@tonic-gate  * If the incoming request is larger than this, then we are guaranteed to be
33307c478bd9Sstevel@tonic-gate  * able to return at least one more directory entry if one exists.
33317c478bd9Sstevel@tonic-gate  *
33327c478bd9Sstevel@tonic-gate  * NFS3_READDIRPLUS_ENTRY is made up of the following:
33337c478bd9Sstevel@tonic-gate  *
33347c478bd9Sstevel@tonic-gate  * boolean - 1 * BYTES_PER_XDR_UNIT
33357c478bd9Sstevel@tonic-gate  * file id - 2 * BYTES_PER_XDR_UNIT
33367c478bd9Sstevel@tonic-gate  * directory name length - 1 * BYTES_PER_XDR_UNIT
33377c478bd9Sstevel@tonic-gate  * cookie - 2 * BYTES_PER_XDR_UNIT
33387c478bd9Sstevel@tonic-gate  * attribute flag - 1 * BYTES_PER_XDR_UNIT
33397c478bd9Sstevel@tonic-gate  * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
33407c478bd9Sstevel@tonic-gate  * status byte for file handle - 1 *  BYTES_PER_XDR_UNIT
33417c478bd9Sstevel@tonic-gate  * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3342da6c28aaSamw  * Maximum length of a file handle (NFS3_MAXFHSIZE)
33437c478bd9Sstevel@tonic-gate  * name length of the entry to the nearest bytes
33447c478bd9Sstevel@tonic-gate  */
33457c478bd9Sstevel@tonic-gate #define	NFS3_READDIRPLUS_ENTRY(namelen)	\
33467c478bd9Sstevel@tonic-gate 	((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
33477c478bd9Sstevel@tonic-gate 		BYTES_PER_XDR_UNIT + \
334827242a7cSthurlow 	NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
33497c478bd9Sstevel@tonic-gate 
33507c478bd9Sstevel@tonic-gate static int rfs3_readdir_unit = MAXBSIZE;
33517c478bd9Sstevel@tonic-gate 
33527c478bd9Sstevel@tonic-gate /* ARGSUSED */
33537c478bd9Sstevel@tonic-gate void
33547c478bd9Sstevel@tonic-gate rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
33555cb0d679SMarcel Telka     struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
33567c478bd9Sstevel@tonic-gate {
33577c478bd9Sstevel@tonic-gate 	int error;
33587c478bd9Sstevel@tonic-gate 	vnode_t *vp;
33597c478bd9Sstevel@tonic-gate 	struct vattr *vap;
33607c478bd9Sstevel@tonic-gate 	struct vattr va;
33617c478bd9Sstevel@tonic-gate 	struct iovec iov;
33627c478bd9Sstevel@tonic-gate 	struct uio uio;
33637c478bd9Sstevel@tonic-gate 	char *data;
33647c478bd9Sstevel@tonic-gate 	int iseof;
33657c478bd9Sstevel@tonic-gate 	struct dirent64 *dp;
33667c478bd9Sstevel@tonic-gate 	vnode_t *nvp;
33677c478bd9Sstevel@tonic-gate 	struct vattr *nvap;
33687c478bd9Sstevel@tonic-gate 	struct vattr nva;
33697c478bd9Sstevel@tonic-gate 	entryplus3_info *infop = NULL;
33707c478bd9Sstevel@tonic-gate 	int size = 0;
33717c478bd9Sstevel@tonic-gate 	int nents = 0;
33727c478bd9Sstevel@tonic-gate 	int bufsize = 0;
33737c478bd9Sstevel@tonic-gate 	int entrysize = 0;
33747c478bd9Sstevel@tonic-gate 	int tofit = 0;
33757c478bd9Sstevel@tonic-gate 	int rd_unit = rfs3_readdir_unit;
33767c478bd9Sstevel@tonic-gate 	int prev_len;
33777c478bd9Sstevel@tonic-gate 	int space_left;
33787c478bd9Sstevel@tonic-gate 	int i;
33797c478bd9Sstevel@tonic-gate 	uint_t *namlen = NULL;
3380b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *ndata = NULL;
3381b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct sockaddr *ca;
3382b89a8333Snatalie li - Sun Microsystems - Irvine United States 	size_t ret;
33837c478bd9Sstevel@tonic-gate 
33847c478bd9Sstevel@tonic-gate 	vap = NULL;
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->dir, exi);
3387e1adf50cSahl 
3388e1adf50cSahl 	DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
3389e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
3390e1adf50cSahl 
33917c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
33927c478bd9Sstevel@tonic-gate 		error = ESTALE;
33937c478bd9Sstevel@tonic-gate 		goto out;
33947c478bd9Sstevel@tonic-gate 	}
33957c478bd9Sstevel@tonic-gate 
339603986916Sjarrett 	if (is_system_labeled()) {
339703986916Sjarrett 		bslabel_t *clabel = req->rq_label;
339803986916Sjarrett 
339903986916Sjarrett 		ASSERT(clabel != NULL);
340003986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
340103986916Sjarrett 		    char *, "got client label from request(1)",
340203986916Sjarrett 		    struct svc_req *, req);
340303986916Sjarrett 
340403986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3405bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3406bd6f1640SJarrett Lu 			    exi)) {
340703986916Sjarrett 				resp->status = NFS3ERR_ACCES;
340803986916Sjarrett 				goto out1;
340903986916Sjarrett 			}
341003986916Sjarrett 		}
341103986916Sjarrett 	}
341203986916Sjarrett 
34137c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
34147c478bd9Sstevel@tonic-gate 
34157c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3416da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
34177c478bd9Sstevel@tonic-gate 
34187c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
34197c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
34207c478bd9Sstevel@tonic-gate 		goto out;
34217c478bd9Sstevel@tonic-gate 	}
34227c478bd9Sstevel@tonic-gate 
3423da6c28aaSamw 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
34247c478bd9Sstevel@tonic-gate 	if (error)
34257c478bd9Sstevel@tonic-gate 		goto out;
34267c478bd9Sstevel@tonic-gate 
34277c478bd9Sstevel@tonic-gate 	/*
34287c478bd9Sstevel@tonic-gate 	 * Don't allow arbitrary counts for allocation
34297c478bd9Sstevel@tonic-gate 	 */
34307c478bd9Sstevel@tonic-gate 	if (args->maxcount > rfs3_tsize(req))
34317c478bd9Sstevel@tonic-gate 		args->maxcount = rfs3_tsize(req);
34327c478bd9Sstevel@tonic-gate 
34337c478bd9Sstevel@tonic-gate 	/*
34347c478bd9Sstevel@tonic-gate 	 * Make sure that there is room to read at least one entry
34357c478bd9Sstevel@tonic-gate 	 * if any are available
34367c478bd9Sstevel@tonic-gate 	 */
34377c478bd9Sstevel@tonic-gate 	args->dircount = MIN(args->dircount, args->maxcount);
34387c478bd9Sstevel@tonic-gate 
34397c478bd9Sstevel@tonic-gate 	if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
34407c478bd9Sstevel@tonic-gate 		args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
34417c478bd9Sstevel@tonic-gate 
34427c478bd9Sstevel@tonic-gate 	/*
34437c478bd9Sstevel@tonic-gate 	 * This allocation relies on a minimum directory entry
34447c478bd9Sstevel@tonic-gate 	 * being roughly 24 bytes.  Therefore, the namlen array
34457c478bd9Sstevel@tonic-gate 	 * will have enough space based on the maximum number of
34467c478bd9Sstevel@tonic-gate 	 * entries to read.
34477c478bd9Sstevel@tonic-gate 	 */
34487c478bd9Sstevel@tonic-gate 	namlen = kmem_alloc(args->dircount, KM_SLEEP);
34497c478bd9Sstevel@tonic-gate 
34507c478bd9Sstevel@tonic-gate 	space_left = args->dircount;
34517c478bd9Sstevel@tonic-gate 	data = kmem_alloc(args->dircount, KM_SLEEP);
34527c478bd9Sstevel@tonic-gate 	dp = (struct dirent64 *)data;
34537c478bd9Sstevel@tonic-gate 	uio.uio_iov = &iov;
34547c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
34557c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
34567c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
34577c478bd9Sstevel@tonic-gate 	uio.uio_loffset = (offset_t)args->cookie;
34587c478bd9Sstevel@tonic-gate 
34597c478bd9Sstevel@tonic-gate 	/*
34607c478bd9Sstevel@tonic-gate 	 * bufsize is used to keep track of the size of the response as we
34617c478bd9Sstevel@tonic-gate 	 * get post op attributes and filehandles for each entry.  This is
34627c478bd9Sstevel@tonic-gate 	 * an optimization as the server may have read more entries than will
34637c478bd9Sstevel@tonic-gate 	 * fit in the buffer specified by maxcount.  We stop calculating
34647c478bd9Sstevel@tonic-gate 	 * post op attributes and filehandles once we have exceeded maxcount.
34657c478bd9Sstevel@tonic-gate 	 * This will minimize the effect of truncation.
34667c478bd9Sstevel@tonic-gate 	 *
34677c478bd9Sstevel@tonic-gate 	 * It is primed with:
34687c478bd9Sstevel@tonic-gate 	 *	1 for the status +
34697c478bd9Sstevel@tonic-gate 	 *	1 for the dir_attributes.attributes boolean +
34707c478bd9Sstevel@tonic-gate 	 *	2 for the cookie verifier
34717c478bd9Sstevel@tonic-gate 	 * all times BYTES_PER_XDR_UNIT to convert from XDR units
34727c478bd9Sstevel@tonic-gate 	 * to bytes.  If there are directory attributes to be
34737c478bd9Sstevel@tonic-gate 	 * returned, then:
34747c478bd9Sstevel@tonic-gate 	 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
34757c478bd9Sstevel@tonic-gate 	 * time BYTES_PER_XDR_UNIT is added to account for them.
34767c478bd9Sstevel@tonic-gate 	 */
34777c478bd9Sstevel@tonic-gate 	bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
34787c478bd9Sstevel@tonic-gate 	if (vap != NULL)
34797c478bd9Sstevel@tonic-gate 		bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
34807c478bd9Sstevel@tonic-gate 
34817c478bd9Sstevel@tonic-gate getmoredents:
34827c478bd9Sstevel@tonic-gate 	/*
34837c478bd9Sstevel@tonic-gate 	 * Here we make a check so that our read unit is not larger than
34847c478bd9Sstevel@tonic-gate 	 * the space left in the buffer.
34857c478bd9Sstevel@tonic-gate 	 */
34867c478bd9Sstevel@tonic-gate 	rd_unit = MIN(rd_unit, space_left);
34877c478bd9Sstevel@tonic-gate 	iov.iov_base = (char *)dp;
34887c478bd9Sstevel@tonic-gate 	iov.iov_len = rd_unit;
34897c478bd9Sstevel@tonic-gate 	uio.uio_resid = rd_unit;
34907c478bd9Sstevel@tonic-gate 	prev_len = rd_unit;
34917c478bd9Sstevel@tonic-gate 
3492da6c28aaSamw 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
34937c478bd9Sstevel@tonic-gate 
34947c478bd9Sstevel@tonic-gate 	if (error) {
34957c478bd9Sstevel@tonic-gate 		kmem_free(data, args->dircount);
34967c478bd9Sstevel@tonic-gate 		goto out;
34977c478bd9Sstevel@tonic-gate 	}
34987c478bd9Sstevel@tonic-gate 
34997c478bd9Sstevel@tonic-gate 	if (uio.uio_resid == prev_len && !iseof) {
35007c478bd9Sstevel@tonic-gate 		if (nents == 0) {
35017c478bd9Sstevel@tonic-gate 			kmem_free(data, args->dircount);
35027c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_TOOSMALL;
35037c478bd9Sstevel@tonic-gate 			goto out1;
35047c478bd9Sstevel@tonic-gate 		}
35057c478bd9Sstevel@tonic-gate 
35067c478bd9Sstevel@tonic-gate 		/*
35077c478bd9Sstevel@tonic-gate 		 * We could not get any more entries, so get the attributes
35087c478bd9Sstevel@tonic-gate 		 * and filehandle for the entries already obtained.
35097c478bd9Sstevel@tonic-gate 		 */
35107c478bd9Sstevel@tonic-gate 		goto good;
35117c478bd9Sstevel@tonic-gate 	}
35127c478bd9Sstevel@tonic-gate 
35137c478bd9Sstevel@tonic-gate 	/*
35147c478bd9Sstevel@tonic-gate 	 * We estimate the size of the response by assuming the
35157c478bd9Sstevel@tonic-gate 	 * entry exists and attributes and filehandle are also valid
35167c478bd9Sstevel@tonic-gate 	 */
35177c478bd9Sstevel@tonic-gate 	for (size = prev_len - uio.uio_resid;
35187c478bd9Sstevel@tonic-gate 	    size > 0;
35197c478bd9Sstevel@tonic-gate 	    size -= dp->d_reclen, dp = nextdp(dp)) {
35207c478bd9Sstevel@tonic-gate 
35217c478bd9Sstevel@tonic-gate 		if (dp->d_ino == 0) {
35227c478bd9Sstevel@tonic-gate 			nents++;
35237c478bd9Sstevel@tonic-gate 			continue;
35247c478bd9Sstevel@tonic-gate 		}
35257c478bd9Sstevel@tonic-gate 
35267c478bd9Sstevel@tonic-gate 		namlen[nents] = strlen(dp->d_name);
35277c478bd9Sstevel@tonic-gate 		entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
35287c478bd9Sstevel@tonic-gate 
35297c478bd9Sstevel@tonic-gate 		/*
35307c478bd9Sstevel@tonic-gate 		 * We need to check to see if the number of bytes left
35317c478bd9Sstevel@tonic-gate 		 * to go into the buffer will actually fit into the
35327c478bd9Sstevel@tonic-gate 		 * buffer.  This is calculated as the size of this
35337c478bd9Sstevel@tonic-gate 		 * entry plus:
35347c478bd9Sstevel@tonic-gate 		 *	1 for the true/false list indicator +
35357c478bd9Sstevel@tonic-gate 		 *	1 for the eof indicator
35367c478bd9Sstevel@tonic-gate 		 * times BYTES_PER_XDR_UNIT to convert from XDR units
35377c478bd9Sstevel@tonic-gate 		 * to bytes.
35387c478bd9Sstevel@tonic-gate 		 *
35397c478bd9Sstevel@tonic-gate 		 * Also check the dircount limit against the first entry read
35407c478bd9Sstevel@tonic-gate 		 *
35417c478bd9Sstevel@tonic-gate 		 */
35427c478bd9Sstevel@tonic-gate 		tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
35437c478bd9Sstevel@tonic-gate 		if (bufsize + tofit > args->maxcount) {
35447c478bd9Sstevel@tonic-gate 			/*
35457c478bd9Sstevel@tonic-gate 			 * We make a check here to see if this was the
35467c478bd9Sstevel@tonic-gate 			 * first entry being measured.  If so, then maxcount
35477c478bd9Sstevel@tonic-gate 			 * was too small to begin with and so we need to
35487c478bd9Sstevel@tonic-gate 			 * return with NFS3ERR_TOOSMALL.
35497c478bd9Sstevel@tonic-gate 			 */
35507c478bd9Sstevel@tonic-gate 			if (nents == 0) {
35517c478bd9Sstevel@tonic-gate 				kmem_free(data, args->dircount);
35527c478bd9Sstevel@tonic-gate 				resp->status = NFS3ERR_TOOSMALL;
35537c478bd9Sstevel@tonic-gate 				goto out1;
35547c478bd9Sstevel@tonic-gate 			}
35557c478bd9Sstevel@tonic-gate 			iseof = FALSE;
35567c478bd9Sstevel@tonic-gate 			goto good;
35577c478bd9Sstevel@tonic-gate 		}
35587c478bd9Sstevel@tonic-gate 		bufsize += entrysize;
35597c478bd9Sstevel@tonic-gate 		nents++;
35607c478bd9Sstevel@tonic-gate 	}
35617c478bd9Sstevel@tonic-gate 
35627c478bd9Sstevel@tonic-gate 	/*
35637c478bd9Sstevel@tonic-gate 	 * If there is enough room to fit at least 1 more entry including
35647c478bd9Sstevel@tonic-gate 	 * post op attributes and filehandle in the buffer AND that we haven't
35657c478bd9Sstevel@tonic-gate 	 * exceeded dircount then go back and get some more.
35667c478bd9Sstevel@tonic-gate 	 */
35677c478bd9Sstevel@tonic-gate 	if (!iseof &&
35687c478bd9Sstevel@tonic-gate 	    (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
35697c478bd9Sstevel@tonic-gate 		space_left -= (prev_len - uio.uio_resid);
35707c478bd9Sstevel@tonic-gate 		if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
35717c478bd9Sstevel@tonic-gate 			goto getmoredents;
35727c478bd9Sstevel@tonic-gate 
35737c478bd9Sstevel@tonic-gate 		/* else, fall through */
35747c478bd9Sstevel@tonic-gate 	}
35757c478bd9Sstevel@tonic-gate good:
35767c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3577da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
35787c478bd9Sstevel@tonic-gate 
35797c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
35807c478bd9Sstevel@tonic-gate 
35817c478bd9Sstevel@tonic-gate 	infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
35827c478bd9Sstevel@tonic-gate 	resp->resok.infop = infop;
35837c478bd9Sstevel@tonic-gate 
35847c478bd9Sstevel@tonic-gate 	dp = (struct dirent64 *)data;
35857c478bd9Sstevel@tonic-gate 	for (i = 0; i < nents; i++) {
35867c478bd9Sstevel@tonic-gate 
35877c478bd9Sstevel@tonic-gate 		if (dp->d_ino == 0) {
35887c478bd9Sstevel@tonic-gate 			infop[i].attr.attributes = FALSE;
35897c478bd9Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
35907c478bd9Sstevel@tonic-gate 			dp = nextdp(dp);
35917c478bd9Sstevel@tonic-gate 			continue;
35927c478bd9Sstevel@tonic-gate 		}
35937c478bd9Sstevel@tonic-gate 
35947c478bd9Sstevel@tonic-gate 		infop[i].namelen = namlen[i];
35957c478bd9Sstevel@tonic-gate 
3596da6c28aaSamw 		error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3597da6c28aaSamw 		    NULL, NULL, NULL);
35987c478bd9Sstevel@tonic-gate 		if (error) {
35997c478bd9Sstevel@tonic-gate 			infop[i].attr.attributes = FALSE;
36007c478bd9Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
36017c478bd9Sstevel@tonic-gate 			dp = nextdp(dp);
36027c478bd9Sstevel@tonic-gate 			continue;
36037c478bd9Sstevel@tonic-gate 		}
36047c478bd9Sstevel@tonic-gate 
36057c478bd9Sstevel@tonic-gate 		nva.va_mask = AT_ALL;
36067c478bd9Sstevel@tonic-gate 		nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
360727246829SVitaliy Gusev 
36082f172c55SRobert Thurlow 		/* Lie about the object type for a referral */
36092f172c55SRobert Thurlow 		if (vn_is_nfs_reparse(nvp, cr))
36102f172c55SRobert Thurlow 			nvap->va_type = VLNK;
36112f172c55SRobert Thurlow 
36127c478bd9Sstevel@tonic-gate 		vattr_to_post_op_attr(nvap, &infop[i].attr);
36137c478bd9Sstevel@tonic-gate 
36147c478bd9Sstevel@tonic-gate 		error = makefh3(&infop[i].fh.handle, nvp, exi);
36157c478bd9Sstevel@tonic-gate 		if (!error)
36167c478bd9Sstevel@tonic-gate 			infop[i].fh.handle_follows = TRUE;
36177c478bd9Sstevel@tonic-gate 		else
36187c478bd9Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
36197c478bd9Sstevel@tonic-gate 
36207c478bd9Sstevel@tonic-gate 		VN_RELE(nvp);
36217c478bd9Sstevel@tonic-gate 		dp = nextdp(dp);
36227c478bd9Sstevel@tonic-gate 	}
36237c478bd9Sstevel@tonic-gate 
3624b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3625b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3626b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ndata == NULL)
3627b89a8333Snatalie li - Sun Microsystems - Irvine United States 		ndata = data;
3628b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3629b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ret > 0) {
3630b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/*
3631b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * We had to drop one or more entries in order to fit
3632b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * during the character conversion.  We need to patch
3633b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * up the size and eof info.
3634b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 */
3635b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (iseof)
3636b89a8333Snatalie li - Sun Microsystems - Irvine United States 			iseof = FALSE;
3637b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3638b89a8333Snatalie li - Sun Microsystems - Irvine United States 		ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3639b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    nents, ret);
3640b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
3641b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3642b89a8333Snatalie li - Sun Microsystems - Irvine United States 
36437c478bd9Sstevel@tonic-gate #if 0 /* notyet */
36447c478bd9Sstevel@tonic-gate 	/*
36457c478bd9Sstevel@tonic-gate 	 * Don't do this.  It causes local disk writes when just
36467c478bd9Sstevel@tonic-gate 	 * reading the file and the overhead is deemed larger
36477c478bd9Sstevel@tonic-gate 	 * than the benefit.
36487c478bd9Sstevel@tonic-gate 	 */
36497c478bd9Sstevel@tonic-gate 	/*
36507c478bd9Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
36517c478bd9Sstevel@tonic-gate 	 */
3652da6c28aaSamw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
36537c478bd9Sstevel@tonic-gate #endif
36547c478bd9Sstevel@tonic-gate 
36557c478bd9Sstevel@tonic-gate 	kmem_free(namlen, args->dircount);
36567c478bd9Sstevel@tonic-gate 
36577c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
36587c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
36597c478bd9Sstevel@tonic-gate 	resp->resok.cookieverf = 0;
3660b89a8333Snatalie li - Sun Microsystems - Irvine United States 	resp->resok.reply.entries = (entryplus3 *)ndata;
36617c478bd9Sstevel@tonic-gate 	resp->resok.reply.eof = iseof;
36627c478bd9Sstevel@tonic-gate 	resp->resok.size = nents;
3663b89a8333Snatalie li - Sun Microsystems - Irvine United States 	resp->resok.count = args->dircount - ret;
36647c478bd9Sstevel@tonic-gate 	resp->resok.maxcount = args->maxcount;
3665e1adf50cSahl 
3666e1adf50cSahl 	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3667e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3668b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ndata != data)
3669b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(data, args->dircount);
3670b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3671e1adf50cSahl 
3672e1adf50cSahl 	VN_RELE(vp);
3673e1adf50cSahl 
36747c478bd9Sstevel@tonic-gate 	return;
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate out:
36777c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
36787c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
36797c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
3680b89a8333Snatalie li - Sun Microsystems - Irvine United States 	} else {
36817c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
3682b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
36837c478bd9Sstevel@tonic-gate out1:
3684e1adf50cSahl 	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3685e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3686e1adf50cSahl 
36877c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
36887c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
36897c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
36907c478bd9Sstevel@tonic-gate 	}
36917c478bd9Sstevel@tonic-gate 
36927c478bd9Sstevel@tonic-gate 	if (namlen != NULL)
36937c478bd9Sstevel@tonic-gate 		kmem_free(namlen, args->dircount);
36947c478bd9Sstevel@tonic-gate 
36957c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
36967c478bd9Sstevel@tonic-gate }
36977c478bd9Sstevel@tonic-gate 
369827242a7cSthurlow void *
36997c478bd9Sstevel@tonic-gate rfs3_readdirplus_getfh(READDIRPLUS3args *args)
37007c478bd9Sstevel@tonic-gate {
37017c478bd9Sstevel@tonic-gate 
370227242a7cSthurlow 	return (&args->dir);
37037c478bd9Sstevel@tonic-gate }
37047c478bd9Sstevel@tonic-gate 
37057c478bd9Sstevel@tonic-gate void
37067c478bd9Sstevel@tonic-gate rfs3_readdirplus_free(READDIRPLUS3res *resp)
37077c478bd9Sstevel@tonic-gate {
37087c478bd9Sstevel@tonic-gate 
37097c478bd9Sstevel@tonic-gate 	if (resp->status == NFS3_OK) {
37107c478bd9Sstevel@tonic-gate 		kmem_free(resp->resok.reply.entries, resp->resok.count);
37117c478bd9Sstevel@tonic-gate 		kmem_free(resp->resok.infop,
37127c478bd9Sstevel@tonic-gate 		    resp->resok.size * sizeof (struct entryplus3_info));
37137c478bd9Sstevel@tonic-gate 	}
37147c478bd9Sstevel@tonic-gate }
37157c478bd9Sstevel@tonic-gate 
37167c478bd9Sstevel@tonic-gate /* ARGSUSED */
37177c478bd9Sstevel@tonic-gate void
37187c478bd9Sstevel@tonic-gate rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
37195cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
37207c478bd9Sstevel@tonic-gate {
37217c478bd9Sstevel@tonic-gate 	int error;
37227c478bd9Sstevel@tonic-gate 	vnode_t *vp;
37237c478bd9Sstevel@tonic-gate 	struct vattr *vap;
37247c478bd9Sstevel@tonic-gate 	struct vattr va;
37257c478bd9Sstevel@tonic-gate 	struct statvfs64 sb;
37267c478bd9Sstevel@tonic-gate 
37277c478bd9Sstevel@tonic-gate 	vap = NULL;
37287c478bd9Sstevel@tonic-gate 
37297c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->fsroot, exi);
3730e1adf50cSahl 
3731e1adf50cSahl 	DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
3732e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
3733e1adf50cSahl 
37347c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
37357c478bd9Sstevel@tonic-gate 		error = ESTALE;
37367c478bd9Sstevel@tonic-gate 		goto out;
37377c478bd9Sstevel@tonic-gate 	}
37387c478bd9Sstevel@tonic-gate 
373903986916Sjarrett 	if (is_system_labeled()) {
374003986916Sjarrett 		bslabel_t *clabel = req->rq_label;
374103986916Sjarrett 
374203986916Sjarrett 		ASSERT(clabel != NULL);
374303986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
374403986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
374503986916Sjarrett 
374603986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3747bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3748bd6f1640SJarrett Lu 			    exi)) {
374903986916Sjarrett 				resp->status = NFS3ERR_ACCES;
375003986916Sjarrett 				goto out1;
375103986916Sjarrett 			}
375203986916Sjarrett 		}
375303986916Sjarrett 	}
375403986916Sjarrett 
37557c478bd9Sstevel@tonic-gate 	error = VFS_STATVFS(vp->v_vfsp, &sb);
37567c478bd9Sstevel@tonic-gate 
37577c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3758da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
37597c478bd9Sstevel@tonic-gate 
37607c478bd9Sstevel@tonic-gate 	if (error)
37617c478bd9Sstevel@tonic-gate 		goto out;
37627c478bd9Sstevel@tonic-gate 
37637c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
37647c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
37657c478bd9Sstevel@tonic-gate 	if (sb.f_blocks != (fsblkcnt64_t)-1)
37667c478bd9Sstevel@tonic-gate 		resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
37677c478bd9Sstevel@tonic-gate 	else
37687c478bd9Sstevel@tonic-gate 		resp->resok.tbytes = (size3)sb.f_blocks;
37697c478bd9Sstevel@tonic-gate 	if (sb.f_bfree != (fsblkcnt64_t)-1)
37707c478bd9Sstevel@tonic-gate 		resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
37717c478bd9Sstevel@tonic-gate 	else
37727c478bd9Sstevel@tonic-gate 		resp->resok.fbytes = (size3)sb.f_bfree;
37737c478bd9Sstevel@tonic-gate 	if (sb.f_bavail != (fsblkcnt64_t)-1)
37747c478bd9Sstevel@tonic-gate 		resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
37757c478bd9Sstevel@tonic-gate 	else
37767c478bd9Sstevel@tonic-gate 		resp->resok.abytes = (size3)sb.f_bavail;
37777c478bd9Sstevel@tonic-gate 	resp->resok.tfiles = (size3)sb.f_files;
37787c478bd9Sstevel@tonic-gate 	resp->resok.ffiles = (size3)sb.f_ffree;
37797c478bd9Sstevel@tonic-gate 	resp->resok.afiles = (size3)sb.f_favail;
37807c478bd9Sstevel@tonic-gate 	resp->resok.invarsec = 0;
3781e1adf50cSahl 
3782e1adf50cSahl 	DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3783e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3784e1adf50cSahl 	VN_RELE(vp);
3785e1adf50cSahl 
37867c478bd9Sstevel@tonic-gate 	return;
37877c478bd9Sstevel@tonic-gate 
37887c478bd9Sstevel@tonic-gate out:
37897c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
37907c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
37917c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
37927c478bd9Sstevel@tonic-gate 	} else
37937c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
379403986916Sjarrett out1:
3795e1adf50cSahl 	DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3796e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3797e1adf50cSahl 
379803986916Sjarrett 	if (vp != NULL)
379903986916Sjarrett 		VN_RELE(vp);
38007c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
38017c478bd9Sstevel@tonic-gate }
38027c478bd9Sstevel@tonic-gate 
380327242a7cSthurlow void *
38047c478bd9Sstevel@tonic-gate rfs3_fsstat_getfh(FSSTAT3args *args)
38057c478bd9Sstevel@tonic-gate {
38067c478bd9Sstevel@tonic-gate 
380727242a7cSthurlow 	return (&args->fsroot);
38087c478bd9Sstevel@tonic-gate }
38097c478bd9Sstevel@tonic-gate 
38105cb0d679SMarcel Telka /* ARGSUSED */
38117c478bd9Sstevel@tonic-gate void
38127c478bd9Sstevel@tonic-gate rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
38135cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
38147c478bd9Sstevel@tonic-gate {
38157c478bd9Sstevel@tonic-gate 	vnode_t *vp;
38167c478bd9Sstevel@tonic-gate 	struct vattr *vap;
38177c478bd9Sstevel@tonic-gate 	struct vattr va;
38187c478bd9Sstevel@tonic-gate 	uint32_t xfer_size;
38197c478bd9Sstevel@tonic-gate 	ulong_t l = 0;
38207c478bd9Sstevel@tonic-gate 	int error;
38217c478bd9Sstevel@tonic-gate 
38227c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->fsroot, exi);
3823e1adf50cSahl 
3824e1adf50cSahl 	DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
3825e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
3826e1adf50cSahl 
38277c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
38287c478bd9Sstevel@tonic-gate 		if (curthread->t_flag & T_WOULDBLOCK) {
38297c478bd9Sstevel@tonic-gate 			curthread->t_flag &= ~T_WOULDBLOCK;
38307c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
38317c478bd9Sstevel@tonic-gate 		} else
38327c478bd9Sstevel@tonic-gate 			resp->status = NFS3ERR_STALE;
38337c478bd9Sstevel@tonic-gate 		vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3834e1adf50cSahl 		goto out;
38357c478bd9Sstevel@tonic-gate 	}
38367c478bd9Sstevel@tonic-gate 
383703986916Sjarrett 	if (is_system_labeled()) {
383803986916Sjarrett 		bslabel_t *clabel = req->rq_label;
383903986916Sjarrett 
384003986916Sjarrett 		ASSERT(clabel != NULL);
384103986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
384203986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
384303986916Sjarrett 
384403986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3845bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3846bd6f1640SJarrett Lu 			    exi)) {
384703986916Sjarrett 				resp->status = NFS3ERR_STALE;
384803986916Sjarrett 				vattr_to_post_op_attr(NULL,
384903986916Sjarrett 				    &resp->resfail.obj_attributes);
3850e1adf50cSahl 				goto out;
385103986916Sjarrett 			}
385203986916Sjarrett 		}
385303986916Sjarrett 	}
385403986916Sjarrett 
38557c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3856da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
38577c478bd9Sstevel@tonic-gate 
38587c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
38597c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
38607c478bd9Sstevel@tonic-gate 	xfer_size = rfs3_tsize(req);
38617c478bd9Sstevel@tonic-gate 	resp->resok.rtmax = xfer_size;
38627c478bd9Sstevel@tonic-gate 	resp->resok.rtpref = xfer_size;
38637c478bd9Sstevel@tonic-gate 	resp->resok.rtmult = DEV_BSIZE;
38647c478bd9Sstevel@tonic-gate 	resp->resok.wtmax = xfer_size;
38657c478bd9Sstevel@tonic-gate 	resp->resok.wtpref = xfer_size;
38667c478bd9Sstevel@tonic-gate 	resp->resok.wtmult = DEV_BSIZE;
38677c478bd9Sstevel@tonic-gate 	resp->resok.dtpref = MAXBSIZE;
38687c478bd9Sstevel@tonic-gate 
38697c478bd9Sstevel@tonic-gate 	/*
38707c478bd9Sstevel@tonic-gate 	 * Large file spec: want maxfilesize based on limit of
38717c478bd9Sstevel@tonic-gate 	 * underlying filesystem.  We can guess 2^31-1 if need be.
38727c478bd9Sstevel@tonic-gate 	 */
3873da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
3874710f82c5SPiyush Shivam 	if (error) {
3875710f82c5SPiyush Shivam 		resp->status = puterrno3(error);
3876710f82c5SPiyush Shivam 		goto out;
3877710f82c5SPiyush Shivam 	}
38787c478bd9Sstevel@tonic-gate 
3879710f82c5SPiyush Shivam 	/*
3880710f82c5SPiyush Shivam 	 * If the underlying file system does not support _PC_FILESIZEBITS,
3881710f82c5SPiyush Shivam 	 * return a reasonable default. Note that error code on VOP_PATHCONF
3882710f82c5SPiyush Shivam 	 * will be 0, even if the underlying file system does not support
3883710f82c5SPiyush Shivam 	 * _PC_FILESIZEBITS.
3884710f82c5SPiyush Shivam 	 */
3885710f82c5SPiyush Shivam 	if (l == (ulong_t)-1) {
38867c478bd9Sstevel@tonic-gate 		resp->resok.maxfilesize = MAXOFF32_T;
3887710f82c5SPiyush Shivam 	} else {
3888710f82c5SPiyush Shivam 		if (l >= (sizeof (uint64_t) * 8))
3889710f82c5SPiyush Shivam 			resp->resok.maxfilesize = INT64_MAX;
3890710f82c5SPiyush Shivam 		else
3891710f82c5SPiyush Shivam 			resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3892710f82c5SPiyush Shivam 	}
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate 	resp->resok.time_delta.seconds = 0;
38957c478bd9Sstevel@tonic-gate 	resp->resok.time_delta.nseconds = 1000;
38967c478bd9Sstevel@tonic-gate 	resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
38977c478bd9Sstevel@tonic-gate 	    FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3898e1adf50cSahl 
3899e1adf50cSahl 	DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3900e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
3901e1adf50cSahl 
3902e1adf50cSahl 	VN_RELE(vp);
3903e1adf50cSahl 
3904e1adf50cSahl 	return;
3905e1adf50cSahl 
3906e1adf50cSahl out:
3907e1adf50cSahl 	DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3908e1adf50cSahl 	    cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
3909e1adf50cSahl 	if (vp != NULL)
3910e1adf50cSahl 		VN_RELE(vp);
39117c478bd9Sstevel@tonic-gate }
39127c478bd9Sstevel@tonic-gate 
391327242a7cSthurlow void *
39147c478bd9Sstevel@tonic-gate rfs3_fsinfo_getfh(FSINFO3args *args)
39157c478bd9Sstevel@tonic-gate {
391627242a7cSthurlow 	return (&args->fsroot);
39177c478bd9Sstevel@tonic-gate }
39187c478bd9Sstevel@tonic-gate 
39197c478bd9Sstevel@tonic-gate /* ARGSUSED */
39207c478bd9Sstevel@tonic-gate void
39217c478bd9Sstevel@tonic-gate rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
39225cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
39237c478bd9Sstevel@tonic-gate {
39247c478bd9Sstevel@tonic-gate 	int error;
39257c478bd9Sstevel@tonic-gate 	vnode_t *vp;
39267c478bd9Sstevel@tonic-gate 	struct vattr *vap;
39277c478bd9Sstevel@tonic-gate 	struct vattr va;
39287c478bd9Sstevel@tonic-gate 	ulong_t val;
39297c478bd9Sstevel@tonic-gate 
39307c478bd9Sstevel@tonic-gate 	vap = NULL;
39317c478bd9Sstevel@tonic-gate 
39327c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
3933e1adf50cSahl 
3934e1adf50cSahl 	DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
3935e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
3936e1adf50cSahl 
39377c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
39387c478bd9Sstevel@tonic-gate 		error = ESTALE;
39397c478bd9Sstevel@tonic-gate 		goto out;
39407c478bd9Sstevel@tonic-gate 	}
39417c478bd9Sstevel@tonic-gate 
394203986916Sjarrett 	if (is_system_labeled()) {
394303986916Sjarrett 		bslabel_t *clabel = req->rq_label;
394403986916Sjarrett 
394503986916Sjarrett 		ASSERT(clabel != NULL);
394603986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
394703986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
394803986916Sjarrett 
394903986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
3950bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3951bd6f1640SJarrett Lu 			    exi)) {
395203986916Sjarrett 				resp->status = NFS3ERR_ACCES;
395303986916Sjarrett 				goto out1;
395403986916Sjarrett 			}
395503986916Sjarrett 		}
395603986916Sjarrett 	}
395703986916Sjarrett 
39587c478bd9Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3959da6c28aaSamw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
39607c478bd9Sstevel@tonic-gate 
3961da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
39627c478bd9Sstevel@tonic-gate 	if (error)
39637c478bd9Sstevel@tonic-gate 		goto out;
39647c478bd9Sstevel@tonic-gate 	resp->resok.info.link_max = (uint32)val;
39657c478bd9Sstevel@tonic-gate 
3966da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
39677c478bd9Sstevel@tonic-gate 	if (error)
39687c478bd9Sstevel@tonic-gate 		goto out;
39697c478bd9Sstevel@tonic-gate 	resp->resok.info.name_max = (uint32)val;
39707c478bd9Sstevel@tonic-gate 
3971da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
39727c478bd9Sstevel@tonic-gate 	if (error)
39737c478bd9Sstevel@tonic-gate 		goto out;
39747c478bd9Sstevel@tonic-gate 	if (val == 1)
39757c478bd9Sstevel@tonic-gate 		resp->resok.info.no_trunc = TRUE;
39767c478bd9Sstevel@tonic-gate 	else
39777c478bd9Sstevel@tonic-gate 		resp->resok.info.no_trunc = FALSE;
39787c478bd9Sstevel@tonic-gate 
3979da6c28aaSamw 	error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
39807c478bd9Sstevel@tonic-gate 	if (error)
39817c478bd9Sstevel@tonic-gate 		goto out;
39827c478bd9Sstevel@tonic-gate 	if (val == 1)
39837c478bd9Sstevel@tonic-gate 		resp->resok.info.chown_restricted = TRUE;
39847c478bd9Sstevel@tonic-gate 	else
39857c478bd9Sstevel@tonic-gate 		resp->resok.info.chown_restricted = FALSE;
39867c478bd9Sstevel@tonic-gate 
39877c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
39887c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
39897c478bd9Sstevel@tonic-gate 	resp->resok.info.case_insensitive = FALSE;
39907c478bd9Sstevel@tonic-gate 	resp->resok.info.case_preserving = TRUE;
3991e1adf50cSahl 	DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
3992e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
3993e1adf50cSahl 	VN_RELE(vp);
39947c478bd9Sstevel@tonic-gate 	return;
39957c478bd9Sstevel@tonic-gate 
39967c478bd9Sstevel@tonic-gate out:
39977c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
39987c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
39997c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
40007c478bd9Sstevel@tonic-gate 	} else
40017c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
400203986916Sjarrett out1:
4003e1adf50cSahl 	DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4004e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
40057c478bd9Sstevel@tonic-gate 	if (vp != NULL)
40067c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
40077c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
40087c478bd9Sstevel@tonic-gate }
40097c478bd9Sstevel@tonic-gate 
401027242a7cSthurlow void *
40117c478bd9Sstevel@tonic-gate rfs3_pathconf_getfh(PATHCONF3args *args)
40127c478bd9Sstevel@tonic-gate {
40137c478bd9Sstevel@tonic-gate 
401427242a7cSthurlow 	return (&args->object);
40157c478bd9Sstevel@tonic-gate }
40167c478bd9Sstevel@tonic-gate 
40177c478bd9Sstevel@tonic-gate void
40187c478bd9Sstevel@tonic-gate rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
40195cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
40207c478bd9Sstevel@tonic-gate {
40217c478bd9Sstevel@tonic-gate 	int error;
40227c478bd9Sstevel@tonic-gate 	vnode_t *vp;
40237c478bd9Sstevel@tonic-gate 	struct vattr *bvap;
40247c478bd9Sstevel@tonic-gate 	struct vattr bva;
40257c478bd9Sstevel@tonic-gate 	struct vattr *avap;
40267c478bd9Sstevel@tonic-gate 	struct vattr ava;
40277c478bd9Sstevel@tonic-gate 
40287c478bd9Sstevel@tonic-gate 	bvap = NULL;
40297c478bd9Sstevel@tonic-gate 	avap = NULL;
40307c478bd9Sstevel@tonic-gate 
40317c478bd9Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
4032e1adf50cSahl 
4033e1adf50cSahl 	DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4034e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
4035e1adf50cSahl 
40367c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
40377c478bd9Sstevel@tonic-gate 		error = ESTALE;
40387c478bd9Sstevel@tonic-gate 		goto out;
40397c478bd9Sstevel@tonic-gate 	}
40407c478bd9Sstevel@tonic-gate 
40417c478bd9Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
4042da6c28aaSamw 	error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
40437c478bd9Sstevel@tonic-gate 
40447c478bd9Sstevel@tonic-gate 	/*
40457c478bd9Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
40467c478bd9Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
40477c478bd9Sstevel@tonic-gate 	 */
40487c478bd9Sstevel@tonic-gate 	if (error)
40497c478bd9Sstevel@tonic-gate 		goto out;
40507c478bd9Sstevel@tonic-gate 
40517c478bd9Sstevel@tonic-gate 	bvap = &bva;
40527c478bd9Sstevel@tonic-gate 
40535cb0d679SMarcel Telka 	if (rdonly(ro, vp)) {
40547c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
40557c478bd9Sstevel@tonic-gate 		goto out1;
40567c478bd9Sstevel@tonic-gate 	}
40577c478bd9Sstevel@tonic-gate 
40587c478bd9Sstevel@tonic-gate 	if (vp->v_type != VREG) {
40597c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
40607c478bd9Sstevel@tonic-gate 		goto out1;
40617c478bd9Sstevel@tonic-gate 	}
40627c478bd9Sstevel@tonic-gate 
406303986916Sjarrett 	if (is_system_labeled()) {
406403986916Sjarrett 		bslabel_t *clabel = req->rq_label;
406503986916Sjarrett 
406603986916Sjarrett 		ASSERT(clabel != NULL);
406703986916Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
406803986916Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
406903986916Sjarrett 
407003986916Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
4071bd6f1640SJarrett Lu 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
4072bd6f1640SJarrett Lu 			    exi)) {
407303986916Sjarrett 				resp->status = NFS3ERR_ACCES;
407403986916Sjarrett 				goto out1;
407503986916Sjarrett 			}
407603986916Sjarrett 		}
407703986916Sjarrett 	}
407803986916Sjarrett 
40797c478bd9Sstevel@tonic-gate 	if (crgetuid(cr) != bva.va_uid &&
4080da6c28aaSamw 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
40817c478bd9Sstevel@tonic-gate 		goto out;
40827c478bd9Sstevel@tonic-gate 
4083f63200e6SJeff A. Smith 	error = VOP_FSYNC(vp, FSYNC, cr, NULL);
40847c478bd9Sstevel@tonic-gate 
40857c478bd9Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
4086da6c28aaSamw 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
40877c478bd9Sstevel@tonic-gate 
40887c478bd9Sstevel@tonic-gate 	if (error)
40897c478bd9Sstevel@tonic-gate 		goto out;
40907c478bd9Sstevel@tonic-gate 
40917c478bd9Sstevel@tonic-gate 	resp->status = NFS3_OK;
40927c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
40937c478bd9Sstevel@tonic-gate 	resp->resok.verf = write3verf;
4094e1adf50cSahl 
4095e1adf50cSahl 	DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4096e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4097e1adf50cSahl 
4098e1adf50cSahl 	VN_RELE(vp);
4099e1adf50cSahl 
41007c478bd9Sstevel@tonic-gate 	return;
41017c478bd9Sstevel@tonic-gate 
41027c478bd9Sstevel@tonic-gate out:
41037c478bd9Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
41047c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
41057c478bd9Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
41067c478bd9Sstevel@tonic-gate 	} else
41077c478bd9Sstevel@tonic-gate 		resp->status = puterrno3(error);
41087c478bd9Sstevel@tonic-gate out1:
4109e1adf50cSahl 	DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4110e1adf50cSahl 	    cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4111e1adf50cSahl 
41127c478bd9Sstevel@tonic-gate 	if (vp != NULL)
41137c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
41147c478bd9Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
41157c478bd9Sstevel@tonic-gate }
41167c478bd9Sstevel@tonic-gate 
411727242a7cSthurlow void *
41187c478bd9Sstevel@tonic-gate rfs3_commit_getfh(COMMIT3args *args)
41197c478bd9Sstevel@tonic-gate {
41207c478bd9Sstevel@tonic-gate 
412127242a7cSthurlow 	return (&args->file);
41227c478bd9Sstevel@tonic-gate }
41237c478bd9Sstevel@tonic-gate 
41247c478bd9Sstevel@tonic-gate static int
41257c478bd9Sstevel@tonic-gate sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
41267c478bd9Sstevel@tonic-gate {
41277c478bd9Sstevel@tonic-gate 
41287c478bd9Sstevel@tonic-gate 	vap->va_mask = 0;
41297c478bd9Sstevel@tonic-gate 
41307c478bd9Sstevel@tonic-gate 	if (sap->mode.set_it) {
41317c478bd9Sstevel@tonic-gate 		vap->va_mode = (mode_t)sap->mode.mode;
41327c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_MODE;
41337c478bd9Sstevel@tonic-gate 	}
41347c478bd9Sstevel@tonic-gate 	if (sap->uid.set_it) {
41357c478bd9Sstevel@tonic-gate 		vap->va_uid = (uid_t)sap->uid.uid;
41367c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_UID;
41377c478bd9Sstevel@tonic-gate 	}
41387c478bd9Sstevel@tonic-gate 	if (sap->gid.set_it) {
41397c478bd9Sstevel@tonic-gate 		vap->va_gid = (gid_t)sap->gid.gid;
41407c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_GID;
41417c478bd9Sstevel@tonic-gate 	}
41427c478bd9Sstevel@tonic-gate 	if (sap->size.set_it) {
41437c478bd9Sstevel@tonic-gate 		if (sap->size.size > (size3)((u_longlong_t)-1))
41447c478bd9Sstevel@tonic-gate 			return (EINVAL);
41457c478bd9Sstevel@tonic-gate 		vap->va_size = sap->size.size;
41467c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_SIZE;
41477c478bd9Sstevel@tonic-gate 	}
41487c478bd9Sstevel@tonic-gate 	if (sap->atime.set_it == SET_TO_CLIENT_TIME) {
41497c478bd9Sstevel@tonic-gate #ifndef _LP64
41507c478bd9Sstevel@tonic-gate 		/* check time validity */
41517c478bd9Sstevel@tonic-gate 		if (!NFS3_TIME_OK(sap->atime.atime.seconds))
41527c478bd9Sstevel@tonic-gate 			return (EOVERFLOW);
41537c478bd9Sstevel@tonic-gate #endif
41547c478bd9Sstevel@tonic-gate 		/*
41557c478bd9Sstevel@tonic-gate 		 * nfs protocol defines times as unsigned so don't extend sign,
41567c478bd9Sstevel@tonic-gate 		 * unless sysadmin set nfs_allow_preepoch_time.
41577c478bd9Sstevel@tonic-gate 		 */
41587c478bd9Sstevel@tonic-gate 		NFS_TIME_T_CONVERT(vap->va_atime.tv_sec,
41597c478bd9Sstevel@tonic-gate 		    sap->atime.atime.seconds);
41607c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds;
41617c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_ATIME;
41627c478bd9Sstevel@tonic-gate 	} else if (sap->atime.set_it == SET_TO_SERVER_TIME) {
41637c478bd9Sstevel@tonic-gate 		gethrestime(&vap->va_atime);
41647c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_ATIME;
41657c478bd9Sstevel@tonic-gate 	}
41667c478bd9Sstevel@tonic-gate 	if (sap->mtime.set_it == SET_TO_CLIENT_TIME) {
41677c478bd9Sstevel@tonic-gate #ifndef _LP64
41687c478bd9Sstevel@tonic-gate 		/* check time validity */
41697c478bd9Sstevel@tonic-gate 		if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
41707c478bd9Sstevel@tonic-gate 			return (EOVERFLOW);
41717c478bd9Sstevel@tonic-gate #endif
41727c478bd9Sstevel@tonic-gate 		/*
41737c478bd9Sstevel@tonic-gate 		 * nfs protocol defines times as unsigned so don't extend sign,
41747c478bd9Sstevel@tonic-gate 		 * unless sysadmin set nfs_allow_preepoch_time.
41757c478bd9Sstevel@tonic-gate 		 */
41767c478bd9Sstevel@tonic-gate 		NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
41777c478bd9Sstevel@tonic-gate 		    sap->mtime.mtime.seconds);
41787c478bd9Sstevel@tonic-gate 		vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
41797c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_MTIME;
41807c478bd9Sstevel@tonic-gate 	} else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
41817c478bd9Sstevel@tonic-gate 		gethrestime(&vap->va_mtime);
41827c478bd9Sstevel@tonic-gate 		vap->va_mask |= AT_MTIME;
41837c478bd9Sstevel@tonic-gate 	}
41847c478bd9Sstevel@tonic-gate 
41857c478bd9Sstevel@tonic-gate 	return (0);
41867c478bd9Sstevel@tonic-gate }
41877c478bd9Sstevel@tonic-gate 
41887c478bd9Sstevel@tonic-gate static ftype3 vt_to_nf3[] = {
41897c478bd9Sstevel@tonic-gate 	0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
41907c478bd9Sstevel@tonic-gate };
41917c478bd9Sstevel@tonic-gate 
41927c478bd9Sstevel@tonic-gate static int
41937c478bd9Sstevel@tonic-gate vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
41947c478bd9Sstevel@tonic-gate {
41957c478bd9Sstevel@tonic-gate 
41967c478bd9Sstevel@tonic-gate 	ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
41977c478bd9Sstevel@tonic-gate 	/* Return error if time or size overflow */
41987c478bd9Sstevel@tonic-gate 	if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
41997c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
42007c478bd9Sstevel@tonic-gate 	}
42017c478bd9Sstevel@tonic-gate 	fap->type = vt_to_nf3[vap->va_type];
42027c478bd9Sstevel@tonic-gate 	fap->mode = (mode3)(vap->va_mode & MODEMASK);
42037c478bd9Sstevel@tonic-gate 	fap->nlink = (uint32)vap->va_nlink;
42047c478bd9Sstevel@tonic-gate 	if (vap->va_uid == UID_NOBODY)
42057c478bd9Sstevel@tonic-gate 		fap->uid = (uid3)NFS_UID_NOBODY;
42067c478bd9Sstevel@tonic-gate 	else
42077c478bd9Sstevel@tonic-gate 		fap->uid = (uid3)vap->va_uid;
42087c478bd9Sstevel@tonic-gate 	if (vap->va_gid == GID_NOBODY)
42097c478bd9Sstevel@tonic-gate 		fap->gid = (gid3)NFS_GID_NOBODY;
42107c478bd9Sstevel@tonic-gate 	else
42117c478bd9Sstevel@tonic-gate 		fap->gid = (gid3)vap->va_gid;
42127c478bd9Sstevel@tonic-gate 	fap->size = (size3)vap->va_size;
42137c478bd9Sstevel@tonic-gate 	fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks;
42147c478bd9Sstevel@tonic-gate 	fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev);
42157c478bd9Sstevel@tonic-gate 	fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev);
42167c478bd9Sstevel@tonic-gate 	fap->fsid = (uint64)vap->va_fsid;
42177c478bd9Sstevel@tonic-gate 	fap->fileid = (fileid3)vap->va_nodeid;
42187c478bd9Sstevel@tonic-gate 	fap->atime.seconds = vap->va_atime.tv_sec;
42197c478bd9Sstevel@tonic-gate 	fap->atime.nseconds = vap->va_atime.tv_nsec;
42207c478bd9Sstevel@tonic-gate 	fap->mtime.seconds = vap->va_mtime.tv_sec;
42217c478bd9Sstevel@tonic-gate 	fap->mtime.nseconds = vap->va_mtime.tv_nsec;
42227c478bd9Sstevel@tonic-gate 	fap->ctime.seconds = vap->va_ctime.tv_sec;
42237c478bd9Sstevel@tonic-gate 	fap->ctime.nseconds = vap->va_ctime.tv_nsec;
42247c478bd9Sstevel@tonic-gate 	return (0);
42257c478bd9Sstevel@tonic-gate }
42267c478bd9Sstevel@tonic-gate 
42277c478bd9Sstevel@tonic-gate static int
42287c478bd9Sstevel@tonic-gate vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap)
42297c478bd9Sstevel@tonic-gate {
42307c478bd9Sstevel@tonic-gate 
42317c478bd9Sstevel@tonic-gate 	/* Return error if time or size overflow */
42327c478bd9Sstevel@tonic-gate 	if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) &&
42337c478bd9Sstevel@tonic-gate 	    NFS_TIME_T_OK(vap->va_ctime.tv_sec) &&
42347c478bd9Sstevel@tonic-gate 	    NFS3_SIZE_OK(vap->va_size))) {
42357c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
42367c478bd9Sstevel@tonic-gate 	}
42377c478bd9Sstevel@tonic-gate 	wccap->size = (size3)vap->va_size;
42387c478bd9Sstevel@tonic-gate 	wccap->mtime.seconds = vap->va_mtime.tv_sec;
42397c478bd9Sstevel@tonic-gate 	wccap->mtime.nseconds = vap->va_mtime.tv_nsec;
42407c478bd9Sstevel@tonic-gate 	wccap->ctime.seconds = vap->va_ctime.tv_sec;
42417c478bd9Sstevel@tonic-gate 	wccap->ctime.nseconds = vap->va_ctime.tv_nsec;
42427c478bd9Sstevel@tonic-gate 	return (0);
42437c478bd9Sstevel@tonic-gate }
42447c478bd9Sstevel@tonic-gate 
42457c478bd9Sstevel@tonic-gate static void
42467c478bd9Sstevel@tonic-gate vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap)
42477c478bd9Sstevel@tonic-gate {
42487c478bd9Sstevel@tonic-gate 
42497c478bd9Sstevel@tonic-gate 	/* don't return attrs if time overflow */
42507c478bd9Sstevel@tonic-gate 	if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
42517c478bd9Sstevel@tonic-gate 		poap->attributes = TRUE;
42527c478bd9Sstevel@tonic-gate 	} else
42537c478bd9Sstevel@tonic-gate 		poap->attributes = FALSE;
42547c478bd9Sstevel@tonic-gate }
42557c478bd9Sstevel@tonic-gate 
42567c478bd9Sstevel@tonic-gate void
42577c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
42587c478bd9Sstevel@tonic-gate {
42597c478bd9Sstevel@tonic-gate 
42607c478bd9Sstevel@tonic-gate 	/* don't return attrs if time overflow */
42617c478bd9Sstevel@tonic-gate 	if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
42627c478bd9Sstevel@tonic-gate 		poap->attributes = TRUE;
42637c478bd9Sstevel@tonic-gate 	} else
42647c478bd9Sstevel@tonic-gate 		poap->attributes = FALSE;
42657c478bd9Sstevel@tonic-gate }
42667c478bd9Sstevel@tonic-gate 
42677c478bd9Sstevel@tonic-gate static void
42687c478bd9Sstevel@tonic-gate vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
42697c478bd9Sstevel@tonic-gate {
42707c478bd9Sstevel@tonic-gate 
42717c478bd9Sstevel@tonic-gate 	vattr_to_pre_op_attr(bvap, &wccp->before);
42727c478bd9Sstevel@tonic-gate 	vattr_to_post_op_attr(avap, &wccp->after);
42737c478bd9Sstevel@tonic-gate }
42747c478bd9Sstevel@tonic-gate 
42757c478bd9Sstevel@tonic-gate void
42767c478bd9Sstevel@tonic-gate rfs3_srvrinit(void)
42777c478bd9Sstevel@tonic-gate {
42787c478bd9Sstevel@tonic-gate 	struct rfs3_verf_overlay {
42797c478bd9Sstevel@tonic-gate 		uint_t id; /* a "unique" identifier */
42807c478bd9Sstevel@tonic-gate 		int ts; /* a unique timestamp */
42817c478bd9Sstevel@tonic-gate 	} *verfp;
42827c478bd9Sstevel@tonic-gate 	timestruc_t now;
42837c478bd9Sstevel@tonic-gate 
42847c478bd9Sstevel@tonic-gate 	/*
42857c478bd9Sstevel@tonic-gate 	 * The following algorithm attempts to find a unique verifier
42867c478bd9Sstevel@tonic-gate 	 * to be used as the write verifier returned from the server
42877c478bd9Sstevel@tonic-gate 	 * to the client.  It is important that this verifier change
42887c478bd9Sstevel@tonic-gate 	 * whenever the server reboots.  Of secondary importance, it
42897c478bd9Sstevel@tonic-gate 	 * is important for the verifier to be unique between two
42907c478bd9Sstevel@tonic-gate 	 * different servers.
42917c478bd9Sstevel@tonic-gate 	 *
42927c478bd9Sstevel@tonic-gate 	 * Thus, an attempt is made to use the system hostid and the
42937c478bd9Sstevel@tonic-gate 	 * current time in seconds when the nfssrv kernel module is
42947c478bd9Sstevel@tonic-gate 	 * loaded.  It is assumed that an NFS server will not be able
42957c478bd9Sstevel@tonic-gate 	 * to boot and then to reboot in less than a second.  If the
42967c478bd9Sstevel@tonic-gate 	 * hostid has not been set, then the current high resolution
42977c478bd9Sstevel@tonic-gate 	 * time is used.  This will ensure different verifiers each
42987c478bd9Sstevel@tonic-gate 	 * time the server reboots and minimize the chances that two
42997c478bd9Sstevel@tonic-gate 	 * different servers will have the same verifier.
43007c478bd9Sstevel@tonic-gate 	 */
43017c478bd9Sstevel@tonic-gate 
43027c478bd9Sstevel@tonic-gate #ifndef	lint
43037c478bd9Sstevel@tonic-gate 	/*
43047c478bd9Sstevel@tonic-gate 	 * We ASSERT that this constant logic expression is
43057c478bd9Sstevel@tonic-gate 	 * always true because in the past, it wasn't.
43067c478bd9Sstevel@tonic-gate 	 */
43077c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (*verfp) <= sizeof (write3verf));
43087c478bd9Sstevel@tonic-gate #endif
43097c478bd9Sstevel@tonic-gate 
43107c478bd9Sstevel@tonic-gate 	gethrestime(&now);
43117c478bd9Sstevel@tonic-gate 	verfp = (struct rfs3_verf_overlay *)&write3verf;
43127c478bd9Sstevel@tonic-gate 	verfp->ts = (int)now.tv_sec;
43135679c89fSjv227347 	verfp->id = zone_get_hostid(NULL);
43147c478bd9Sstevel@tonic-gate 
43157c478bd9Sstevel@tonic-gate 	if (verfp->id == 0)
43167c478bd9Sstevel@tonic-gate 		verfp->id = (uint_t)now.tv_nsec;
43177c478bd9Sstevel@tonic-gate 
4318cfae96c2Sjwahlig 	nfs3_srv_caller_id = fs_new_caller_id();
4319cfae96c2Sjwahlig 
43207c478bd9Sstevel@tonic-gate }
43217c478bd9Sstevel@tonic-gate 
43220a701b1eSRobert Gordon static int
43230a701b1eSRobert Gordon rdma_setup_read_data3(READ3args *args, READ3resok *rok)
43240a701b1eSRobert Gordon {
43250a701b1eSRobert Gordon 	struct clist	*wcl;
4326f837ee4aSSiddheshwar Mahesh 	int		wlist_len;
43270a701b1eSRobert Gordon 	count3		count = rok->count;
43280a701b1eSRobert Gordon 
43290a701b1eSRobert Gordon 	wcl = args->wlist;
4330f837ee4aSSiddheshwar Mahesh 	if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
43310a701b1eSRobert Gordon 		return (FALSE);
43320a701b1eSRobert Gordon 	}
43330a701b1eSRobert Gordon 
43340a701b1eSRobert Gordon 	wcl = args->wlist;
4335f837ee4aSSiddheshwar Mahesh 	rok->wlist_len = wlist_len;
43360a701b1eSRobert Gordon 	rok->wlist = wcl;
43370a701b1eSRobert Gordon 	return (TRUE);
43380a701b1eSRobert Gordon }
43390a701b1eSRobert Gordon 
43407c478bd9Sstevel@tonic-gate void
43417c478bd9Sstevel@tonic-gate rfs3_srvrfini(void)
43427c478bd9Sstevel@tonic-gate {
43437c478bd9Sstevel@tonic-gate 	/* Nothing to do */
43447c478bd9Sstevel@tonic-gate }
4345