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.)

*** 66,77 **** #include <nfs/nfs_acl.h> #include <nfs/nfs_log.h> #include <nfs/lm.h> #include <sys/sunddi.h> - static zone_key_t nfs_export_key; - /* * exi_id support * * exi_id_next The next exi_id available. * exi_id_overflow The exi_id_next already overflowed, so we should --- 66,75 ----
*** 120,130 **** #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1)) extern nfs_export_t * nfs_get_export(void) { ! return (zone_getspecific(nfs_export_key, curzone)); } static uint8_t xor_hash(uint8_t *data, int len) { --- 118,131 ---- #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1)) extern nfs_export_t * nfs_get_export(void) { ! nfs_globals_t *ng = zone_getspecific(nfssrv_zone_key, curzone); ! nfs_export_t *ne = ng->nfs_export; ! ASSERT(ne != NULL); ! return (ne); } static uint8_t xor_hash(uint8_t *data, int len) {
*** 720,734 **** */ void srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec, int seccnt, bool_t isadd) { ! treenode_t *tnode = exip->exi_tree; ASSERT(RW_WRITE_HELD(&ne->exported_lock)); - ASSERT(tnode != NULL); if (seccnt == 0) return; /* * If flavors are being added and the new export root isn't --- 721,746 ---- */ void srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec, int seccnt, bool_t isadd) { ! treenode_t *tnode; ASSERT(RW_WRITE_HELD(&ne->exported_lock)); + /* + * exi_tree can be null for the zone root + * which means we're already at the "top" + * and there's nothing more to "climb". + */ + tnode = exip->exi_tree; + if (tnode == NULL) { + /* Should only happen for... */ + ASSERT(exip == ne->exi_root); + return; + } + if (seccnt == 0) return; /* * If flavors are being added and the new export root isn't
*** 802,811 **** --- 814,824 ---- export_link(nfs_export_t *ne, exportinfo_t *exi) { exportinfo_t **bckt; ASSERT(RW_WRITE_HELD(&ne->exported_lock)); + ASSERT(exi->exi_zoneid == ne->ne_globals->nfs_zoneid); bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)]; exp_hash_link(exi, fid_hash, bckt); bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
*** 853,873 **** } while (avl_find(&exi_id_tree, &e, NULL) != NULL); return (ret); } ! /*ARGSUSED*/ ! static void * ! nfs_export_zone_init(zoneid_t zoneid) { int i; nfs_export_t *ne; ne = kmem_zalloc(sizeof (*ne), KM_SLEEP); rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL); /* * Allocate the place holder for the public file handle, which * is all zeroes. It is initially set to the root filesystem. */ ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP); --- 866,914 ---- } while (avl_find(&exi_id_tree, &e, NULL) != NULL); return (ret); } ! /* ! * Get the root file handle for this zone. ! * Called when nfs_svc() starts ! */ ! int ! nfs_export_get_rootfh(nfs_globals_t *g) { + nfs_export_t *ne = g->nfs_export; + int err; + + ne->exi_rootfid.fid_len = MAXFIDSZ; + err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid); + if (err != 0) { + ne->exi_rootfid.fid_len = 0; + return (err); + } + + /* Setup the fhandle template exi_fh */ + ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid; + ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len; + bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata, + ne->exi_rootfid.fid_len); + ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data); + + return (0); + } + + void + nfs_export_zone_init(nfs_globals_t *ng) + { int i; nfs_export_t *ne; ne = kmem_zalloc(sizeof (*ne), KM_SLEEP); rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL); + ne->ne_globals = ng; /* "up" pointer */ + /* * Allocate the place holder for the public file handle, which * is all zeroes. It is initially set to the root filesystem. */ ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
*** 881,901 **** ne->exi_root->exi_export.ex_path[1] = '\0'; ne->exi_root->exi_count = 1; mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL); ! ne->exi_root->exi_zone = zone_find_by_id_nolock(zoneid); ! ne->exi_root->exi_vp = ne->exi_root->exi_zone->zone_rootvp; ! ne->exi_rootfid.fid_len = MAXFIDSZ; ! if (vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid) != 0) { ! mutex_destroy(&ne->exi_root->exi_lock); ! kmem_free(ne->exi_root->exi_export.ex_path, ! ne->exi_root->exi_export.ex_pathlen + 1); ! kmem_free(ne->exi_root, sizeof (*ne->exi_root)); ! return (NULL); ! } /* Initialize auth cache and auth cache lock */ for (i = 0; i < AUTH_TABLESIZE; i++) { ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); avl_create(ne->exi_root->exi_cache[i], --- 922,940 ---- ne->exi_root->exi_export.ex_path[1] = '\0'; ne->exi_root->exi_count = 1; mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL); ! ASSERT(curzone->zone_id == ng->nfs_zoneid); ! ne->exi_root->exi_vp = ZONE_ROOTVP(); ! ne->exi_root->exi_zoneid = ng->nfs_zoneid; + /* + * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid + * because we can't correctly return errors here. + */ + /* Initialize auth cache and auth cache lock */ for (i = 0; i < AUTH_TABLESIZE; i++) { ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); avl_create(ne->exi_root->exi_cache[i],
*** 902,917 **** nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt), offsetof(struct auth_cache_clnt, authc_link)); } rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL); ! /* Setup the fhandle template */ ! ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid; ! ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len; ! bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata, ! ne->exi_rootfid.fid_len); ! ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data); rw_enter(&ne->exported_lock, RW_WRITER); /* Publish the exportinfo in the hash table */ export_link(ne, ne->exi_root); --- 941,951 ---- nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt), offsetof(struct auth_cache_clnt, authc_link)); } rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL); ! /* setup exi_fh later, in nfs_export_get_rootfid */ rw_enter(&ne->exported_lock, RW_WRITER); /* Publish the exportinfo in the hash table */ export_link(ne, ne->exi_root);
*** 923,950 **** mutex_exit(&nfs_exi_id_lock); rw_exit(&ne->exported_lock); ne->ns_root = NULL; ! return (ne); } ! /*ARGSUSED*/ ! static void ! nfs_export_zone_fini(zoneid_t zoneid, void *data) { int i; ! nfs_export_t *ne = data; struct exportinfo *exi; rw_enter(&ne->exported_lock, RW_WRITER); - mutex_enter(&nfs_exi_id_lock); avl_remove(&exi_id_tree, ne->exi_root); export_unlink(ne, ne->exi_root); - mutex_exit(&nfs_exi_id_lock); rw_exit(&ne->exported_lock); /* Deallocate the place holder for the public file handle */ srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo, ne->exi_root->exi_export.ex_seccnt); --- 957,1039 ---- mutex_exit(&nfs_exi_id_lock); rw_exit(&ne->exported_lock); ne->ns_root = NULL; ! ng->nfs_export = ne; } ! /* ! * During zone shutdown, remove exports ! */ ! void ! nfs_export_zone_shutdown(nfs_globals_t *ng) { + nfs_export_t *ne = ng->nfs_export; + struct exportinfo *exi, *nexi; + int i, errors; + + rw_enter(&ne->exported_lock, RW_READER); + + errors = 0; + for (i = 0; i < EXPTABLESIZE; i++) { + + exi = ne->exptable[i]; + if (exi != NULL) + exi_hold(exi); + + while (exi != NULL) { + + /* + * Get and hold next export before + * dropping the rwlock and unexport + */ + nexi = exi->fid_hash.next; + if (nexi != NULL) + exi_hold(nexi); + + rw_exit(&ne->exported_lock); + + /* + * Skip ne->exi_root which gets special + * create/destroy handling. + */ + if (exi != ne->exi_root && + unexport(ne, exi) != 0) + errors++; + exi_rele(exi); + + rw_enter(&ne->exported_lock, RW_READER); + exi = nexi; + } + } + if (errors > 0) { + cmn_err(CE_NOTE, + "NFS: failed un-exports in zone %d", + (int) ng->nfs_zoneid); + } + + rw_exit(&ne->exported_lock); + } + + void + nfs_export_zone_fini(nfs_globals_t *ng) + { int i; ! nfs_export_t *ne = ng->nfs_export; struct exportinfo *exi; + ng->nfs_export = NULL; + rw_enter(&ne->exported_lock, RW_WRITER); + mutex_enter(&nfs_exi_id_lock); avl_remove(&exi_id_tree, ne->exi_root); + mutex_exit(&nfs_exi_id_lock); + export_unlink(ne, ne->exi_root); rw_exit(&ne->exported_lock); /* Deallocate the place holder for the public file handle */ srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo, ne->exi_root->exi_export.ex_seccnt);
*** 958,975 **** kmem_free(ne->exi_root->exi_export.ex_path, ne->exi_root->exi_export.ex_pathlen + 1); kmem_free(ne->exi_root, sizeof (*ne->exi_root)); exi = avl_first(&exi_id_tree); while (exi != NULL) { ! struct exportinfo *nexi = AVL_NEXT(&exi_id_tree, exi); ! if (zoneid == exi->exi_zoneid) ! (void) unexport(ne, exi); ! exi = nexi; } ! rw_destroy(&ne->exported_lock); kmem_free(ne, sizeof (*ne)); } /* --- 1047,1074 ---- kmem_free(ne->exi_root->exi_export.ex_path, ne->exi_root->exi_export.ex_pathlen + 1); kmem_free(ne->exi_root, sizeof (*ne->exi_root)); + /* + * The shutdown hook should have left the exi_id_tree + * with nothing belonging to this zone. + */ + mutex_enter(&nfs_exi_id_lock); + i = 0; exi = avl_first(&exi_id_tree); while (exi != NULL) { ! if (exi->exi_zoneid == ng->nfs_zoneid) ! i++; ! exi = AVL_NEXT(&exi_id_tree, exi); } ! mutex_exit(&nfs_exi_id_lock); ! if (i > 0) { ! cmn_err(CE_NOTE, ! "NFS: zone %d has %d export IDs left after shutdown", ! (int) ng->nfs_zoneid, i); ! } rw_destroy(&ne->exported_lock); kmem_free(ne, sizeof (*ne)); } /*
*** 985,1007 **** exi_id_next = 0; exi_id_overflow = FALSE; avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo), offsetof(struct exportinfo, exi_id_link)); - zone_key_create(&nfs_export_key, nfs_export_zone_init, - NULL, nfs_export_zone_fini); - nfslog_init(); } /* * Finalization routine for export routines. */ void nfs_exportfini(void) { - (void) zone_key_delete(nfs_export_key); avl_destroy(&exi_id_tree); mutex_destroy(&nfs_exi_id_lock); } /* --- 1084,1102 ----
*** 1841,1851 **** * Need to call into the NFSv4 server and release all data * held on this particular export. This is important since * the v4 server may be holding file locks or vnodes under * this export. */ ! rfs4_clean_state_exi(exi); /* * Notify the lock manager that the filesystem is being * unexported. */ --- 1936,1946 ---- * Need to call into the NFSv4 server and release all data * held on this particular export. This is important since * the v4 server may be holding file locks or vnodes under * this export. */ ! rfs4_clean_state_exi(ne, exi); /* * Notify the lock manager that the filesystem is being * unexported. */