--- old/usr/src/uts/common/fs/nfs/nfs3_srv.c	Mon Feb  3 11:23:25 2020
+++ new/usr/src/uts/common/fs/nfs/nfs3_srv.c	Mon Feb  3 11:23:25 2020
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.
  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 by Delphix. All rights reserved.
  */
@@ -28,6 +28,7 @@
 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
 /* All Rights Reserved */
 
+
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/systm.h>
@@ -68,13 +69,18 @@
 #include <inet/ip6.h>
 
 /*
+ * Zone global variables of NFSv3 server
+ */
+typedef struct nfs3_srv {
+	writeverf3	write3verf;
+} nfs3_srv_t;
+
+/*
  * These are the interface routines for the server side of the
  * Network File System.  See the NFS version 3 protocol specification
  * for a description of this interface.
  */
 
-static writeverf3 write3verf;
-
 static int	sattr3_to_vattr(sattr3 *, struct vattr *);
 static int	vattr_to_fattr3(struct vattr *, fattr3 *);
 static int	vattr_to_wcc_attr(struct vattr *, wcc_attr *);
@@ -86,6 +92,15 @@
 
 u_longlong_t nfs3_srv_caller_id;
 
+static nfs3_srv_t *
+nfs3_get_srv(void)
+{
+	nfs_globals_t *ng = nfs_srv_getzg();
+	nfs3_srv_t *srv = ng->nfs3_srv;
+	ASSERT(srv != NULL);
+	return (srv);
+}
+
 /* ARGSUSED */
 void
 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
@@ -97,8 +112,9 @@
 
 	vp = nfs3_fhtovp(&args->object, exi);
 
-	DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, GETATTR3args *, args);
+	DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    GETATTR3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -119,8 +135,9 @@
 			goto out;
 		resp->status = NFS3_OK;
 
-		DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
-		    cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
+		DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
+		    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+		    GETATTR3res *, resp);
 
 		VN_RELE(vp);
 
@@ -134,8 +151,9 @@
 	} else
 		resp->status = puterrno3(error);
 
-	DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
+	DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    GETATTR3res *, resp);
 
 	if (vp != NULL)
 		VN_RELE(vp);
@@ -168,8 +186,9 @@
 
 	vp = nfs3_fhtovp(&args->object, exi);
 
-	DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, SETATTR3args *, args);
+	DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    SETATTR3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -330,8 +349,9 @@
 	resp->status = NFS3_OK;
 	vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
 
-	DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
+	DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    SETATTR3res *, resp);
 
 	VN_RELE(vp);
 
@@ -344,8 +364,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
+	DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    SETATTR3res *, resp);
 
 	if (vp != NULL) {
 		if (in_crit)
@@ -390,16 +411,19 @@
 	 * location of the public filehandle.
 	 */
 	if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
-		dvp = rootdir;
+		ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
+		dvp = ZONE_ROOTVP();
 		VN_HOLD(dvp);
 
-		DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
-		    cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
+		DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
+		    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+		    LOOKUP3args *, args);
 	} else {
 		dvp = nfs3_fhtovp(&args->what.dir, exi);
 
-		DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
-		    cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
+		DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
+		    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+		    LOOKUP3args *, args);
 
 		if (dvp == NULL) {
 			error = ESTALE;
@@ -421,10 +445,11 @@
 	}
 
 	fhp = &args->what.dir;
+	ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL */
 	if (strcmp(args->what.name, "..") == 0 &&
 	    EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
 		if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
-		    (dvp->v_flag & VROOT)) {
+		    ((dvp->v_flag & VROOT) || VN_IS_CURZONEROOT(dvp))) {
 			/*
 			 * special case for ".." and 'nohide'exported root
 			 */
@@ -455,6 +480,7 @@
 		publicfh_flag = TRUE;
 
 		exi_rele(exi);
+		exi = NULL;
 
 		error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 		    &exi, &sec);
@@ -538,7 +564,6 @@
 	va.va_mask = AT_ALL;
 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 
-	exi_rele(exi);
 	VN_RELE(vp);
 
 	resp->status = NFS3_OK;
@@ -553,9 +578,11 @@
 	if (auth_weak)
 		resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
 
-	DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
+	DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    LOOKUP3res *, resp);
 	VN_RELE(dvp);
+	exi_rele(exi);
 
 	return;
 
@@ -566,12 +593,13 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
+	DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    LOOKUP3res *, resp);
+
 	if (exi != NULL)
 		exi_rele(exi);
 
-	DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
-
 	if (dvp != NULL)
 		VN_RELE(dvp);
 	vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
@@ -603,8 +631,9 @@
 
 	vp = nfs3_fhtovp(&args->object, exi);
 
-	DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
+	DTRACE_NFSV3_5(op__access__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    ACCESS3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -714,8 +743,9 @@
 	resp->status = NFS3_OK;
 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 
-	DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
+	DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    ACCESS3res *, resp);
 
 	VN_RELE(vp);
 
@@ -727,8 +757,9 @@
 		resp->status = NFS3ERR_JUKEBOX;
 	} else
 		resp->status = puterrno3(error);
-	DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
+	DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    ACCESS3res *, resp);
 	if (vp != NULL)
 		VN_RELE(vp);
 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
@@ -761,8 +792,9 @@
 
 	vp = nfs3_fhtovp(&args->symlink, exi);
 
-	DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
+	DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READLINK3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -811,10 +843,11 @@
 	if (is_referral) {
 		char *s;
 		size_t strsz;
+		kstat_named_t *stat = exi->exi_ne->ne_globals->svstat[NFS_V3];
 
 		/* Get an artificial symlink based on a referral */
 		s = build_symlink(vp, cr, &strsz);
-		global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
+		stat[NFS_REFERLINKS].value.ui64++;
 		DTRACE_PROBE2(nfs3serv__func__referral__reflink,
 		    vnode_t *, vp, char *, s);
 		if (s == NULL)
@@ -882,8 +915,9 @@
 	vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
 	resp->resok.data = name;
 
-	DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
+	DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READLINK3res *, resp);
 	VN_RELE(vp);
 
 	if (name != data)
@@ -898,8 +932,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
+	DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READLINK3res *, resp);
 	if (vp != NULL)
 		VN_RELE(vp);
 	vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
@@ -949,9 +984,11 @@
 
 	vp = nfs3_fhtovp(&args->file, exi);
 
-	DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READ3args *, args);
+	DTRACE_NFSV3_5(op__read__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READ3args *, args);
 
+
 	if (vp == NULL) {
 		error = ESTALE;
 		goto out;
@@ -1205,8 +1242,9 @@
 	}
 
 done:
-	DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READ3res *, resp);
+	DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READ3res *, resp);
 
 	VN_RELE(vp);
 
@@ -1222,8 +1260,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READ3res *, resp);
+	DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READ3res *, resp);
 
 	if (vp != NULL) {
 		if (need_rwunlock)
@@ -1268,6 +1307,7 @@
 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
     struct svc_req *req, cred_t *cr, bool_t ro)
 {
+	nfs3_srv_t *ns;
 	int error;
 	vnode_t *vp;
 	struct vattr *bvap = NULL;
@@ -1288,8 +1328,9 @@
 
 	vp = nfs3_fhtovp(&args->file, exi);
 
-	DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
+	DTRACE_NFSV3_5(op__write__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    WRITE3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -1296,6 +1337,9 @@
 		goto err;
 	}
 
+	ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
+	ns = nfs3_get_srv();
+
 	if (is_system_labeled()) {
 		bslabel_t *clabel = req->rq_label;
 
@@ -1383,7 +1427,7 @@
 		vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
 		resp->resok.count = 0;
 		resp->resok.committed = args->stable;
-		resp->resok.verf = write3verf;
+		resp->resok.verf = ns->write3verf;
 		goto out;
 	}
 
@@ -1485,7 +1529,7 @@
 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
 	resp->resok.count = args->count - uio.uio_resid;
 	resp->resok.committed = args->stable;
-	resp->resok.verf = write3verf;
+	resp->resok.verf = ns->write3verf;
 	goto out;
 
 err:
@@ -1497,8 +1541,9 @@
 err1:
 	vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
 out:
-	DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
+	DTRACE_NFSV3_5(op__write__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    WRITE3res *, resp);
 
 	if (vp != NULL) {
 		if (rwlock_ret != -1)
@@ -1543,8 +1588,9 @@
 
 	dvp = nfs3_fhtovp(&args->where.dir, exi);
 
-	DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
+	DTRACE_NFSV3_5(op__create__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    CREATE3args *, args);
 
 	if (dvp == NULL) {
 		error = ESTALE;
@@ -1843,8 +1889,9 @@
 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
 
-	DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
+	DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    CREATE3res *, resp);
 
 	VN_RELE(dvp);
 	return;
@@ -1856,8 +1903,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
+	DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    CREATE3res *, resp);
 
 	if (name != NULL && name != args->where.name)
 		kmem_free(name, MAXPATHLEN + 1);
@@ -1900,8 +1948,9 @@
 
 	dvp = nfs3_fhtovp(&args->where.dir, exi);
 
-	DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
+	DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    MKDIR3args *, args);
 
 	if (dvp == NULL) {
 		error = ESTALE;
@@ -2000,8 +2049,9 @@
 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
 
-	DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
+	DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    MKDIR3res *, resp);
 	VN_RELE(dvp);
 
 	return;
@@ -2013,8 +2063,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
+	DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    MKDIR3res *, resp);
 	if (dvp != NULL)
 		VN_RELE(dvp);
 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
@@ -2049,8 +2100,9 @@
 
 	dvp = nfs3_fhtovp(&args->where.dir, exi);
 
-	DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
+	DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    SYMLINK3args *, args);
 
 	if (dvp == NULL) {
 		error = ESTALE;
@@ -2187,8 +2239,9 @@
 	if (symdata != NULL && symdata != args->symlink.symlink_data)
 		kmem_free(symdata, MAXPATHLEN + 1);
 
-	DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
+	DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    SYMLINK3res *, resp);
 
 	if (dvp != NULL)
 		VN_RELE(dvp);
@@ -2225,8 +2278,9 @@
 
 	dvp = nfs3_fhtovp(&args->where.dir, exi);
 
-	DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
+	DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    MKNOD3args *, args);
 
 	if (dvp == NULL) {
 		error = ESTALE;
@@ -2372,8 +2426,9 @@
 
 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 	vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
-	DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
+	DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    MKNOD3res *, resp);
 	VN_RELE(dvp);
 	return;
 
@@ -2384,8 +2439,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
+	DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
+	    MKNOD3res *, resp);
 	if (dvp != NULL)
 		VN_RELE(dvp);
 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
@@ -2417,8 +2473,9 @@
 
 	vp = nfs3_fhtovp(&args->object.dir, exi);
 
-	DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
+	DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    REMOVE3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -2526,8 +2583,9 @@
 err1:
 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
 out:
-	DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
+	DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    REMOVE3res *, resp);
 
 	if (name != NULL && name != args->object.name)
 		kmem_free(name, MAXPATHLEN + 1);
@@ -2561,8 +2619,9 @@
 
 	vp = nfs3_fhtovp(&args->object.dir, exi);
 
-	DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
+	DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    RMDIR3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -2618,7 +2677,8 @@
 		goto err1;
 	}
 
-	error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
+	ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
+	error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
 
 	if (name != args->object.name)
 		kmem_free(name, MAXPATHLEN + 1);
@@ -2656,8 +2716,9 @@
 err1:
 	vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
 out:
-	DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
+	DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    RMDIR3res *, resp);
 	if (vp != NULL)
 		VN_RELE(vp);
 
@@ -2702,8 +2763,9 @@
 
 	fvp = nfs3_fhtovp(&args->from.dir, exi);
 
-	DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
+	DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
+	    RENAME3args *, args);
 
 	if (fvp == NULL) {
 		error = ESTALE;
@@ -2820,10 +2882,10 @@
 	}
 
 	/*
-	 * Check for renaming over a delegated file.  Check rfs4_deleg_policy
+	 * Check for renaming over a delegated file.  Check nfs4_deleg_policy
 	 * first to avoid VOP_LOOKUP if possible.
 	 */
-	if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
+	if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE &&
 	    VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
 	    NULL, NULL, NULL) == 0) {
 
@@ -2887,8 +2949,9 @@
 	if (toname != NULL && toname != args->to.name)
 		kmem_free(toname, MAXPATHLEN + 1);
 
-	DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
+	DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
+	    RENAME3res *, resp);
 	if (fvp != NULL)
 		VN_RELE(fvp);
 	if (tvp != NULL)
@@ -2928,8 +2991,9 @@
 
 	vp = nfs3_fhtovp(&args->file, exi);
 
-	DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, LINK3args *, args);
+	DTRACE_NFSV3_5(op__link__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    LINK3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -3041,8 +3105,9 @@
 	vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
 	vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
 
-	DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
+	DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    LINK3res *, resp);
 
 	VN_RELE(vp);
 
@@ -3058,8 +3123,9 @@
 	if (name != NULL && name != args->link.name)
 		kmem_free(name, MAXPATHLEN + 1);
 
-	DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
+	DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    LINK3res *, resp);
 
 	if (vp != NULL)
 		VN_RELE(vp);
@@ -3127,8 +3193,9 @@
 
 	vp = nfs3_fhtovp(&args->dir, exi);
 
-	DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
+	DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READDIR3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -3292,8 +3359,9 @@
 	resp->resok.count = args->count;
 	resp->resok.freecount = count;
 
-	DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
+	DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READDIR3res *, resp);
 
 	VN_RELE(vp);
 
@@ -3306,9 +3374,12 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
+	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
 
+	DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READDIR3res *, resp);
+
 	if (vp != NULL) {
 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
 		VN_RELE(vp);
@@ -3398,8 +3469,9 @@
 
 	vp = nfs3_fhtovp(&args->dir, exi);
 
-	DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
+	DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READDIRPLUS3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -3681,12 +3753,10 @@
 	resp->resok.count = args->dircount - ret;
 	resp->resok.maxcount = args->maxcount;
 
-	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
-	if (ndata != data)
-		kmem_free(data, args->dircount);
+	DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READDIRPLUS3res *, resp);
 
-
 	VN_RELE(vp);
 
 	return;
@@ -3699,9 +3769,12 @@
 		resp->status = puterrno3(error);
 	}
 out1:
-	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
+	vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
 
+	DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    READDIRPLUS3res *, resp);
+
 	if (vp != NULL) {
 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
 		VN_RELE(vp);
@@ -3746,8 +3819,9 @@
 
 	vp = nfs3_fhtovp(&args->fsroot, exi);
 
-	DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
+	DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    FSSTAT3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -3797,8 +3871,9 @@
 	resp->resok.afiles = (size3)sb.f_favail;
 	resp->resok.invarsec = 0;
 
-	DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
+	DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    FSSTAT3res *, resp);
 	VN_RELE(vp);
 
 	return;
@@ -3810,8 +3885,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
+	DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    FSSTAT3res *, resp);
 
 	if (vp != NULL)
 		VN_RELE(vp);
@@ -3839,8 +3915,9 @@
 
 	vp = nfs3_fhtovp(&args->fsroot, exi);
 
-	DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
+	DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    FSINFO3args *, args);
 
 	if (vp == NULL) {
 		if (curthread->t_flag & T_WOULDBLOCK) {
@@ -3914,8 +3991,9 @@
 	resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
 	    FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
 
-	DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
+	DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    FSINFO3res *, resp);
 
 	VN_RELE(vp);
 
@@ -3922,8 +4000,9 @@
 	return;
 
 out:
-	DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
+	DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi,
+	    FSINFO3res *, resp);
 	if (vp != NULL)
 		VN_RELE(vp);
 }
@@ -3949,8 +4028,9 @@
 
 	vp = nfs3_fhtovp(&args->object, exi);
 
-	DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
+	DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    PATHCONF3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -4006,8 +4086,9 @@
 	vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 	resp->resok.info.case_insensitive = FALSE;
 	resp->resok.info.case_preserving = TRUE;
-	DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
+	DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    PATHCONF3res *, resp);
 	VN_RELE(vp);
 	return;
 
@@ -4018,8 +4099,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
+	DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    PATHCONF3res *, resp);
 	if (vp != NULL)
 		VN_RELE(vp);
 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
@@ -4036,6 +4118,7 @@
 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
     struct svc_req *req, cred_t *cr, bool_t ro)
 {
+	nfs3_srv_t *ns;
 	int error;
 	vnode_t *vp;
 	struct vattr *bvap;
@@ -4048,8 +4131,9 @@
 
 	vp = nfs3_fhtovp(&args->file, exi);
 
-	DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
+	DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    COMMIT3args *, args);
 
 	if (vp == NULL) {
 		error = ESTALE;
@@ -4056,6 +4140,8 @@
 		goto out;
 	}
 
+	ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
+	ns = nfs3_get_srv();
 	bva.va_mask = AT_ALL;
 	error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
 
@@ -4108,10 +4194,11 @@
 
 	resp->status = NFS3_OK;
 	vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
-	resp->resok.verf = write3verf;
+	resp->resok.verf = ns->write3verf;
 
-	DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
+	DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    COMMIT3res *, resp);
 
 	VN_RELE(vp);
 
@@ -4124,8 +4211,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
-	DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
-	    cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
+	DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
+	    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
+	    COMMIT3res *, resp);
 
 	if (vp != NULL)
 		VN_RELE(vp);
@@ -4203,7 +4291,7 @@
 	return (0);
 }
 
-static ftype3 vt_to_nf3[] = {
+static const ftype3 vt_to_nf3[] = {
 	0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
 };
 
@@ -4285,14 +4373,31 @@
 static void
 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
 {
-
 	vattr_to_pre_op_attr(bvap, &wccp->before);
 	vattr_to_post_op_attr(avap, &wccp->after);
 }
 
+static int
+rdma_setup_read_data3(READ3args *args, READ3resok *rok)
+{
+	struct clist	*wcl;
+	int		wlist_len;
+	count3		count = rok->count;
+
+	wcl = args->wlist;
+	if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE)
+		return (FALSE);
+
+	wcl = args->wlist;
+	rok->wlist_len = wlist_len;
+	rok->wlist = wcl;
+	return (TRUE);
+}
+
 void
-rfs3_srvrinit(void)
+rfs3_srv_zone_init(nfs_globals_t *ng)
 {
+	nfs3_srv_t *ns;
 	struct rfs3_verf_overlay {
 		uint_t id; /* a "unique" identifier */
 		int ts; /* a unique timestamp */
@@ -4299,6 +4404,8 @@
 	} *verfp;
 	timestruc_t now;
 
+	ns = kmem_zalloc(sizeof (*ns), KM_SLEEP);
+
 	/*
 	 * The following algorithm attempts to find a unique verifier
 	 * to be used as the write verifier returned from the server
@@ -4322,11 +4429,11 @@
 	 * We ASSERT that this constant logic expression is
 	 * always true because in the past, it wasn't.
 	 */
-	ASSERT(sizeof (*verfp) <= sizeof (write3verf));
+	ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf));
 #endif
 
 	gethrestime(&now);
-	verfp = (struct rfs3_verf_overlay *)&write3verf;
+	verfp = (struct rfs3_verf_overlay *)&ns->write3verf;
 	verfp->ts = (int)now.tv_sec;
 	verfp->id = zone_get_hostid(NULL);
 
@@ -4333,28 +4440,25 @@
 	if (verfp->id == 0)
 		verfp->id = (uint_t)now.tv_nsec;
 
-	nfs3_srv_caller_id = fs_new_caller_id();
-
+	ng->nfs3_srv = ns;
 }
 
-static int
-rdma_setup_read_data3(READ3args *args, READ3resok *rok)
+void
+rfs3_srv_zone_fini(nfs_globals_t *ng)
 {
-	struct clist	*wcl;
-	int		wlist_len;
-	count3		count = rok->count;
+	nfs3_srv_t *ns = ng->nfs3_srv;
 
-	wcl = args->wlist;
-	if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
-		return (FALSE);
-	}
+	ng->nfs3_srv = NULL;
 
-	wcl = args->wlist;
-	rok->wlist_len = wlist_len;
-	rok->wlist = wcl;
-	return (TRUE);
+	kmem_free(ns, sizeof (*ns));
 }
 
+void
+rfs3_srvrinit(void)
+{
+	nfs3_srv_caller_id = fs_new_caller_id();
+}
+
 void
 rfs3_srvrfini(void)
 {
