Print this page
Fix NFS design problems re. multiple zone keys
Make NFS server zone-specific data all have the same lifetime
Fix rfs4_clean_state_exi
Fix exi_cache_reclaim
Fix mistakes in zone keys work
More fixes re. exi_zoneid and exi_tree
(danmcd -> Keep some ASSERT()s around for readability.)

@@ -50,14 +50,12 @@
 #include <nfs/nfs_clnt.h>
 #include <nfs/auth.h>
 
 static struct kmem_cache *exi_cache_handle;
 static void exi_cache_reclaim(void *);
+static void exi_cache_reclaim_zone(nfs_globals_t *);
 static void exi_cache_trim(struct exportinfo *exi);
-static void *nfsauth_zone_init(zoneid_t);
-static void nfsauth_zone_shutdown(zoneid_t zoneid, void *data);
-static void nfsauth_zone_fini(zoneid_t, void *);
 
 extern pri_t minclsyspri;
 
 /* NFS auth cache statistics */
 volatile uint_t nfsauth_cache_hit;

@@ -174,18 +172,25 @@
 static void nfsauth_free_node(struct auth_cache *);
 static void nfsauth_refresh_thread(nfsauth_globals_t *);
 
 static int nfsauth_cache_compar(const void *, const void *);
 
-static zone_key_t       nfsauth_zone_key;
+static nfsauth_globals_t *
+nfsauth_get_zg(void)
+{
+        nfs_globals_t *ng = zone_getspecific(nfssrv_zone_key, curzone);
+        nfsauth_globals_t *nag = ng->nfs_auth;
+        ASSERT(nag != NULL);
+        return (nag);
+}
 
 void
 mountd_args(uint_t did)
 {
         nfsauth_globals_t *nag;
 
-        nag = zone_getspecific(nfsauth_zone_key, curzone);
+        nag = nfsauth_get_zg();
         mutex_enter(&nag->mountd_lock);
         if (nag->mountd_dh != NULL)
                 door_ki_rele(nag->mountd_dh);
         nag->mountd_dh = door_ki_lookup(did);
         mutex_exit(&nag->mountd_lock);

@@ -192,13 +197,10 @@
 }
 
 void
 nfsauth_init(void)
 {
-        zone_key_create(&nfsauth_zone_key, nfsauth_zone_init,
-            nfsauth_zone_shutdown, nfsauth_zone_fini);
-
         exi_cache_handle = kmem_cache_create("exi_cache_handle",
             sizeof (struct auth_cache), 0, NULL, NULL,
             exi_cache_reclaim, NULL, NULL, 0);
 }
 

@@ -206,13 +208,12 @@
 nfsauth_fini(void)
 {
         kmem_cache_destroy(exi_cache_handle);
 }
 
-/*ARGSUSED*/
-static void *
-nfsauth_zone_init(zoneid_t zoneid)
+void
+nfsauth_zone_init(nfs_globals_t *ng)
 {
         nfsauth_globals_t *nag;
 
         nag = kmem_zalloc(sizeof (*nag), KM_SLEEP);
 

@@ -225,19 +226,18 @@
         list_create(&nag->refreshq_queue, sizeof (refreshq_exi_node_t),
             offsetof(refreshq_exi_node_t, ren_node));
         cv_init(&nag->refreshq_cv, NULL, CV_DEFAULT, NULL);
         nag->refreshq_thread_state = REFRESHQ_THREAD_NEED_CREATE;
 
-        return (nag);
+        ng->nfs_auth = nag;
 }
 
-/*ARGSUSED*/
-static void
-nfsauth_zone_shutdown(zoneid_t zoneid, void *data)
+void
+nfsauth_zone_shutdown(nfs_globals_t *ng)
 {
         refreshq_exi_node_t     *ren;
-        nfsauth_globals_t       *nag = data;
+        nfsauth_globals_t       *nag = ng->nfs_auth;
 
         /* Prevent the nfsauth_refresh_thread from getting new work */
         mutex_enter(&nag->refreshq_lock);
         if (nag->refreshq_thread_state == REFRESHQ_THREAD_RUNNING) {
                 nag->refreshq_thread_state = REFRESHQ_THREAD_FINI_REQ;

@@ -268,16 +268,17 @@
                 exi_rele(ren->ren_exi);
                 kmem_free(ren, sizeof (*ren));
         }
 }
 
-/*ARGSUSED*/
-static void
-nfsauth_zone_fini(zoneid_t zoneid, void *data)
+void
+nfsauth_zone_fini(nfs_globals_t *ng)
 {
-        nfsauth_globals_t *nag = data;
+        nfsauth_globals_t *nag = ng->nfs_auth;
 
+        ng->nfs_auth = NULL;
+
         list_destroy(&nag->refreshq_queue);
         cv_destroy(&nag->refreshq_cv);
         mutex_destroy(&nag->refreshq_lock);
         mutex_destroy(&nag->mountd_lock);
         /* Extra cleanup. */

@@ -876,11 +877,11 @@
         avl_index_t             where;  /* used for avl_find()/avl_insert() */
 
         ASSERT(cr != NULL);
 
         ASSERT3P(curzone, ==, exi->exi_zone);
-        nag = zone_getspecific(nfsauth_zone_key, curzone);
+        nag = nfsauth_get_zg();
 
         /*
          * Now check whether this client already
          * has an entry for this flavor in the cache
          * for this export.

@@ -1453,22 +1454,45 @@
                         nfsauth_free_clnt_node(node);
         }
 }
 
 /*
- * Called by the kernel memory allocator when
- * memory is low. Free unused cache entries.
- * If that's not enough, the VM system will
- * call again for some more.
+ * Called by the kernel memory allocator when memory is low.
+ * Free unused cache entries. If that's not enough, the VM system
+ * will call again for some more.
+ *
+ * This needs to operate on all zones, so we take a reader lock
+ * on the list of zones and walk the list.  This is OK here
+ * becuase exi_cache_trim doesn't block or cause new objects
+ * to be allocated (basically just frees lots of stuff).
+ * Use care if nfssrv_globals_rwl is taken as reader in any
+ * other cases because it will block nfs_server_zone_init
+ * and nfs_server_zone_fini, which enter as writer.
  */
 /*ARGSUSED*/
 void
 exi_cache_reclaim(void *cdrarg)
 {
+        nfs_globals_t *ng;
+
+        rw_enter(&nfssrv_globals_rwl, RW_READER);
+
+        ng = list_head(&nfssrv_globals_list);
+        while (ng != NULL) {
+                exi_cache_reclaim_zone(ng);
+                ng = list_next(&nfssrv_globals_list, ng);
+        }
+
+        rw_exit(&nfssrv_globals_rwl);
+}
+
+static void
+exi_cache_reclaim_zone(nfs_globals_t *ng)
+{
         int i;
         struct exportinfo *exi;
-        nfs_export_t *ne = nfs_get_export();
+        nfs_export_t *ne = ng->nfs_export;
 
         rw_enter(&ne->exported_lock, RW_READER);
 
         for (i = 0; i < EXPTABLESIZE; i++) {
                 for (exi = ne->exptable[i]; exi; exi = exi->fid_hash.next)

@@ -1478,11 +1502,11 @@
         rw_exit(&ne->exported_lock);
 
         atomic_inc_uint(&nfsauth_cache_reclaim);
 }
 
-void
+static void
 exi_cache_trim(struct exportinfo *exi)
 {
         struct auth_cache_clnt *c;
         struct auth_cache_clnt *nextc;
         struct auth_cache *p;