xref: /onnv-gate/usr/src/uts/common/fs/nfs/nfs3_srv.c (revision 13002:ce7d2a030660)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51610Sthurlow  * Common Development and Distribution License (the "License").
61610Sthurlow  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*13002SKaren.Rochford@Sun.COM  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
260Sstevel@tonic-gate /* All Rights Reserved */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/cred.h>
320Sstevel@tonic-gate #include <sys/buf.h>
330Sstevel@tonic-gate #include <sys/vfs.h>
340Sstevel@tonic-gate #include <sys/vnode.h>
350Sstevel@tonic-gate #include <sys/uio.h>
360Sstevel@tonic-gate #include <sys/errno.h>
370Sstevel@tonic-gate #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/statvfs.h>
390Sstevel@tonic-gate #include <sys/kmem.h>
400Sstevel@tonic-gate #include <sys/dirent.h>
410Sstevel@tonic-gate #include <sys/cmn_err.h>
420Sstevel@tonic-gate #include <sys/debug.h>
430Sstevel@tonic-gate #include <sys/systeminfo.h>
440Sstevel@tonic-gate #include <sys/flock.h>
450Sstevel@tonic-gate #include <sys/nbmlock.h>
460Sstevel@tonic-gate #include <sys/policy.h>
474971Sjarrett #include <sys/sdt.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #include <rpc/types.h>
500Sstevel@tonic-gate #include <rpc/auth.h>
510Sstevel@tonic-gate #include <rpc/svc.h>
527387SRobert.Gordon@Sun.COM #include <rpc/rpc_rdma.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include <nfs/nfs.h>
550Sstevel@tonic-gate #include <nfs/export.h>
567961SNatalie.Li@Sun.COM #include <nfs/nfs_cmd.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #include <sys/strsubr.h>
590Sstevel@tonic-gate 
604971Sjarrett #include <sys/tsol/label.h>
614971Sjarrett #include <sys/tsol/tndb.h>
624971Sjarrett 
638662SJordan.Vaughan@Sun.com #include <sys/zone.h>
648662SJordan.Vaughan@Sun.com 
654971Sjarrett #include <inet/ip.h>
664971Sjarrett #include <inet/ip6.h>
674971Sjarrett 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * These are the interface routines for the server side of the
700Sstevel@tonic-gate  * Network File System.  See the NFS version 3 protocol specification
710Sstevel@tonic-gate  * for a description of this interface.
720Sstevel@tonic-gate  */
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #ifdef DEBUG
750Sstevel@tonic-gate int rfs3_do_pre_op_attr = 1;
760Sstevel@tonic-gate int rfs3_do_post_op_attr = 1;
770Sstevel@tonic-gate int rfs3_do_post_op_fh3 = 1;
780Sstevel@tonic-gate #endif
790Sstevel@tonic-gate 
800Sstevel@tonic-gate static writeverf3 write3verf;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static int	sattr3_to_vattr(sattr3 *, struct vattr *);
830Sstevel@tonic-gate static int	vattr_to_fattr3(struct vattr *, fattr3 *);
840Sstevel@tonic-gate static int	vattr_to_wcc_attr(struct vattr *, wcc_attr *);
850Sstevel@tonic-gate static void	vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
860Sstevel@tonic-gate static void	vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
877387SRobert.Gordon@Sun.COM static int	rdma_setup_read_data3(READ3args *, READ3resok *);
880Sstevel@tonic-gate 
8911539SChunli.Zhang@Sun.COM extern int nfs_loaned_buffers;
9011539SChunli.Zhang@Sun.COM 
915599Sjwahlig u_longlong_t nfs3_srv_caller_id;
925599Sjwahlig 
930Sstevel@tonic-gate /* ARGSUSED */
940Sstevel@tonic-gate void
rfs3_getattr(GETATTR3args * args,GETATTR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)950Sstevel@tonic-gate rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
960Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
970Sstevel@tonic-gate {
980Sstevel@tonic-gate 	int error;
990Sstevel@tonic-gate 	vnode_t *vp;
1000Sstevel@tonic-gate 	struct vattr va;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
1035982Sahl 
1045982Sahl 	DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req,
1055982Sahl 	    cred_t *, cr, vnode_t *, vp, GETATTR3args *, args);
1065982Sahl 
1070Sstevel@tonic-gate 	if (vp == NULL) {
1080Sstevel@tonic-gate 		error = ESTALE;
1090Sstevel@tonic-gate 		goto out;
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1130Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &va, 0, cr);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	if (!error) {
11611291SRobert.Thurlow@Sun.COM 		/* Lie about the object type for a referral */
11711291SRobert.Thurlow@Sun.COM 		if (vn_is_nfs_reparse(vp, cr))
11811291SRobert.Thurlow@Sun.COM 			va.va_type = VLNK;
11911291SRobert.Thurlow@Sun.COM 
1200Sstevel@tonic-gate 		/* overflow error if time or size is out of range */
1210Sstevel@tonic-gate 		error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
1220Sstevel@tonic-gate 		if (error)
1230Sstevel@tonic-gate 			goto out;
1240Sstevel@tonic-gate 		resp->status = NFS3_OK;
1255982Sahl 
1265982Sahl 		DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
1275982Sahl 		    cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
1285982Sahl 
1295982Sahl 		VN_RELE(vp);
1305982Sahl 
1310Sstevel@tonic-gate 		return;
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate out:
1350Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
1360Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
1370Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
1380Sstevel@tonic-gate 	} else
1390Sstevel@tonic-gate 		resp->status = puterrno3(error);
1405982Sahl 
1415982Sahl 	DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
1425982Sahl 	    cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
1435982Sahl 
1445982Sahl 	if (vp != NULL)
1455982Sahl 		VN_RELE(vp);
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1481610Sthurlow void *
rfs3_getattr_getfh(GETATTR3args * args)1490Sstevel@tonic-gate rfs3_getattr_getfh(GETATTR3args *args)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 
1521610Sthurlow 	return (&args->object);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate void
rfs3_setattr(SETATTR3args * args,SETATTR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)1560Sstevel@tonic-gate rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
1570Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate 	int error;
1600Sstevel@tonic-gate 	vnode_t *vp;
1610Sstevel@tonic-gate 	struct vattr *bvap;
1620Sstevel@tonic-gate 	struct vattr bva;
1630Sstevel@tonic-gate 	struct vattr *avap;
1640Sstevel@tonic-gate 	struct vattr ava;
1650Sstevel@tonic-gate 	int flag;
1660Sstevel@tonic-gate 	int in_crit = 0;
1670Sstevel@tonic-gate 	struct flock64 bf;
1685599Sjwahlig 	caller_context_t ct;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	bvap = NULL;
1710Sstevel@tonic-gate 	avap = NULL;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
1745982Sahl 
1755982Sahl 	DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req,
1765982Sahl 	    cred_t *, cr, vnode_t *, vp, SETATTR3args *, args);
1775982Sahl 
1780Sstevel@tonic-gate 	if (vp == NULL) {
1790Sstevel@tonic-gate 		error = ESTALE;
1800Sstevel@tonic-gate 		goto out;
1810Sstevel@tonic-gate 	}
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	error = sattr3_to_vattr(&args->new_attributes, &ava);
1840Sstevel@tonic-gate 	if (error)
1850Sstevel@tonic-gate 		goto out;
1860Sstevel@tonic-gate 
1874971Sjarrett 	if (is_system_labeled()) {
1884971Sjarrett 		bslabel_t *clabel = req->rq_label;
1894971Sjarrett 
1904971Sjarrett 		ASSERT(clabel != NULL);
1914971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
1924971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
1934971Sjarrett 
1944971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
1959871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1969871SJarrett.Lu@Sun.COM 			    exi)) {
1974971Sjarrett 				resp->status = NFS3ERR_ACCES;
1984971Sjarrett 				goto out1;
1994971Sjarrett 			}
2004971Sjarrett 		}
2014971Sjarrett 	}
2024971Sjarrett 
2030Sstevel@tonic-gate 	/*
2040Sstevel@tonic-gate 	 * We need to specially handle size changes because of
2050Sstevel@tonic-gate 	 * possible conflicting NBMAND locks. Get into critical
2060Sstevel@tonic-gate 	 * region before VOP_GETATTR, so the size attribute is
2070Sstevel@tonic-gate 	 * valid when checking conflicts.
2080Sstevel@tonic-gate 	 *
2090Sstevel@tonic-gate 	 * Also, check to see if the v4 side of the server has
2100Sstevel@tonic-gate 	 * delegated this file.  If so, then we return JUKEBOX to
2110Sstevel@tonic-gate 	 * allow the client to retrasmit its request.
2120Sstevel@tonic-gate 	 */
2130Sstevel@tonic-gate 	if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
2140Sstevel@tonic-gate 		if (nbl_need_check(vp)) {
2150Sstevel@tonic-gate 			nbl_start_crit(vp, RW_READER);
2160Sstevel@tonic-gate 			in_crit = 1;
2170Sstevel@tonic-gate 		}
2180Sstevel@tonic-gate 	}
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
2210Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &bva, 0, cr);
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	/*
2240Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
2250Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
2260Sstevel@tonic-gate 	 */
2270Sstevel@tonic-gate 	if (error)
2280Sstevel@tonic-gate 		goto out;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate #ifdef DEBUG
2310Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr)
2320Sstevel@tonic-gate 		bvap = &bva;
2330Sstevel@tonic-gate #else
2340Sstevel@tonic-gate 	bvap = &bva;
2350Sstevel@tonic-gate #endif
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if (rdonly(exi, req) || vn_is_readonly(vp)) {
2380Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
2390Sstevel@tonic-gate 		goto out1;
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	if (args->guard.check &&
2430Sstevel@tonic-gate 	    (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
2440Sstevel@tonic-gate 	    args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
2450Sstevel@tonic-gate 		resp->status = NFS3ERR_NOT_SYNC;
2460Sstevel@tonic-gate 		goto out1;
2470Sstevel@tonic-gate 	}
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
2500Sstevel@tonic-gate 		flag = ATTR_UTIME;
2510Sstevel@tonic-gate 	else
2520Sstevel@tonic-gate 		flag = 0;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	/*
2550Sstevel@tonic-gate 	 * If the filesystem is exported with nosuid, then mask off
2560Sstevel@tonic-gate 	 * the setuid and setgid bits.
2570Sstevel@tonic-gate 	 */
2580Sstevel@tonic-gate 	if ((ava.va_mask & AT_MODE) && vp->v_type == VREG &&
2590Sstevel@tonic-gate 	    (exi->exi_export.ex_flags & EX_NOSUID))
2600Sstevel@tonic-gate 		ava.va_mode &= ~(VSUID | VSGID);
2610Sstevel@tonic-gate 
2625599Sjwahlig 	ct.cc_sysid = 0;
2635599Sjwahlig 	ct.cc_pid = 0;
2645599Sjwahlig 	ct.cc_caller_id = nfs3_srv_caller_id;
2655599Sjwahlig 	ct.cc_flags = CC_DONTBLOCK;
2665599Sjwahlig 
2670Sstevel@tonic-gate 	/*
2680Sstevel@tonic-gate 	 * We need to specially handle size changes because it is
2690Sstevel@tonic-gate 	 * possible for the client to create a file with modes
2700Sstevel@tonic-gate 	 * which indicate read-only, but with the file opened for
2710Sstevel@tonic-gate 	 * writing.  If the client then tries to set the size of
2720Sstevel@tonic-gate 	 * the file, then the normal access checking done in
2730Sstevel@tonic-gate 	 * VOP_SETATTR would prevent the client from doing so,
2740Sstevel@tonic-gate 	 * although it should be legal for it to do so.  To get
2750Sstevel@tonic-gate 	 * around this, we do the access checking for ourselves
2760Sstevel@tonic-gate 	 * and then use VOP_SPACE which doesn't do the access
2770Sstevel@tonic-gate 	 * checking which VOP_SETATTR does. VOP_SPACE can only
2780Sstevel@tonic-gate 	 * operate on VREG files, let VOP_SETATTR handle the other
2790Sstevel@tonic-gate 	 * extremely rare cases.
2800Sstevel@tonic-gate 	 * Also the client should not be allowed to change the
2810Sstevel@tonic-gate 	 * size of the file if there is a conflicting non-blocking
2820Sstevel@tonic-gate 	 * mandatory lock in the region the change.
2830Sstevel@tonic-gate 	 */
2840Sstevel@tonic-gate 	if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
2850Sstevel@tonic-gate 		if (in_crit) {
2860Sstevel@tonic-gate 			u_offset_t offset;
2870Sstevel@tonic-gate 			ssize_t length;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 			if (ava.va_size < bva.va_size) {
2900Sstevel@tonic-gate 				offset = ava.va_size;
2910Sstevel@tonic-gate 				length = bva.va_size - ava.va_size;
2920Sstevel@tonic-gate 			} else {
2930Sstevel@tonic-gate 				offset = bva.va_size;
2940Sstevel@tonic-gate 				length = ava.va_size - bva.va_size;
2950Sstevel@tonic-gate 			}
2965331Samw 			if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
2975331Samw 			    NULL)) {
2980Sstevel@tonic-gate 				error = EACCES;
2990Sstevel@tonic-gate 				goto out;
3000Sstevel@tonic-gate 			}
3010Sstevel@tonic-gate 		}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 		if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) {
3040Sstevel@tonic-gate 			ava.va_mask &= ~AT_SIZE;
3050Sstevel@tonic-gate 			bf.l_type = F_WRLCK;
3060Sstevel@tonic-gate 			bf.l_whence = 0;
3070Sstevel@tonic-gate 			bf.l_start = (off64_t)ava.va_size;
3080Sstevel@tonic-gate 			bf.l_len = 0;
3090Sstevel@tonic-gate 			bf.l_sysid = 0;
3100Sstevel@tonic-gate 			bf.l_pid = 0;
3110Sstevel@tonic-gate 			error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
3125599Sjwahlig 			    (offset_t)ava.va_size, cr, &ct);
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	if (!error && ava.va_mask)
3175599Sjwahlig 		error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
3185599Sjwahlig 
3195599Sjwahlig 	/* check if a monitor detected a delegation conflict */
3205599Sjwahlig 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
3215599Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
3225599Sjwahlig 		goto out1;
3235599Sjwahlig 	}
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate #ifdef DEBUG
3260Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
3270Sstevel@tonic-gate 		ava.va_mask = AT_ALL;
3280Sstevel@tonic-gate 		avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
3290Sstevel@tonic-gate 	} else
3300Sstevel@tonic-gate 		avap = NULL;
3310Sstevel@tonic-gate #else
3320Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
3330Sstevel@tonic-gate 	avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
3340Sstevel@tonic-gate #endif
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	/*
3370Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
3380Sstevel@tonic-gate 	 */
3395599Sjwahlig 	(void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if (error)
3420Sstevel@tonic-gate 		goto out;
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	if (in_crit)
3450Sstevel@tonic-gate 		nbl_end_crit(vp);
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	resp->status = NFS3_OK;
3480Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
3495982Sahl 
3505982Sahl 	DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
3515982Sahl 	    cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
3525982Sahl 
3535982Sahl 	VN_RELE(vp);
3545982Sahl 
3550Sstevel@tonic-gate 	return;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate out:
3580Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
3590Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
3600Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
3610Sstevel@tonic-gate 	} else
3620Sstevel@tonic-gate 		resp->status = puterrno3(error);
3630Sstevel@tonic-gate out1:
3645982Sahl 	DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
3655982Sahl 	    cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
3665982Sahl 
3670Sstevel@tonic-gate 	if (vp != NULL) {
3680Sstevel@tonic-gate 		if (in_crit)
3690Sstevel@tonic-gate 			nbl_end_crit(vp);
3700Sstevel@tonic-gate 		VN_RELE(vp);
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate 
3751610Sthurlow void *
rfs3_setattr_getfh(SETATTR3args * args)3760Sstevel@tonic-gate rfs3_setattr_getfh(SETATTR3args *args)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 
3791610Sthurlow 	return (&args->object);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate /* ARGSUSED */
3830Sstevel@tonic-gate void
rfs3_lookup(LOOKUP3args * args,LOOKUP3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)3840Sstevel@tonic-gate rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
3850Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	int error;
3880Sstevel@tonic-gate 	vnode_t *vp;
3890Sstevel@tonic-gate 	vnode_t *dvp;
3900Sstevel@tonic-gate 	struct vattr *vap;
3910Sstevel@tonic-gate 	struct vattr va;
3920Sstevel@tonic-gate 	struct vattr *dvap;
3930Sstevel@tonic-gate 	struct vattr dva;
3940Sstevel@tonic-gate 	nfs_fh3 *fhp;
3950Sstevel@tonic-gate 	struct sec_ol sec = {0, 0};
3960Sstevel@tonic-gate 	bool_t publicfh_flag = FALSE, auth_weak = FALSE;
3977961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
3987961SNatalie.Li@Sun.COM 	char *name = NULL;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	dvap = NULL;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/*
4030Sstevel@tonic-gate 	 * Allow lookups from the root - the default
4040Sstevel@tonic-gate 	 * location of the public filehandle.
4050Sstevel@tonic-gate 	 */
4060Sstevel@tonic-gate 	if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
4070Sstevel@tonic-gate 		dvp = rootdir;
4080Sstevel@tonic-gate 		VN_HOLD(dvp);
4095982Sahl 
4105982Sahl 		DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
4115982Sahl 		    cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
4120Sstevel@tonic-gate 	} else {
4131610Sthurlow 		dvp = nfs3_fhtovp(&args->what.dir, exi);
4145982Sahl 
4155982Sahl 		DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
4165982Sahl 		    cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
4175982Sahl 
4180Sstevel@tonic-gate 		if (dvp == NULL) {
4190Sstevel@tonic-gate 			error = ESTALE;
4200Sstevel@tonic-gate 			goto out;
4210Sstevel@tonic-gate 		}
4220Sstevel@tonic-gate 	}
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate #ifdef DEBUG
4250Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
4260Sstevel@tonic-gate 		dva.va_mask = AT_ALL;
4275331Samw 		dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate #else
4300Sstevel@tonic-gate 	dva.va_mask = AT_ALL;
4315331Samw 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
4320Sstevel@tonic-gate #endif
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	if (args->what.name == nfs3nametoolong) {
4350Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
4360Sstevel@tonic-gate 		goto out1;
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	if (args->what.name == NULL || *(args->what.name) == '\0') {
4400Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
4410Sstevel@tonic-gate 		goto out1;
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 
4441610Sthurlow 	fhp = &args->what.dir;
4450Sstevel@tonic-gate 	if (strcmp(args->what.name, "..") == 0 &&
4461610Sthurlow 	    EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
4470Sstevel@tonic-gate 		resp->status = NFS3ERR_NOENT;
4480Sstevel@tonic-gate 		goto out1;
4490Sstevel@tonic-gate 	}
4500Sstevel@tonic-gate 
4517961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
4527961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, args->what.name,
4537961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
4547961SNatalie.Li@Sun.COM 
4557961SNatalie.Li@Sun.COM 	if (name == NULL) {
4567961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_ACCES;
4577961SNatalie.Li@Sun.COM 		goto out1;
4587961SNatalie.Li@Sun.COM 	}
4597961SNatalie.Li@Sun.COM 
4600Sstevel@tonic-gate 	/*
4610Sstevel@tonic-gate 	 * If the public filehandle is used then allow
4620Sstevel@tonic-gate 	 * a multi-component lookup
4630Sstevel@tonic-gate 	 */
4641610Sthurlow 	if (PUBLIC_FH3(&args->what.dir)) {
4650Sstevel@tonic-gate 		publicfh_flag = TRUE;
4667961SNatalie.Li@Sun.COM 		error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
4675599Sjwahlig 		    &exi, &sec);
4680Sstevel@tonic-gate 		if (error && exi != NULL)
4694971Sjarrett 			exi_rele(exi); /* See comment below Re: publicfh_flag */
4704971Sjarrett 		/*
4714971Sjarrett 		 * Since WebNFS may bypass MOUNT, we need to ensure this
4724971Sjarrett 		 * request didn't come from an unlabeled admin_low client.
4734971Sjarrett 		 */
4744971Sjarrett 		if (is_system_labeled() && error == 0) {
4754971Sjarrett 			int		addr_type;
4764971Sjarrett 			void		*ipaddr;
4774971Sjarrett 			tsol_tpc_t	*tp;
4784971Sjarrett 
4794971Sjarrett 			if (ca->sa_family == AF_INET) {
4804971Sjarrett 				addr_type = IPV4_VERSION;
4814971Sjarrett 				ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
4824971Sjarrett 			} else if (ca->sa_family == AF_INET6) {
4834971Sjarrett 				addr_type = IPV6_VERSION;
4844971Sjarrett 				ipaddr = &((struct sockaddr_in6 *)
4854971Sjarrett 				    ca)->sin6_addr;
4864971Sjarrett 			}
4874971Sjarrett 			tp = find_tpc(ipaddr, addr_type, B_FALSE);
4884971Sjarrett 			if (tp == NULL || tp->tpc_tp.tp_doi !=
4894971Sjarrett 			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
4904971Sjarrett 			    SUN_CIPSO) {
4914971Sjarrett 				if (exi != NULL)
4924971Sjarrett 					exi_rele(exi);
4934971Sjarrett 				VN_RELE(vp);
4944971Sjarrett 				resp->status = NFS3ERR_ACCES;
4954971Sjarrett 				error = 1;
4964971Sjarrett 			}
4974971Sjarrett 			if (tp != NULL)
4984971Sjarrett 				TPC_RELE(tp);
4994971Sjarrett 		}
5000Sstevel@tonic-gate 	} else {
5017961SNatalie.Li@Sun.COM 		error = VOP_LOOKUP(dvp, name, &vp,
5025599Sjwahlig 		    NULL, 0, NULL, cr, NULL, NULL, NULL);
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate 
5057961SNatalie.Li@Sun.COM 	if (name != args->what.name)
5067961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
5077961SNatalie.Li@Sun.COM 
5084971Sjarrett 	if (is_system_labeled() && error == 0) {
5094971Sjarrett 		bslabel_t *clabel = req->rq_label;
5104971Sjarrett 
5114971Sjarrett 		ASSERT(clabel != NULL);
5124971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
5134971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
5144971Sjarrett 
5154971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
5164971Sjarrett 			if (!do_rfs_label_check(clabel, dvp,
5179871SJarrett.Lu@Sun.COM 			    DOMINANCE_CHECK, exi)) {
5184971Sjarrett 				if (publicfh_flag && exi != NULL)
5194971Sjarrett 					exi_rele(exi);
5204971Sjarrett 				VN_RELE(vp);
5214971Sjarrett 				resp->status = NFS3ERR_ACCES;
5224971Sjarrett 				error = 1;
5234971Sjarrett 			}
5244971Sjarrett 		}
5254971Sjarrett 	}
5264971Sjarrett 
5270Sstevel@tonic-gate #ifdef DEBUG
5280Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
5290Sstevel@tonic-gate 		dva.va_mask = AT_ALL;
5305331Samw 		dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
5310Sstevel@tonic-gate 	} else
5320Sstevel@tonic-gate 		dvap = NULL;
5330Sstevel@tonic-gate #else
5340Sstevel@tonic-gate 	dva.va_mask = AT_ALL;
5355331Samw 	dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
5360Sstevel@tonic-gate #endif
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	if (error)
5390Sstevel@tonic-gate 		goto out;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	if (sec.sec_flags & SEC_QUERY) {
5420Sstevel@tonic-gate 		error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
5430Sstevel@tonic-gate 	} else {
5440Sstevel@tonic-gate 		error = makefh3(&resp->resok.object, vp, exi);
5450Sstevel@tonic-gate 		if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
5460Sstevel@tonic-gate 			auth_weak = TRUE;
5470Sstevel@tonic-gate 	}
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	if (error) {
5500Sstevel@tonic-gate 		VN_RELE(vp);
5510Sstevel@tonic-gate 		goto out;
5520Sstevel@tonic-gate 	}
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	/*
5550Sstevel@tonic-gate 	 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
5560Sstevel@tonic-gate 	 * and have obtained a new exportinfo in exi which needs to be
5570Sstevel@tonic-gate 	 * released. Note the the original exportinfo pointed to by exi
5580Sstevel@tonic-gate 	 * will be released by the caller, common_dispatch.
5590Sstevel@tonic-gate 	 */
5600Sstevel@tonic-gate 	if (publicfh_flag)
5610Sstevel@tonic-gate 		exi_rele(exi);
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate #ifdef DEBUG
5640Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
5650Sstevel@tonic-gate 		va.va_mask = AT_ALL;
5660Sstevel@tonic-gate 		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
5670Sstevel@tonic-gate 	} else
5680Sstevel@tonic-gate 		vap = NULL;
5690Sstevel@tonic-gate #else
5700Sstevel@tonic-gate 	va.va_mask = AT_ALL;
5710Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
5720Sstevel@tonic-gate #endif
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	VN_RELE(vp);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	resp->status = NFS3_OK;
5770Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
5780Sstevel@tonic-gate 	vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	/*
5810Sstevel@tonic-gate 	 * If it's public fh, no 0x81, and client's flavor is
5820Sstevel@tonic-gate 	 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
5830Sstevel@tonic-gate 	 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
5840Sstevel@tonic-gate 	 */
5850Sstevel@tonic-gate 	if (auth_weak)
5860Sstevel@tonic-gate 		resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
5870Sstevel@tonic-gate 
5885982Sahl 	DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
5895982Sahl 	    cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
5905982Sahl 	VN_RELE(dvp);
5915982Sahl 
5920Sstevel@tonic-gate 	return;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate out:
5950Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
5960Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
5970Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
5980Sstevel@tonic-gate 	} else
5990Sstevel@tonic-gate 		resp->status = puterrno3(error);
6000Sstevel@tonic-gate out1:
6015982Sahl 	DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
6025982Sahl 	    cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
6035982Sahl 
6040Sstevel@tonic-gate 	if (dvp != NULL)
6050Sstevel@tonic-gate 		VN_RELE(dvp);
6060Sstevel@tonic-gate 	vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate 
6101610Sthurlow void *
rfs3_lookup_getfh(LOOKUP3args * args)6110Sstevel@tonic-gate rfs3_lookup_getfh(LOOKUP3args *args)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate 
6141610Sthurlow 	return (&args->what.dir);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate /* ARGSUSED */
6180Sstevel@tonic-gate void
rfs3_access(ACCESS3args * args,ACCESS3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)6190Sstevel@tonic-gate rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
6200Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate 	int error;
6230Sstevel@tonic-gate 	vnode_t *vp;
6240Sstevel@tonic-gate 	struct vattr *vap;
6250Sstevel@tonic-gate 	struct vattr va;
6260Sstevel@tonic-gate 	int checkwriteperm;
6274971Sjarrett 	boolean_t dominant_label = B_FALSE;
6284971Sjarrett 	boolean_t equal_label = B_FALSE;
6294971Sjarrett 	boolean_t admin_low_client;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	vap = NULL;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
6345982Sahl 
6355982Sahl 	DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
6365982Sahl 	    cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
6375982Sahl 
6380Sstevel@tonic-gate 	if (vp == NULL) {
6390Sstevel@tonic-gate 		error = ESTALE;
6400Sstevel@tonic-gate 		goto out;
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	/*
6440Sstevel@tonic-gate 	 * If the file system is exported read only, it is not appropriate
6450Sstevel@tonic-gate 	 * to check write permissions for regular files and directories.
6460Sstevel@tonic-gate 	 * Special files are interpreted by the client, so the underlying
6470Sstevel@tonic-gate 	 * permissions are sent back to the client for interpretation.
6480Sstevel@tonic-gate 	 */
6490Sstevel@tonic-gate 	if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR))
6500Sstevel@tonic-gate 		checkwriteperm = 0;
6510Sstevel@tonic-gate 	else
6520Sstevel@tonic-gate 		checkwriteperm = 1;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/*
6550Sstevel@tonic-gate 	 * We need the mode so that we can correctly determine access
6560Sstevel@tonic-gate 	 * permissions relative to a mandatory lock file.  Access to
6570Sstevel@tonic-gate 	 * mandatory lock files is denied on the server, so it might
6580Sstevel@tonic-gate 	 * as well be reflected to the server during the open.
6590Sstevel@tonic-gate 	 */
6600Sstevel@tonic-gate 	va.va_mask = AT_MODE;
6615331Samw 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
6620Sstevel@tonic-gate 	if (error)
6630Sstevel@tonic-gate 		goto out;
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate #ifdef DEBUG
6660Sstevel@tonic-gate 	if (rfs3_do_post_op_attr)
6670Sstevel@tonic-gate 		vap = &va;
6680Sstevel@tonic-gate #else
6690Sstevel@tonic-gate 	vap = &va;
6700Sstevel@tonic-gate #endif
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	resp->resok.access = 0;
6730Sstevel@tonic-gate 
6744971Sjarrett 	if (is_system_labeled()) {
6754971Sjarrett 		bslabel_t *clabel = req->rq_label;
6764971Sjarrett 
6774971Sjarrett 		ASSERT(clabel != NULL);
6784971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
6794971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
6804971Sjarrett 
6814971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
6824971Sjarrett 			if ((equal_label = do_rfs_label_check(clabel, vp,
6839871SJarrett.Lu@Sun.COM 			    EQUALITY_CHECK, exi)) == B_FALSE) {
6844971Sjarrett 				dominant_label = do_rfs_label_check(clabel,
6859871SJarrett.Lu@Sun.COM 				    vp, DOMINANCE_CHECK, exi);
6864971Sjarrett 			} else
6874971Sjarrett 				dominant_label = B_TRUE;
6884971Sjarrett 			admin_low_client = B_FALSE;
6894971Sjarrett 		} else
6904971Sjarrett 			admin_low_client = B_TRUE;
6914971Sjarrett 	}
6924971Sjarrett 
6930Sstevel@tonic-gate 	if (args->access & ACCESS3_READ) {
6945331Samw 		error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
6950Sstevel@tonic-gate 		if (error) {
6960Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
6970Sstevel@tonic-gate 				goto out;
6984971Sjarrett 		} else if (!MANDLOCK(vp, va.va_mode) &&
6994971Sjarrett 		    (!is_system_labeled() || admin_low_client ||
7004971Sjarrett 		    dominant_label))
7010Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_READ;
7020Sstevel@tonic-gate 	}
7030Sstevel@tonic-gate 	if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
7045331Samw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
7050Sstevel@tonic-gate 		if (error) {
7060Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
7070Sstevel@tonic-gate 				goto out;
7084971Sjarrett 		} else if (!is_system_labeled() || admin_low_client ||
7094971Sjarrett 		    dominant_label)
7100Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_LOOKUP;
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 	if (checkwriteperm &&
7130Sstevel@tonic-gate 	    (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
7145331Samw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
7150Sstevel@tonic-gate 		if (error) {
7160Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
7170Sstevel@tonic-gate 				goto out;
7184971Sjarrett 		} else if (!MANDLOCK(vp, va.va_mode) &&
7194971Sjarrett 		    (!is_system_labeled() || admin_low_client || equal_label)) {
7200Sstevel@tonic-gate 			resp->resok.access |=
7210Sstevel@tonic-gate 			    (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND));
7220Sstevel@tonic-gate 		}
7230Sstevel@tonic-gate 	}
7240Sstevel@tonic-gate 	if (checkwriteperm &&
7250Sstevel@tonic-gate 	    (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
7265331Samw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
7270Sstevel@tonic-gate 		if (error) {
7280Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
7290Sstevel@tonic-gate 				goto out;
7304971Sjarrett 		} else if (!is_system_labeled() || admin_low_client ||
7314971Sjarrett 		    equal_label)
7320Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_DELETE;
7330Sstevel@tonic-gate 	}
7340Sstevel@tonic-gate 	if (args->access & ACCESS3_EXECUTE) {
7355331Samw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
7360Sstevel@tonic-gate 		if (error) {
7370Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
7380Sstevel@tonic-gate 				goto out;
7394971Sjarrett 		} else if (!MANDLOCK(vp, va.va_mode) &&
7404971Sjarrett 		    (!is_system_labeled() || admin_low_client ||
7414971Sjarrett 		    dominant_label))
7420Sstevel@tonic-gate 			resp->resok.access |= ACCESS3_EXECUTE;
7430Sstevel@tonic-gate 	}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate #ifdef DEBUG
7460Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
7470Sstevel@tonic-gate 		va.va_mask = AT_ALL;
7480Sstevel@tonic-gate 		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
7490Sstevel@tonic-gate 	} else
7500Sstevel@tonic-gate 		vap = NULL;
7510Sstevel@tonic-gate #else
7520Sstevel@tonic-gate 	va.va_mask = AT_ALL;
7530Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
7540Sstevel@tonic-gate #endif
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	resp->status = NFS3_OK;
7570Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
7585982Sahl 
7595982Sahl 	DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
7605982Sahl 	    cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
7615982Sahl 
7625982Sahl 	VN_RELE(vp);
7635982Sahl 
7640Sstevel@tonic-gate 	return;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate out:
7670Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
7680Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
7690Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
7700Sstevel@tonic-gate 	} else
7710Sstevel@tonic-gate 		resp->status = puterrno3(error);
7725982Sahl 	DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
7735982Sahl 	    cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
7740Sstevel@tonic-gate 	if (vp != NULL)
7750Sstevel@tonic-gate 		VN_RELE(vp);
7760Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate 
7791610Sthurlow void *
rfs3_access_getfh(ACCESS3args * args)7800Sstevel@tonic-gate rfs3_access_getfh(ACCESS3args *args)
7810Sstevel@tonic-gate {
7820Sstevel@tonic-gate 
7831610Sthurlow 	return (&args->object);
7840Sstevel@tonic-gate }
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate /* ARGSUSED */
7870Sstevel@tonic-gate void
rfs3_readlink(READLINK3args * args,READLINK3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)7880Sstevel@tonic-gate rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
7890Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
7900Sstevel@tonic-gate {
7910Sstevel@tonic-gate 	int error;
7920Sstevel@tonic-gate 	vnode_t *vp;
7930Sstevel@tonic-gate 	struct vattr *vap;
7940Sstevel@tonic-gate 	struct vattr va;
7950Sstevel@tonic-gate 	struct iovec iov;
7960Sstevel@tonic-gate 	struct uio uio;
7970Sstevel@tonic-gate 	char *data;
7987961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
7997961SNatalie.Li@Sun.COM 	char *name = NULL;
80011291SRobert.Thurlow@Sun.COM 	int is_referral = 0;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	vap = NULL;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->symlink, exi);
8055982Sahl 
8065982Sahl 	DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
8075982Sahl 	    cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
8085982Sahl 
8090Sstevel@tonic-gate 	if (vp == NULL) {
8100Sstevel@tonic-gate 		error = ESTALE;
8110Sstevel@tonic-gate 		goto out;
8120Sstevel@tonic-gate 	}
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	va.va_mask = AT_ALL;
8155331Samw 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
8160Sstevel@tonic-gate 	if (error)
8170Sstevel@tonic-gate 		goto out;
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate #ifdef DEBUG
8200Sstevel@tonic-gate 	if (rfs3_do_post_op_attr)
8210Sstevel@tonic-gate 		vap = &va;
8220Sstevel@tonic-gate #else
8230Sstevel@tonic-gate 	vap = &va;
8240Sstevel@tonic-gate #endif
8250Sstevel@tonic-gate 
82611291SRobert.Thurlow@Sun.COM 	/* We lied about the object type for a referral */
82711291SRobert.Thurlow@Sun.COM 	if (vn_is_nfs_reparse(vp, cr))
82811291SRobert.Thurlow@Sun.COM 		is_referral = 1;
82911291SRobert.Thurlow@Sun.COM 
83011291SRobert.Thurlow@Sun.COM 	if (vp->v_type != VLNK && !is_referral) {
8310Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
8320Sstevel@tonic-gate 		goto out1;
8330Sstevel@tonic-gate 	}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	if (MANDLOCK(vp, va.va_mode)) {
8360Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
8370Sstevel@tonic-gate 		goto out1;
8380Sstevel@tonic-gate 	}
8390Sstevel@tonic-gate 
8404971Sjarrett 	if (is_system_labeled()) {
8414971Sjarrett 		bslabel_t *clabel = req->rq_label;
8424971Sjarrett 
8434971Sjarrett 		ASSERT(clabel != NULL);
8444971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
8454971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
8464971Sjarrett 
8474971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
8489871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
8499871SJarrett.Lu@Sun.COM 			    exi)) {
8504971Sjarrett 				resp->status = NFS3ERR_ACCES;
8514971Sjarrett 				goto out1;
8524971Sjarrett 			}
8534971Sjarrett 		}
8544971Sjarrett 	}
8554971Sjarrett 
8560Sstevel@tonic-gate 	data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
8570Sstevel@tonic-gate 
85811291SRobert.Thurlow@Sun.COM 	if (is_referral) {
85911291SRobert.Thurlow@Sun.COM 		char *s;
86011291SRobert.Thurlow@Sun.COM 		size_t strsz;
86111291SRobert.Thurlow@Sun.COM 
86211291SRobert.Thurlow@Sun.COM 		/* Get an artificial symlink based on a referral */
86311291SRobert.Thurlow@Sun.COM 		s = build_symlink(vp, cr, &strsz);
86411291SRobert.Thurlow@Sun.COM 		global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
86511291SRobert.Thurlow@Sun.COM 		DTRACE_PROBE2(nfs3serv__func__referral__reflink,
86611291SRobert.Thurlow@Sun.COM 		    vnode_t *, vp, char *, s);
86711291SRobert.Thurlow@Sun.COM 		if (s == NULL)
86811291SRobert.Thurlow@Sun.COM 			error = EINVAL;
86911291SRobert.Thurlow@Sun.COM 		else {
87011291SRobert.Thurlow@Sun.COM 			error = 0;
87111291SRobert.Thurlow@Sun.COM 			(void) strlcpy(data, s, MAXPATHLEN + 1);
87211291SRobert.Thurlow@Sun.COM 			kmem_free(s, strsz);
87311291SRobert.Thurlow@Sun.COM 		}
87411291SRobert.Thurlow@Sun.COM 
87511291SRobert.Thurlow@Sun.COM 	} else {
87611291SRobert.Thurlow@Sun.COM 
87711291SRobert.Thurlow@Sun.COM 		iov.iov_base = data;
87811291SRobert.Thurlow@Sun.COM 		iov.iov_len = MAXPATHLEN;
87911291SRobert.Thurlow@Sun.COM 		uio.uio_iov = &iov;
88011291SRobert.Thurlow@Sun.COM 		uio.uio_iovcnt = 1;
88111291SRobert.Thurlow@Sun.COM 		uio.uio_segflg = UIO_SYSSPACE;
88211291SRobert.Thurlow@Sun.COM 		uio.uio_extflg = UIO_COPY_CACHED;
88311291SRobert.Thurlow@Sun.COM 		uio.uio_loffset = 0;
88411291SRobert.Thurlow@Sun.COM 		uio.uio_resid = MAXPATHLEN;
88511291SRobert.Thurlow@Sun.COM 
88611291SRobert.Thurlow@Sun.COM 		error = VOP_READLINK(vp, &uio, cr, NULL);
88711291SRobert.Thurlow@Sun.COM 
88811291SRobert.Thurlow@Sun.COM 		if (!error)
88911291SRobert.Thurlow@Sun.COM 			*(data + MAXPATHLEN - uio.uio_resid) = '\0';
89011291SRobert.Thurlow@Sun.COM 	}
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate #ifdef DEBUG
8930Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
8940Sstevel@tonic-gate 		va.va_mask = AT_ALL;
8955331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
8960Sstevel@tonic-gate 	} else
8970Sstevel@tonic-gate 		vap = NULL;
8980Sstevel@tonic-gate #else
8990Sstevel@tonic-gate 	va.va_mask = AT_ALL;
9005331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
9010Sstevel@tonic-gate #endif
90211291SRobert.Thurlow@Sun.COM 	/* Lie about object type again just to be consistent */
90311291SRobert.Thurlow@Sun.COM 	if (is_referral && vap != NULL)
90411291SRobert.Thurlow@Sun.COM 		vap->va_type = VLNK;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate #if 0 /* notyet */
9070Sstevel@tonic-gate 	/*
9080Sstevel@tonic-gate 	 * Don't do this.  It causes local disk writes when just
9090Sstevel@tonic-gate 	 * reading the file and the overhead is deemed larger
9100Sstevel@tonic-gate 	 * than the benefit.
9110Sstevel@tonic-gate 	 */
9120Sstevel@tonic-gate 	/*
9130Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
9140Sstevel@tonic-gate 	 */
9155331Samw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
9160Sstevel@tonic-gate #endif
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	if (error) {
9190Sstevel@tonic-gate 		kmem_free(data, MAXPATHLEN + 1);
9200Sstevel@tonic-gate 		goto out;
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate 
9237961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
9247961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
9257961SNatalie.Li@Sun.COM 	    MAXPATHLEN + 1);
9267961SNatalie.Li@Sun.COM 
9277961SNatalie.Li@Sun.COM 	if (name == NULL) {
9287961SNatalie.Li@Sun.COM 		/*
9297961SNatalie.Li@Sun.COM 		 * Even though the conversion failed, we return
9307961SNatalie.Li@Sun.COM 		 * something. We just don't translate it.
9317961SNatalie.Li@Sun.COM 		 */
9327961SNatalie.Li@Sun.COM 		name = data;
9337961SNatalie.Li@Sun.COM 	}
9347961SNatalie.Li@Sun.COM 
9350Sstevel@tonic-gate 	resp->status = NFS3_OK;
9360Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
9377961SNatalie.Li@Sun.COM 	resp->resok.data = name;
9385982Sahl 
9395982Sahl 	DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
9405982Sahl 	    cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
9415982Sahl 	VN_RELE(vp);
9425982Sahl 
9437961SNatalie.Li@Sun.COM 	if (name != data)
9447961SNatalie.Li@Sun.COM 		kmem_free(data, MAXPATHLEN + 1);
9457961SNatalie.Li@Sun.COM 
9460Sstevel@tonic-gate 	return;
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate out:
9490Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
9500Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
9510Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
9520Sstevel@tonic-gate 	} else
9530Sstevel@tonic-gate 		resp->status = puterrno3(error);
9540Sstevel@tonic-gate out1:
9555982Sahl 	DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
9565982Sahl 	    cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
9570Sstevel@tonic-gate 	if (vp != NULL)
9580Sstevel@tonic-gate 		VN_RELE(vp);
9590Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate 
9621610Sthurlow void *
rfs3_readlink_getfh(READLINK3args * args)9630Sstevel@tonic-gate rfs3_readlink_getfh(READLINK3args *args)
9640Sstevel@tonic-gate {
9650Sstevel@tonic-gate 
9661610Sthurlow 	return (&args->symlink);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate void
rfs3_readlink_free(READLINK3res * resp)9700Sstevel@tonic-gate rfs3_readlink_free(READLINK3res *resp)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	if (resp->status == NFS3_OK)
9740Sstevel@tonic-gate 		kmem_free(resp->resok.data, MAXPATHLEN + 1);
9750Sstevel@tonic-gate }
9760Sstevel@tonic-gate 
9777387SRobert.Gordon@Sun.COM /*
9787387SRobert.Gordon@Sun.COM  * Server routine to handle read
9797387SRobert.Gordon@Sun.COM  * May handle RDMA data as well as mblks
9807387SRobert.Gordon@Sun.COM  */
9810Sstevel@tonic-gate /* ARGSUSED */
9820Sstevel@tonic-gate void
rfs3_read(READ3args * args,READ3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)9830Sstevel@tonic-gate rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
9840Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
9850Sstevel@tonic-gate {
9860Sstevel@tonic-gate 	int error;
9870Sstevel@tonic-gate 	vnode_t *vp;
9880Sstevel@tonic-gate 	struct vattr *vap;
9890Sstevel@tonic-gate 	struct vattr va;
9900Sstevel@tonic-gate 	struct iovec iov;
9910Sstevel@tonic-gate 	struct uio uio;
9920Sstevel@tonic-gate 	u_offset_t offset;
99311610SChunli.Zhang@Sun.COM 	mblk_t *mp = NULL;
9940Sstevel@tonic-gate 	int alloc_err = 0;
9950Sstevel@tonic-gate 	int in_crit = 0;
9960Sstevel@tonic-gate 	int need_rwunlock = 0;
9975599Sjwahlig 	caller_context_t ct;
99811539SChunli.Zhang@Sun.COM 	int rdma_used = 0;
99911539SChunli.Zhang@Sun.COM 	int loaned_buffers;
100011539SChunli.Zhang@Sun.COM 	struct uio *uiop;
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	vap = NULL;
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
10055982Sahl 
10065982Sahl 	DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
10075982Sahl 	    cred_t *, cr, vnode_t *, vp, READ3args *, args);
10085982Sahl 
10090Sstevel@tonic-gate 	if (vp == NULL) {
10100Sstevel@tonic-gate 		error = ESTALE;
10110Sstevel@tonic-gate 		goto out;
10120Sstevel@tonic-gate 	}
10130Sstevel@tonic-gate 
1014*13002SKaren.Rochford@Sun.COM 	if (args->wlist) {
1015*13002SKaren.Rochford@Sun.COM 		if (args->count > clist_len(args->wlist)) {
1016*13002SKaren.Rochford@Sun.COM 			error = EINVAL;
1017*13002SKaren.Rochford@Sun.COM 			goto out;
1018*13002SKaren.Rochford@Sun.COM 		}
101911539SChunli.Zhang@Sun.COM 		rdma_used = 1;
1020*13002SKaren.Rochford@Sun.COM 	}
102111539SChunli.Zhang@Sun.COM 
102211539SChunli.Zhang@Sun.COM 	/* use loaned buffers for TCP */
102311539SChunli.Zhang@Sun.COM 	loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
102411539SChunli.Zhang@Sun.COM 
10254971Sjarrett 	if (is_system_labeled()) {
10264971Sjarrett 		bslabel_t *clabel = req->rq_label;
10274971Sjarrett 
10284971Sjarrett 		ASSERT(clabel != NULL);
10294971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *,
10304971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
10314971Sjarrett 
10324971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
10339871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
10349871SJarrett.Lu@Sun.COM 			    exi)) {
10354971Sjarrett 				resp->status = NFS3ERR_ACCES;
10364971Sjarrett 				goto out1;
10374971Sjarrett 			}
10384971Sjarrett 		}
10394971Sjarrett 	}
10404971Sjarrett 
10415599Sjwahlig 	ct.cc_sysid = 0;
10425599Sjwahlig 	ct.cc_pid = 0;
10435599Sjwahlig 	ct.cc_caller_id = nfs3_srv_caller_id;
10445599Sjwahlig 	ct.cc_flags = CC_DONTBLOCK;
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	/*
10470Sstevel@tonic-gate 	 * Enter the critical region before calling VOP_RWLOCK
10480Sstevel@tonic-gate 	 * to avoid a deadlock with write requests.
10490Sstevel@tonic-gate 	 */
10500Sstevel@tonic-gate 	if (nbl_need_check(vp)) {
10510Sstevel@tonic-gate 		nbl_start_crit(vp, RW_READER);
10520Sstevel@tonic-gate 		in_crit = 1;
10535331Samw 		if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
10545331Samw 		    NULL)) {
10550Sstevel@tonic-gate 			error = EACCES;
10560Sstevel@tonic-gate 			goto out;
10570Sstevel@tonic-gate 		}
10580Sstevel@tonic-gate 	}
10590Sstevel@tonic-gate 
10605599Sjwahlig 	error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
10615599Sjwahlig 
10625599Sjwahlig 	/* check if a monitor detected a delegation conflict */
10635599Sjwahlig 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
10645599Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
10655599Sjwahlig 		goto out1;
10665599Sjwahlig 	}
10675599Sjwahlig 
10680Sstevel@tonic-gate 	need_rwunlock = 1;
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	va.va_mask = AT_ALL;
10715599Sjwahlig 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	/*
10740Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
10750Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
10760Sstevel@tonic-gate 	 */
10770Sstevel@tonic-gate 	if (error)
10780Sstevel@tonic-gate 		goto out;
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate #ifdef DEBUG
10810Sstevel@tonic-gate 	if (rfs3_do_post_op_attr)
10820Sstevel@tonic-gate 		vap = &va;
10830Sstevel@tonic-gate #else
10840Sstevel@tonic-gate 	vap = &va;
10850Sstevel@tonic-gate #endif
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	if (vp->v_type != VREG) {
10880Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
10890Sstevel@tonic-gate 		goto out1;
10900Sstevel@tonic-gate 	}
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	if (crgetuid(cr) != va.va_uid) {
10935599Sjwahlig 		error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
10940Sstevel@tonic-gate 		if (error) {
10950Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK)
10960Sstevel@tonic-gate 				goto out;
10975599Sjwahlig 			error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
10980Sstevel@tonic-gate 			if (error)
10990Sstevel@tonic-gate 				goto out;
11000Sstevel@tonic-gate 		}
11010Sstevel@tonic-gate 	}
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	if (MANDLOCK(vp, va.va_mode)) {
11040Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
11050Sstevel@tonic-gate 		goto out1;
11060Sstevel@tonic-gate 	}
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 	offset = args->offset;
11090Sstevel@tonic-gate 	if (offset >= va.va_size) {
11105599Sjwahlig 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
11110Sstevel@tonic-gate 		if (in_crit)
11120Sstevel@tonic-gate 			nbl_end_crit(vp);
11130Sstevel@tonic-gate 		resp->status = NFS3_OK;
11140Sstevel@tonic-gate 		vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
11150Sstevel@tonic-gate 		resp->resok.count = 0;
11160Sstevel@tonic-gate 		resp->resok.eof = TRUE;
11170Sstevel@tonic-gate 		resp->resok.data.data_len = 0;
11180Sstevel@tonic-gate 		resp->resok.data.data_val = NULL;
11190Sstevel@tonic-gate 		resp->resok.data.mp = NULL;
11207387SRobert.Gordon@Sun.COM 		/* RDMA */
11217387SRobert.Gordon@Sun.COM 		resp->resok.wlist = args->wlist;
11227387SRobert.Gordon@Sun.COM 		resp->resok.wlist_len = resp->resok.count;
11239348SSiddheshwar.Mahesh@Sun.COM 		if (resp->resok.wlist)
11249348SSiddheshwar.Mahesh@Sun.COM 			clist_zero_len(resp->resok.wlist);
11255982Sahl 		goto done;
11260Sstevel@tonic-gate 	}
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	if (args->count == 0) {
11295599Sjwahlig 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
11300Sstevel@tonic-gate 		if (in_crit)
11310Sstevel@tonic-gate 			nbl_end_crit(vp);
11320Sstevel@tonic-gate 		resp->status = NFS3_OK;
11330Sstevel@tonic-gate 		vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
11340Sstevel@tonic-gate 		resp->resok.count = 0;
11350Sstevel@tonic-gate 		resp->resok.eof = FALSE;
11360Sstevel@tonic-gate 		resp->resok.data.data_len = 0;
11370Sstevel@tonic-gate 		resp->resok.data.data_val = NULL;
11380Sstevel@tonic-gate 		resp->resok.data.mp = NULL;
11397387SRobert.Gordon@Sun.COM 		/* RDMA */
11407387SRobert.Gordon@Sun.COM 		resp->resok.wlist = args->wlist;
11417387SRobert.Gordon@Sun.COM 		resp->resok.wlist_len = resp->resok.count;
11429348SSiddheshwar.Mahesh@Sun.COM 		if (resp->resok.wlist)
11439348SSiddheshwar.Mahesh@Sun.COM 			clist_zero_len(resp->resok.wlist);
11445982Sahl 		goto done;
11450Sstevel@tonic-gate 	}
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 	/*
11480Sstevel@tonic-gate 	 * do not allocate memory more the max. allowed
11490Sstevel@tonic-gate 	 * transfer size
11500Sstevel@tonic-gate 	 */
11510Sstevel@tonic-gate 	if (args->count > rfs3_tsize(req))
11520Sstevel@tonic-gate 		args->count = rfs3_tsize(req);
11530Sstevel@tonic-gate 
115411539SChunli.Zhang@Sun.COM 	if (loaned_buffers) {
115511539SChunli.Zhang@Sun.COM 		uiop = (uio_t *)rfs_setup_xuio(vp);
115611539SChunli.Zhang@Sun.COM 		ASSERT(uiop != NULL);
115711539SChunli.Zhang@Sun.COM 		uiop->uio_segflg = UIO_SYSSPACE;
115811539SChunli.Zhang@Sun.COM 		uiop->uio_loffset = args->offset;
115911539SChunli.Zhang@Sun.COM 		uiop->uio_resid = args->count;
116011539SChunli.Zhang@Sun.COM 
116111539SChunli.Zhang@Sun.COM 		/* Jump to do the read if successful */
116211539SChunli.Zhang@Sun.COM 		if (VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cr, &ct) == 0) {
116311539SChunli.Zhang@Sun.COM 			/*
116411539SChunli.Zhang@Sun.COM 			 * Need to hold the vnode until after VOP_RETZCBUF()
116511539SChunli.Zhang@Sun.COM 			 * is called.
116611539SChunli.Zhang@Sun.COM 			 */
116711539SChunli.Zhang@Sun.COM 			VN_HOLD(vp);
116811539SChunli.Zhang@Sun.COM 			goto doio_read;
116911539SChunli.Zhang@Sun.COM 		}
117011539SChunli.Zhang@Sun.COM 
117111539SChunli.Zhang@Sun.COM 		DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int,
117211539SChunli.Zhang@Sun.COM 		    uiop->uio_loffset, int, uiop->uio_resid);
117311539SChunli.Zhang@Sun.COM 
117411539SChunli.Zhang@Sun.COM 		uiop->uio_extflg = 0;
117511539SChunli.Zhang@Sun.COM 		/* failure to setup for zero copy */
117611539SChunli.Zhang@Sun.COM 		rfs_free_xuio((void *)uiop);
117711539SChunli.Zhang@Sun.COM 		loaned_buffers = 0;
117811539SChunli.Zhang@Sun.COM 	}
117911539SChunli.Zhang@Sun.COM 
11800Sstevel@tonic-gate 	/*
11817387SRobert.Gordon@Sun.COM 	 * If returning data via RDMA Write, then grab the chunk list.
11827387SRobert.Gordon@Sun.COM 	 * If we aren't returning READ data w/RDMA_WRITE, then grab
11837387SRobert.Gordon@Sun.COM 	 * a mblk.
11840Sstevel@tonic-gate 	 */
118511539SChunli.Zhang@Sun.COM 	if (rdma_used) {
11867387SRobert.Gordon@Sun.COM 		(void) rdma_get_wchunk(req, &iov, args->wlist);
11877387SRobert.Gordon@Sun.COM 	} else {
11887387SRobert.Gordon@Sun.COM 		/*
11897387SRobert.Gordon@Sun.COM 		 * mp will contain the data to be sent out in the read reply.
11907387SRobert.Gordon@Sun.COM 		 * This will be freed after the reply has been sent out (by the
11917387SRobert.Gordon@Sun.COM 		 * driver).
11927387SRobert.Gordon@Sun.COM 		 * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so
11937387SRobert.Gordon@Sun.COM 		 * that the call to xdrmblk_putmblk() never fails.
11947387SRobert.Gordon@Sun.COM 		 */
11957387SRobert.Gordon@Sun.COM 		mp = allocb_wait(RNDUP(args->count), BPRI_MED, STR_NOSIG,
11967387SRobert.Gordon@Sun.COM 		    &alloc_err);
11977387SRobert.Gordon@Sun.COM 		ASSERT(mp != NULL);
11987387SRobert.Gordon@Sun.COM 		ASSERT(alloc_err == 0);
11997387SRobert.Gordon@Sun.COM 
12007387SRobert.Gordon@Sun.COM 		iov.iov_base = (caddr_t)mp->b_datap->db_base;
12017387SRobert.Gordon@Sun.COM 		iov.iov_len = args->count;
12027387SRobert.Gordon@Sun.COM 	}
12037387SRobert.Gordon@Sun.COM 
12040Sstevel@tonic-gate 	uio.uio_iov = &iov;
12050Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
12060Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
12070Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
12080Sstevel@tonic-gate 	uio.uio_loffset = args->offset;
12090Sstevel@tonic-gate 	uio.uio_resid = args->count;
121011539SChunli.Zhang@Sun.COM 	uiop = &uio;
121111539SChunli.Zhang@Sun.COM 
121211539SChunli.Zhang@Sun.COM doio_read:
121311539SChunli.Zhang@Sun.COM 	error = VOP_READ(vp, uiop, 0, cr, &ct);
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	if (error) {
121611539SChunli.Zhang@Sun.COM 		if (mp)
121711539SChunli.Zhang@Sun.COM 			freemsg(mp);
12185599Sjwahlig 		/* check if a monitor detected a delegation conflict */
12195599Sjwahlig 		if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
12205599Sjwahlig 			resp->status = NFS3ERR_JUKEBOX;
12215599Sjwahlig 			goto out1;
12225599Sjwahlig 		}
12230Sstevel@tonic-gate 		goto out;
12240Sstevel@tonic-gate 	}
12250Sstevel@tonic-gate 
122611539SChunli.Zhang@Sun.COM 	/* make mblk using zc buffers */
122711539SChunli.Zhang@Sun.COM 	if (loaned_buffers) {
122811539SChunli.Zhang@Sun.COM 		mp = uio_to_mblk(uiop);
122911539SChunli.Zhang@Sun.COM 		ASSERT(mp != NULL);
123011539SChunli.Zhang@Sun.COM 	}
123111539SChunli.Zhang@Sun.COM 
12320Sstevel@tonic-gate 	va.va_mask = AT_ALL;
12335599Sjwahlig 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate #ifdef DEBUG
12360Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
12370Sstevel@tonic-gate 		if (error)
12380Sstevel@tonic-gate 			vap = NULL;
12390Sstevel@tonic-gate 		else
12400Sstevel@tonic-gate 			vap = &va;
12410Sstevel@tonic-gate 	} else
12420Sstevel@tonic-gate 		vap = NULL;
12430Sstevel@tonic-gate #else
12440Sstevel@tonic-gate 	if (error)
12450Sstevel@tonic-gate 		vap = NULL;
12460Sstevel@tonic-gate 	else
12470Sstevel@tonic-gate 		vap = &va;
12480Sstevel@tonic-gate #endif
12490Sstevel@tonic-gate 
12505599Sjwahlig 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	if (in_crit)
12530Sstevel@tonic-gate 		nbl_end_crit(vp);
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 	resp->status = NFS3_OK;
12560Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
125711539SChunli.Zhang@Sun.COM 	resp->resok.count = args->count - uiop->uio_resid;
12580Sstevel@tonic-gate 	if (!error && offset + resp->resok.count == va.va_size)
12590Sstevel@tonic-gate 		resp->resok.eof = TRUE;
12600Sstevel@tonic-gate 	else
12610Sstevel@tonic-gate 		resp->resok.eof = FALSE;
12620Sstevel@tonic-gate 	resp->resok.data.data_len = resp->resok.count;
126311539SChunli.Zhang@Sun.COM 
126411539SChunli.Zhang@Sun.COM 	if (mp)
126511539SChunli.Zhang@Sun.COM 		rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
126611539SChunli.Zhang@Sun.COM 
12670Sstevel@tonic-gate 	resp->resok.data.mp = mp;
12680Sstevel@tonic-gate 	resp->resok.size = (uint_t)args->count;
12695982Sahl 
127011539SChunli.Zhang@Sun.COM 	if (rdma_used) {
12717387SRobert.Gordon@Sun.COM 		resp->resok.data.data_val = (caddr_t)iov.iov_base;
12727387SRobert.Gordon@Sun.COM 		if (!rdma_setup_read_data3(args, &(resp->resok))) {
12737387SRobert.Gordon@Sun.COM 			resp->status = NFS3ERR_INVAL;
12747387SRobert.Gordon@Sun.COM 		}
12757387SRobert.Gordon@Sun.COM 	} else {
12767387SRobert.Gordon@Sun.COM 		resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
12777387SRobert.Gordon@Sun.COM 		(resp->resok).wlist = NULL;
12787387SRobert.Gordon@Sun.COM 	}
12797387SRobert.Gordon@Sun.COM 
12805982Sahl done:
12815982Sahl 	DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
12825982Sahl 	    cred_t *, cr, vnode_t *, vp, READ3res *, resp);
12835982Sahl 
12845982Sahl 	VN_RELE(vp);
12855982Sahl 
12860Sstevel@tonic-gate 	return;
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate out:
12890Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
12900Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
12910Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
12920Sstevel@tonic-gate 	} else
12930Sstevel@tonic-gate 		resp->status = puterrno3(error);
12940Sstevel@tonic-gate out1:
12955982Sahl 	DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
12965982Sahl 	    cred_t *, cr, vnode_t *, vp, READ3res *, resp);
12975982Sahl 
12980Sstevel@tonic-gate 	if (vp != NULL) {
12990Sstevel@tonic-gate 		if (need_rwunlock)
13005599Sjwahlig 			VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
13010Sstevel@tonic-gate 		if (in_crit)
13020Sstevel@tonic-gate 			nbl_end_crit(vp);
13030Sstevel@tonic-gate 		VN_RELE(vp);
13040Sstevel@tonic-gate 	}
13050Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
13060Sstevel@tonic-gate }
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate void
rfs3_read_free(READ3res * resp)13090Sstevel@tonic-gate rfs3_read_free(READ3res *resp)
13100Sstevel@tonic-gate {
13110Sstevel@tonic-gate 	mblk_t *mp;
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	if (resp->status == NFS3_OK) {
13140Sstevel@tonic-gate 		mp = resp->resok.data.mp;
13150Sstevel@tonic-gate 		if (mp != NULL)
131611539SChunli.Zhang@Sun.COM 			freemsg(mp);
13170Sstevel@tonic-gate 	}
13180Sstevel@tonic-gate }
13190Sstevel@tonic-gate 
13201610Sthurlow void *
rfs3_read_getfh(READ3args * args)13210Sstevel@tonic-gate rfs3_read_getfh(READ3args *args)
13220Sstevel@tonic-gate {
13230Sstevel@tonic-gate 
13241610Sthurlow 	return (&args->file);
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate #define	MAX_IOVECS	12
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate #ifdef DEBUG
13300Sstevel@tonic-gate static int rfs3_write_hits = 0;
13310Sstevel@tonic-gate static int rfs3_write_misses = 0;
13320Sstevel@tonic-gate #endif
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate void
rfs3_write(WRITE3args * args,WRITE3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)13350Sstevel@tonic-gate rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
13360Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
13370Sstevel@tonic-gate {
13380Sstevel@tonic-gate 	int error;
13390Sstevel@tonic-gate 	vnode_t *vp;
13400Sstevel@tonic-gate 	struct vattr *bvap = NULL;
13410Sstevel@tonic-gate 	struct vattr bva;
13420Sstevel@tonic-gate 	struct vattr *avap = NULL;
13430Sstevel@tonic-gate 	struct vattr ava;
13440Sstevel@tonic-gate 	u_offset_t rlimit;
13450Sstevel@tonic-gate 	struct uio uio;
13460Sstevel@tonic-gate 	struct iovec iov[MAX_IOVECS];
13470Sstevel@tonic-gate 	mblk_t *m;
13480Sstevel@tonic-gate 	struct iovec *iovp;
13490Sstevel@tonic-gate 	int iovcnt;
13500Sstevel@tonic-gate 	int ioflag;
13510Sstevel@tonic-gate 	cred_t *savecred;
13520Sstevel@tonic-gate 	int in_crit = 0;
13530Sstevel@tonic-gate 	int rwlock_ret = -1;
13545599Sjwahlig 	caller_context_t ct;
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
13575982Sahl 
13585982Sahl 	DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
13595982Sahl 	    cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
13605982Sahl 
13610Sstevel@tonic-gate 	if (vp == NULL) {
13620Sstevel@tonic-gate 		error = ESTALE;
13635982Sahl 		goto err;
13640Sstevel@tonic-gate 	}
13650Sstevel@tonic-gate 
13664971Sjarrett 	if (is_system_labeled()) {
13674971Sjarrett 		bslabel_t *clabel = req->rq_label;
13684971Sjarrett 
13694971Sjarrett 		ASSERT(clabel != NULL);
13704971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
13714971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
13724971Sjarrett 
13734971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
13749871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
13759871SJarrett.Lu@Sun.COM 			    exi)) {
13764971Sjarrett 				resp->status = NFS3ERR_ACCES;
13775982Sahl 				goto err1;
13784971Sjarrett 			}
13794971Sjarrett 		}
13804971Sjarrett 	}
13814971Sjarrett 
13825599Sjwahlig 	ct.cc_sysid = 0;
13835599Sjwahlig 	ct.cc_pid = 0;
13845599Sjwahlig 	ct.cc_caller_id = nfs3_srv_caller_id;
13855599Sjwahlig 	ct.cc_flags = CC_DONTBLOCK;
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	/*
13880Sstevel@tonic-gate 	 * We have to enter the critical region before calling VOP_RWLOCK
13890Sstevel@tonic-gate 	 * to avoid a deadlock with ufs.
13900Sstevel@tonic-gate 	 */
13910Sstevel@tonic-gate 	if (nbl_need_check(vp)) {
13920Sstevel@tonic-gate 		nbl_start_crit(vp, RW_READER);
13930Sstevel@tonic-gate 		in_crit = 1;
13945331Samw 		if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
13955331Samw 		    NULL)) {
13960Sstevel@tonic-gate 			error = EACCES;
13975982Sahl 			goto err;
13980Sstevel@tonic-gate 		}
13990Sstevel@tonic-gate 	}
14000Sstevel@tonic-gate 
14015599Sjwahlig 	rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
14025599Sjwahlig 
14035599Sjwahlig 	/* check if a monitor detected a delegation conflict */
14045599Sjwahlig 	if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
14055599Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
14065599Sjwahlig 		rwlock_ret = -1;
14075982Sahl 		goto err1;
14085599Sjwahlig 	}
14095599Sjwahlig 
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
14125599Sjwahlig 	error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	/*
14150Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
14160Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
14170Sstevel@tonic-gate 	 */
14180Sstevel@tonic-gate 	if (error)
14195982Sahl 		goto err;
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 	bvap = &bva;
14220Sstevel@tonic-gate #ifdef DEBUG
14230Sstevel@tonic-gate 	if (!rfs3_do_pre_op_attr)
14240Sstevel@tonic-gate 		bvap = NULL;
14250Sstevel@tonic-gate #endif
14260Sstevel@tonic-gate 	avap = bvap;
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	if (args->count != args->data.data_len) {
14290Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
14305982Sahl 		goto err1;
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	if (rdonly(exi, req)) {
14340Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
14355982Sahl 		goto err1;
14360Sstevel@tonic-gate 	}
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	if (vp->v_type != VREG) {
14390Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
14405982Sahl 		goto err1;
14410Sstevel@tonic-gate 	}
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	if (crgetuid(cr) != bva.va_uid &&
14445599Sjwahlig 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
14455982Sahl 		goto err;
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	if (MANDLOCK(vp, bva.va_mode)) {
14480Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
14495982Sahl 		goto err1;
14500Sstevel@tonic-gate 	}
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate 	if (args->count == 0) {
14530Sstevel@tonic-gate 		resp->status = NFS3_OK;
14540Sstevel@tonic-gate 		vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
14550Sstevel@tonic-gate 		resp->resok.count = 0;
14560Sstevel@tonic-gate 		resp->resok.committed = args->stable;
14570Sstevel@tonic-gate 		resp->resok.verf = write3verf;
14585982Sahl 		goto out;
14590Sstevel@tonic-gate 	}
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	if (args->mblk != NULL) {
14620Sstevel@tonic-gate 		iovcnt = 0;
14630Sstevel@tonic-gate 		for (m = args->mblk; m != NULL; m = m->b_cont)
14640Sstevel@tonic-gate 			iovcnt++;
14650Sstevel@tonic-gate 		if (iovcnt <= MAX_IOVECS) {
14660Sstevel@tonic-gate #ifdef DEBUG
14670Sstevel@tonic-gate 			rfs3_write_hits++;
14680Sstevel@tonic-gate #endif
14690Sstevel@tonic-gate 			iovp = iov;
14700Sstevel@tonic-gate 		} else {
14710Sstevel@tonic-gate #ifdef DEBUG
14720Sstevel@tonic-gate 			rfs3_write_misses++;
14730Sstevel@tonic-gate #endif
14740Sstevel@tonic-gate 			iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
14750Sstevel@tonic-gate 		}
14760Sstevel@tonic-gate 		mblk_to_iov(args->mblk, iovcnt, iovp);
14777387SRobert.Gordon@Sun.COM 
14787387SRobert.Gordon@Sun.COM 	} else if (args->rlist != NULL) {
14797387SRobert.Gordon@Sun.COM 		iovcnt = 1;
14807387SRobert.Gordon@Sun.COM 		iovp = iov;
14817387SRobert.Gordon@Sun.COM 		iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
14827387SRobert.Gordon@Sun.COM 		iovp->iov_len = args->count;
14830Sstevel@tonic-gate 	} else {
14840Sstevel@tonic-gate 		iovcnt = 1;
14850Sstevel@tonic-gate 		iovp = iov;
14860Sstevel@tonic-gate 		iovp->iov_base = args->data.data_val;
14870Sstevel@tonic-gate 		iovp->iov_len = args->count;
14880Sstevel@tonic-gate 	}
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 	uio.uio_iov = iovp;
14910Sstevel@tonic-gate 	uio.uio_iovcnt = iovcnt;
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
14940Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_DEFAULT;
14950Sstevel@tonic-gate 	uio.uio_loffset = args->offset;
14960Sstevel@tonic-gate 	uio.uio_resid = args->count;
14970Sstevel@tonic-gate 	uio.uio_llimit = curproc->p_fsz_ctl;
14980Sstevel@tonic-gate 	rlimit = uio.uio_llimit - args->offset;
14990Sstevel@tonic-gate 	if (rlimit < (u_offset_t)uio.uio_resid)
15000Sstevel@tonic-gate 		uio.uio_resid = (int)rlimit;
15010Sstevel@tonic-gate 
15020Sstevel@tonic-gate 	if (args->stable == UNSTABLE)
15030Sstevel@tonic-gate 		ioflag = 0;
15040Sstevel@tonic-gate 	else if (args->stable == FILE_SYNC)
15050Sstevel@tonic-gate 		ioflag = FSYNC;
15060Sstevel@tonic-gate 	else if (args->stable == DATA_SYNC)
15070Sstevel@tonic-gate 		ioflag = FDSYNC;
15080Sstevel@tonic-gate 	else {
15090Sstevel@tonic-gate 		if (iovp != iov)
15100Sstevel@tonic-gate 			kmem_free(iovp, sizeof (*iovp) * iovcnt);
15110Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
15125982Sahl 		goto err1;
15130Sstevel@tonic-gate 	}
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	/*
15160Sstevel@tonic-gate 	 * We're changing creds because VM may fault and we need
15170Sstevel@tonic-gate 	 * the cred of the current thread to be used if quota
15180Sstevel@tonic-gate 	 * checking is enabled.
15190Sstevel@tonic-gate 	 */
15200Sstevel@tonic-gate 	savecred = curthread->t_cred;
15210Sstevel@tonic-gate 	curthread->t_cred = cr;
15225599Sjwahlig 	error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
15230Sstevel@tonic-gate 	curthread->t_cred = savecred;
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 	if (iovp != iov)
15260Sstevel@tonic-gate 		kmem_free(iovp, sizeof (*iovp) * iovcnt);
15270Sstevel@tonic-gate 
15285599Sjwahlig 	/* check if a monitor detected a delegation conflict */
15295599Sjwahlig 	if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
15305599Sjwahlig 		resp->status = NFS3ERR_JUKEBOX;
15315982Sahl 		goto err1;
15325599Sjwahlig 	}
15335599Sjwahlig 
15340Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
15355599Sjwahlig 	avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate #ifdef DEBUG
15380Sstevel@tonic-gate 	if (!rfs3_do_post_op_attr)
15390Sstevel@tonic-gate 		avap = NULL;
15400Sstevel@tonic-gate #endif
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	if (error)
15435982Sahl 		goto err;
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	/*
15460Sstevel@tonic-gate 	 * If we were unable to get the V_WRITELOCK_TRUE, then we
15470Sstevel@tonic-gate 	 * may not have accurate after attrs, so check if
15480Sstevel@tonic-gate 	 * we have both attributes, they have a non-zero va_seq, and
15490Sstevel@tonic-gate 	 * va_seq has changed by exactly one,
15500Sstevel@tonic-gate 	 * if not, turn off the before attr.
15510Sstevel@tonic-gate 	 */
15520Sstevel@tonic-gate 	if (rwlock_ret != V_WRITELOCK_TRUE) {
15530Sstevel@tonic-gate 		if (bvap == NULL || avap == NULL ||
15545599Sjwahlig 		    bvap->va_seq == 0 || avap->va_seq == 0 ||
15555599Sjwahlig 		    avap->va_seq != (bvap->va_seq + 1)) {
15560Sstevel@tonic-gate 			bvap = NULL;
15570Sstevel@tonic-gate 		}
15580Sstevel@tonic-gate 	}
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	resp->status = NFS3_OK;
15610Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
15620Sstevel@tonic-gate 	resp->resok.count = args->count - uio.uio_resid;
15630Sstevel@tonic-gate 	resp->resok.committed = args->stable;
15640Sstevel@tonic-gate 	resp->resok.verf = write3verf;
15655982Sahl 	goto out;
15665982Sahl 
15675982Sahl err:
15680Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
15690Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
15700Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
15710Sstevel@tonic-gate 	} else
15720Sstevel@tonic-gate 		resp->status = puterrno3(error);
15735982Sahl err1:
15745982Sahl 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
15755982Sahl out:
15765982Sahl 	DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
15775982Sahl 	    cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
15785982Sahl 
15790Sstevel@tonic-gate 	if (vp != NULL) {
15800Sstevel@tonic-gate 		if (rwlock_ret != -1)
15815599Sjwahlig 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
15820Sstevel@tonic-gate 		if (in_crit)
15830Sstevel@tonic-gate 			nbl_end_crit(vp);
15840Sstevel@tonic-gate 		VN_RELE(vp);
15850Sstevel@tonic-gate 	}
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate 
15881610Sthurlow void *
rfs3_write_getfh(WRITE3args * args)15890Sstevel@tonic-gate rfs3_write_getfh(WRITE3args *args)
15900Sstevel@tonic-gate {
15910Sstevel@tonic-gate 
15921610Sthurlow 	return (&args->file);
15930Sstevel@tonic-gate }
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate void
rfs3_create(CREATE3args * args,CREATE3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)15960Sstevel@tonic-gate rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
15970Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
15980Sstevel@tonic-gate {
15990Sstevel@tonic-gate 	int error;
16000Sstevel@tonic-gate 	int in_crit = 0;
16010Sstevel@tonic-gate 	vnode_t *vp;
16020Sstevel@tonic-gate 	vnode_t *tvp = NULL;
16030Sstevel@tonic-gate 	vnode_t *dvp;
16040Sstevel@tonic-gate 	struct vattr *vap;
16050Sstevel@tonic-gate 	struct vattr va;
16060Sstevel@tonic-gate 	struct vattr *dbvap;
16070Sstevel@tonic-gate 	struct vattr dbva;
16080Sstevel@tonic-gate 	struct vattr *davap;
16090Sstevel@tonic-gate 	struct vattr dava;
16100Sstevel@tonic-gate 	enum vcexcl excl;
16110Sstevel@tonic-gate 	nfstime3 *mtime;
16120Sstevel@tonic-gate 	len_t reqsize;
16130Sstevel@tonic-gate 	bool_t trunc;
16147961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
16157961SNatalie.Li@Sun.COM 	char *name = NULL;
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	dbvap = NULL;
16180Sstevel@tonic-gate 	davap = NULL;
16190Sstevel@tonic-gate 
16201610Sthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
16215982Sahl 
16225982Sahl 	DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
16235982Sahl 	    cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
16245982Sahl 
16250Sstevel@tonic-gate 	if (dvp == NULL) {
16260Sstevel@tonic-gate 		error = ESTALE;
16270Sstevel@tonic-gate 		goto out;
16280Sstevel@tonic-gate 	}
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate #ifdef DEBUG
16310Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
16320Sstevel@tonic-gate 		dbva.va_mask = AT_ALL;
16335331Samw 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
16340Sstevel@tonic-gate 	} else
16350Sstevel@tonic-gate 		dbvap = NULL;
16360Sstevel@tonic-gate #else
16370Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
16385331Samw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
16390Sstevel@tonic-gate #endif
16400Sstevel@tonic-gate 	davap = dbvap;
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
16430Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
16440Sstevel@tonic-gate 		goto out1;
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
16480Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
16490Sstevel@tonic-gate 		goto out1;
16500Sstevel@tonic-gate 	}
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 	if (rdonly(exi, req)) {
16530Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
16540Sstevel@tonic-gate 		goto out1;
16550Sstevel@tonic-gate 	}
16560Sstevel@tonic-gate 
16574971Sjarrett 	if (is_system_labeled()) {
16584971Sjarrett 		bslabel_t *clabel = req->rq_label;
16594971Sjarrett 
16604971Sjarrett 		ASSERT(clabel != NULL);
16614971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
16624971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
16634971Sjarrett 
16644971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
16659871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
16669871SJarrett.Lu@Sun.COM 			    exi)) {
16674971Sjarrett 				resp->status = NFS3ERR_ACCES;
16684971Sjarrett 				goto out1;
16694971Sjarrett 			}
16704971Sjarrett 		}
16714971Sjarrett 	}
16724971Sjarrett 
16737961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
16747961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, args->where.name,
16757961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
16767961SNatalie.Li@Sun.COM 
16777961SNatalie.Li@Sun.COM 	if (name == NULL) {
16787961SNatalie.Li@Sun.COM 		/* This is really a Solaris EILSEQ */
16797961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_INVAL;
16807961SNatalie.Li@Sun.COM 		goto out1;
16817961SNatalie.Li@Sun.COM 	}
16827961SNatalie.Li@Sun.COM 
16830Sstevel@tonic-gate 	if (args->how.mode == EXCLUSIVE) {
16840Sstevel@tonic-gate 		va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
16850Sstevel@tonic-gate 		va.va_type = VREG;
16860Sstevel@tonic-gate 		va.va_mode = (mode_t)0;
16870Sstevel@tonic-gate 		/*
16880Sstevel@tonic-gate 		 * Ensure no time overflows and that types match
16890Sstevel@tonic-gate 		 */
16900Sstevel@tonic-gate 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
16910Sstevel@tonic-gate 		va.va_mtime.tv_sec = mtime->seconds % INT32_MAX;
16920Sstevel@tonic-gate 		va.va_mtime.tv_nsec = mtime->nseconds;
16930Sstevel@tonic-gate 		excl = EXCL;
16940Sstevel@tonic-gate 	} else {
16950Sstevel@tonic-gate 		error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes,
16960Sstevel@tonic-gate 		    &va);
16970Sstevel@tonic-gate 		if (error)
16980Sstevel@tonic-gate 			goto out;
16990Sstevel@tonic-gate 		va.va_mask |= AT_TYPE;
17000Sstevel@tonic-gate 		va.va_type = VREG;
17010Sstevel@tonic-gate 		if (args->how.mode == GUARDED)
17020Sstevel@tonic-gate 			excl = EXCL;
17030Sstevel@tonic-gate 		else {
17040Sstevel@tonic-gate 			excl = NONEXCL;
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate 			/*
17070Sstevel@tonic-gate 			 * During creation of file in non-exclusive mode
17080Sstevel@tonic-gate 			 * if size of file is being set then make sure
17090Sstevel@tonic-gate 			 * that if the file already exists that no conflicting
17100Sstevel@tonic-gate 			 * non-blocking mandatory locks exists in the region
17110Sstevel@tonic-gate 			 * being modified. If there are conflicting locks fail
17120Sstevel@tonic-gate 			 * the operation with EACCES.
17130Sstevel@tonic-gate 			 */
17140Sstevel@tonic-gate 			if (va.va_mask & AT_SIZE) {
17150Sstevel@tonic-gate 				struct vattr tva;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 				/*
17180Sstevel@tonic-gate 				 * Does file already exist?
17190Sstevel@tonic-gate 				 */
17207961SNatalie.Li@Sun.COM 				error = VOP_LOOKUP(dvp, name, &tvp,
17215599Sjwahlig 				    NULL, 0, NULL, cr, NULL, NULL, NULL);
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 				/*
17240Sstevel@tonic-gate 				 * Check to see if the file has been delegated
17250Sstevel@tonic-gate 				 * to a v4 client.  If so, then begin recall of
17260Sstevel@tonic-gate 				 * the delegation and return JUKEBOX to allow
17270Sstevel@tonic-gate 				 * the client to retrasmit its request.
17280Sstevel@tonic-gate 				 */
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 				trunc = va.va_size == 0;
17310Sstevel@tonic-gate 				if (!error &&
17320Sstevel@tonic-gate 				    rfs4_check_delegated(FWRITE, tvp, trunc)) {
17330Sstevel@tonic-gate 					resp->status = NFS3ERR_JUKEBOX;
17340Sstevel@tonic-gate 					goto out1;
17350Sstevel@tonic-gate 				}
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 				/*
17380Sstevel@tonic-gate 				 * Check for NBMAND lock conflicts
17390Sstevel@tonic-gate 				 */
17400Sstevel@tonic-gate 				if (!error && nbl_need_check(tvp)) {
17410Sstevel@tonic-gate 					u_offset_t offset;
17420Sstevel@tonic-gate 					ssize_t len;
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 					nbl_start_crit(tvp, RW_READER);
17450Sstevel@tonic-gate 					in_crit = 1;
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 					tva.va_mask = AT_SIZE;
17485331Samw 					error = VOP_GETATTR(tvp, &tva, 0, cr,
17495599Sjwahlig 					    NULL);
17500Sstevel@tonic-gate 					/*
17510Sstevel@tonic-gate 					 * Can't check for conflicts, so return
17520Sstevel@tonic-gate 					 * error.
17530Sstevel@tonic-gate 					 */
17540Sstevel@tonic-gate 					if (error)
17550Sstevel@tonic-gate 						goto out;
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 					offset = tva.va_size < va.va_size ?
17585599Sjwahlig 					    tva.va_size : va.va_size;
17590Sstevel@tonic-gate 					len = tva.va_size < va.va_size ?
17605599Sjwahlig 					    va.va_size - tva.va_size :
17615599Sjwahlig 					    tva.va_size - va.va_size;
17620Sstevel@tonic-gate 					if (nbl_conflict(tvp, NBL_WRITE,
17635599Sjwahlig 					    offset, len, 0, NULL)) {
17640Sstevel@tonic-gate 						error = EACCES;
17650Sstevel@tonic-gate 						goto out;
17660Sstevel@tonic-gate 					}
17670Sstevel@tonic-gate 				} else if (tvp) {
17680Sstevel@tonic-gate 					VN_RELE(tvp);
17690Sstevel@tonic-gate 					tvp = NULL;
17700Sstevel@tonic-gate 				}
17710Sstevel@tonic-gate 			}
17720Sstevel@tonic-gate 		}
17730Sstevel@tonic-gate 		if (va.va_mask & AT_SIZE)
17740Sstevel@tonic-gate 			reqsize = va.va_size;
17750Sstevel@tonic-gate 	}
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	/*
17780Sstevel@tonic-gate 	 * Must specify the mode.
17790Sstevel@tonic-gate 	 */
17800Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
17810Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
17820Sstevel@tonic-gate 		goto out1;
17830Sstevel@tonic-gate 	}
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate 	/*
17860Sstevel@tonic-gate 	 * If the filesystem is exported with nosuid, then mask off
17870Sstevel@tonic-gate 	 * the setuid and setgid bits.
17880Sstevel@tonic-gate 	 */
17890Sstevel@tonic-gate 	if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
17900Sstevel@tonic-gate 		va.va_mode &= ~(VSUID | VSGID);
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate tryagain:
17930Sstevel@tonic-gate 	/*
17940Sstevel@tonic-gate 	 * The file open mode used is VWRITE.  If the client needs
17950Sstevel@tonic-gate 	 * some other semantic, then it should do the access checking
17960Sstevel@tonic-gate 	 * itself.  It would have been nice to have the file open mode
17970Sstevel@tonic-gate 	 * passed as part of the arguments.
17980Sstevel@tonic-gate 	 */
17997961SNatalie.Li@Sun.COM 	error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
18005331Samw 	    &vp, cr, 0, NULL, NULL);
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate #ifdef DEBUG
18030Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
18040Sstevel@tonic-gate 		dava.va_mask = AT_ALL;
18055331Samw 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
18060Sstevel@tonic-gate 	} else
18070Sstevel@tonic-gate 		davap = NULL;
18080Sstevel@tonic-gate #else
18090Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
18105331Samw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
18110Sstevel@tonic-gate #endif
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 	if (error) {
18140Sstevel@tonic-gate 		/*
18150Sstevel@tonic-gate 		 * If we got something other than file already exists
18160Sstevel@tonic-gate 		 * then just return this error.  Otherwise, we got
18170Sstevel@tonic-gate 		 * EEXIST.  If we were doing a GUARDED create, then
18180Sstevel@tonic-gate 		 * just return this error.  Otherwise, we need to
18190Sstevel@tonic-gate 		 * make sure that this wasn't a duplicate of an
18200Sstevel@tonic-gate 		 * exclusive create request.
18210Sstevel@tonic-gate 		 *
18220Sstevel@tonic-gate 		 * The assumption is made that a non-exclusive create
18230Sstevel@tonic-gate 		 * request will never return EEXIST.
18240Sstevel@tonic-gate 		 */
18250Sstevel@tonic-gate 		if (error != EEXIST || args->how.mode == GUARDED)
18260Sstevel@tonic-gate 			goto out;
18270Sstevel@tonic-gate 		/*
18280Sstevel@tonic-gate 		 * Lookup the file so that we can get a vnode for it.
18290Sstevel@tonic-gate 		 */
18307961SNatalie.Li@Sun.COM 		error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
18315331Samw 		    NULL, cr, NULL, NULL, NULL);
18320Sstevel@tonic-gate 		if (error) {
18330Sstevel@tonic-gate 			/*
18340Sstevel@tonic-gate 			 * We couldn't find the file that we thought that
18350Sstevel@tonic-gate 			 * we just created.  So, we'll just try creating
18360Sstevel@tonic-gate 			 * it again.
18370Sstevel@tonic-gate 			 */
18380Sstevel@tonic-gate 			if (error == ENOENT)
18390Sstevel@tonic-gate 				goto tryagain;
18400Sstevel@tonic-gate 			goto out;
18410Sstevel@tonic-gate 		}
18420Sstevel@tonic-gate 
18430Sstevel@tonic-gate 		/*
18440Sstevel@tonic-gate 		 * If the file is delegated to a v4 client, go ahead
18450Sstevel@tonic-gate 		 * and initiate recall, this create is a hint that a
18460Sstevel@tonic-gate 		 * conflicting v3 open has occurred.
18470Sstevel@tonic-gate 		 */
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 		if (rfs4_check_delegated(FWRITE, vp, FALSE)) {
18500Sstevel@tonic-gate 			VN_RELE(vp);
18510Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
18520Sstevel@tonic-gate 			goto out1;
18530Sstevel@tonic-gate 		}
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 		va.va_mask = AT_ALL;
18565331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 		mtime = (nfstime3 *)&args->how.createhow3_u.verf;
18590Sstevel@tonic-gate 		/* % with INT32_MAX to prevent overflows */
18600Sstevel@tonic-gate 		if (args->how.mode == EXCLUSIVE && (vap == NULL ||
18610Sstevel@tonic-gate 		    vap->va_mtime.tv_sec !=
18620Sstevel@tonic-gate 		    (mtime->seconds % INT32_MAX) ||
18630Sstevel@tonic-gate 		    vap->va_mtime.tv_nsec != mtime->nseconds)) {
18640Sstevel@tonic-gate 			VN_RELE(vp);
18650Sstevel@tonic-gate 			error = EEXIST;
18660Sstevel@tonic-gate 			goto out;
18670Sstevel@tonic-gate 		}
18680Sstevel@tonic-gate 	} else {
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 		if ((args->how.mode == UNCHECKED ||
18710Sstevel@tonic-gate 		    args->how.mode == GUARDED) &&
18720Sstevel@tonic-gate 		    args->how.createhow3_u.obj_attributes.size.set_it &&
18730Sstevel@tonic-gate 		    va.va_size == 0)
18740Sstevel@tonic-gate 			trunc = TRUE;
18750Sstevel@tonic-gate 		else
18760Sstevel@tonic-gate 			trunc = FALSE;
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 		if (rfs4_check_delegated(FWRITE, vp, trunc)) {
18790Sstevel@tonic-gate 			VN_RELE(vp);
18800Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
18810Sstevel@tonic-gate 			goto out1;
18820Sstevel@tonic-gate 		}
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 		va.va_mask = AT_ALL;
18855331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 		/*
18880Sstevel@tonic-gate 		 * We need to check to make sure that the file got
18890Sstevel@tonic-gate 		 * created to the indicated size.  If not, we do a
18900Sstevel@tonic-gate 		 * setattr to try to change the size, but we don't
18910Sstevel@tonic-gate 		 * try too hard.  This shouldn't a problem as most
18920Sstevel@tonic-gate 		 * clients will only specifiy a size of zero which
18930Sstevel@tonic-gate 		 * local file systems handle.  However, even if
18940Sstevel@tonic-gate 		 * the client does specify a non-zero size, it can
18950Sstevel@tonic-gate 		 * still recover by checking the size of the file
18960Sstevel@tonic-gate 		 * after it has created it and then issue a setattr
18970Sstevel@tonic-gate 		 * request of its own to set the size of the file.
18980Sstevel@tonic-gate 		 */
18990Sstevel@tonic-gate 		if (vap != NULL &&
19000Sstevel@tonic-gate 		    (args->how.mode == UNCHECKED ||
19010Sstevel@tonic-gate 		    args->how.mode == GUARDED) &&
19020Sstevel@tonic-gate 		    args->how.createhow3_u.obj_attributes.size.set_it &&
19030Sstevel@tonic-gate 		    vap->va_size != reqsize) {
19040Sstevel@tonic-gate 			va.va_mask = AT_SIZE;
19050Sstevel@tonic-gate 			va.va_size = reqsize;
19060Sstevel@tonic-gate 			(void) VOP_SETATTR(vp, &va, 0, cr, NULL);
19070Sstevel@tonic-gate 			va.va_mask = AT_ALL;
19085331Samw 			vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
19090Sstevel@tonic-gate 		}
19100Sstevel@tonic-gate 	}
19110Sstevel@tonic-gate 
19127961SNatalie.Li@Sun.COM 	if (name != args->where.name)
19137961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
19147961SNatalie.Li@Sun.COM 
19150Sstevel@tonic-gate #ifdef DEBUG
19160Sstevel@tonic-gate 	if (!rfs3_do_post_op_attr)
19170Sstevel@tonic-gate 		vap = NULL;
19180Sstevel@tonic-gate #endif
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate #ifdef DEBUG
19210Sstevel@tonic-gate 	if (!rfs3_do_post_op_fh3)
19220Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
19230Sstevel@tonic-gate 	else {
19240Sstevel@tonic-gate #endif
19250Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
19260Sstevel@tonic-gate 	if (error)
19270Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
19280Sstevel@tonic-gate 	else
19290Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
19300Sstevel@tonic-gate #ifdef DEBUG
19310Sstevel@tonic-gate 	}
19320Sstevel@tonic-gate #endif
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 	/*
19350Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
19360Sstevel@tonic-gate 	 */
19375331Samw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
19385331Samw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
19390Sstevel@tonic-gate 
19400Sstevel@tonic-gate 	VN_RELE(vp);
19410Sstevel@tonic-gate 	if (tvp != NULL) {
19420Sstevel@tonic-gate 		if (in_crit)
19430Sstevel@tonic-gate 			nbl_end_crit(tvp);
19440Sstevel@tonic-gate 		VN_RELE(tvp);
19450Sstevel@tonic-gate 	}
19460Sstevel@tonic-gate 
19470Sstevel@tonic-gate 	resp->status = NFS3_OK;
19480Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
19490Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
19505982Sahl 
19515982Sahl 	DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
19525982Sahl 	    cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
19535982Sahl 
19545982Sahl 	VN_RELE(dvp);
19550Sstevel@tonic-gate 	return;
19560Sstevel@tonic-gate 
19570Sstevel@tonic-gate out:
19580Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
19590Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
19600Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
19610Sstevel@tonic-gate 	} else
19620Sstevel@tonic-gate 		resp->status = puterrno3(error);
19630Sstevel@tonic-gate out1:
19645982Sahl 	DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
19655982Sahl 	    cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
19665982Sahl 
19677961SNatalie.Li@Sun.COM 	if (name != NULL && name != args->where.name)
19687961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
19697961SNatalie.Li@Sun.COM 
19700Sstevel@tonic-gate 	if (tvp != NULL) {
19710Sstevel@tonic-gate 		if (in_crit)
19720Sstevel@tonic-gate 			nbl_end_crit(tvp);
19730Sstevel@tonic-gate 		VN_RELE(tvp);
19740Sstevel@tonic-gate 	}
19750Sstevel@tonic-gate 	if (dvp != NULL)
19760Sstevel@tonic-gate 		VN_RELE(dvp);
19770Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
19780Sstevel@tonic-gate }
19790Sstevel@tonic-gate 
19801610Sthurlow void *
rfs3_create_getfh(CREATE3args * args)19810Sstevel@tonic-gate rfs3_create_getfh(CREATE3args *args)
19820Sstevel@tonic-gate {
19830Sstevel@tonic-gate 
19841610Sthurlow 	return (&args->where.dir);
19850Sstevel@tonic-gate }
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate void
rfs3_mkdir(MKDIR3args * args,MKDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)19880Sstevel@tonic-gate rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
19890Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
19900Sstevel@tonic-gate {
19910Sstevel@tonic-gate 	int error;
19920Sstevel@tonic-gate 	vnode_t *vp = NULL;
19930Sstevel@tonic-gate 	vnode_t *dvp;
19940Sstevel@tonic-gate 	struct vattr *vap;
19950Sstevel@tonic-gate 	struct vattr va;
19960Sstevel@tonic-gate 	struct vattr *dbvap;
19970Sstevel@tonic-gate 	struct vattr dbva;
19980Sstevel@tonic-gate 	struct vattr *davap;
19990Sstevel@tonic-gate 	struct vattr dava;
20007961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
20017961SNatalie.Li@Sun.COM 	char *name = NULL;
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	dbvap = NULL;
20040Sstevel@tonic-gate 	davap = NULL;
20050Sstevel@tonic-gate 
20061610Sthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
20075982Sahl 
20085982Sahl 	DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
20095982Sahl 	    cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
20105982Sahl 
20110Sstevel@tonic-gate 	if (dvp == NULL) {
20120Sstevel@tonic-gate 		error = ESTALE;
20130Sstevel@tonic-gate 		goto out;
20140Sstevel@tonic-gate 	}
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate #ifdef DEBUG
20170Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
20180Sstevel@tonic-gate 		dbva.va_mask = AT_ALL;
20195331Samw 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
20200Sstevel@tonic-gate 	} else
20210Sstevel@tonic-gate 		dbvap = NULL;
20220Sstevel@tonic-gate #else
20230Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
20245331Samw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
20250Sstevel@tonic-gate #endif
20260Sstevel@tonic-gate 	davap = dbvap;
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
20290Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
20300Sstevel@tonic-gate 		goto out1;
20310Sstevel@tonic-gate 	}
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
20340Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
20350Sstevel@tonic-gate 		goto out1;
20360Sstevel@tonic-gate 	}
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 	if (rdonly(exi, req)) {
20390Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
20400Sstevel@tonic-gate 		goto out1;
20410Sstevel@tonic-gate 	}
20420Sstevel@tonic-gate 
20434971Sjarrett 	if (is_system_labeled()) {
20444971Sjarrett 		bslabel_t *clabel = req->rq_label;
20454971Sjarrett 
20464971Sjarrett 		ASSERT(clabel != NULL);
20474971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
20484971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
20494971Sjarrett 
20504971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
20519871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
20529871SJarrett.Lu@Sun.COM 			    exi)) {
20534971Sjarrett 				resp->status = NFS3ERR_ACCES;
20544971Sjarrett 				goto out1;
20554971Sjarrett 			}
20564971Sjarrett 		}
20574971Sjarrett 	}
20584971Sjarrett 
20590Sstevel@tonic-gate 	error = sattr3_to_vattr(&args->attributes, &va);
20600Sstevel@tonic-gate 	if (error)
20610Sstevel@tonic-gate 		goto out;
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
20640Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
20650Sstevel@tonic-gate 		goto out1;
20660Sstevel@tonic-gate 	}
20670Sstevel@tonic-gate 
20687961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
20697961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, args->where.name,
20707961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
20717961SNatalie.Li@Sun.COM 
20727961SNatalie.Li@Sun.COM 	if (name == NULL) {
20737961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_INVAL;
20747961SNatalie.Li@Sun.COM 		goto out1;
20757961SNatalie.Li@Sun.COM 	}
20767961SNatalie.Li@Sun.COM 
20770Sstevel@tonic-gate 	va.va_mask |= AT_TYPE;
20780Sstevel@tonic-gate 	va.va_type = VDIR;
20790Sstevel@tonic-gate 
20807961SNatalie.Li@Sun.COM 	error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
20817961SNatalie.Li@Sun.COM 
20827961SNatalie.Li@Sun.COM 	if (name != args->where.name)
20837961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate #ifdef DEBUG
20860Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
20870Sstevel@tonic-gate 		dava.va_mask = AT_ALL;
20885331Samw 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
20890Sstevel@tonic-gate 	} else
20900Sstevel@tonic-gate 		davap = NULL;
20910Sstevel@tonic-gate #else
20920Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
20935331Samw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
20940Sstevel@tonic-gate #endif
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 	/*
20970Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
20980Sstevel@tonic-gate 	 */
20995331Samw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
21000Sstevel@tonic-gate 
21010Sstevel@tonic-gate 	if (error)
21020Sstevel@tonic-gate 		goto out;
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate #ifdef DEBUG
21050Sstevel@tonic-gate 	if (!rfs3_do_post_op_fh3)
21060Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
21070Sstevel@tonic-gate 	else {
21080Sstevel@tonic-gate #endif
21090Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
21100Sstevel@tonic-gate 	if (error)
21110Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
21120Sstevel@tonic-gate 	else
21130Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
21140Sstevel@tonic-gate #ifdef DEBUG
21150Sstevel@tonic-gate 	}
21160Sstevel@tonic-gate #endif
21170Sstevel@tonic-gate 
21180Sstevel@tonic-gate #ifdef DEBUG
21190Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
21200Sstevel@tonic-gate 		va.va_mask = AT_ALL;
21215331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
21220Sstevel@tonic-gate 	} else
21230Sstevel@tonic-gate 		vap = NULL;
21240Sstevel@tonic-gate #else
21250Sstevel@tonic-gate 	va.va_mask = AT_ALL;
21265331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
21270Sstevel@tonic-gate #endif
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 	/*
21300Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
21310Sstevel@tonic-gate 	 */
21325331Samw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 	VN_RELE(vp);
21350Sstevel@tonic-gate 
21360Sstevel@tonic-gate 	resp->status = NFS3_OK;
21370Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
21380Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
21395982Sahl 
21405982Sahl 	DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
21415982Sahl 	    cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
21425982Sahl 	VN_RELE(dvp);
21435982Sahl 
21440Sstevel@tonic-gate 	return;
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate out:
21470Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
21480Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
21490Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
21500Sstevel@tonic-gate 	} else
21510Sstevel@tonic-gate 		resp->status = puterrno3(error);
21520Sstevel@tonic-gate out1:
21535982Sahl 	DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
21545982Sahl 	    cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
21550Sstevel@tonic-gate 	if (dvp != NULL)
21560Sstevel@tonic-gate 		VN_RELE(dvp);
21570Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
21580Sstevel@tonic-gate }
21590Sstevel@tonic-gate 
21601610Sthurlow void *
rfs3_mkdir_getfh(MKDIR3args * args)21610Sstevel@tonic-gate rfs3_mkdir_getfh(MKDIR3args *args)
21620Sstevel@tonic-gate {
21630Sstevel@tonic-gate 
21641610Sthurlow 	return (&args->where.dir);
21650Sstevel@tonic-gate }
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate void
rfs3_symlink(SYMLINK3args * args,SYMLINK3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)21680Sstevel@tonic-gate rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
21690Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
21700Sstevel@tonic-gate {
21710Sstevel@tonic-gate 	int error;
21720Sstevel@tonic-gate 	vnode_t *vp;
21730Sstevel@tonic-gate 	vnode_t *dvp;
21740Sstevel@tonic-gate 	struct vattr *vap;
21750Sstevel@tonic-gate 	struct vattr va;
21760Sstevel@tonic-gate 	struct vattr *dbvap;
21770Sstevel@tonic-gate 	struct vattr dbva;
21780Sstevel@tonic-gate 	struct vattr *davap;
21790Sstevel@tonic-gate 	struct vattr dava;
21807961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
21817961SNatalie.Li@Sun.COM 	char *name = NULL;
21827961SNatalie.Li@Sun.COM 	char *symdata = NULL;
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 	dbvap = NULL;
21850Sstevel@tonic-gate 	davap = NULL;
21860Sstevel@tonic-gate 
21871610Sthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
21885982Sahl 
21895982Sahl 	DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
21905982Sahl 	    cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
21915982Sahl 
21920Sstevel@tonic-gate 	if (dvp == NULL) {
21930Sstevel@tonic-gate 		error = ESTALE;
21945982Sahl 		goto err;
21950Sstevel@tonic-gate 	}
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate #ifdef DEBUG
21980Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
21990Sstevel@tonic-gate 		dbva.va_mask = AT_ALL;
22005331Samw 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
22010Sstevel@tonic-gate 	} else
22020Sstevel@tonic-gate 		dbvap = NULL;
22030Sstevel@tonic-gate #else
22040Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
22055331Samw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
22060Sstevel@tonic-gate #endif
22070Sstevel@tonic-gate 	davap = dbvap;
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
22100Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
22115982Sahl 		goto err1;
22120Sstevel@tonic-gate 	}
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
22150Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
22165982Sahl 		goto err1;
22170Sstevel@tonic-gate 	}
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 	if (rdonly(exi, req)) {
22200Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
22215982Sahl 		goto err1;
22220Sstevel@tonic-gate 	}
22230Sstevel@tonic-gate 
22244971Sjarrett 	if (is_system_labeled()) {
22254971Sjarrett 		bslabel_t *clabel = req->rq_label;
22264971Sjarrett 
22274971Sjarrett 		ASSERT(clabel != NULL);
22284971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
22294971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
22304971Sjarrett 
22314971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
22329871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
22339871SJarrett.Lu@Sun.COM 			    exi)) {
22344971Sjarrett 				resp->status = NFS3ERR_ACCES;
22355982Sahl 				goto err1;
22364971Sjarrett 			}
22374971Sjarrett 		}
22384971Sjarrett 	}
22394971Sjarrett 
22400Sstevel@tonic-gate 	error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
22410Sstevel@tonic-gate 	if (error)
22425982Sahl 		goto err;
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
22450Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
22465982Sahl 		goto err1;
22470Sstevel@tonic-gate 	}
22480Sstevel@tonic-gate 
22490Sstevel@tonic-gate 	if (args->symlink.symlink_data == nfs3nametoolong) {
22500Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
22515982Sahl 		goto err1;
22520Sstevel@tonic-gate 	}
22530Sstevel@tonic-gate 
22547961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
22557961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, args->where.name,
22567961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
22577961SNatalie.Li@Sun.COM 
22587961SNatalie.Li@Sun.COM 	if (name == NULL) {
22597961SNatalie.Li@Sun.COM 		/* This is really a Solaris EILSEQ */
22607961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_INVAL;
22617961SNatalie.Li@Sun.COM 		goto err1;
22627961SNatalie.Li@Sun.COM 	}
22637961SNatalie.Li@Sun.COM 
22647961SNatalie.Li@Sun.COM 	symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
22657961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
22667961SNatalie.Li@Sun.COM 	if (symdata == NULL) {
22677961SNatalie.Li@Sun.COM 		/* This is really a Solaris EILSEQ */
22687961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_INVAL;
22697961SNatalie.Li@Sun.COM 		goto err1;
22707961SNatalie.Li@Sun.COM 	}
22717961SNatalie.Li@Sun.COM 
22727961SNatalie.Li@Sun.COM 
22730Sstevel@tonic-gate 	va.va_mask |= AT_TYPE;
22740Sstevel@tonic-gate 	va.va_type = VLNK;
22750Sstevel@tonic-gate 
22767961SNatalie.Li@Sun.COM 	error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate #ifdef DEBUG
22790Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
22800Sstevel@tonic-gate 		dava.va_mask = AT_ALL;
22815331Samw 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
22820Sstevel@tonic-gate 	} else
22830Sstevel@tonic-gate 		davap = NULL;
22840Sstevel@tonic-gate #else
22850Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
22865331Samw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
22870Sstevel@tonic-gate #endif
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	if (error)
22905982Sahl 		goto err;
22910Sstevel@tonic-gate 
22927961SNatalie.Li@Sun.COM 	error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
22935599Sjwahlig 	    NULL, NULL, NULL);
22940Sstevel@tonic-gate 
22950Sstevel@tonic-gate 	/*
22960Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
22970Sstevel@tonic-gate 	 */
22985331Samw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 	resp->status = NFS3_OK;
23020Sstevel@tonic-gate 	if (error) {
23030Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
23040Sstevel@tonic-gate 		vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
23050Sstevel@tonic-gate 		vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
23065982Sahl 		goto out;
23070Sstevel@tonic-gate 	}
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate #ifdef DEBUG
23100Sstevel@tonic-gate 	if (!rfs3_do_post_op_fh3)
23110Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
23120Sstevel@tonic-gate 	else {
23130Sstevel@tonic-gate #endif
23140Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
23150Sstevel@tonic-gate 	if (error)
23160Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
23170Sstevel@tonic-gate 	else
23180Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
23190Sstevel@tonic-gate #ifdef DEBUG
23200Sstevel@tonic-gate 	}
23210Sstevel@tonic-gate #endif
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate #ifdef DEBUG
23240Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
23250Sstevel@tonic-gate 		va.va_mask = AT_ALL;
23265331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
23270Sstevel@tonic-gate 	} else
23280Sstevel@tonic-gate 		vap = NULL;
23290Sstevel@tonic-gate #else
23300Sstevel@tonic-gate 	va.va_mask = AT_ALL;
23315331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
23320Sstevel@tonic-gate #endif
23330Sstevel@tonic-gate 
23340Sstevel@tonic-gate 	/*
23350Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
23360Sstevel@tonic-gate 	 */
23375331Samw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	VN_RELE(vp);
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
23420Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
23435982Sahl 	goto out;
23445982Sahl 
23455982Sahl err:
23460Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
23470Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
23480Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
23490Sstevel@tonic-gate 	} else
23500Sstevel@tonic-gate 		resp->status = puterrno3(error);
23515982Sahl err1:
23525982Sahl 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
23535982Sahl out:
23547961SNatalie.Li@Sun.COM 	if (name != NULL && name != args->where.name)
23557961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
23567961SNatalie.Li@Sun.COM 	if (symdata != NULL && symdata != args->symlink.symlink_data)
23577961SNatalie.Li@Sun.COM 		kmem_free(symdata, MAXPATHLEN + 1);
23587961SNatalie.Li@Sun.COM 
23595982Sahl 	DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
23605982Sahl 	    cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
23615982Sahl 
23620Sstevel@tonic-gate 	if (dvp != NULL)
23630Sstevel@tonic-gate 		VN_RELE(dvp);
23640Sstevel@tonic-gate }
23650Sstevel@tonic-gate 
23661610Sthurlow void *
rfs3_symlink_getfh(SYMLINK3args * args)23670Sstevel@tonic-gate rfs3_symlink_getfh(SYMLINK3args *args)
23680Sstevel@tonic-gate {
23690Sstevel@tonic-gate 
23701610Sthurlow 	return (&args->where.dir);
23710Sstevel@tonic-gate }
23720Sstevel@tonic-gate 
23730Sstevel@tonic-gate void
rfs3_mknod(MKNOD3args * args,MKNOD3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)23740Sstevel@tonic-gate rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
23750Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
23760Sstevel@tonic-gate {
23770Sstevel@tonic-gate 	int error;
23780Sstevel@tonic-gate 	vnode_t *vp;
23796402Sgt29601 	vnode_t *realvp;
23800Sstevel@tonic-gate 	vnode_t *dvp;
23810Sstevel@tonic-gate 	struct vattr *vap;
23820Sstevel@tonic-gate 	struct vattr va;
23830Sstevel@tonic-gate 	struct vattr *dbvap;
23840Sstevel@tonic-gate 	struct vattr dbva;
23850Sstevel@tonic-gate 	struct vattr *davap;
23860Sstevel@tonic-gate 	struct vattr dava;
23870Sstevel@tonic-gate 	int mode;
23880Sstevel@tonic-gate 	enum vcexcl excl;
23897961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
23907961SNatalie.Li@Sun.COM 	char *name = NULL;
23910Sstevel@tonic-gate 
23920Sstevel@tonic-gate 	dbvap = NULL;
23930Sstevel@tonic-gate 	davap = NULL;
23940Sstevel@tonic-gate 
23951610Sthurlow 	dvp = nfs3_fhtovp(&args->where.dir, exi);
23965982Sahl 
23975982Sahl 	DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
23985982Sahl 	    cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
23995982Sahl 
24000Sstevel@tonic-gate 	if (dvp == NULL) {
24010Sstevel@tonic-gate 		error = ESTALE;
24020Sstevel@tonic-gate 		goto out;
24030Sstevel@tonic-gate 	}
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate #ifdef DEBUG
24060Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
24070Sstevel@tonic-gate 		dbva.va_mask = AT_ALL;
24085331Samw 		dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
24090Sstevel@tonic-gate 	} else
24100Sstevel@tonic-gate 		dbvap = NULL;
24110Sstevel@tonic-gate #else
24120Sstevel@tonic-gate 	dbva.va_mask = AT_ALL;
24135331Samw 	dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
24140Sstevel@tonic-gate #endif
24150Sstevel@tonic-gate 	davap = dbvap;
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate 	if (args->where.name == nfs3nametoolong) {
24180Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
24190Sstevel@tonic-gate 		goto out1;
24200Sstevel@tonic-gate 	}
24210Sstevel@tonic-gate 
24220Sstevel@tonic-gate 	if (args->where.name == NULL || *(args->where.name) == '\0') {
24230Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
24240Sstevel@tonic-gate 		goto out1;
24250Sstevel@tonic-gate 	}
24260Sstevel@tonic-gate 
24270Sstevel@tonic-gate 	if (rdonly(exi, req)) {
24280Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
24290Sstevel@tonic-gate 		goto out1;
24300Sstevel@tonic-gate 	}
24310Sstevel@tonic-gate 
24324971Sjarrett 	if (is_system_labeled()) {
24334971Sjarrett 		bslabel_t *clabel = req->rq_label;
24344971Sjarrett 
24354971Sjarrett 		ASSERT(clabel != NULL);
24364971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
24374971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
24384971Sjarrett 
24394971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
24409871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
24419871SJarrett.Lu@Sun.COM 			    exi)) {
24424971Sjarrett 				resp->status = NFS3ERR_ACCES;
24434971Sjarrett 				goto out1;
24444971Sjarrett 			}
24454971Sjarrett 		}
24464971Sjarrett 	}
24474971Sjarrett 
24480Sstevel@tonic-gate 	switch (args->what.type) {
24490Sstevel@tonic-gate 	case NF3CHR:
24500Sstevel@tonic-gate 	case NF3BLK:
24510Sstevel@tonic-gate 		error = sattr3_to_vattr(
24520Sstevel@tonic-gate 		    &args->what.mknoddata3_u.device.dev_attributes, &va);
24530Sstevel@tonic-gate 		if (error)
24540Sstevel@tonic-gate 			goto out;
24550Sstevel@tonic-gate 		if (secpolicy_sys_devices(cr) != 0) {
24560Sstevel@tonic-gate 			resp->status = NFS3ERR_PERM;
24570Sstevel@tonic-gate 			goto out1;
24580Sstevel@tonic-gate 		}
24590Sstevel@tonic-gate 		if (args->what.type == NF3CHR)
24600Sstevel@tonic-gate 			va.va_type = VCHR;
24610Sstevel@tonic-gate 		else
24620Sstevel@tonic-gate 			va.va_type = VBLK;
24630Sstevel@tonic-gate 		va.va_rdev = makedevice(
24640Sstevel@tonic-gate 		    args->what.mknoddata3_u.device.spec.specdata1,
24650Sstevel@tonic-gate 		    args->what.mknoddata3_u.device.spec.specdata2);
24660Sstevel@tonic-gate 		va.va_mask |= AT_TYPE | AT_RDEV;
24670Sstevel@tonic-gate 		break;
24680Sstevel@tonic-gate 	case NF3SOCK:
24690Sstevel@tonic-gate 		error = sattr3_to_vattr(
24700Sstevel@tonic-gate 		    &args->what.mknoddata3_u.pipe_attributes, &va);
24710Sstevel@tonic-gate 		if (error)
24720Sstevel@tonic-gate 			goto out;
24730Sstevel@tonic-gate 		va.va_type = VSOCK;
24740Sstevel@tonic-gate 		va.va_mask |= AT_TYPE;
24750Sstevel@tonic-gate 		break;
24760Sstevel@tonic-gate 	case NF3FIFO:
24770Sstevel@tonic-gate 		error = sattr3_to_vattr(
24780Sstevel@tonic-gate 		    &args->what.mknoddata3_u.pipe_attributes, &va);
24790Sstevel@tonic-gate 		if (error)
24800Sstevel@tonic-gate 			goto out;
24810Sstevel@tonic-gate 		va.va_type = VFIFO;
24820Sstevel@tonic-gate 		va.va_mask |= AT_TYPE;
24830Sstevel@tonic-gate 		break;
24840Sstevel@tonic-gate 	default:
24850Sstevel@tonic-gate 		resp->status = NFS3ERR_BADTYPE;
24860Sstevel@tonic-gate 		goto out1;
24870Sstevel@tonic-gate 	}
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate 	/*
24900Sstevel@tonic-gate 	 * Must specify the mode.
24910Sstevel@tonic-gate 	 */
24920Sstevel@tonic-gate 	if (!(va.va_mask & AT_MODE)) {
24930Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
24940Sstevel@tonic-gate 		goto out1;
24950Sstevel@tonic-gate 	}
24960Sstevel@tonic-gate 
24977961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
24987961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, args->where.name,
24997961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
25007961SNatalie.Li@Sun.COM 
25017961SNatalie.Li@Sun.COM 	if (name == NULL) {
25027961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_INVAL;
25037961SNatalie.Li@Sun.COM 		goto out1;
25047961SNatalie.Li@Sun.COM 	}
25057961SNatalie.Li@Sun.COM 
25060Sstevel@tonic-gate 	excl = EXCL;
25070Sstevel@tonic-gate 
25080Sstevel@tonic-gate 	mode = 0;
25090Sstevel@tonic-gate 
25107961SNatalie.Li@Sun.COM 	error = VOP_CREATE(dvp, name, &va, excl, mode,
25115331Samw 	    &vp, cr, 0, NULL, NULL);
25120Sstevel@tonic-gate 
25137961SNatalie.Li@Sun.COM 	if (name != args->where.name)
25147961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
25157961SNatalie.Li@Sun.COM 
25160Sstevel@tonic-gate #ifdef DEBUG
25170Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
25180Sstevel@tonic-gate 		dava.va_mask = AT_ALL;
25195331Samw 		davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
25200Sstevel@tonic-gate 	} else
25210Sstevel@tonic-gate 		davap = NULL;
25220Sstevel@tonic-gate #else
25230Sstevel@tonic-gate 	dava.va_mask = AT_ALL;
25245331Samw 	davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
25250Sstevel@tonic-gate #endif
25260Sstevel@tonic-gate 
25270Sstevel@tonic-gate 	/*
25280Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
25290Sstevel@tonic-gate 	 */
25305331Samw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
25310Sstevel@tonic-gate 
25320Sstevel@tonic-gate 	if (error)
25330Sstevel@tonic-gate 		goto out;
25340Sstevel@tonic-gate 
25350Sstevel@tonic-gate 	resp->status = NFS3_OK;
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate #ifdef DEBUG
25380Sstevel@tonic-gate 	if (!rfs3_do_post_op_fh3)
25390Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
25400Sstevel@tonic-gate 	else {
25410Sstevel@tonic-gate #endif
25420Sstevel@tonic-gate 	error = makefh3(&resp->resok.obj.handle, vp, exi);
25430Sstevel@tonic-gate 	if (error)
25440Sstevel@tonic-gate 		resp->resok.obj.handle_follows = FALSE;
25450Sstevel@tonic-gate 	else
25460Sstevel@tonic-gate 		resp->resok.obj.handle_follows = TRUE;
25470Sstevel@tonic-gate #ifdef DEBUG
25480Sstevel@tonic-gate 	}
25490Sstevel@tonic-gate #endif
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate #ifdef DEBUG
25520Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
25530Sstevel@tonic-gate 		va.va_mask = AT_ALL;
25545331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
25550Sstevel@tonic-gate 	} else
25560Sstevel@tonic-gate 		vap = NULL;
25570Sstevel@tonic-gate #else
25580Sstevel@tonic-gate 	va.va_mask = AT_ALL;
25595331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
25600Sstevel@tonic-gate #endif
25610Sstevel@tonic-gate 
25620Sstevel@tonic-gate 	/*
25630Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
25646402Sgt29601 	 *
25656402Sgt29601 	 * if a underlying vp exists, pass it to VOP_FSYNC
25660Sstevel@tonic-gate 	 */
25676402Sgt29601 	if (VOP_REALVP(vp, &realvp, NULL) == 0)
25686402Sgt29601 		(void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
25696402Sgt29601 	else
25706402Sgt29601 		(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate 	VN_RELE(vp);
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
25750Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
25765982Sahl 	DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
25775982Sahl 	    cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
25785982Sahl 	VN_RELE(dvp);
25790Sstevel@tonic-gate 	return;
25800Sstevel@tonic-gate 
25810Sstevel@tonic-gate out:
25820Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
25830Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
25840Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
25850Sstevel@tonic-gate 	} else
25860Sstevel@tonic-gate 		resp->status = puterrno3(error);
25870Sstevel@tonic-gate out1:
25885982Sahl 	DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
25895982Sahl 	    cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
25900Sstevel@tonic-gate 	if (dvp != NULL)
25910Sstevel@tonic-gate 		VN_RELE(dvp);
25920Sstevel@tonic-gate 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate 
25951610Sthurlow void *
rfs3_mknod_getfh(MKNOD3args * args)25960Sstevel@tonic-gate rfs3_mknod_getfh(MKNOD3args *args)
25970Sstevel@tonic-gate {
25980Sstevel@tonic-gate 
25991610Sthurlow 	return (&args->where.dir);
26000Sstevel@tonic-gate }
26010Sstevel@tonic-gate 
26020Sstevel@tonic-gate void
rfs3_remove(REMOVE3args * args,REMOVE3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)26030Sstevel@tonic-gate rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
26040Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
26050Sstevel@tonic-gate {
26060Sstevel@tonic-gate 	int error = 0;
26070Sstevel@tonic-gate 	vnode_t *vp;
26080Sstevel@tonic-gate 	struct vattr *bvap;
26090Sstevel@tonic-gate 	struct vattr bva;
26100Sstevel@tonic-gate 	struct vattr *avap;
26110Sstevel@tonic-gate 	struct vattr ava;
26120Sstevel@tonic-gate 	vnode_t *targvp = NULL;
26137961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
26147961SNatalie.Li@Sun.COM 	char *name = NULL;
26150Sstevel@tonic-gate 
26160Sstevel@tonic-gate 	bvap = NULL;
26170Sstevel@tonic-gate 	avap = NULL;
26180Sstevel@tonic-gate 
26191610Sthurlow 	vp = nfs3_fhtovp(&args->object.dir, exi);
26205982Sahl 
26215982Sahl 	DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
26225982Sahl 	    cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
26235982Sahl 
26240Sstevel@tonic-gate 	if (vp == NULL) {
26250Sstevel@tonic-gate 		error = ESTALE;
26265982Sahl 		goto err;
26270Sstevel@tonic-gate 	}
26280Sstevel@tonic-gate 
26290Sstevel@tonic-gate #ifdef DEBUG
26300Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
26310Sstevel@tonic-gate 		bva.va_mask = AT_ALL;
26325331Samw 		bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
26330Sstevel@tonic-gate 	} else
26340Sstevel@tonic-gate 		bvap = NULL;
26350Sstevel@tonic-gate #else
26360Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
26375331Samw 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
26380Sstevel@tonic-gate #endif
26390Sstevel@tonic-gate 	avap = bvap;
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
26420Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
26435982Sahl 		goto err1;
26440Sstevel@tonic-gate 	}
26450Sstevel@tonic-gate 
26460Sstevel@tonic-gate 	if (args->object.name == nfs3nametoolong) {
26470Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
26485982Sahl 		goto err1;
26490Sstevel@tonic-gate 	}
26500Sstevel@tonic-gate 
26510Sstevel@tonic-gate 	if (args->object.name == NULL || *(args->object.name) == '\0') {
26520Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
26535982Sahl 		goto err1;
26540Sstevel@tonic-gate 	}
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate 	if (rdonly(exi, req)) {
26570Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
26585982Sahl 		goto err1;
26590Sstevel@tonic-gate 	}
26600Sstevel@tonic-gate 
26614971Sjarrett 	if (is_system_labeled()) {
26624971Sjarrett 		bslabel_t *clabel = req->rq_label;
26634971Sjarrett 
26644971Sjarrett 		ASSERT(clabel != NULL);
26654971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *,
26664971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
26674971Sjarrett 
26684971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
26699871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
26709871SJarrett.Lu@Sun.COM 			    exi)) {
26714971Sjarrett 				resp->status = NFS3ERR_ACCES;
26725982Sahl 				goto err1;
26734971Sjarrett 			}
26744971Sjarrett 		}
26754971Sjarrett 	}
26764971Sjarrett 
26777961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
26787961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, args->object.name,
26797961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
26807961SNatalie.Li@Sun.COM 
26817961SNatalie.Li@Sun.COM 	if (name == NULL) {
26827961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_INVAL;
26837961SNatalie.Li@Sun.COM 		goto err1;
26847961SNatalie.Li@Sun.COM 	}
26857961SNatalie.Li@Sun.COM 
26860Sstevel@tonic-gate 	/*
26870Sstevel@tonic-gate 	 * Check for a conflict with a non-blocking mandatory share
26880Sstevel@tonic-gate 	 * reservation and V4 delegations
26890Sstevel@tonic-gate 	 */
26907961SNatalie.Li@Sun.COM 	error = VOP_LOOKUP(vp, name, &targvp, NULL, 0,
26915599Sjwahlig 	    NULL, cr, NULL, NULL, NULL);
26920Sstevel@tonic-gate 	if (error != 0)
26935982Sahl 		goto err;
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate 	if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
26960Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
26975982Sahl 		goto err1;
26980Sstevel@tonic-gate 	}
26990Sstevel@tonic-gate 
27000Sstevel@tonic-gate 	if (!nbl_need_check(targvp)) {
27017961SNatalie.Li@Sun.COM 		error = VOP_REMOVE(vp, name, cr, NULL, 0);
27020Sstevel@tonic-gate 	} else {
27030Sstevel@tonic-gate 		nbl_start_crit(targvp, RW_READER);
27045331Samw 		if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
27050Sstevel@tonic-gate 			error = EACCES;
27060Sstevel@tonic-gate 		} else {
27077961SNatalie.Li@Sun.COM 			error = VOP_REMOVE(vp, name, cr, NULL, 0);
27080Sstevel@tonic-gate 		}
27090Sstevel@tonic-gate 		nbl_end_crit(targvp);
27100Sstevel@tonic-gate 	}
27110Sstevel@tonic-gate 	VN_RELE(targvp);
27120Sstevel@tonic-gate 	targvp = NULL;
27130Sstevel@tonic-gate 
27140Sstevel@tonic-gate #ifdef DEBUG
27150Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
27160Sstevel@tonic-gate 		ava.va_mask = AT_ALL;
27175331Samw 		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
27180Sstevel@tonic-gate 	} else
27190Sstevel@tonic-gate 		avap = NULL;
27200Sstevel@tonic-gate #else
27210Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
27225331Samw 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
27230Sstevel@tonic-gate #endif
27240Sstevel@tonic-gate 
27250Sstevel@tonic-gate 	/*
27260Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
27270Sstevel@tonic-gate 	 */
27285331Samw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
27290Sstevel@tonic-gate 
27300Sstevel@tonic-gate 	if (error)
27315982Sahl 		goto err;
27320Sstevel@tonic-gate 
27330Sstevel@tonic-gate 	resp->status = NFS3_OK;
27340Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
27355982Sahl 	goto out;
27365982Sahl 
27375982Sahl err:
27380Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
27390Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
27400Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
27410Sstevel@tonic-gate 	} else
27420Sstevel@tonic-gate 		resp->status = puterrno3(error);
27435982Sahl err1:
27445982Sahl 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
27455982Sahl out:
27465982Sahl 	DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
27475982Sahl 	    cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
27487961SNatalie.Li@Sun.COM 
27497961SNatalie.Li@Sun.COM 	if (name != NULL && name != args->object.name)
27507961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
27517961SNatalie.Li@Sun.COM 
27520Sstevel@tonic-gate 	if (vp != NULL)
27530Sstevel@tonic-gate 		VN_RELE(vp);
27540Sstevel@tonic-gate }
27550Sstevel@tonic-gate 
27561610Sthurlow void *
rfs3_remove_getfh(REMOVE3args * args)27570Sstevel@tonic-gate rfs3_remove_getfh(REMOVE3args *args)
27580Sstevel@tonic-gate {
27590Sstevel@tonic-gate 
27601610Sthurlow 	return (&args->object.dir);
27610Sstevel@tonic-gate }
27620Sstevel@tonic-gate 
27630Sstevel@tonic-gate void
rfs3_rmdir(RMDIR3args * args,RMDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)27640Sstevel@tonic-gate rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
27650Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
27660Sstevel@tonic-gate {
27670Sstevel@tonic-gate 	int error;
27680Sstevel@tonic-gate 	vnode_t *vp;
27690Sstevel@tonic-gate 	struct vattr *bvap;
27700Sstevel@tonic-gate 	struct vattr bva;
27710Sstevel@tonic-gate 	struct vattr *avap;
27720Sstevel@tonic-gate 	struct vattr ava;
27737961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
27747961SNatalie.Li@Sun.COM 	char *name = NULL;
27750Sstevel@tonic-gate 
27760Sstevel@tonic-gate 	bvap = NULL;
27770Sstevel@tonic-gate 	avap = NULL;
27780Sstevel@tonic-gate 
27791610Sthurlow 	vp = nfs3_fhtovp(&args->object.dir, exi);
27805982Sahl 
27815982Sahl 	DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
27825982Sahl 	    cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
27835982Sahl 
27840Sstevel@tonic-gate 	if (vp == NULL) {
27850Sstevel@tonic-gate 		error = ESTALE;
27865982Sahl 		goto err;
27870Sstevel@tonic-gate 	}
27880Sstevel@tonic-gate 
27890Sstevel@tonic-gate #ifdef DEBUG
27900Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
27910Sstevel@tonic-gate 		bva.va_mask = AT_ALL;
27925331Samw 		bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
27930Sstevel@tonic-gate 	} else
27940Sstevel@tonic-gate 		bvap = NULL;
27950Sstevel@tonic-gate #else
27960Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
27975331Samw 	bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
27980Sstevel@tonic-gate #endif
27990Sstevel@tonic-gate 	avap = bvap;
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
28020Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
28035982Sahl 		goto err1;
28040Sstevel@tonic-gate 	}
28050Sstevel@tonic-gate 
28060Sstevel@tonic-gate 	if (args->object.name == nfs3nametoolong) {
28070Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
28085982Sahl 		goto err1;
28090Sstevel@tonic-gate 	}
28100Sstevel@tonic-gate 
28110Sstevel@tonic-gate 	if (args->object.name == NULL || *(args->object.name) == '\0') {
28120Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
28135982Sahl 		goto err1;
28140Sstevel@tonic-gate 	}
28150Sstevel@tonic-gate 
28160Sstevel@tonic-gate 	if (rdonly(exi, req)) {
28170Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
28185982Sahl 		goto err1;
28190Sstevel@tonic-gate 	}
28200Sstevel@tonic-gate 
28214971Sjarrett 	if (is_system_labeled()) {
28224971Sjarrett 		bslabel_t *clabel = req->rq_label;
28234971Sjarrett 
28244971Sjarrett 		ASSERT(clabel != NULL);
28254971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *,
28264971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
28274971Sjarrett 
28284971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
28299871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
28309871SJarrett.Lu@Sun.COM 			    exi)) {
28314971Sjarrett 				resp->status = NFS3ERR_ACCES;
28325982Sahl 				goto err1;
28334971Sjarrett 			}
28344971Sjarrett 		}
28354971Sjarrett 	}
28364971Sjarrett 
28377961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
28387961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, args->object.name,
28397961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
28407961SNatalie.Li@Sun.COM 
28417961SNatalie.Li@Sun.COM 	if (name == NULL) {
28427961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_INVAL;
28437961SNatalie.Li@Sun.COM 		goto err1;
28447961SNatalie.Li@Sun.COM 	}
28457961SNatalie.Li@Sun.COM 
28467961SNatalie.Li@Sun.COM 	error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
28477961SNatalie.Li@Sun.COM 
28487961SNatalie.Li@Sun.COM 	if (name != args->object.name)
28497961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
28500Sstevel@tonic-gate 
28510Sstevel@tonic-gate #ifdef DEBUG
28520Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
28530Sstevel@tonic-gate 		ava.va_mask = AT_ALL;
28545331Samw 		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
28550Sstevel@tonic-gate 	} else
28560Sstevel@tonic-gate 		avap = NULL;
28570Sstevel@tonic-gate #else
28580Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
28595331Samw 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
28600Sstevel@tonic-gate #endif
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 	/*
28630Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
28640Sstevel@tonic-gate 	 */
28655331Samw 	(void) VOP_FSYNC(vp, 0, cr, NULL);
28660Sstevel@tonic-gate 
28670Sstevel@tonic-gate 	if (error) {
28680Sstevel@tonic-gate 		/*
28690Sstevel@tonic-gate 		 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
28700Sstevel@tonic-gate 		 * if the directory is not empty.  A System V NFS server
28710Sstevel@tonic-gate 		 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
28720Sstevel@tonic-gate 		 * over the wire.
28730Sstevel@tonic-gate 		 */
28740Sstevel@tonic-gate 		if (error == EEXIST)
28750Sstevel@tonic-gate 			error = ENOTEMPTY;
28765982Sahl 		goto err;
28770Sstevel@tonic-gate 	}
28780Sstevel@tonic-gate 
28790Sstevel@tonic-gate 	resp->status = NFS3_OK;
28800Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
28815982Sahl 	goto out;
28825982Sahl 
28835982Sahl err:
28840Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
28850Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
28860Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
28870Sstevel@tonic-gate 	} else
28880Sstevel@tonic-gate 		resp->status = puterrno3(error);
28895982Sahl err1:
28905982Sahl 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
28915982Sahl out:
28925982Sahl 	DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
28935982Sahl 	    cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
28940Sstevel@tonic-gate 	if (vp != NULL)
28950Sstevel@tonic-gate 		VN_RELE(vp);
28965982Sahl 
28970Sstevel@tonic-gate }
28980Sstevel@tonic-gate 
28991610Sthurlow void *
rfs3_rmdir_getfh(RMDIR3args * args)29000Sstevel@tonic-gate rfs3_rmdir_getfh(RMDIR3args *args)
29010Sstevel@tonic-gate {
29020Sstevel@tonic-gate 
29031610Sthurlow 	return (&args->object.dir);
29040Sstevel@tonic-gate }
29050Sstevel@tonic-gate 
29060Sstevel@tonic-gate void
rfs3_rename(RENAME3args * args,RENAME3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)29070Sstevel@tonic-gate rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
29080Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
29090Sstevel@tonic-gate {
29100Sstevel@tonic-gate 	int error = 0;
29110Sstevel@tonic-gate 	vnode_t *fvp;
29120Sstevel@tonic-gate 	vnode_t *tvp;
29130Sstevel@tonic-gate 	vnode_t *targvp;
29140Sstevel@tonic-gate 	struct vattr *fbvap;
29150Sstevel@tonic-gate 	struct vattr fbva;
29160Sstevel@tonic-gate 	struct vattr *favap;
29170Sstevel@tonic-gate 	struct vattr fava;
29180Sstevel@tonic-gate 	struct vattr *tbvap;
29190Sstevel@tonic-gate 	struct vattr tbva;
29200Sstevel@tonic-gate 	struct vattr *tavap;
29210Sstevel@tonic-gate 	struct vattr tava;
29221610Sthurlow 	nfs_fh3 *fh3;
29230Sstevel@tonic-gate 	struct exportinfo *to_exi;
29240Sstevel@tonic-gate 	vnode_t *srcvp = NULL;
29254971Sjarrett 	bslabel_t *clabel;
29267961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
29277961SNatalie.Li@Sun.COM 	char *name = NULL;
29287961SNatalie.Li@Sun.COM 	char *toname = NULL;
29290Sstevel@tonic-gate 
29300Sstevel@tonic-gate 	fbvap = NULL;
29310Sstevel@tonic-gate 	favap = NULL;
29320Sstevel@tonic-gate 	tbvap = NULL;
29330Sstevel@tonic-gate 	tavap = NULL;
29340Sstevel@tonic-gate 	tvp = NULL;
29350Sstevel@tonic-gate 
29361610Sthurlow 	fvp = nfs3_fhtovp(&args->from.dir, exi);
29375982Sahl 
29385982Sahl 	DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
29395982Sahl 	    cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
29405982Sahl 
29410Sstevel@tonic-gate 	if (fvp == NULL) {
29420Sstevel@tonic-gate 		error = ESTALE;
29435982Sahl 		goto err;
29440Sstevel@tonic-gate 	}
29450Sstevel@tonic-gate 
29464971Sjarrett 	if (is_system_labeled()) {
29474971Sjarrett 		clabel = req->rq_label;
29484971Sjarrett 		ASSERT(clabel != NULL);
29494971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
29504971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
29514971Sjarrett 
29524971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
29539871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
29549871SJarrett.Lu@Sun.COM 			    exi)) {
29554971Sjarrett 				resp->status = NFS3ERR_ACCES;
29565982Sahl 				goto err1;
29574971Sjarrett 			}
29584971Sjarrett 		}
29594971Sjarrett 	}
29604971Sjarrett 
29610Sstevel@tonic-gate #ifdef DEBUG
29620Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
29630Sstevel@tonic-gate 		fbva.va_mask = AT_ALL;
29645331Samw 		fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
29650Sstevel@tonic-gate 	} else
29660Sstevel@tonic-gate 		fbvap = NULL;
29670Sstevel@tonic-gate #else
29680Sstevel@tonic-gate 	fbva.va_mask = AT_ALL;
29695331Samw 	fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
29700Sstevel@tonic-gate #endif
29710Sstevel@tonic-gate 	favap = fbvap;
29720Sstevel@tonic-gate 
29731610Sthurlow 	fh3 = &args->to.dir;
29741610Sthurlow 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
29750Sstevel@tonic-gate 	if (to_exi == NULL) {
29760Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
29775982Sahl 		goto err1;
29780Sstevel@tonic-gate 	}
29790Sstevel@tonic-gate 	exi_rele(to_exi);
29800Sstevel@tonic-gate 
29810Sstevel@tonic-gate 	if (to_exi != exi) {
29820Sstevel@tonic-gate 		resp->status = NFS3ERR_XDEV;
29835982Sahl 		goto err1;
29840Sstevel@tonic-gate 	}
29850Sstevel@tonic-gate 
29861610Sthurlow 	tvp = nfs3_fhtovp(&args->to.dir, exi);
29870Sstevel@tonic-gate 	if (tvp == NULL) {
29880Sstevel@tonic-gate 		error = ESTALE;
29895982Sahl 		goto err;
29900Sstevel@tonic-gate 	}
29910Sstevel@tonic-gate 
29920Sstevel@tonic-gate #ifdef DEBUG
29930Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
29940Sstevel@tonic-gate 		tbva.va_mask = AT_ALL;
29955331Samw 		tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
29960Sstevel@tonic-gate 	} else
29970Sstevel@tonic-gate 		tbvap = NULL;
29980Sstevel@tonic-gate #else
29990Sstevel@tonic-gate 	tbva.va_mask = AT_ALL;
30005331Samw 	tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
30010Sstevel@tonic-gate #endif
30020Sstevel@tonic-gate 	tavap = tbvap;
30030Sstevel@tonic-gate 
30040Sstevel@tonic-gate 	if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
30050Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
30065982Sahl 		goto err1;
30070Sstevel@tonic-gate 	}
30080Sstevel@tonic-gate 
30090Sstevel@tonic-gate 	if (args->from.name == nfs3nametoolong ||
30100Sstevel@tonic-gate 	    args->to.name == nfs3nametoolong) {
30110Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
30125982Sahl 		goto err1;
30130Sstevel@tonic-gate 	}
30140Sstevel@tonic-gate 	if (args->from.name == NULL || *(args->from.name) == '\0' ||
30150Sstevel@tonic-gate 	    args->to.name == NULL || *(args->to.name) == '\0') {
30160Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
30175982Sahl 		goto err1;
30180Sstevel@tonic-gate 	}
30190Sstevel@tonic-gate 
30200Sstevel@tonic-gate 	if (rdonly(exi, req)) {
30210Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
30225982Sahl 		goto err1;
30230Sstevel@tonic-gate 	}
30240Sstevel@tonic-gate 
30254971Sjarrett 	if (is_system_labeled()) {
30264971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
30279871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
30289871SJarrett.Lu@Sun.COM 			    exi)) {
30294971Sjarrett 				resp->status = NFS3ERR_ACCES;
30305982Sahl 				goto err1;
30314971Sjarrett 			}
30324971Sjarrett 		}
30334971Sjarrett 	}
30344971Sjarrett 
30357961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
30367961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, args->from.name,
30377961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
30387961SNatalie.Li@Sun.COM 
30397961SNatalie.Li@Sun.COM 	if (name == NULL) {
30407961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_INVAL;
30417961SNatalie.Li@Sun.COM 		goto err1;
30427961SNatalie.Li@Sun.COM 	}
30437961SNatalie.Li@Sun.COM 
30447961SNatalie.Li@Sun.COM 	toname = nfscmd_convname(ca, exi, args->to.name,
30457961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
30467961SNatalie.Li@Sun.COM 
30477961SNatalie.Li@Sun.COM 	if (toname == NULL) {
30487961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_INVAL;
30497961SNatalie.Li@Sun.COM 		goto err1;
30507961SNatalie.Li@Sun.COM 	}
30517961SNatalie.Li@Sun.COM 
30520Sstevel@tonic-gate 	/*
30530Sstevel@tonic-gate 	 * Check for a conflict with a non-blocking mandatory share
30540Sstevel@tonic-gate 	 * reservation or V4 delegations.
30550Sstevel@tonic-gate 	 */
30567961SNatalie.Li@Sun.COM 	error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
30575599Sjwahlig 	    NULL, cr, NULL, NULL, NULL);
30580Sstevel@tonic-gate 	if (error != 0)
30595982Sahl 		goto err;
30600Sstevel@tonic-gate 
30610Sstevel@tonic-gate 	/*
30620Sstevel@tonic-gate 	 * If we rename a delegated file we should recall the
30630Sstevel@tonic-gate 	 * delegation, since future opens should fail or would
30640Sstevel@tonic-gate 	 * refer to a new file.
30650Sstevel@tonic-gate 	 */
30660Sstevel@tonic-gate 	if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
30670Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
30685982Sahl 		goto err1;
30690Sstevel@tonic-gate 	}
30700Sstevel@tonic-gate 
30710Sstevel@tonic-gate 	/*
30720Sstevel@tonic-gate 	 * Check for renaming over a delegated file.  Check rfs4_deleg_policy
30730Sstevel@tonic-gate 	 * first to avoid VOP_LOOKUP if possible.
30740Sstevel@tonic-gate 	 */
30750Sstevel@tonic-gate 	if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
30767961SNatalie.Li@Sun.COM 	    VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
30775331Samw 	    NULL, NULL, NULL) == 0) {
30780Sstevel@tonic-gate 
30790Sstevel@tonic-gate 		if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
30800Sstevel@tonic-gate 			VN_RELE(targvp);
30810Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
30825982Sahl 			goto err1;
30830Sstevel@tonic-gate 		}
30840Sstevel@tonic-gate 		VN_RELE(targvp);
30850Sstevel@tonic-gate 	}
30860Sstevel@tonic-gate 
30870Sstevel@tonic-gate 	if (!nbl_need_check(srcvp)) {
30887961SNatalie.Li@Sun.COM 		error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
30890Sstevel@tonic-gate 	} else {
30900Sstevel@tonic-gate 		nbl_start_crit(srcvp, RW_READER);
30917961SNatalie.Li@Sun.COM 		if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
30920Sstevel@tonic-gate 			error = EACCES;
30937961SNatalie.Li@Sun.COM 		else
30947961SNatalie.Li@Sun.COM 			error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
30950Sstevel@tonic-gate 		nbl_end_crit(srcvp);
30960Sstevel@tonic-gate 	}
30976976Seschrock 	if (error == 0)
30986976Seschrock 		vn_renamepath(tvp, srcvp, args->to.name,
30995599Sjwahlig 		    strlen(args->to.name));
31000Sstevel@tonic-gate 	VN_RELE(srcvp);
31010Sstevel@tonic-gate 	srcvp = NULL;
31020Sstevel@tonic-gate 
31030Sstevel@tonic-gate #ifdef DEBUG
31040Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
31050Sstevel@tonic-gate 		fava.va_mask = AT_ALL;
31065331Samw 		favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
31070Sstevel@tonic-gate 		tava.va_mask = AT_ALL;
31085331Samw 		tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
31090Sstevel@tonic-gate 	} else {
31100Sstevel@tonic-gate 		favap = NULL;
31110Sstevel@tonic-gate 		tavap = NULL;
31120Sstevel@tonic-gate 	}
31130Sstevel@tonic-gate #else
31140Sstevel@tonic-gate 	fava.va_mask = AT_ALL;
31155331Samw 	favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
31160Sstevel@tonic-gate 	tava.va_mask = AT_ALL;
31175331Samw 	tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
31180Sstevel@tonic-gate #endif
31190Sstevel@tonic-gate 
31200Sstevel@tonic-gate 	/*
31210Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
31220Sstevel@tonic-gate 	 */
31235331Samw 	(void) VOP_FSYNC(fvp, 0, cr, NULL);
31245331Samw 	(void) VOP_FSYNC(tvp, 0, cr, NULL);
31250Sstevel@tonic-gate 
31260Sstevel@tonic-gate 	if (error)
31275982Sahl 		goto err;
31280Sstevel@tonic-gate 
31290Sstevel@tonic-gate 	resp->status = NFS3_OK;
31300Sstevel@tonic-gate 	vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
31310Sstevel@tonic-gate 	vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
31325982Sahl 	goto out;
31335982Sahl 
31345982Sahl err:
31350Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
31360Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
31370Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
31387961SNatalie.Li@Sun.COM 	} else {
31390Sstevel@tonic-gate 		resp->status = puterrno3(error);
31407961SNatalie.Li@Sun.COM 	}
31415982Sahl err1:
31425982Sahl 	vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
31435982Sahl 	vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
31447961SNatalie.Li@Sun.COM 
31455982Sahl out:
31467961SNatalie.Li@Sun.COM 	if (name != NULL && name != args->from.name)
31477961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
31487961SNatalie.Li@Sun.COM 	if (toname != NULL && toname != args->to.name)
31497961SNatalie.Li@Sun.COM 		kmem_free(toname, MAXPATHLEN + 1);
31507961SNatalie.Li@Sun.COM 
31515982Sahl 	DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
31525982Sahl 	    cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
31530Sstevel@tonic-gate 	if (fvp != NULL)
31540Sstevel@tonic-gate 		VN_RELE(fvp);
31550Sstevel@tonic-gate 	if (tvp != NULL)
31560Sstevel@tonic-gate 		VN_RELE(tvp);
31570Sstevel@tonic-gate }
31580Sstevel@tonic-gate 
31591610Sthurlow void *
rfs3_rename_getfh(RENAME3args * args)31600Sstevel@tonic-gate rfs3_rename_getfh(RENAME3args *args)
31610Sstevel@tonic-gate {
31620Sstevel@tonic-gate 
31631610Sthurlow 	return (&args->from.dir);
31640Sstevel@tonic-gate }
31650Sstevel@tonic-gate 
31660Sstevel@tonic-gate void
rfs3_link(LINK3args * args,LINK3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)31670Sstevel@tonic-gate rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
31680Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
31690Sstevel@tonic-gate {
31700Sstevel@tonic-gate 	int error;
31710Sstevel@tonic-gate 	vnode_t *vp;
31720Sstevel@tonic-gate 	vnode_t *dvp;
31730Sstevel@tonic-gate 	struct vattr *vap;
31740Sstevel@tonic-gate 	struct vattr va;
31750Sstevel@tonic-gate 	struct vattr *bvap;
31760Sstevel@tonic-gate 	struct vattr bva;
31770Sstevel@tonic-gate 	struct vattr *avap;
31780Sstevel@tonic-gate 	struct vattr ava;
31790Sstevel@tonic-gate 	nfs_fh3	*fh3;
31800Sstevel@tonic-gate 	struct exportinfo *to_exi;
31814971Sjarrett 	bslabel_t *clabel;
31827961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
31837961SNatalie.Li@Sun.COM 	char *name = NULL;
31840Sstevel@tonic-gate 
31850Sstevel@tonic-gate 	vap = NULL;
31860Sstevel@tonic-gate 	bvap = NULL;
31870Sstevel@tonic-gate 	avap = NULL;
31880Sstevel@tonic-gate 	dvp = NULL;
31890Sstevel@tonic-gate 
31900Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
31915982Sahl 
31925982Sahl 	DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
31935982Sahl 	    cred_t *, cr, vnode_t *, vp, LINK3args *, args);
31945982Sahl 
31950Sstevel@tonic-gate 	if (vp == NULL) {
31960Sstevel@tonic-gate 		error = ESTALE;
31970Sstevel@tonic-gate 		goto out;
31980Sstevel@tonic-gate 	}
31990Sstevel@tonic-gate 
32000Sstevel@tonic-gate #ifdef DEBUG
32010Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
32020Sstevel@tonic-gate 		va.va_mask = AT_ALL;
32035331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
32040Sstevel@tonic-gate 	} else
32050Sstevel@tonic-gate 		vap = NULL;
32060Sstevel@tonic-gate #else
32070Sstevel@tonic-gate 	va.va_mask = AT_ALL;
32085331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
32090Sstevel@tonic-gate #endif
32100Sstevel@tonic-gate 
32111610Sthurlow 	fh3 = &args->link.dir;
32121610Sthurlow 	to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
32130Sstevel@tonic-gate 	if (to_exi == NULL) {
32140Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
32150Sstevel@tonic-gate 		goto out1;
32160Sstevel@tonic-gate 	}
32170Sstevel@tonic-gate 	exi_rele(to_exi);
32180Sstevel@tonic-gate 
32190Sstevel@tonic-gate 	if (to_exi != exi) {
32200Sstevel@tonic-gate 		resp->status = NFS3ERR_XDEV;
32210Sstevel@tonic-gate 		goto out1;
32220Sstevel@tonic-gate 	}
32230Sstevel@tonic-gate 
32244971Sjarrett 	if (is_system_labeled()) {
32254971Sjarrett 		clabel = req->rq_label;
32264971Sjarrett 
32274971Sjarrett 		ASSERT(clabel != NULL);
32284971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
32294971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
32304971Sjarrett 
32314971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
32329871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
32339871SJarrett.Lu@Sun.COM 			    exi)) {
32344971Sjarrett 				resp->status = NFS3ERR_ACCES;
32354971Sjarrett 				goto out1;
32364971Sjarrett 			}
32374971Sjarrett 		}
32384971Sjarrett 	}
32394971Sjarrett 
32401610Sthurlow 	dvp = nfs3_fhtovp(&args->link.dir, exi);
32410Sstevel@tonic-gate 	if (dvp == NULL) {
32420Sstevel@tonic-gate 		error = ESTALE;
32430Sstevel@tonic-gate 		goto out;
32440Sstevel@tonic-gate 	}
32450Sstevel@tonic-gate 
32460Sstevel@tonic-gate #ifdef DEBUG
32470Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
32480Sstevel@tonic-gate 		bva.va_mask = AT_ALL;
32495331Samw 		bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
32500Sstevel@tonic-gate 	} else
32510Sstevel@tonic-gate 		bvap = NULL;
32520Sstevel@tonic-gate #else
32530Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
32545331Samw 	bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
32550Sstevel@tonic-gate #endif
32560Sstevel@tonic-gate 
32570Sstevel@tonic-gate 	if (dvp->v_type != VDIR) {
32580Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
32590Sstevel@tonic-gate 		goto out1;
32600Sstevel@tonic-gate 	}
32610Sstevel@tonic-gate 
32620Sstevel@tonic-gate 	if (args->link.name == nfs3nametoolong) {
32630Sstevel@tonic-gate 		resp->status = NFS3ERR_NAMETOOLONG;
32640Sstevel@tonic-gate 		goto out1;
32650Sstevel@tonic-gate 	}
32660Sstevel@tonic-gate 
32670Sstevel@tonic-gate 	if (args->link.name == NULL || *(args->link.name) == '\0') {
32680Sstevel@tonic-gate 		resp->status = NFS3ERR_ACCES;
32690Sstevel@tonic-gate 		goto out1;
32700Sstevel@tonic-gate 	}
32710Sstevel@tonic-gate 
32720Sstevel@tonic-gate 	if (rdonly(exi, req)) {
32730Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
32740Sstevel@tonic-gate 		goto out1;
32750Sstevel@tonic-gate 	}
32760Sstevel@tonic-gate 
32774971Sjarrett 	if (is_system_labeled()) {
32784971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
32794971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
32804971Sjarrett 
32814971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
32829871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
32839871SJarrett.Lu@Sun.COM 			    exi)) {
32844971Sjarrett 				resp->status = NFS3ERR_ACCES;
32854971Sjarrett 				goto out1;
32864971Sjarrett 			}
32874971Sjarrett 		}
32884971Sjarrett 	}
32894971Sjarrett 
32907961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
32917961SNatalie.Li@Sun.COM 	name = nfscmd_convname(ca, exi, args->link.name,
32927961SNatalie.Li@Sun.COM 	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
32937961SNatalie.Li@Sun.COM 
32947961SNatalie.Li@Sun.COM 	if (name == NULL) {
32957961SNatalie.Li@Sun.COM 		resp->status = NFS3ERR_SERVERFAULT;
32967961SNatalie.Li@Sun.COM 		goto out1;
32977961SNatalie.Li@Sun.COM 	}
32987961SNatalie.Li@Sun.COM 
32997961SNatalie.Li@Sun.COM 	error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
33000Sstevel@tonic-gate 
33010Sstevel@tonic-gate #ifdef DEBUG
33020Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
33030Sstevel@tonic-gate 		va.va_mask = AT_ALL;
33045331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
33050Sstevel@tonic-gate 		ava.va_mask = AT_ALL;
33065331Samw 		avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
33070Sstevel@tonic-gate 	} else {
33080Sstevel@tonic-gate 		vap = NULL;
33090Sstevel@tonic-gate 		avap = NULL;
33100Sstevel@tonic-gate 	}
33110Sstevel@tonic-gate #else
33120Sstevel@tonic-gate 	va.va_mask = AT_ALL;
33135331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
33140Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
33155331Samw 	avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
33160Sstevel@tonic-gate #endif
33170Sstevel@tonic-gate 
33180Sstevel@tonic-gate 	/*
33190Sstevel@tonic-gate 	 * Force modified data and metadata out to stable storage.
33200Sstevel@tonic-gate 	 */
33215331Samw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
33225331Samw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
33230Sstevel@tonic-gate 
33240Sstevel@tonic-gate 	if (error)
33250Sstevel@tonic-gate 		goto out;
33260Sstevel@tonic-gate 
33270Sstevel@tonic-gate 	VN_RELE(dvp);
33280Sstevel@tonic-gate 
33290Sstevel@tonic-gate 	resp->status = NFS3_OK;
33300Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
33310Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
33325982Sahl 
33335982Sahl 	DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
33345982Sahl 	    cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
33355982Sahl 
33365982Sahl 	VN_RELE(vp);
33375982Sahl 
33380Sstevel@tonic-gate 	return;
33390Sstevel@tonic-gate 
33400Sstevel@tonic-gate out:
33410Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
33420Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
33430Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
33440Sstevel@tonic-gate 	} else
33450Sstevel@tonic-gate 		resp->status = puterrno3(error);
33460Sstevel@tonic-gate out1:
33477961SNatalie.Li@Sun.COM 	if (name != NULL && name != args->link.name)
33487961SNatalie.Li@Sun.COM 		kmem_free(name, MAXPATHLEN + 1);
33497961SNatalie.Li@Sun.COM 
33505982Sahl 	DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
33515982Sahl 	    cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
33525982Sahl 
33530Sstevel@tonic-gate 	if (vp != NULL)
33540Sstevel@tonic-gate 		VN_RELE(vp);
33550Sstevel@tonic-gate 	if (dvp != NULL)
33560Sstevel@tonic-gate 		VN_RELE(dvp);
33570Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
33580Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
33590Sstevel@tonic-gate }
33600Sstevel@tonic-gate 
33611610Sthurlow void *
rfs3_link_getfh(LINK3args * args)33620Sstevel@tonic-gate rfs3_link_getfh(LINK3args *args)
33630Sstevel@tonic-gate {
33640Sstevel@tonic-gate 
33651610Sthurlow 	return (&args->file);
33660Sstevel@tonic-gate }
33670Sstevel@tonic-gate 
33680Sstevel@tonic-gate /*
33690Sstevel@tonic-gate  * This macro defines the size of a response which contains attribute
33700Sstevel@tonic-gate  * information and one directory entry (whose length is specified by
33710Sstevel@tonic-gate  * the macro parameter).  If the incoming request is larger than this,
33720Sstevel@tonic-gate  * then we are guaranteed to be able to return at one directory entry
33730Sstevel@tonic-gate  * if one exists.  Therefore, we do not need to check for
33740Sstevel@tonic-gate  * NFS3ERR_TOOSMALL if the requested size is larger then this.  If it
33750Sstevel@tonic-gate  * is not, then we need to check to make sure that this error does not
33760Sstevel@tonic-gate  * need to be returned.
33770Sstevel@tonic-gate  *
33780Sstevel@tonic-gate  * NFS3_READDIR_MIN_COUNT is comprised of following :
33790Sstevel@tonic-gate  *
33800Sstevel@tonic-gate  * status - 1 * BYTES_PER_XDR_UNIT
33810Sstevel@tonic-gate  * attr. flag - 1 * BYTES_PER_XDR_UNIT
33820Sstevel@tonic-gate  * cookie verifier - 2 * BYTES_PER_XDR_UNIT
33830Sstevel@tonic-gate  * attributes  - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
33840Sstevel@tonic-gate  * boolean - 1 * BYTES_PER_XDR_UNIT
33850Sstevel@tonic-gate  * file id - 2 * BYTES_PER_XDR_UNIT
33865331Samw  * directory name length - 1 * BYTES_PER_XDR_UNIT
33870Sstevel@tonic-gate  * cookie - 2 * BYTES_PER_XDR_UNIT
33880Sstevel@tonic-gate  * end of list - 1 * BYTES_PER_XDR_UNIT
33890Sstevel@tonic-gate  * end of file - 1 * BYTES_PER_XDR_UNIT
33900Sstevel@tonic-gate  * Name length of directory to the nearest byte
33910Sstevel@tonic-gate  */
33920Sstevel@tonic-gate 
33930Sstevel@tonic-gate #define	NFS3_READDIR_MIN_COUNT(length)	\
33940Sstevel@tonic-gate 	((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
33950Sstevel@tonic-gate 		BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
33960Sstevel@tonic-gate 
33970Sstevel@tonic-gate /* ARGSUSED */
33980Sstevel@tonic-gate void
rfs3_readdir(READDIR3args * args,READDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)33990Sstevel@tonic-gate rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
34000Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
34010Sstevel@tonic-gate {
34020Sstevel@tonic-gate 	int error;
34030Sstevel@tonic-gate 	vnode_t *vp;
34040Sstevel@tonic-gate 	struct vattr *vap;
34050Sstevel@tonic-gate 	struct vattr va;
34060Sstevel@tonic-gate 	struct iovec iov;
34070Sstevel@tonic-gate 	struct uio uio;
34080Sstevel@tonic-gate 	char *data;
34090Sstevel@tonic-gate 	int iseof;
34100Sstevel@tonic-gate 	int bufsize;
34110Sstevel@tonic-gate 	int namlen;
34120Sstevel@tonic-gate 	uint_t count;
34137961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
34140Sstevel@tonic-gate 
34150Sstevel@tonic-gate 	vap = NULL;
34160Sstevel@tonic-gate 
34170Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->dir, exi);
34185982Sahl 
34195982Sahl 	DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
34205982Sahl 	    cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
34215982Sahl 
34220Sstevel@tonic-gate 	if (vp == NULL) {
34230Sstevel@tonic-gate 		error = ESTALE;
34240Sstevel@tonic-gate 		goto out;
34250Sstevel@tonic-gate 	}
34260Sstevel@tonic-gate 
34274971Sjarrett 	if (is_system_labeled()) {
34284971Sjarrett 		bslabel_t *clabel = req->rq_label;
34294971Sjarrett 
34304971Sjarrett 		ASSERT(clabel != NULL);
34314971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
34324971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
34334971Sjarrett 
34344971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
34359871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
34369871SJarrett.Lu@Sun.COM 			    exi)) {
34374971Sjarrett 				resp->status = NFS3ERR_ACCES;
34384971Sjarrett 				goto out1;
34394971Sjarrett 			}
34404971Sjarrett 		}
34414971Sjarrett 	}
34424971Sjarrett 
34430Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
34440Sstevel@tonic-gate 
34450Sstevel@tonic-gate #ifdef DEBUG
34460Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
34470Sstevel@tonic-gate 		va.va_mask = AT_ALL;
34485331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
34490Sstevel@tonic-gate 	} else
34500Sstevel@tonic-gate 		vap = NULL;
34510Sstevel@tonic-gate #else
34520Sstevel@tonic-gate 	va.va_mask = AT_ALL;
34535331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
34540Sstevel@tonic-gate #endif
34550Sstevel@tonic-gate 
34560Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
34570Sstevel@tonic-gate 		resp->status = NFS3ERR_NOTDIR;
34580Sstevel@tonic-gate 		goto out1;
34590Sstevel@tonic-gate 	}
34600Sstevel@tonic-gate 
34615331Samw 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
34620Sstevel@tonic-gate 	if (error)
34630Sstevel@tonic-gate 		goto out;
34640Sstevel@tonic-gate 
34650Sstevel@tonic-gate 	/*
34660Sstevel@tonic-gate 	 * Now don't allow arbitrary count to alloc;
34670Sstevel@tonic-gate 	 * allow the maximum not to exceed rfs3_tsize()
34680Sstevel@tonic-gate 	 */
34690Sstevel@tonic-gate 	if (args->count > rfs3_tsize(req))
34700Sstevel@tonic-gate 		args->count = rfs3_tsize(req);
34710Sstevel@tonic-gate 
34720Sstevel@tonic-gate 	/*
34730Sstevel@tonic-gate 	 * Make sure that there is room to read at least one entry
34740Sstevel@tonic-gate 	 * if any are available.
34750Sstevel@tonic-gate 	 */
34760Sstevel@tonic-gate 	if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
34770Sstevel@tonic-gate 		count = DIRENT64_RECLEN(MAXNAMELEN);
34780Sstevel@tonic-gate 	else
34790Sstevel@tonic-gate 		count = args->count;
34800Sstevel@tonic-gate 
34810Sstevel@tonic-gate 	data = kmem_alloc(count, KM_SLEEP);
34820Sstevel@tonic-gate 
34830Sstevel@tonic-gate 	iov.iov_base = data;
34840Sstevel@tonic-gate 	iov.iov_len = count;
34850Sstevel@tonic-gate 	uio.uio_iov = &iov;
34860Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
34870Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
34880Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
34890Sstevel@tonic-gate 	uio.uio_loffset = (offset_t)args->cookie;
34900Sstevel@tonic-gate 	uio.uio_resid = count;
34910Sstevel@tonic-gate 
34925331Samw 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
34930Sstevel@tonic-gate 
34940Sstevel@tonic-gate #ifdef DEBUG
34950Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
34960Sstevel@tonic-gate 		va.va_mask = AT_ALL;
34975331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
34980Sstevel@tonic-gate 	} else
34990Sstevel@tonic-gate 		vap = NULL;
35000Sstevel@tonic-gate #else
35010Sstevel@tonic-gate 	va.va_mask = AT_ALL;
35025331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
35030Sstevel@tonic-gate #endif
35040Sstevel@tonic-gate 
35050Sstevel@tonic-gate 	if (error) {
35060Sstevel@tonic-gate 		kmem_free(data, count);
35070Sstevel@tonic-gate 		goto out;
35080Sstevel@tonic-gate 	}
35090Sstevel@tonic-gate 
35100Sstevel@tonic-gate 	/*
35110Sstevel@tonic-gate 	 * If the count was not large enough to be able to guarantee
35120Sstevel@tonic-gate 	 * to be able to return at least one entry, then need to
35130Sstevel@tonic-gate 	 * check to see if NFS3ERR_TOOSMALL should be returned.
35140Sstevel@tonic-gate 	 */
35150Sstevel@tonic-gate 	if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
35160Sstevel@tonic-gate 		/*
35170Sstevel@tonic-gate 		 * bufsize is used to keep track of the size of the response.
35180Sstevel@tonic-gate 		 * It is primed with:
35190Sstevel@tonic-gate 		 *	1 for the status +
35200Sstevel@tonic-gate 		 *	1 for the dir_attributes.attributes boolean +
35210Sstevel@tonic-gate 		 *	2 for the cookie verifier
35220Sstevel@tonic-gate 		 * all times BYTES_PER_XDR_UNIT to convert from XDR units
35230Sstevel@tonic-gate 		 * to bytes.  If there are directory attributes to be
35240Sstevel@tonic-gate 		 * returned, then:
35250Sstevel@tonic-gate 		 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
35260Sstevel@tonic-gate 		 * time BYTES_PER_XDR_UNIT is added to account for them.
35270Sstevel@tonic-gate 		 */
35280Sstevel@tonic-gate 		bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
35290Sstevel@tonic-gate 		if (vap != NULL)
35300Sstevel@tonic-gate 			bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
35310Sstevel@tonic-gate 		/*
35320Sstevel@tonic-gate 		 * An entry is composed of:
35330Sstevel@tonic-gate 		 *	1 for the true/false list indicator +
35340Sstevel@tonic-gate 		 *	2 for the fileid +
35350Sstevel@tonic-gate 		 *	1 for the length of the name +
35360Sstevel@tonic-gate 		 *	2 for the cookie +
35370Sstevel@tonic-gate 		 * all times BYTES_PER_XDR_UNIT to convert from
35380Sstevel@tonic-gate 		 * XDR units to bytes, plus the length of the name
35390Sstevel@tonic-gate 		 * rounded up to the nearest BYTES_PER_XDR_UNIT.
35400Sstevel@tonic-gate 		 */
35410Sstevel@tonic-gate 		if (count != uio.uio_resid) {
35420Sstevel@tonic-gate 			namlen = strlen(((struct dirent64 *)data)->d_name);
35430Sstevel@tonic-gate 			bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
35445599Sjwahlig 			    roundup(namlen, BYTES_PER_XDR_UNIT);
35450Sstevel@tonic-gate 		}
35460Sstevel@tonic-gate 		/*
35470Sstevel@tonic-gate 		 * We need to check to see if the number of bytes left
35480Sstevel@tonic-gate 		 * to go into the buffer will actually fit into the
35490Sstevel@tonic-gate 		 * buffer.  This is calculated as the size of this
35500Sstevel@tonic-gate 		 * entry plus:
35510Sstevel@tonic-gate 		 *	1 for the true/false list indicator +
35520Sstevel@tonic-gate 		 *	1 for the eof indicator
35530Sstevel@tonic-gate 		 * times BYTES_PER_XDR_UNIT to convert from from
35540Sstevel@tonic-gate 		 * XDR units to bytes.
35550Sstevel@tonic-gate 		 */
35560Sstevel@tonic-gate 		bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
35570Sstevel@tonic-gate 		if (bufsize > args->count) {
35580Sstevel@tonic-gate 			kmem_free(data, count);
35590Sstevel@tonic-gate 			resp->status = NFS3ERR_TOOSMALL;
35600Sstevel@tonic-gate 			goto out1;
35610Sstevel@tonic-gate 		}
35620Sstevel@tonic-gate 	}
35630Sstevel@tonic-gate 
35647961SNatalie.Li@Sun.COM 	/*
35657961SNatalie.Li@Sun.COM 	 * Have a valid readir buffer for the native character
35667961SNatalie.Li@Sun.COM 	 * set. Need to check if a conversion is necessary and
35677961SNatalie.Li@Sun.COM 	 * potentially rewrite the whole buffer. Note that if the
35687961SNatalie.Li@Sun.COM 	 * conversion expands names enough, the structure may not
35697961SNatalie.Li@Sun.COM 	 * fit. In this case, we need to drop entries until if fits
35707961SNatalie.Li@Sun.COM 	 * and patch the counts in order that the next readdir will
35717961SNatalie.Li@Sun.COM 	 * get the correct entries.
35727961SNatalie.Li@Sun.COM 	 */
35737961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
35747961SNatalie.Li@Sun.COM 	data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
35757961SNatalie.Li@Sun.COM 
35767961SNatalie.Li@Sun.COM 
35770Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
35780Sstevel@tonic-gate 
35790Sstevel@tonic-gate #if 0 /* notyet */
35800Sstevel@tonic-gate 	/*
35810Sstevel@tonic-gate 	 * Don't do this.  It causes local disk writes when just
35820Sstevel@tonic-gate 	 * reading the file and the overhead is deemed larger
35830Sstevel@tonic-gate 	 * than the benefit.
35840Sstevel@tonic-gate 	 */
35850Sstevel@tonic-gate 	/*
35860Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
35870Sstevel@tonic-gate 	 */
35885331Samw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
35890Sstevel@tonic-gate #endif
35900Sstevel@tonic-gate 
35910Sstevel@tonic-gate 	resp->status = NFS3_OK;
35920Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
35930Sstevel@tonic-gate 	resp->resok.cookieverf = 0;
35940Sstevel@tonic-gate 	resp->resok.reply.entries = (entry3 *)data;
35950Sstevel@tonic-gate 	resp->resok.reply.eof = iseof;
35960Sstevel@tonic-gate 	resp->resok.size = count - uio.uio_resid;
35970Sstevel@tonic-gate 	resp->resok.count = args->count;
35980Sstevel@tonic-gate 	resp->resok.freecount = count;
35995982Sahl 
36005982Sahl 	DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
36015982Sahl 	    cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
36025982Sahl 
36035982Sahl 	VN_RELE(vp);
36045982Sahl 
36050Sstevel@tonic-gate 	return;
36060Sstevel@tonic-gate 
36070Sstevel@tonic-gate out:
36080Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
36090Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
36100Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
36110Sstevel@tonic-gate 	} else
36120Sstevel@tonic-gate 		resp->status = puterrno3(error);
36130Sstevel@tonic-gate out1:
36145982Sahl 	DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
36155982Sahl 	    cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
36165982Sahl 
36170Sstevel@tonic-gate 	if (vp != NULL) {
36180Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
36190Sstevel@tonic-gate 		VN_RELE(vp);
36200Sstevel@tonic-gate 	}
36210Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
36220Sstevel@tonic-gate }
36230Sstevel@tonic-gate 
36241610Sthurlow void *
rfs3_readdir_getfh(READDIR3args * args)36250Sstevel@tonic-gate rfs3_readdir_getfh(READDIR3args *args)
36260Sstevel@tonic-gate {
36270Sstevel@tonic-gate 
36281610Sthurlow 	return (&args->dir);
36290Sstevel@tonic-gate }
36300Sstevel@tonic-gate 
36310Sstevel@tonic-gate void
rfs3_readdir_free(READDIR3res * resp)36320Sstevel@tonic-gate rfs3_readdir_free(READDIR3res *resp)
36330Sstevel@tonic-gate {
36340Sstevel@tonic-gate 
36350Sstevel@tonic-gate 	if (resp->status == NFS3_OK)
36360Sstevel@tonic-gate 		kmem_free(resp->resok.reply.entries, resp->resok.freecount);
36370Sstevel@tonic-gate }
36380Sstevel@tonic-gate 
36390Sstevel@tonic-gate #ifdef nextdp
36400Sstevel@tonic-gate #undef nextdp
36410Sstevel@tonic-gate #endif
36420Sstevel@tonic-gate #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
36430Sstevel@tonic-gate 
36440Sstevel@tonic-gate /*
36450Sstevel@tonic-gate  * This macro computes the size of a response which contains
36460Sstevel@tonic-gate  * one directory entry including the attributes as well as file handle.
36470Sstevel@tonic-gate  * If the incoming request is larger than this, then we are guaranteed to be
36480Sstevel@tonic-gate  * able to return at least one more directory entry if one exists.
36490Sstevel@tonic-gate  *
36500Sstevel@tonic-gate  * NFS3_READDIRPLUS_ENTRY is made up of the following:
36510Sstevel@tonic-gate  *
36520Sstevel@tonic-gate  * boolean - 1 * BYTES_PER_XDR_UNIT
36530Sstevel@tonic-gate  * file id - 2 * BYTES_PER_XDR_UNIT
36540Sstevel@tonic-gate  * directory name length - 1 * BYTES_PER_XDR_UNIT
36550Sstevel@tonic-gate  * cookie - 2 * BYTES_PER_XDR_UNIT
36560Sstevel@tonic-gate  * attribute flag - 1 * BYTES_PER_XDR_UNIT
36570Sstevel@tonic-gate  * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
36580Sstevel@tonic-gate  * status byte for file handle - 1 *  BYTES_PER_XDR_UNIT
36590Sstevel@tonic-gate  * length of a file handle - 1 * BYTES_PER_XDR_UNIT
36605331Samw  * Maximum length of a file handle (NFS3_MAXFHSIZE)
36610Sstevel@tonic-gate  * name length of the entry to the nearest bytes
36620Sstevel@tonic-gate  */
36630Sstevel@tonic-gate #define	NFS3_READDIRPLUS_ENTRY(namelen)	\
36640Sstevel@tonic-gate 	((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
36650Sstevel@tonic-gate 		BYTES_PER_XDR_UNIT + \
36661610Sthurlow 	NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
36670Sstevel@tonic-gate 
36680Sstevel@tonic-gate static int rfs3_readdir_unit = MAXBSIZE;
36690Sstevel@tonic-gate 
36700Sstevel@tonic-gate /* ARGSUSED */
36710Sstevel@tonic-gate void
rfs3_readdirplus(READDIRPLUS3args * args,READDIRPLUS3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)36720Sstevel@tonic-gate rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
36730Sstevel@tonic-gate 	struct exportinfo *exi, struct svc_req *req, cred_t *cr)
36740Sstevel@tonic-gate {
36750Sstevel@tonic-gate 	int error;
36760Sstevel@tonic-gate 	vnode_t *vp;
36770Sstevel@tonic-gate 	struct vattr *vap;
36780Sstevel@tonic-gate 	struct vattr va;
36790Sstevel@tonic-gate 	struct iovec iov;
36800Sstevel@tonic-gate 	struct uio uio;
36810Sstevel@tonic-gate 	char *data;
36820Sstevel@tonic-gate 	int iseof;
36830Sstevel@tonic-gate 	struct dirent64 *dp;
36840Sstevel@tonic-gate 	vnode_t *nvp;
36850Sstevel@tonic-gate 	struct vattr *nvap;
36860Sstevel@tonic-gate 	struct vattr nva;
36870Sstevel@tonic-gate 	entryplus3_info *infop = NULL;
36880Sstevel@tonic-gate 	int size = 0;
36890Sstevel@tonic-gate 	int nents = 0;
36900Sstevel@tonic-gate 	int bufsize = 0;
36910Sstevel@tonic-gate 	int entrysize = 0;
36920Sstevel@tonic-gate 	int tofit = 0;
36930Sstevel@tonic-gate 	int rd_unit = rfs3_readdir_unit;
36940Sstevel@tonic-gate 	int prev_len;
36950Sstevel@tonic-gate 	int space_left;
36960Sstevel@tonic-gate 	int i;
36970Sstevel@tonic-gate 	uint_t *namlen = NULL;
36987961SNatalie.Li@Sun.COM 	char *ndata = NULL;
36997961SNatalie.Li@Sun.COM 	struct sockaddr *ca;
37007961SNatalie.Li@Sun.COM 	size_t ret;
37010Sstevel@tonic-gate 
37020Sstevel@tonic-gate 	vap = NULL;
37030Sstevel@tonic-gate 
37040Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->dir, exi);
37055982Sahl 
37065982Sahl 	DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
37075982Sahl 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
37085982Sahl 
37090Sstevel@tonic-gate 	if (vp == NULL) {
37100Sstevel@tonic-gate 		error = ESTALE;
37110Sstevel@tonic-gate 		goto out;
37120Sstevel@tonic-gate 	}
37130Sstevel@tonic-gate 
37144971Sjarrett 	if (is_system_labeled()) {
37154971Sjarrett 		bslabel_t *clabel = req->rq_label;
37164971Sjarrett 
37174971Sjarrett 		ASSERT(clabel != NULL);
37184971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
37194971Sjarrett 		    char *, "got client label from request(1)",
37204971Sjarrett 		    struct svc_req *, req);
37214971Sjarrett 
37224971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
37239871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
37249871SJarrett.Lu@Sun.COM 			    exi)) {
37254971Sjarrett 				resp->status = NFS3ERR_ACCES;
37264971Sjarrett 				goto out1;
37274971Sjarrett 			}
37284971Sjarrett 		}
37294971Sjarrett 	}
37304971Sjarrett 
37310Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
37320Sstevel@tonic-gate 
37330Sstevel@tonic-gate #ifdef DEBUG
37340Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr) {
37350Sstevel@tonic-gate 		va.va_mask = AT_ALL;
37365331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
37370Sstevel@tonic-gate 	} else
37380Sstevel@tonic-gate 		vap = NULL;
37390Sstevel@tonic-gate #else
37400Sstevel@tonic-gate 	va.va_mask = AT_ALL;
37415331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
37420Sstevel@tonic-gate #endif
37430Sstevel@tonic-gate 
37440Sstevel@tonic-gate 	if (vp->v_type != VDIR) {
37450Sstevel@tonic-gate 		error = ENOTDIR;
37460Sstevel@tonic-gate 		goto out;
37470Sstevel@tonic-gate 	}
37480Sstevel@tonic-gate 
37495331Samw 	error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
37500Sstevel@tonic-gate 	if (error)
37510Sstevel@tonic-gate 		goto out;
37520Sstevel@tonic-gate 
37530Sstevel@tonic-gate 	/*
37540Sstevel@tonic-gate 	 * Don't allow arbitrary counts for allocation
37550Sstevel@tonic-gate 	 */
37560Sstevel@tonic-gate 	if (args->maxcount > rfs3_tsize(req))
37570Sstevel@tonic-gate 		args->maxcount = rfs3_tsize(req);
37580Sstevel@tonic-gate 
37590Sstevel@tonic-gate 	/*
37600Sstevel@tonic-gate 	 * Make sure that there is room to read at least one entry
37610Sstevel@tonic-gate 	 * if any are available
37620Sstevel@tonic-gate 	 */
37630Sstevel@tonic-gate 	args->dircount = MIN(args->dircount, args->maxcount);
37640Sstevel@tonic-gate 
37650Sstevel@tonic-gate 	if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
37660Sstevel@tonic-gate 		args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
37670Sstevel@tonic-gate 
37680Sstevel@tonic-gate 	/*
37690Sstevel@tonic-gate 	 * This allocation relies on a minimum directory entry
37700Sstevel@tonic-gate 	 * being roughly 24 bytes.  Therefore, the namlen array
37710Sstevel@tonic-gate 	 * will have enough space based on the maximum number of
37720Sstevel@tonic-gate 	 * entries to read.
37730Sstevel@tonic-gate 	 */
37740Sstevel@tonic-gate 	namlen = kmem_alloc(args->dircount, KM_SLEEP);
37750Sstevel@tonic-gate 
37760Sstevel@tonic-gate 	space_left = args->dircount;
37770Sstevel@tonic-gate 	data = kmem_alloc(args->dircount, KM_SLEEP);
37780Sstevel@tonic-gate 	dp = (struct dirent64 *)data;
37790Sstevel@tonic-gate 	uio.uio_iov = &iov;
37800Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
37810Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
37820Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
37830Sstevel@tonic-gate 	uio.uio_loffset = (offset_t)args->cookie;
37840Sstevel@tonic-gate 
37850Sstevel@tonic-gate 	/*
37860Sstevel@tonic-gate 	 * bufsize is used to keep track of the size of the response as we
37870Sstevel@tonic-gate 	 * get post op attributes and filehandles for each entry.  This is
37880Sstevel@tonic-gate 	 * an optimization as the server may have read more entries than will
37890Sstevel@tonic-gate 	 * fit in the buffer specified by maxcount.  We stop calculating
37900Sstevel@tonic-gate 	 * post op attributes and filehandles once we have exceeded maxcount.
37910Sstevel@tonic-gate 	 * This will minimize the effect of truncation.
37920Sstevel@tonic-gate 	 *
37930Sstevel@tonic-gate 	 * It is primed with:
37940Sstevel@tonic-gate 	 *	1 for the status +
37950Sstevel@tonic-gate 	 *	1 for the dir_attributes.attributes boolean +
37960Sstevel@tonic-gate 	 *	2 for the cookie verifier
37970Sstevel@tonic-gate 	 * all times BYTES_PER_XDR_UNIT to convert from XDR units
37980Sstevel@tonic-gate 	 * to bytes.  If there are directory attributes to be
37990Sstevel@tonic-gate 	 * returned, then:
38000Sstevel@tonic-gate 	 *	NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
38010Sstevel@tonic-gate 	 * time BYTES_PER_XDR_UNIT is added to account for them.
38020Sstevel@tonic-gate 	 */
38030Sstevel@tonic-gate 	bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
38040Sstevel@tonic-gate 	if (vap != NULL)
38050Sstevel@tonic-gate 		bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
38060Sstevel@tonic-gate 
38070Sstevel@tonic-gate getmoredents:
38080Sstevel@tonic-gate 	/*
38090Sstevel@tonic-gate 	 * Here we make a check so that our read unit is not larger than
38100Sstevel@tonic-gate 	 * the space left in the buffer.
38110Sstevel@tonic-gate 	 */
38120Sstevel@tonic-gate 	rd_unit = MIN(rd_unit, space_left);
38130Sstevel@tonic-gate 	iov.iov_base = (char *)dp;
38140Sstevel@tonic-gate 	iov.iov_len = rd_unit;
38150Sstevel@tonic-gate 	uio.uio_resid = rd_unit;
38160Sstevel@tonic-gate 	prev_len = rd_unit;
38170Sstevel@tonic-gate 
38185331Samw 	error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
38190Sstevel@tonic-gate 
38200Sstevel@tonic-gate 	if (error) {
38210Sstevel@tonic-gate 		kmem_free(data, args->dircount);
38220Sstevel@tonic-gate 		goto out;
38230Sstevel@tonic-gate 	}
38240Sstevel@tonic-gate 
38250Sstevel@tonic-gate 	if (uio.uio_resid == prev_len && !iseof) {
38260Sstevel@tonic-gate 		if (nents == 0) {
38270Sstevel@tonic-gate 			kmem_free(data, args->dircount);
38280Sstevel@tonic-gate 			resp->status = NFS3ERR_TOOSMALL;
38290Sstevel@tonic-gate 			goto out1;
38300Sstevel@tonic-gate 		}
38310Sstevel@tonic-gate 
38320Sstevel@tonic-gate 		/*
38330Sstevel@tonic-gate 		 * We could not get any more entries, so get the attributes
38340Sstevel@tonic-gate 		 * and filehandle for the entries already obtained.
38350Sstevel@tonic-gate 		 */
38360Sstevel@tonic-gate 		goto good;
38370Sstevel@tonic-gate 	}
38380Sstevel@tonic-gate 
38390Sstevel@tonic-gate 	/*
38400Sstevel@tonic-gate 	 * We estimate the size of the response by assuming the
38410Sstevel@tonic-gate 	 * entry exists and attributes and filehandle are also valid
38420Sstevel@tonic-gate 	 */
38430Sstevel@tonic-gate 	for (size = prev_len - uio.uio_resid;
38445599Sjwahlig 	    size > 0;
38455599Sjwahlig 	    size -= dp->d_reclen, dp = nextdp(dp)) {
38460Sstevel@tonic-gate 
38470Sstevel@tonic-gate 		if (dp->d_ino == 0) {
38480Sstevel@tonic-gate 			nents++;
38490Sstevel@tonic-gate 			continue;
38500Sstevel@tonic-gate 		}
38510Sstevel@tonic-gate 
38520Sstevel@tonic-gate 		namlen[nents] = strlen(dp->d_name);
38530Sstevel@tonic-gate 		entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
38540Sstevel@tonic-gate 
38550Sstevel@tonic-gate 		/*
38560Sstevel@tonic-gate 		 * We need to check to see if the number of bytes left
38570Sstevel@tonic-gate 		 * to go into the buffer will actually fit into the
38580Sstevel@tonic-gate 		 * buffer.  This is calculated as the size of this
38590Sstevel@tonic-gate 		 * entry plus:
38600Sstevel@tonic-gate 		 *	1 for the true/false list indicator +
38610Sstevel@tonic-gate 		 *	1 for the eof indicator
38620Sstevel@tonic-gate 		 * times BYTES_PER_XDR_UNIT to convert from XDR units
38630Sstevel@tonic-gate 		 * to bytes.
38640Sstevel@tonic-gate 		 *
38650Sstevel@tonic-gate 		 * Also check the dircount limit against the first entry read
38660Sstevel@tonic-gate 		 *
38670Sstevel@tonic-gate 		 */
38680Sstevel@tonic-gate 		tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
38690Sstevel@tonic-gate 		if (bufsize + tofit > args->maxcount) {
38700Sstevel@tonic-gate 			/*
38710Sstevel@tonic-gate 			 * We make a check here to see if this was the
38720Sstevel@tonic-gate 			 * first entry being measured.  If so, then maxcount
38730Sstevel@tonic-gate 			 * was too small to begin with and so we need to
38740Sstevel@tonic-gate 			 * return with NFS3ERR_TOOSMALL.
38750Sstevel@tonic-gate 			 */
38760Sstevel@tonic-gate 			if (nents == 0) {
38770Sstevel@tonic-gate 				kmem_free(data, args->dircount);
38780Sstevel@tonic-gate 				resp->status = NFS3ERR_TOOSMALL;
38790Sstevel@tonic-gate 				goto out1;
38800Sstevel@tonic-gate 			}
38810Sstevel@tonic-gate 			iseof = FALSE;
38820Sstevel@tonic-gate 			goto good;
38830Sstevel@tonic-gate 		}
38840Sstevel@tonic-gate 		bufsize += entrysize;
38850Sstevel@tonic-gate 		nents++;
38860Sstevel@tonic-gate 	}
38870Sstevel@tonic-gate 
38880Sstevel@tonic-gate 	/*
38890Sstevel@tonic-gate 	 * If there is enough room to fit at least 1 more entry including
38900Sstevel@tonic-gate 	 * post op attributes and filehandle in the buffer AND that we haven't
38910Sstevel@tonic-gate 	 * exceeded dircount then go back and get some more.
38920Sstevel@tonic-gate 	 */
38930Sstevel@tonic-gate 	if (!iseof &&
38940Sstevel@tonic-gate 	    (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
38950Sstevel@tonic-gate 		space_left -= (prev_len - uio.uio_resid);
38960Sstevel@tonic-gate 		if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
38970Sstevel@tonic-gate 			goto getmoredents;
38980Sstevel@tonic-gate 
38990Sstevel@tonic-gate 		/* else, fall through */
39000Sstevel@tonic-gate 	}
39010Sstevel@tonic-gate 
39020Sstevel@tonic-gate good:
39030Sstevel@tonic-gate 
39040Sstevel@tonic-gate #ifdef DEBUG
39050Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
39060Sstevel@tonic-gate 		va.va_mask = AT_ALL;
39075331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
39080Sstevel@tonic-gate 	} else
39090Sstevel@tonic-gate 		vap = NULL;
39100Sstevel@tonic-gate #else
39110Sstevel@tonic-gate 	va.va_mask = AT_ALL;
39125331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
39130Sstevel@tonic-gate #endif
39140Sstevel@tonic-gate 
39150Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
39160Sstevel@tonic-gate 
39170Sstevel@tonic-gate 	infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
39180Sstevel@tonic-gate 	resp->resok.infop = infop;
39190Sstevel@tonic-gate 
39200Sstevel@tonic-gate 	dp = (struct dirent64 *)data;
39210Sstevel@tonic-gate 	for (i = 0; i < nents; i++) {
39220Sstevel@tonic-gate 
39230Sstevel@tonic-gate 		if (dp->d_ino == 0) {
39240Sstevel@tonic-gate 			infop[i].attr.attributes = FALSE;
39250Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
39260Sstevel@tonic-gate 			dp = nextdp(dp);
39270Sstevel@tonic-gate 			continue;
39280Sstevel@tonic-gate 		}
39290Sstevel@tonic-gate 
39300Sstevel@tonic-gate 		infop[i].namelen = namlen[i];
39310Sstevel@tonic-gate 
39325331Samw 		error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
39335599Sjwahlig 		    NULL, NULL, NULL);
39340Sstevel@tonic-gate 		if (error) {
39350Sstevel@tonic-gate 			infop[i].attr.attributes = FALSE;
39360Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
39370Sstevel@tonic-gate 			dp = nextdp(dp);
39380Sstevel@tonic-gate 			continue;
39390Sstevel@tonic-gate 		}
39400Sstevel@tonic-gate 
39410Sstevel@tonic-gate #ifdef DEBUG
39420Sstevel@tonic-gate 		if (rfs3_do_post_op_attr) {
39430Sstevel@tonic-gate 			nva.va_mask = AT_ALL;
39440Sstevel@tonic-gate 			nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ?
39455599Sjwahlig 			    NULL : &nva;
39460Sstevel@tonic-gate 		} else
39470Sstevel@tonic-gate 			nvap = NULL;
39480Sstevel@tonic-gate #else
39490Sstevel@tonic-gate 		nva.va_mask = AT_ALL;
39500Sstevel@tonic-gate 		nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
39510Sstevel@tonic-gate #endif
395211291SRobert.Thurlow@Sun.COM 		/* Lie about the object type for a referral */
395311291SRobert.Thurlow@Sun.COM 		if (vn_is_nfs_reparse(nvp, cr))
395411291SRobert.Thurlow@Sun.COM 			nvap->va_type = VLNK;
395511291SRobert.Thurlow@Sun.COM 
39560Sstevel@tonic-gate 		vattr_to_post_op_attr(nvap, &infop[i].attr);
39570Sstevel@tonic-gate 
39580Sstevel@tonic-gate #ifdef DEBUG
39590Sstevel@tonic-gate 		if (!rfs3_do_post_op_fh3)
39600Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
39610Sstevel@tonic-gate 		else {
39620Sstevel@tonic-gate #endif
39630Sstevel@tonic-gate 		error = makefh3(&infop[i].fh.handle, nvp, exi);
39640Sstevel@tonic-gate 		if (!error)
39650Sstevel@tonic-gate 			infop[i].fh.handle_follows = TRUE;
39660Sstevel@tonic-gate 		else
39670Sstevel@tonic-gate 			infop[i].fh.handle_follows = FALSE;
39680Sstevel@tonic-gate #ifdef DEBUG
39690Sstevel@tonic-gate 		}
39700Sstevel@tonic-gate #endif
39710Sstevel@tonic-gate 
39720Sstevel@tonic-gate 		VN_RELE(nvp);
39730Sstevel@tonic-gate 		dp = nextdp(dp);
39740Sstevel@tonic-gate 	}
39750Sstevel@tonic-gate 
39767961SNatalie.Li@Sun.COM 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
39777961SNatalie.Li@Sun.COM 	ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
39787961SNatalie.Li@Sun.COM 	if (ndata == NULL)
39797961SNatalie.Li@Sun.COM 		ndata = data;
39807961SNatalie.Li@Sun.COM 
39817961SNatalie.Li@Sun.COM 	if (ret > 0) {
39827961SNatalie.Li@Sun.COM 		/*
39837961SNatalie.Li@Sun.COM 		 * We had to drop one or more entries in order to fit
39847961SNatalie.Li@Sun.COM 		 * during the character conversion.  We need to patch
39857961SNatalie.Li@Sun.COM 		 * up the size and eof info.
39867961SNatalie.Li@Sun.COM 		 */
39877961SNatalie.Li@Sun.COM 		if (iseof)
39887961SNatalie.Li@Sun.COM 			iseof = FALSE;
39897961SNatalie.Li@Sun.COM 
39907961SNatalie.Li@Sun.COM 		ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
39917961SNatalie.Li@Sun.COM 		    nents, ret);
39927961SNatalie.Li@Sun.COM 	}
39937961SNatalie.Li@Sun.COM 
39947961SNatalie.Li@Sun.COM 
39950Sstevel@tonic-gate #if 0 /* notyet */
39960Sstevel@tonic-gate 	/*
39970Sstevel@tonic-gate 	 * Don't do this.  It causes local disk writes when just
39980Sstevel@tonic-gate 	 * reading the file and the overhead is deemed larger
39990Sstevel@tonic-gate 	 * than the benefit.
40000Sstevel@tonic-gate 	 */
40010Sstevel@tonic-gate 	/*
40020Sstevel@tonic-gate 	 * Force modified metadata out to stable storage.
40030Sstevel@tonic-gate 	 */
40045331Samw 	(void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
40050Sstevel@tonic-gate #endif
40060Sstevel@tonic-gate 
40070Sstevel@tonic-gate 	kmem_free(namlen, args->dircount);
40080Sstevel@tonic-gate 
40090Sstevel@tonic-gate 	resp->status = NFS3_OK;
40100Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
40110Sstevel@tonic-gate 	resp->resok.cookieverf = 0;
40127961SNatalie.Li@Sun.COM 	resp->resok.reply.entries = (entryplus3 *)ndata;
40130Sstevel@tonic-gate 	resp->resok.reply.eof = iseof;
40140Sstevel@tonic-gate 	resp->resok.size = nents;
40157961SNatalie.Li@Sun.COM 	resp->resok.count = args->dircount - ret;
40160Sstevel@tonic-gate 	resp->resok.maxcount = args->maxcount;
40175982Sahl 
40185982Sahl 	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
40195982Sahl 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
40207961SNatalie.Li@Sun.COM 	if (ndata != data)
40217961SNatalie.Li@Sun.COM 		kmem_free(data, args->dircount);
40227961SNatalie.Li@Sun.COM 
40235982Sahl 
40245982Sahl 	VN_RELE(vp);
40255982Sahl 
40260Sstevel@tonic-gate 	return;
40270Sstevel@tonic-gate 
40280Sstevel@tonic-gate out:
40290Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
40300Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
40310Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
40327961SNatalie.Li@Sun.COM 	} else {
40330Sstevel@tonic-gate 		resp->status = puterrno3(error);
40347961SNatalie.Li@Sun.COM 	}
40350Sstevel@tonic-gate out1:
40365982Sahl 	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
40375982Sahl 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
40385982Sahl 
40390Sstevel@tonic-gate 	if (vp != NULL) {
40400Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
40410Sstevel@tonic-gate 		VN_RELE(vp);
40420Sstevel@tonic-gate 	}
40430Sstevel@tonic-gate 
40440Sstevel@tonic-gate 	if (namlen != NULL)
40450Sstevel@tonic-gate 		kmem_free(namlen, args->dircount);
40460Sstevel@tonic-gate 
40470Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
40480Sstevel@tonic-gate }
40490Sstevel@tonic-gate 
40501610Sthurlow void *
rfs3_readdirplus_getfh(READDIRPLUS3args * args)40510Sstevel@tonic-gate rfs3_readdirplus_getfh(READDIRPLUS3args *args)
40520Sstevel@tonic-gate {
40530Sstevel@tonic-gate 
40541610Sthurlow 	return (&args->dir);
40550Sstevel@tonic-gate }
40560Sstevel@tonic-gate 
40570Sstevel@tonic-gate void
rfs3_readdirplus_free(READDIRPLUS3res * resp)40580Sstevel@tonic-gate rfs3_readdirplus_free(READDIRPLUS3res *resp)
40590Sstevel@tonic-gate {
40600Sstevel@tonic-gate 
40610Sstevel@tonic-gate 	if (resp->status == NFS3_OK) {
40620Sstevel@tonic-gate 		kmem_free(resp->resok.reply.entries, resp->resok.count);
40630Sstevel@tonic-gate 		kmem_free(resp->resok.infop,
40645599Sjwahlig 		    resp->resok.size * sizeof (struct entryplus3_info));
40650Sstevel@tonic-gate 	}
40660Sstevel@tonic-gate }
40670Sstevel@tonic-gate 
40680Sstevel@tonic-gate /* ARGSUSED */
40690Sstevel@tonic-gate void
rfs3_fsstat(FSSTAT3args * args,FSSTAT3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)40700Sstevel@tonic-gate rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
40710Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
40720Sstevel@tonic-gate {
40730Sstevel@tonic-gate 	int error;
40740Sstevel@tonic-gate 	vnode_t *vp;
40750Sstevel@tonic-gate 	struct vattr *vap;
40760Sstevel@tonic-gate 	struct vattr va;
40770Sstevel@tonic-gate 	struct statvfs64 sb;
40780Sstevel@tonic-gate 
40790Sstevel@tonic-gate 	vap = NULL;
40800Sstevel@tonic-gate 
40810Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->fsroot, exi);
40825982Sahl 
40835982Sahl 	DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
40845982Sahl 	    cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
40855982Sahl 
40860Sstevel@tonic-gate 	if (vp == NULL) {
40870Sstevel@tonic-gate 		error = ESTALE;
40880Sstevel@tonic-gate 		goto out;
40890Sstevel@tonic-gate 	}
40900Sstevel@tonic-gate 
40914971Sjarrett 	if (is_system_labeled()) {
40924971Sjarrett 		bslabel_t *clabel = req->rq_label;
40934971Sjarrett 
40944971Sjarrett 		ASSERT(clabel != NULL);
40954971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
40964971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
40974971Sjarrett 
40984971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
40999871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
41009871SJarrett.Lu@Sun.COM 			    exi)) {
41014971Sjarrett 				resp->status = NFS3ERR_ACCES;
41024971Sjarrett 				goto out1;
41034971Sjarrett 			}
41044971Sjarrett 		}
41054971Sjarrett 	}
41064971Sjarrett 
41070Sstevel@tonic-gate 	error = VFS_STATVFS(vp->v_vfsp, &sb);
41080Sstevel@tonic-gate 
41090Sstevel@tonic-gate #ifdef DEBUG
41100Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
41110Sstevel@tonic-gate 		va.va_mask = AT_ALL;
41125331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
41130Sstevel@tonic-gate 	} else
41140Sstevel@tonic-gate 		vap = NULL;
41150Sstevel@tonic-gate #else
41160Sstevel@tonic-gate 	va.va_mask = AT_ALL;
41175331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
41180Sstevel@tonic-gate #endif
41190Sstevel@tonic-gate 
41200Sstevel@tonic-gate 	if (error)
41210Sstevel@tonic-gate 		goto out;
41220Sstevel@tonic-gate 
41230Sstevel@tonic-gate 	resp->status = NFS3_OK;
41240Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
41250Sstevel@tonic-gate 	if (sb.f_blocks != (fsblkcnt64_t)-1)
41260Sstevel@tonic-gate 		resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
41270Sstevel@tonic-gate 	else
41280Sstevel@tonic-gate 		resp->resok.tbytes = (size3)sb.f_blocks;
41290Sstevel@tonic-gate 	if (sb.f_bfree != (fsblkcnt64_t)-1)
41300Sstevel@tonic-gate 		resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
41310Sstevel@tonic-gate 	else
41320Sstevel@tonic-gate 		resp->resok.fbytes = (size3)sb.f_bfree;
41330Sstevel@tonic-gate 	if (sb.f_bavail != (fsblkcnt64_t)-1)
41340Sstevel@tonic-gate 		resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
41350Sstevel@tonic-gate 	else
41360Sstevel@tonic-gate 		resp->resok.abytes = (size3)sb.f_bavail;
41370Sstevel@tonic-gate 	resp->resok.tfiles = (size3)sb.f_files;
41380Sstevel@tonic-gate 	resp->resok.ffiles = (size3)sb.f_ffree;
41390Sstevel@tonic-gate 	resp->resok.afiles = (size3)sb.f_favail;
41400Sstevel@tonic-gate 	resp->resok.invarsec = 0;
41415982Sahl 
41425982Sahl 	DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
41435982Sahl 	    cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
41445982Sahl 	VN_RELE(vp);
41455982Sahl 
41460Sstevel@tonic-gate 	return;
41470Sstevel@tonic-gate 
41480Sstevel@tonic-gate out:
41490Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
41500Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
41510Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
41520Sstevel@tonic-gate 	} else
41530Sstevel@tonic-gate 		resp->status = puterrno3(error);
41544971Sjarrett out1:
41555982Sahl 	DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
41565982Sahl 	    cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
41575982Sahl 
41584971Sjarrett 	if (vp != NULL)
41594971Sjarrett 		VN_RELE(vp);
41600Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
41610Sstevel@tonic-gate }
41620Sstevel@tonic-gate 
41631610Sthurlow void *
rfs3_fsstat_getfh(FSSTAT3args * args)41640Sstevel@tonic-gate rfs3_fsstat_getfh(FSSTAT3args *args)
41650Sstevel@tonic-gate {
41660Sstevel@tonic-gate 
41671610Sthurlow 	return (&args->fsroot);
41680Sstevel@tonic-gate }
41690Sstevel@tonic-gate 
41700Sstevel@tonic-gate void
rfs3_fsinfo(FSINFO3args * args,FSINFO3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)41710Sstevel@tonic-gate rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
41720Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
41730Sstevel@tonic-gate {
41740Sstevel@tonic-gate 	vnode_t *vp;
41750Sstevel@tonic-gate 	struct vattr *vap;
41760Sstevel@tonic-gate 	struct vattr va;
41770Sstevel@tonic-gate 	uint32_t xfer_size;
41780Sstevel@tonic-gate 	ulong_t l = 0;
41790Sstevel@tonic-gate 	int error;
41800Sstevel@tonic-gate 
41810Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->fsroot, exi);
41825982Sahl 
41835982Sahl 	DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
41845982Sahl 	    cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
41855982Sahl 
41860Sstevel@tonic-gate 	if (vp == NULL) {
41870Sstevel@tonic-gate 		if (curthread->t_flag & T_WOULDBLOCK) {
41880Sstevel@tonic-gate 			curthread->t_flag &= ~T_WOULDBLOCK;
41890Sstevel@tonic-gate 			resp->status = NFS3ERR_JUKEBOX;
41900Sstevel@tonic-gate 		} else
41910Sstevel@tonic-gate 			resp->status = NFS3ERR_STALE;
41920Sstevel@tonic-gate 		vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
41935982Sahl 		goto out;
41940Sstevel@tonic-gate 	}
41950Sstevel@tonic-gate 
41964971Sjarrett 	if (is_system_labeled()) {
41974971Sjarrett 		bslabel_t *clabel = req->rq_label;
41984971Sjarrett 
41994971Sjarrett 		ASSERT(clabel != NULL);
42004971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
42014971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
42024971Sjarrett 
42034971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
42049871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
42059871SJarrett.Lu@Sun.COM 			    exi)) {
42064971Sjarrett 				resp->status = NFS3ERR_STALE;
42074971Sjarrett 				vattr_to_post_op_attr(NULL,
42084971Sjarrett 				    &resp->resfail.obj_attributes);
42095982Sahl 				goto out;
42104971Sjarrett 			}
42114971Sjarrett 		}
42124971Sjarrett 	}
42134971Sjarrett 
42140Sstevel@tonic-gate #ifdef DEBUG
42150Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
42160Sstevel@tonic-gate 		va.va_mask = AT_ALL;
42175331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
42180Sstevel@tonic-gate 	} else
42190Sstevel@tonic-gate 		vap = NULL;
42200Sstevel@tonic-gate #else
42210Sstevel@tonic-gate 	va.va_mask = AT_ALL;
42225331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
42230Sstevel@tonic-gate #endif
42240Sstevel@tonic-gate 
42250Sstevel@tonic-gate 	resp->status = NFS3_OK;
42260Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
42270Sstevel@tonic-gate 	xfer_size = rfs3_tsize(req);
42280Sstevel@tonic-gate 	resp->resok.rtmax = xfer_size;
42290Sstevel@tonic-gate 	resp->resok.rtpref = xfer_size;
42300Sstevel@tonic-gate 	resp->resok.rtmult = DEV_BSIZE;
42310Sstevel@tonic-gate 	resp->resok.wtmax = xfer_size;
42320Sstevel@tonic-gate 	resp->resok.wtpref = xfer_size;
42330Sstevel@tonic-gate 	resp->resok.wtmult = DEV_BSIZE;
42340Sstevel@tonic-gate 	resp->resok.dtpref = MAXBSIZE;
42350Sstevel@tonic-gate 
42360Sstevel@tonic-gate 	/*
42370Sstevel@tonic-gate 	 * Large file spec: want maxfilesize based on limit of
42380Sstevel@tonic-gate 	 * underlying filesystem.  We can guess 2^31-1 if need be.
42390Sstevel@tonic-gate 	 */
42405331Samw 	error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
424110035SPiyush.Shivam@Sun.COM 	if (error) {
424210035SPiyush.Shivam@Sun.COM 		resp->status = puterrno3(error);
424310035SPiyush.Shivam@Sun.COM 		goto out;
424410035SPiyush.Shivam@Sun.COM 	}
424510035SPiyush.Shivam@Sun.COM 
424610035SPiyush.Shivam@Sun.COM 	/*
424710035SPiyush.Shivam@Sun.COM 	 * If the underlying file system does not support _PC_FILESIZEBITS,
424810035SPiyush.Shivam@Sun.COM 	 * return a reasonable default. Note that error code on VOP_PATHCONF
424910035SPiyush.Shivam@Sun.COM 	 * will be 0, even if the underlying file system does not support
425010035SPiyush.Shivam@Sun.COM 	 * _PC_FILESIZEBITS.
425110035SPiyush.Shivam@Sun.COM 	 */
425210035SPiyush.Shivam@Sun.COM 	if (l == (ulong_t)-1) {
42530Sstevel@tonic-gate 		resp->resok.maxfilesize = MAXOFF32_T;
425410035SPiyush.Shivam@Sun.COM 	} else {
425510035SPiyush.Shivam@Sun.COM 		if (l >= (sizeof (uint64_t) * 8))
425610035SPiyush.Shivam@Sun.COM 			resp->resok.maxfilesize = INT64_MAX;
425710035SPiyush.Shivam@Sun.COM 		else
425810035SPiyush.Shivam@Sun.COM 			resp->resok.maxfilesize = (1LL << (l-1)) - 1;
425910035SPiyush.Shivam@Sun.COM 	}
42600Sstevel@tonic-gate 
42610Sstevel@tonic-gate 	resp->resok.time_delta.seconds = 0;
42620Sstevel@tonic-gate 	resp->resok.time_delta.nseconds = 1000;
42630Sstevel@tonic-gate 	resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
42640Sstevel@tonic-gate 	    FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
42655982Sahl 
42665982Sahl 	DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
42675982Sahl 	    cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
42685982Sahl 
42695982Sahl 	VN_RELE(vp);
42705982Sahl 
42715982Sahl 	return;
42725982Sahl 
42735982Sahl out:
42745982Sahl 	DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
42755982Sahl 	    cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
42765982Sahl 	if (vp != NULL)
42775982Sahl 		VN_RELE(vp);
42780Sstevel@tonic-gate }
42790Sstevel@tonic-gate 
42801610Sthurlow void *
rfs3_fsinfo_getfh(FSINFO3args * args)42810Sstevel@tonic-gate rfs3_fsinfo_getfh(FSINFO3args *args)
42820Sstevel@tonic-gate {
42830Sstevel@tonic-gate 
42841610Sthurlow 	return (&args->fsroot);
42850Sstevel@tonic-gate }
42860Sstevel@tonic-gate 
42870Sstevel@tonic-gate /* ARGSUSED */
42880Sstevel@tonic-gate void
rfs3_pathconf(PATHCONF3args * args,PATHCONF3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)42890Sstevel@tonic-gate rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
42900Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
42910Sstevel@tonic-gate {
42920Sstevel@tonic-gate 	int error;
42930Sstevel@tonic-gate 	vnode_t *vp;
42940Sstevel@tonic-gate 	struct vattr *vap;
42950Sstevel@tonic-gate 	struct vattr va;
42960Sstevel@tonic-gate 	ulong_t val;
42970Sstevel@tonic-gate 
42980Sstevel@tonic-gate 	vap = NULL;
42990Sstevel@tonic-gate 
43000Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->object, exi);
43015982Sahl 
43025982Sahl 	DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
43035982Sahl 	    cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
43045982Sahl 
43050Sstevel@tonic-gate 	if (vp == NULL) {
43060Sstevel@tonic-gate 		error = ESTALE;
43070Sstevel@tonic-gate 		goto out;
43080Sstevel@tonic-gate 	}
43090Sstevel@tonic-gate 
43104971Sjarrett 	if (is_system_labeled()) {
43114971Sjarrett 		bslabel_t *clabel = req->rq_label;
43124971Sjarrett 
43134971Sjarrett 		ASSERT(clabel != NULL);
43144971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
43154971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
43164971Sjarrett 
43174971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
43189871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
43199871SJarrett.Lu@Sun.COM 			    exi)) {
43204971Sjarrett 				resp->status = NFS3ERR_ACCES;
43214971Sjarrett 				goto out1;
43224971Sjarrett 			}
43234971Sjarrett 		}
43244971Sjarrett 	}
43254971Sjarrett 
43260Sstevel@tonic-gate #ifdef DEBUG
43270Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
43280Sstevel@tonic-gate 		va.va_mask = AT_ALL;
43295331Samw 		vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
43300Sstevel@tonic-gate 	} else
43310Sstevel@tonic-gate 		vap = NULL;
43320Sstevel@tonic-gate #else
43330Sstevel@tonic-gate 	va.va_mask = AT_ALL;
43345331Samw 	vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
43350Sstevel@tonic-gate #endif
43360Sstevel@tonic-gate 
43375331Samw 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
43380Sstevel@tonic-gate 	if (error)
43390Sstevel@tonic-gate 		goto out;
43400Sstevel@tonic-gate 	resp->resok.info.link_max = (uint32)val;
43410Sstevel@tonic-gate 
43425331Samw 	error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
43430Sstevel@tonic-gate 	if (error)
43440Sstevel@tonic-gate 		goto out;
43450Sstevel@tonic-gate 	resp->resok.info.name_max = (uint32)val;
43460Sstevel@tonic-gate 
43475331Samw 	error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
43480Sstevel@tonic-gate 	if (error)
43490Sstevel@tonic-gate 		goto out;
43500Sstevel@tonic-gate 	if (val == 1)
43510Sstevel@tonic-gate 		resp->resok.info.no_trunc = TRUE;
43520Sstevel@tonic-gate 	else
43530Sstevel@tonic-gate 		resp->resok.info.no_trunc = FALSE;
43540Sstevel@tonic-gate 
43555331Samw 	error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
43560Sstevel@tonic-gate 	if (error)
43570Sstevel@tonic-gate 		goto out;
43580Sstevel@tonic-gate 	if (val == 1)
43590Sstevel@tonic-gate 		resp->resok.info.chown_restricted = TRUE;
43600Sstevel@tonic-gate 	else
43610Sstevel@tonic-gate 		resp->resok.info.chown_restricted = FALSE;
43620Sstevel@tonic-gate 
43630Sstevel@tonic-gate 	resp->status = NFS3_OK;
43640Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
43650Sstevel@tonic-gate 	resp->resok.info.case_insensitive = FALSE;
43660Sstevel@tonic-gate 	resp->resok.info.case_preserving = TRUE;
43675982Sahl 	DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
43685982Sahl 	    cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
43695982Sahl 	VN_RELE(vp);
43700Sstevel@tonic-gate 	return;
43710Sstevel@tonic-gate 
43720Sstevel@tonic-gate out:
43730Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
43740Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
43750Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
43760Sstevel@tonic-gate 	} else
43770Sstevel@tonic-gate 		resp->status = puterrno3(error);
43784971Sjarrett out1:
43795982Sahl 	DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
43805982Sahl 	    cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
43810Sstevel@tonic-gate 	if (vp != NULL)
43820Sstevel@tonic-gate 		VN_RELE(vp);
43830Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
43840Sstevel@tonic-gate }
43850Sstevel@tonic-gate 
43861610Sthurlow void *
rfs3_pathconf_getfh(PATHCONF3args * args)43870Sstevel@tonic-gate rfs3_pathconf_getfh(PATHCONF3args *args)
43880Sstevel@tonic-gate {
43890Sstevel@tonic-gate 
43901610Sthurlow 	return (&args->object);
43910Sstevel@tonic-gate }
43920Sstevel@tonic-gate 
43930Sstevel@tonic-gate void
rfs3_commit(COMMIT3args * args,COMMIT3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)43940Sstevel@tonic-gate rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
43950Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
43960Sstevel@tonic-gate {
43970Sstevel@tonic-gate 	int error;
43980Sstevel@tonic-gate 	vnode_t *vp;
43990Sstevel@tonic-gate 	struct vattr *bvap;
44000Sstevel@tonic-gate 	struct vattr bva;
44010Sstevel@tonic-gate 	struct vattr *avap;
44020Sstevel@tonic-gate 	struct vattr ava;
44030Sstevel@tonic-gate 
44040Sstevel@tonic-gate 	bvap = NULL;
44050Sstevel@tonic-gate 	avap = NULL;
44060Sstevel@tonic-gate 
44070Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->file, exi);
44085982Sahl 
44095982Sahl 	DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
44105982Sahl 	    cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
44115982Sahl 
44120Sstevel@tonic-gate 	if (vp == NULL) {
44130Sstevel@tonic-gate 		error = ESTALE;
44140Sstevel@tonic-gate 		goto out;
44150Sstevel@tonic-gate 	}
44160Sstevel@tonic-gate 
44170Sstevel@tonic-gate 	bva.va_mask = AT_ALL;
44185331Samw 	error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
44190Sstevel@tonic-gate 
44200Sstevel@tonic-gate 	/*
44210Sstevel@tonic-gate 	 * If we can't get the attributes, then we can't do the
44220Sstevel@tonic-gate 	 * right access checking.  So, we'll fail the request.
44230Sstevel@tonic-gate 	 */
44240Sstevel@tonic-gate 	if (error)
44250Sstevel@tonic-gate 		goto out;
44260Sstevel@tonic-gate 
44270Sstevel@tonic-gate #ifdef DEBUG
44280Sstevel@tonic-gate 	if (rfs3_do_pre_op_attr)
44290Sstevel@tonic-gate 		bvap = &bva;
44300Sstevel@tonic-gate 	else
44310Sstevel@tonic-gate 		bvap = NULL;
44320Sstevel@tonic-gate #else
44330Sstevel@tonic-gate 	bvap = &bva;
44340Sstevel@tonic-gate #endif
44350Sstevel@tonic-gate 
44360Sstevel@tonic-gate 	if (rdonly(exi, req)) {
44370Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
44380Sstevel@tonic-gate 		goto out1;
44390Sstevel@tonic-gate 	}
44400Sstevel@tonic-gate 
44410Sstevel@tonic-gate 	if (vp->v_type != VREG) {
44420Sstevel@tonic-gate 		resp->status = NFS3ERR_INVAL;
44430Sstevel@tonic-gate 		goto out1;
44440Sstevel@tonic-gate 	}
44450Sstevel@tonic-gate 
44464971Sjarrett 	if (is_system_labeled()) {
44474971Sjarrett 		bslabel_t *clabel = req->rq_label;
44484971Sjarrett 
44494971Sjarrett 		ASSERT(clabel != NULL);
44504971Sjarrett 		DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
44514971Sjarrett 		    "got client label from request(1)", struct svc_req *, req);
44524971Sjarrett 
44534971Sjarrett 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
44549871SJarrett.Lu@Sun.COM 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
44559871SJarrett.Lu@Sun.COM 			    exi)) {
44564971Sjarrett 				resp->status = NFS3ERR_ACCES;
44574971Sjarrett 				goto out1;
44584971Sjarrett 			}
44594971Sjarrett 		}
44604971Sjarrett 	}
44614971Sjarrett 
44620Sstevel@tonic-gate 	if (crgetuid(cr) != bva.va_uid &&
44635331Samw 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
44640Sstevel@tonic-gate 		goto out;
44650Sstevel@tonic-gate 
446611894SJeff.A.Smith@Sun.Com 	error = VOP_FSYNC(vp, FSYNC, cr, NULL);
44670Sstevel@tonic-gate 
44680Sstevel@tonic-gate #ifdef DEBUG
44690Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
44700Sstevel@tonic-gate 		ava.va_mask = AT_ALL;
44715331Samw 		avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
44720Sstevel@tonic-gate 	} else
44730Sstevel@tonic-gate 		avap = NULL;
44740Sstevel@tonic-gate #else
44750Sstevel@tonic-gate 	ava.va_mask = AT_ALL;
44765331Samw 	avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
44770Sstevel@tonic-gate #endif
44780Sstevel@tonic-gate 
44790Sstevel@tonic-gate 	if (error)
44800Sstevel@tonic-gate 		goto out;
44810Sstevel@tonic-gate 
44820Sstevel@tonic-gate 	resp->status = NFS3_OK;
44830Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
44840Sstevel@tonic-gate 	resp->resok.verf = write3verf;
44855982Sahl 
44865982Sahl 	DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
44875982Sahl 	    cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
44885982Sahl 
44895982Sahl 	VN_RELE(vp);
44905982Sahl 
44910Sstevel@tonic-gate 	return;
44920Sstevel@tonic-gate 
44930Sstevel@tonic-gate out:
44940Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
44950Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
44960Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
44970Sstevel@tonic-gate 	} else
44980Sstevel@tonic-gate 		resp->status = puterrno3(error);
44990Sstevel@tonic-gate out1:
45005982Sahl 	DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
45015982Sahl 	    cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
45025982Sahl 
45030Sstevel@tonic-gate 	if (vp != NULL)
45040Sstevel@tonic-gate 		VN_RELE(vp);
45050Sstevel@tonic-gate 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
45060Sstevel@tonic-gate }
45070Sstevel@tonic-gate 
45081610Sthurlow void *
rfs3_commit_getfh(COMMIT3args * args)45090Sstevel@tonic-gate rfs3_commit_getfh(COMMIT3args *args)
45100Sstevel@tonic-gate {
45110Sstevel@tonic-gate 
45121610Sthurlow 	return (&args->file);
45130Sstevel@tonic-gate }
45140Sstevel@tonic-gate 
45150Sstevel@tonic-gate static int
sattr3_to_vattr(sattr3 * sap,struct vattr * vap)45160Sstevel@tonic-gate sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
45170Sstevel@tonic-gate {
45180Sstevel@tonic-gate 
45190Sstevel@tonic-gate 	vap->va_mask = 0;
45200Sstevel@tonic-gate 
45210Sstevel@tonic-gate 	if (sap->mode.set_it) {
45220Sstevel@tonic-gate 		vap->va_mode = (mode_t)sap->mode.mode;
45230Sstevel@tonic-gate 		vap->va_mask |= AT_MODE;
45240Sstevel@tonic-gate 	}
45250Sstevel@tonic-gate 	if (sap->uid.set_it) {
45260Sstevel@tonic-gate 		vap->va_uid = (uid_t)sap->uid.uid;
45270Sstevel@tonic-gate 		vap->va_mask |= AT_UID;
45280Sstevel@tonic-gate 	}
45290Sstevel@tonic-gate 	if (sap->gid.set_it) {
45300Sstevel@tonic-gate 		vap->va_gid = (gid_t)sap->gid.gid;
45310Sstevel@tonic-gate 		vap->va_mask |= AT_GID;
45320Sstevel@tonic-gate 	}
45330Sstevel@tonic-gate 	if (sap->size.set_it) {
45340Sstevel@tonic-gate 		if (sap->size.size > (size3)((u_longlong_t)-1))
45350Sstevel@tonic-gate 			return (EINVAL);
45360Sstevel@tonic-gate 		vap->va_size = sap->size.size;
45370Sstevel@tonic-gate 		vap->va_mask |= AT_SIZE;
45380Sstevel@tonic-gate 	}
45390Sstevel@tonic-gate 	if (sap->atime.set_it == SET_TO_CLIENT_TIME) {
45400Sstevel@tonic-gate #ifndef _LP64
45410Sstevel@tonic-gate 		/* check time validity */
45420Sstevel@tonic-gate 		if (!NFS3_TIME_OK(sap->atime.atime.seconds))
45430Sstevel@tonic-gate 			return (EOVERFLOW);
45440Sstevel@tonic-gate #endif
45450Sstevel@tonic-gate 		/*
45460Sstevel@tonic-gate 		 * nfs protocol defines times as unsigned so don't extend sign,
45470Sstevel@tonic-gate 		 * unless sysadmin set nfs_allow_preepoch_time.
45480Sstevel@tonic-gate 		 */
45490Sstevel@tonic-gate 		NFS_TIME_T_CONVERT(vap->va_atime.tv_sec,
45505599Sjwahlig 		    sap->atime.atime.seconds);
45510Sstevel@tonic-gate 		vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds;
45520Sstevel@tonic-gate 		vap->va_mask |= AT_ATIME;
45530Sstevel@tonic-gate 	} else if (sap->atime.set_it == SET_TO_SERVER_TIME) {
45540Sstevel@tonic-gate 		gethrestime(&vap->va_atime);
45550Sstevel@tonic-gate 		vap->va_mask |= AT_ATIME;
45560Sstevel@tonic-gate 	}
45570Sstevel@tonic-gate 	if (sap->mtime.set_it == SET_TO_CLIENT_TIME) {
45580Sstevel@tonic-gate #ifndef _LP64
45590Sstevel@tonic-gate 		/* check time validity */
45600Sstevel@tonic-gate 		if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
45610Sstevel@tonic-gate 			return (EOVERFLOW);
45620Sstevel@tonic-gate #endif
45630Sstevel@tonic-gate 		/*
45640Sstevel@tonic-gate 		 * nfs protocol defines times as unsigned so don't extend sign,
45650Sstevel@tonic-gate 		 * unless sysadmin set nfs_allow_preepoch_time.
45660Sstevel@tonic-gate 		 */
45670Sstevel@tonic-gate 		NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
45685599Sjwahlig 		    sap->mtime.mtime.seconds);
45690Sstevel@tonic-gate 		vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
45700Sstevel@tonic-gate 		vap->va_mask |= AT_MTIME;
45710Sstevel@tonic-gate 	} else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
45720Sstevel@tonic-gate 		gethrestime(&vap->va_mtime);
45730Sstevel@tonic-gate 		vap->va_mask |= AT_MTIME;
45740Sstevel@tonic-gate 	}
45750Sstevel@tonic-gate 
45760Sstevel@tonic-gate 	return (0);
45770Sstevel@tonic-gate }
45780Sstevel@tonic-gate 
45790Sstevel@tonic-gate static ftype3 vt_to_nf3[] = {
45800Sstevel@tonic-gate 	0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
45810Sstevel@tonic-gate };
45820Sstevel@tonic-gate 
45830Sstevel@tonic-gate static int
vattr_to_fattr3(struct vattr * vap,fattr3 * fap)45840Sstevel@tonic-gate vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
45850Sstevel@tonic-gate {
45860Sstevel@tonic-gate 
45870Sstevel@tonic-gate 	ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
45880Sstevel@tonic-gate 	/* Return error if time or size overflow */
45890Sstevel@tonic-gate 	if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
45900Sstevel@tonic-gate 		return (EOVERFLOW);
45910Sstevel@tonic-gate 	}
45920Sstevel@tonic-gate 	fap->type = vt_to_nf3[vap->va_type];
45930Sstevel@tonic-gate 	fap->mode = (mode3)(vap->va_mode & MODEMASK);
45940Sstevel@tonic-gate 	fap->nlink = (uint32)vap->va_nlink;
45950Sstevel@tonic-gate 	if (vap->va_uid == UID_NOBODY)
45960Sstevel@tonic-gate 		fap->uid = (uid3)NFS_UID_NOBODY;
45970Sstevel@tonic-gate 	else
45980Sstevel@tonic-gate 		fap->uid = (uid3)vap->va_uid;
45990Sstevel@tonic-gate 	if (vap->va_gid == GID_NOBODY)
46000Sstevel@tonic-gate 		fap->gid = (gid3)NFS_GID_NOBODY;
46010Sstevel@tonic-gate 	else
46020Sstevel@tonic-gate 		fap->gid = (gid3)vap->va_gid;
46030Sstevel@tonic-gate 	fap->size = (size3)vap->va_size;
46040Sstevel@tonic-gate 	fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks;
46050Sstevel@tonic-gate 	fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev);
46060Sstevel@tonic-gate 	fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev);
46070Sstevel@tonic-gate 	fap->fsid = (uint64)vap->va_fsid;
46080Sstevel@tonic-gate 	fap->fileid = (fileid3)vap->va_nodeid;
46090Sstevel@tonic-gate 	fap->atime.seconds = vap->va_atime.tv_sec;
46100Sstevel@tonic-gate 	fap->atime.nseconds = vap->va_atime.tv_nsec;
46110Sstevel@tonic-gate 	fap->mtime.seconds = vap->va_mtime.tv_sec;
46120Sstevel@tonic-gate 	fap->mtime.nseconds = vap->va_mtime.tv_nsec;
46130Sstevel@tonic-gate 	fap->ctime.seconds = vap->va_ctime.tv_sec;
46140Sstevel@tonic-gate 	fap->ctime.nseconds = vap->va_ctime.tv_nsec;
46150Sstevel@tonic-gate 	return (0);
46160Sstevel@tonic-gate }
46170Sstevel@tonic-gate 
46180Sstevel@tonic-gate static int
vattr_to_wcc_attr(struct vattr * vap,wcc_attr * wccap)46190Sstevel@tonic-gate vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap)
46200Sstevel@tonic-gate {
46210Sstevel@tonic-gate 
46220Sstevel@tonic-gate 	/* Return error if time or size overflow */
46237387SRobert.Gordon@Sun.COM 	if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) &&
46245599Sjwahlig 	    NFS_TIME_T_OK(vap->va_ctime.tv_sec) &&
46255599Sjwahlig 	    NFS3_SIZE_OK(vap->va_size))) {
46260Sstevel@tonic-gate 		return (EOVERFLOW);
46270Sstevel@tonic-gate 	}
46280Sstevel@tonic-gate 	wccap->size = (size3)vap->va_size;
46290Sstevel@tonic-gate 	wccap->mtime.seconds = vap->va_mtime.tv_sec;
46300Sstevel@tonic-gate 	wccap->mtime.nseconds = vap->va_mtime.tv_nsec;
46310Sstevel@tonic-gate 	wccap->ctime.seconds = vap->va_ctime.tv_sec;
46320Sstevel@tonic-gate 	wccap->ctime.nseconds = vap->va_ctime.tv_nsec;
46330Sstevel@tonic-gate 	return (0);
46340Sstevel@tonic-gate }
46350Sstevel@tonic-gate 
46360Sstevel@tonic-gate static void
vattr_to_pre_op_attr(struct vattr * vap,pre_op_attr * poap)46370Sstevel@tonic-gate vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap)
46380Sstevel@tonic-gate {
46390Sstevel@tonic-gate 
46400Sstevel@tonic-gate 	/* don't return attrs if time overflow */
46410Sstevel@tonic-gate 	if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
46420Sstevel@tonic-gate 		poap->attributes = TRUE;
46430Sstevel@tonic-gate 	} else
46440Sstevel@tonic-gate 		poap->attributes = FALSE;
46450Sstevel@tonic-gate }
46460Sstevel@tonic-gate 
46470Sstevel@tonic-gate void
vattr_to_post_op_attr(struct vattr * vap,post_op_attr * poap)46480Sstevel@tonic-gate vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
46490Sstevel@tonic-gate {
46500Sstevel@tonic-gate 
46510Sstevel@tonic-gate 	/* don't return attrs if time overflow */
46520Sstevel@tonic-gate 	if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
46530Sstevel@tonic-gate 		poap->attributes = TRUE;
46540Sstevel@tonic-gate 	} else
46550Sstevel@tonic-gate 		poap->attributes = FALSE;
46560Sstevel@tonic-gate }
46570Sstevel@tonic-gate 
46580Sstevel@tonic-gate static void
vattr_to_wcc_data(struct vattr * bvap,struct vattr * avap,wcc_data * wccp)46590Sstevel@tonic-gate vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
46600Sstevel@tonic-gate {
46610Sstevel@tonic-gate 
46620Sstevel@tonic-gate 	vattr_to_pre_op_attr(bvap, &wccp->before);
46630Sstevel@tonic-gate 	vattr_to_post_op_attr(avap, &wccp->after);
46640Sstevel@tonic-gate }
46650Sstevel@tonic-gate 
46660Sstevel@tonic-gate void
rfs3_srvrinit(void)46670Sstevel@tonic-gate rfs3_srvrinit(void)
46680Sstevel@tonic-gate {
46690Sstevel@tonic-gate 	struct rfs3_verf_overlay {
46700Sstevel@tonic-gate 		uint_t id; /* a "unique" identifier */
46710Sstevel@tonic-gate 		int ts; /* a unique timestamp */
46720Sstevel@tonic-gate 	} *verfp;
46730Sstevel@tonic-gate 	timestruc_t now;
46740Sstevel@tonic-gate 
46750Sstevel@tonic-gate 	/*
46760Sstevel@tonic-gate 	 * The following algorithm attempts to find a unique verifier
46770Sstevel@tonic-gate 	 * to be used as the write verifier returned from the server
46780Sstevel@tonic-gate 	 * to the client.  It is important that this verifier change
46790Sstevel@tonic-gate 	 * whenever the server reboots.  Of secondary importance, it
46800Sstevel@tonic-gate 	 * is important for the verifier to be unique between two
46810Sstevel@tonic-gate 	 * different servers.
46820Sstevel@tonic-gate 	 *
46830Sstevel@tonic-gate 	 * Thus, an attempt is made to use the system hostid and the
46840Sstevel@tonic-gate 	 * current time in seconds when the nfssrv kernel module is
46850Sstevel@tonic-gate 	 * loaded.  It is assumed that an NFS server will not be able
46860Sstevel@tonic-gate 	 * to boot and then to reboot in less than a second.  If the
46870Sstevel@tonic-gate 	 * hostid has not been set, then the current high resolution
46880Sstevel@tonic-gate 	 * time is used.  This will ensure different verifiers each
46890Sstevel@tonic-gate 	 * time the server reboots and minimize the chances that two
46900Sstevel@tonic-gate 	 * different servers will have the same verifier.
46910Sstevel@tonic-gate 	 */
46920Sstevel@tonic-gate 
46930Sstevel@tonic-gate #ifndef	lint
46940Sstevel@tonic-gate 	/*
46950Sstevel@tonic-gate 	 * We ASSERT that this constant logic expression is
46960Sstevel@tonic-gate 	 * always true because in the past, it wasn't.
46970Sstevel@tonic-gate 	 */
46980Sstevel@tonic-gate 	ASSERT(sizeof (*verfp) <= sizeof (write3verf));
46990Sstevel@tonic-gate #endif
47000Sstevel@tonic-gate 
47010Sstevel@tonic-gate 	gethrestime(&now);
47020Sstevel@tonic-gate 	verfp = (struct rfs3_verf_overlay *)&write3verf;
47030Sstevel@tonic-gate 	verfp->ts = (int)now.tv_sec;
47048662SJordan.Vaughan@Sun.com 	verfp->id = zone_get_hostid(NULL);
47050Sstevel@tonic-gate 
47060Sstevel@tonic-gate 	if (verfp->id == 0)
47070Sstevel@tonic-gate 		verfp->id = (uint_t)now.tv_nsec;
47080Sstevel@tonic-gate 
47095599Sjwahlig 	nfs3_srv_caller_id = fs_new_caller_id();
47105599Sjwahlig 
47110Sstevel@tonic-gate }
47120Sstevel@tonic-gate 
47137387SRobert.Gordon@Sun.COM static int
rdma_setup_read_data3(READ3args * args,READ3resok * rok)47147387SRobert.Gordon@Sun.COM rdma_setup_read_data3(READ3args *args, READ3resok *rok)
47157387SRobert.Gordon@Sun.COM {
47167387SRobert.Gordon@Sun.COM 	struct clist	*wcl;
47179348SSiddheshwar.Mahesh@Sun.COM 	int		wlist_len;
47187387SRobert.Gordon@Sun.COM 	count3		count = rok->count;
47197387SRobert.Gordon@Sun.COM 
47207387SRobert.Gordon@Sun.COM 	wcl = args->wlist;
47219348SSiddheshwar.Mahesh@Sun.COM 	if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
47227387SRobert.Gordon@Sun.COM 		return (FALSE);
47237387SRobert.Gordon@Sun.COM 	}
47247387SRobert.Gordon@Sun.COM 
47257387SRobert.Gordon@Sun.COM 	wcl = args->wlist;
47269348SSiddheshwar.Mahesh@Sun.COM 	rok->wlist_len = wlist_len;
47277387SRobert.Gordon@Sun.COM 	rok->wlist = wcl;
47287387SRobert.Gordon@Sun.COM 	return (TRUE);
47297387SRobert.Gordon@Sun.COM }
47307387SRobert.Gordon@Sun.COM 
47310Sstevel@tonic-gate void
rfs3_srvrfini(void)47320Sstevel@tonic-gate rfs3_srvrfini(void)
47330Sstevel@tonic-gate {
47340Sstevel@tonic-gate 	/* Nothing to do */
47350Sstevel@tonic-gate }
4736