Print this page
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16
        
@@ -18,18 +18,19 @@
  *
  * CDDL HEADER END
  */
 
 /*
- * 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.
  */
 
 /* 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>
 #include <sys/cred.h>
 #include <sys/buf.h>
@@ -66,17 +67,22 @@
 
 #include <inet/ip.h>
 #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 *);
 static void     vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
 static void     vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
@@ -84,10 +90,19 @@
 
 extern int nfs_loaned_buffers;
 
 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,
     struct svc_req *req, cred_t *cr, bool_t ro)
 {
@@ -95,12 +110,13 @@
         vnode_t *vp;
         struct vattr va;
 
         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;
                 goto out;
         }
@@ -117,12 +133,13 @@
                 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
                 if (error)
                         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);
 
                 return;
         }
@@ -132,12 +149,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
 }
 
@@ -166,12 +184,13 @@
         bvap = NULL;
         avap = NULL;
 
         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;
                 goto out;
         }
@@ -328,12 +347,13 @@
                 nbl_end_crit(vp);
 
         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);
 
         return;
 
@@ -342,12 +362,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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)
                         nbl_end_crit(vp);
                 VN_RELE(vp);
@@ -388,20 +409,23 @@
         /*
          * Allow lookups from the root - the default
          * 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;
                         goto out;
                 }
@@ -419,14 +443,15 @@
                 resp->status = NFS3ERR_ACCES;
                 goto out1;
         }
 
         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
                          */
                         if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
                                 resp->status = NFS3ERR_ACCES;
@@ -453,10 +478,11 @@
          */
         if (PUBLIC_FH3(&args->what.dir)) {
                 publicfh_flag = TRUE;
 
                 exi_rele(exi);
+                exi = NULL;
 
                 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
                     &exi, &sec);
 
                 /*
@@ -536,11 +562,10 @@
         }
 
         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;
         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
         vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
@@ -551,13 +576,15 @@
          * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
          */
         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;
 
 out:
         if (curthread->t_flag & T_WOULDBLOCK) {
@@ -564,16 +591,17 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
 
 }
@@ -601,12 +629,13 @@
 
         vap = NULL;
 
         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;
                 goto out;
         }
@@ -712,12 +741,13 @@
         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 
         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);
 
         return;
 
@@ -725,12 +755,13 @@
         if (curthread->t_flag & T_WOULDBLOCK) {
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 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);
 }
 
@@ -759,12 +790,13 @@
 
         vap = NULL;
 
         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;
                 goto out;
         }
@@ -809,14 +841,15 @@
         data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
 
         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)
                         error = EINVAL;
                 else {
@@ -880,12 +913,13 @@
 
         resp->status = NFS3_OK;
         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)
                 kmem_free(data, MAXPATHLEN + 1);
 
@@ -896,12 +930,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
 }
 
@@ -947,13 +982,15 @@
 
         vap = NULL;
 
         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;
         }
 
@@ -1203,12 +1240,13 @@
                 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
                 (resp->resok).wlist = NULL;
         }
 
 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);
 
         if (iovp != NULL)
                 kmem_free(iovp, iovcnt * sizeof (struct iovec));
@@ -1220,12 +1258,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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)
                         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
                 if (in_crit)
@@ -1266,10 +1305,11 @@
 
 void
 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;
         struct vattr bva;
         struct vattr *avap = NULL;
@@ -1286,18 +1326,22 @@
         int rwlock_ret = -1;
         caller_context_t ct;
 
         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;
                 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;
 
                 ASSERT(clabel != NULL);
                 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
@@ -1381,11 +1425,11 @@
         if (args->count == 0) {
                 resp->status = NFS3_OK;
                 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;
         }
 
         if (args->mblk != NULL) {
                 iovcnt = 0;
@@ -1483,11 +1527,11 @@
 
         resp->status = NFS3_OK;
         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:
         if (curthread->t_flag & T_WOULDBLOCK) {
                 curthread->t_flag &= ~T_WOULDBLOCK;
@@ -1495,12 +1539,13 @@
         } else
                 resp->status = puterrno3(error);
 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)
                         VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
                 if (in_crit)
@@ -1541,12 +1586,13 @@
         dbvap = NULL;
         davap = NULL;
 
         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;
                 goto out;
         }
@@ -1841,12 +1887,13 @@
 
         resp->status = NFS3_OK;
         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;
 
 out:
@@ -1854,12 +1901,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
 
         if (tvp != NULL) {
@@ -1898,12 +1946,13 @@
         dbvap = NULL;
         davap = NULL;
 
         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;
                 goto out;
         }
@@ -1998,12 +2047,13 @@
 
         resp->status = NFS3_OK;
         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;
 
 out:
@@ -2011,12 +2061,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
 }
 
@@ -2047,12 +2098,13 @@
         dbvap = NULL;
         davap = NULL;
 
         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;
                 goto err;
         }
@@ -2185,12 +2237,13 @@
         if (name != NULL && name != args->where.name)
                 kmem_free(name, MAXPATHLEN + 1);
         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);
 }
 
@@ -2223,12 +2276,13 @@
         dbvap = NULL;
         davap = NULL;
 
         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;
                 goto out;
         }
@@ -2370,12 +2424,13 @@
 
         VN_RELE(vp);
 
         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;
 
 out:
         if (curthread->t_flag & T_WOULDBLOCK) {
@@ -2382,12 +2437,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
 }
 
@@ -2415,12 +2471,13 @@
         bvap = NULL;
         avap = NULL;
 
         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;
                 goto err;
         }
@@ -2524,12 +2581,13 @@
         } else
                 resp->status = puterrno3(error);
 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);
 
         if (vp != NULL)
@@ -2559,12 +2617,13 @@
         bvap = NULL;
         avap = NULL;
 
         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;
                 goto err;
         }
@@ -2616,11 +2675,12 @@
         if (name == NULL) {
                 resp->status = NFS3ERR_INVAL;
                 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);
 
         ava.va_mask = AT_ALL;
@@ -2654,12 +2714,13 @@
         } else
                 resp->status = puterrno3(error);
 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);
 
 }
 
@@ -2700,12 +2761,13 @@
         tavap = NULL;
         tvp = NULL;
 
         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;
                 goto err;
         }
@@ -2818,14 +2880,14 @@
                 resp->status = NFS3ERR_JUKEBOX;
                 goto err1;
         }
 
         /*
-         * 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) {
 
                 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
                         VN_RELE(targvp);
@@ -2885,12 +2947,13 @@
         if (name != NULL && name != args->from.name)
                 kmem_free(name, MAXPATHLEN + 1);
         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)
                 VN_RELE(tvp);
 }
@@ -2926,12 +2989,13 @@
         avap = NULL;
         dvp = NULL;
 
         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;
                 goto out;
         }
@@ -3039,12 +3103,13 @@
 
         resp->status = NFS3_OK;
         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);
 
         return;
 
@@ -3056,12 +3121,13 @@
                 resp->status = puterrno3(error);
 out1:
         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);
         if (dvp != NULL)
                 VN_RELE(dvp);
@@ -3125,12 +3191,13 @@
 
         vap = NULL;
 
         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;
                 goto out;
         }
@@ -3290,12 +3357,13 @@
         resp->resok.reply.eof = iseof;
         resp->resok.size = count - uio.uio_resid;
         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);
 
         return;
 
@@ -3304,13 +3372,16 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
         }
         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
@@ -3396,12 +3467,13 @@
 
         vap = NULL;
 
         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;
                 goto out;
         }
@@ -3679,16 +3751,14 @@
         resp->resok.reply.eof = iseof;
         resp->resok.size = nents;
         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;
 
 out:
@@ -3697,13 +3767,16 @@
                 resp->status = NFS3ERR_JUKEBOX;
         } else {
                 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);
         }
 
@@ -3744,12 +3817,13 @@
 
         vap = NULL;
 
         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;
                 goto out;
         }
@@ -3795,12 +3869,13 @@
         resp->resok.tfiles = (size3)sb.f_files;
         resp->resok.ffiles = (size3)sb.f_ffree;
         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;
 
 out:
@@ -3808,12 +3883,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
 }
@@ -3837,12 +3913,13 @@
         ulong_t l = 0;
         int error;
 
         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) {
                         curthread->t_flag &= ~T_WOULDBLOCK;
                         resp->status = NFS3ERR_JUKEBOX;
@@ -3912,20 +3989,22 @@
         resp->resok.time_delta.seconds = 0;
         resp->resok.time_delta.nseconds = 1000;
         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);
 
         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);
 }
 
 void *
@@ -3947,12 +4026,13 @@
 
         vap = NULL;
 
         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;
                 goto out;
         }
@@ -4004,12 +4084,13 @@
 
         resp->status = NFS3_OK;
         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;
 
 out:
         if (curthread->t_flag & T_WOULDBLOCK) {
@@ -4016,12 +4097,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
 }
 
@@ -4034,10 +4116,11 @@
 
 void
 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;
         struct vattr bva;
         struct vattr *avap;
@@ -4046,18 +4129,21 @@
         bvap = NULL;
         avap = NULL;
 
         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;
                 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);
 
         /*
          * If we can't get the attributes, then we can't do the
@@ -4106,14 +4192,15 @@
         if (error)
                 goto out;
 
         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);
 
         return;
 
@@ -4122,12 +4209,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } 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);
         vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
 }
@@ -4201,11 +4289,11 @@
         }
 
         return (0);
 }
 
-static ftype3 vt_to_nf3[] = {
+static const ftype3 vt_to_nf3[] = {
         0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
 };
 
 static int
 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
@@ -4283,24 +4371,43 @@
 }
 
 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 */
         } *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
          * to the client.  It is important that this verifier change
          * whenever the server reboots.  Of secondary importance, it
@@ -4320,43 +4427,40 @@
 #ifndef lint
         /*
          * 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);
 
         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)
 {
         /* Nothing to do */
 }