Print this page
Untrip aggressive assert AND use EXI_TO_ZONEROOTVP
Revert exi_zone to exi_zoneid, and install exi_ne backpointer
Hyperaggressive asserts pt 1/N
Ooops exi_zoneid isn't a variable again yet
Be far more judicious in the use of curzone-using macros.
(Merge and extra asserts by danmcd.)
Bad assertions
nfs_export_zone_init() can't assume called in zone-context.
curzone reality check and teardown changes to use the RIGHT zone
Try to remove assumption that zone's root vnode is marked VROOT


 685  * Find for given treenode the exportinfo which has its
 686  * exp_visible linked on its exi_visible list.
 687  *
 688  * Note: We could add new pointer either to treenode or
 689  * to exp_visible, which will point there directly.
 690  * This would buy some speed for some memory.
 691  */
 692 exportinfo_t *
 693 vis2exi(treenode_t *tnode)
 694 {
 695         exportinfo_t *exi_ret = NULL;
 696 
 697         for (;;) {
 698                 tnode = tnode->tree_parent;
 699                 if (TREE_ROOT(tnode)) {
 700                         exi_ret = tnode->tree_exi;
 701                         break;
 702                 }
 703         }
 704 
 705         ASSERT(exi_ret); /* Every visible should have its home exportinfo */

 706         return (exi_ret);
 707 }
 708 
 709 /*
 710  * For NFS V4.
 711  * Add or remove the newly exported or unexported security flavors of the
 712  * given exportinfo from its ancestors upto the system root.
 713  */
 714 void
 715 srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
 716     int seccnt, bool_t isadd)
 717 {
 718         treenode_t *tnode;
 719 
 720         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 721 
 722         /*
 723          * exi_tree can be null for the zone root
 724          * which means we're already at the "top"
 725          * and there's nothing more to "climb".
 726          */
 727         tnode = exip->exi_tree;
 728         if (tnode == NULL) {
 729                 /* Should only happen for... */
 730                 ASSERT(exip == ne->exi_root);
 731                 return;
 732         }
 733 
 734         if (seccnt == 0)
 735                 return;
 736 
 737         /*
 738          * If flavors are being added and the new export root isn't
 739          * also VROOT, its implicitly allowed flavors are inherited from
 740          * its pseudonode.
 741          * Note - for VROOT exports the implicitly allowed flavors were
 742          * transferred from the PSEUDO export in exportfs()
 743          */
 744         if (isadd && !(exip->exi_vp->v_flag & VROOT) &&

 745             tnode->tree_vis->vis_seccnt > 0) {
 746                 srv_secinfo_add(&exip->exi_export.ex_secinfo,
 747                     &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 748                     tnode->tree_vis->vis_seccnt, FALSE);
 749         }
 750 
 751         /*
 752          * Move to parent node and propagate sec flavor
 753          * to exportinfo and to visible structures.
 754          */
 755         tnode = tnode->tree_parent;
 756 
 757         while (tnode != NULL) {
 758 
 759                 /* If there is exportinfo, update it */
 760                 if (tnode->tree_exi != NULL) {
 761                         secinfo_t **pxsec =
 762                             &tnode->tree_exi->exi_export.ex_secinfo;
 763                         int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
 764                         int is_pseudo = PSEUDO(tnode->tree_exi);


 790         if ((exi)->hash_name.prev) \
 791                 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
 792         if ((exi)->hash_name.next) \
 793                 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
 794         (exi)->hash_name.bckt = NULL;
 795 
 796 #define exp_hash_link(exi, hash_name, bucket) \
 797         (exi)->hash_name.bckt = (bucket); \
 798         (exi)->hash_name.prev = NULL; \
 799         (exi)->hash_name.next = *(bucket); \
 800         if ((exi)->hash_name.next) \
 801                 (exi)->hash_name.next->hash_name.prev = (exi); \
 802         *(bucket) = (exi);
 803 
 804 void
 805 export_link(nfs_export_t *ne, exportinfo_t *exi)
 806 {
 807         exportinfo_t **bckt;
 808 
 809         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 810         ASSERT(exi->exi_zoneid == ne->ne_globals->nfs_zoneid);
 811 
 812         bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 813         exp_hash_link(exi, fid_hash, bckt);
 814 
 815         bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 816             strlen(exi->exi_export.ex_path))];
 817         exp_hash_link(exi, path_hash, bckt);

 818 }
 819 
 820 /*
 821  * Helper functions for exi_id handling
 822  */
 823 static int
 824 exi_id_compar(const void *v1, const void *v2)
 825 {
 826         const struct exportinfo *e1 = v1;
 827         const struct exportinfo *e2 = v2;
 828 
 829         if (e1->exi_id < e2->exi_id)
 830                 return (-1);
 831         if (e1->exi_id > e2->exi_id)
 832                 return (1);
 833 
 834         return (0);
 835 }
 836 
 837 int


 874         if (err != 0) {
 875                 ne->exi_rootfid.fid_len = 0;
 876                 return (err);
 877         }
 878 
 879         /* Setup the fhandle template exi_fh */
 880         ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 881         ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
 882         bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
 883             ne->exi_rootfid.fid_len);
 884         ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
 885 
 886         return (0);
 887 }
 888 
 889 void
 890 nfs_export_zone_init(nfs_globals_t *ng)
 891 {
 892         int i;
 893         nfs_export_t *ne;

 894 
 895         ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 896 
 897         rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
 898 
 899         ne->ne_globals = ng; /* "up" pointer */
 900 
 901         /*
 902          * Allocate the place holder for the public file handle, which
 903          * is all zeroes. It is initially set to the root filesystem.
 904          */
 905         ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
 906         ne->exi_public = ne->exi_root;
 907 
 908         ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
 909         ne->exi_root->exi_export.ex_pathlen = 1;  /* length of "/" */
 910         ne->exi_root->exi_export.ex_path =
 911             kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 912         ne->exi_root->exi_export.ex_path[0] = '/';
 913         ne->exi_root->exi_export.ex_path[1] = '\0';
 914 
 915         ne->exi_root->exi_count = 1;
 916         mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 917 
 918         ne->exi_root->exi_vp = ZONE_ROOTVP();











 919         ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 920 
 921         /*
 922          * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
 923          * because we can't correctly return errors here.
 924          */
 925 
 926         /* Initialize auth cache and auth cache lock */
 927         for (i = 0; i < AUTH_TABLESIZE; i++) {
 928                 ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 929                     KM_SLEEP);
 930                 avl_create(ne->exi_root->exi_cache[i],
 931                     nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 932                     offsetof(struct auth_cache_clnt, authc_link));
 933         }
 934         rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 935 
 936         /* setup exi_fh later, in nfs_export_get_rootfid */
 937 
 938         rw_enter(&ne->exported_lock, RW_WRITER);


1378                     strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1379                         DTRACE_PROBE(nfss__i__exported_lock2_stop);
1380                         rw_exit(&ne->exported_lock);
1381                         VN_RELE(vp);
1382                         if (dvp != NULL)
1383                                 VN_RELE(dvp);
1384                         pn_free(&lookpn);
1385                         return (EEXIST);
1386                 }
1387         }
1388         DTRACE_PROBE(nfss__i__exported_lock2_stop);
1389         rw_exit(&ne->exported_lock);
1390         pn_free(&lookpn);
1391 
1392         exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1393         exi->exi_fsid = fsid;
1394         exi->exi_fid = fid;
1395         exi->exi_vp = vp;
1396         exi->exi_count = 1;
1397         exi->exi_zoneid = crgetzoneid(cr);

1398         exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1399             VSW_VOLATILEDEV) ? 1 : 0;
1400         mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1401         exi->exi_dvp = dvp;
1402 
1403         /*
1404          * Initialize auth cache and auth cache lock
1405          */
1406         for (i = 0; i < AUTH_TABLESIZE; i++) {
1407                 exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1408                 avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
1409                     sizeof (struct auth_cache_clnt),
1410                     offsetof(struct auth_cache_clnt, authc_link));
1411         }
1412         rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1413 
1414         /*
1415          * Build up the template fhandle
1416          */
1417         exi->exi_fh.fh_fsid = fsid;


1847         for (i = 0; i < AUTH_TABLESIZE; i++) {
1848                 avl_destroy(exi->exi_cache[i]);
1849                 kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
1850         }
1851 
1852         kmem_free(exi, sizeof (*exi));
1853 
1854         return (error);
1855 }
1856 
1857 /*
1858  * Remove the exportinfo from the export list
1859  */
1860 void
1861 export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1862 {
1863         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1864 
1865         exp_hash_unlink(exi, fid_hash);
1866         exp_hash_unlink(exi, path_hash);


1867 }
1868 
1869 /*
1870  * Unexport an exported filesystem
1871  */
1872 static int
1873 unexport(nfs_export_t *ne, struct exportinfo *exi)
1874 {
1875         struct secinfo cursec[MAX_FLAVORS];
1876         int curcnt;
1877 
1878         rw_enter(&ne->exported_lock, RW_WRITER);
1879 
1880         /* Check if exi is still linked in the export table */
1881         if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1882                 rw_exit(&ne->exported_lock);
1883                 return (EINVAL);
1884         }
1885 
1886         mutex_enter(&nfs_exi_id_lock);


1920         rw_exit(&ne->exported_lock);
1921 
1922         /*
1923          * Need to call into the NFSv4 server and release all data
1924          * held on this particular export.  This is important since
1925          * the v4 server may be holding file locks or vnodes under
1926          * this export.
1927          */
1928         rfs4_clean_state_exi(ne, exi);
1929 
1930         /*
1931          * Notify the lock manager that the filesystem is being
1932          * unexported.
1933          */
1934         lm_unexport(exi);
1935 
1936         /*
1937          * If this was a public export, restore
1938          * the public filehandle to the root.
1939          */





1940         if (exi == ne->exi_public) {
1941                 ne->exi_public = ne->exi_root;
1942 
1943                 nfslog_share_record(ne->exi_public, CRED());
1944         }
1945 
1946         if (exi->exi_export.ex_flags & EX_LOG)
1947                 nfslog_unshare_record(exi, CRED());
1948 
1949         exi_rele(exi);
1950         return (0);
1951 }
1952 
1953 /*
1954  * Get file handle system call.
1955  * Takes file name and returns a file handle for it.
1956  * Credentials must be verified before calling.
1957  */
1958 int
1959 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)


2154                         break;
2155                 }
2156 
2157                 if (v4srv)
2158                         exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2159                 else
2160                         exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
2161 
2162                 if (exi != NULL) {
2163                         /*
2164                          * Found the export info
2165                          */
2166                         break;
2167                 }
2168 
2169                 /*
2170                  * We have just failed finding a matching export.
2171                  * If we're at the root of this filesystem, then
2172                  * it's time to stop (with failure).
2173                  */
2174                 if (vp->v_flag & VROOT) {

2175                         error = EINVAL;
2176                         break;
2177                 }
2178 
2179                 if (walk != NULL)
2180                         (*walk)++;
2181 
2182                 /*
2183                  * Now, do a ".." up vp. If dvp is supplied, use it,
2184                  * otherwise, look it up.
2185                  */
2186                 if (dvp == NULL) {
2187                         error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
2188                             NULL, NULL, NULL);
2189                         if (error)
2190                                 break;
2191                 }
2192                 VN_RELE(vp);
2193                 vp = dvp;
2194                 dvp = NULL;




 685  * Find for given treenode the exportinfo which has its
 686  * exp_visible linked on its exi_visible list.
 687  *
 688  * Note: We could add new pointer either to treenode or
 689  * to exp_visible, which will point there directly.
 690  * This would buy some speed for some memory.
 691  */
 692 exportinfo_t *
 693 vis2exi(treenode_t *tnode)
 694 {
 695         exportinfo_t *exi_ret = NULL;
 696 
 697         for (;;) {
 698                 tnode = tnode->tree_parent;
 699                 if (TREE_ROOT(tnode)) {
 700                         exi_ret = tnode->tree_exi;
 701                         break;
 702                 }
 703         }
 704 
 705         /* Every visible should have its home exportinfo */
 706         ASSERT(exi_ret != NULL);
 707         return (exi_ret);
 708 }
 709 
 710 /*
 711  * For NFS V4.
 712  * Add or remove the newly exported or unexported security flavors of the
 713  * given exportinfo from its ancestors upto the system root.
 714  */
 715 static void
 716 srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
 717     int seccnt, bool_t isadd)
 718 {
 719         treenode_t *tnode;
 720 
 721         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 722 
 723         /*
 724          * exi_tree can be null for the zone root
 725          * which means we're already at the "top"
 726          * and there's nothing more to "climb".
 727          */
 728         tnode = exip->exi_tree;
 729         if (tnode == NULL) {
 730                 /* Should only happen for... */
 731                 ASSERT(exip == ne->exi_root);
 732                 return;
 733         }
 734 
 735         if (seccnt == 0)
 736                 return;
 737 
 738         /*
 739          * If flavors are being added and the new export root isn't
 740          * also VROOT, its implicitly allowed flavors are inherited from
 741          * its pseudonode.
 742          * Note - for VROOT exports the implicitly allowed flavors were
 743          * transferred from the PSEUDO export in exportfs()
 744          */
 745         if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
 746             !VN_CMP(exip->exi_vp, EXI_TO_ZONEROOTVP(exip)) &&
 747             tnode->tree_vis->vis_seccnt > 0) {
 748                 srv_secinfo_add(&exip->exi_export.ex_secinfo,
 749                     &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 750                     tnode->tree_vis->vis_seccnt, FALSE);
 751         }
 752 
 753         /*
 754          * Move to parent node and propagate sec flavor
 755          * to exportinfo and to visible structures.
 756          */
 757         tnode = tnode->tree_parent;
 758 
 759         while (tnode != NULL) {
 760 
 761                 /* If there is exportinfo, update it */
 762                 if (tnode->tree_exi != NULL) {
 763                         secinfo_t **pxsec =
 764                             &tnode->tree_exi->exi_export.ex_secinfo;
 765                         int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
 766                         int is_pseudo = PSEUDO(tnode->tree_exi);


 792         if ((exi)->hash_name.prev) \
 793                 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
 794         if ((exi)->hash_name.next) \
 795                 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
 796         (exi)->hash_name.bckt = NULL;
 797 
 798 #define exp_hash_link(exi, hash_name, bucket) \
 799         (exi)->hash_name.bckt = (bucket); \
 800         (exi)->hash_name.prev = NULL; \
 801         (exi)->hash_name.next = *(bucket); \
 802         if ((exi)->hash_name.next) \
 803                 (exi)->hash_name.next->hash_name.prev = (exi); \
 804         *(bucket) = (exi);
 805 
 806 void
 807 export_link(nfs_export_t *ne, exportinfo_t *exi)
 808 {
 809         exportinfo_t **bckt;
 810 
 811         ASSERT(RW_WRITE_HELD(&ne->exported_lock));

 812 
 813         bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 814         exp_hash_link(exi, fid_hash, bckt);
 815 
 816         bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 817             strlen(exi->exi_export.ex_path))];
 818         exp_hash_link(exi, path_hash, bckt);
 819         exi->exi_ne = ne;
 820 }
 821 
 822 /*
 823  * Helper functions for exi_id handling
 824  */
 825 static int
 826 exi_id_compar(const void *v1, const void *v2)
 827 {
 828         const struct exportinfo *e1 = v1;
 829         const struct exportinfo *e2 = v2;
 830 
 831         if (e1->exi_id < e2->exi_id)
 832                 return (-1);
 833         if (e1->exi_id > e2->exi_id)
 834                 return (1);
 835 
 836         return (0);
 837 }
 838 
 839 int


 876         if (err != 0) {
 877                 ne->exi_rootfid.fid_len = 0;
 878                 return (err);
 879         }
 880 
 881         /* Setup the fhandle template exi_fh */
 882         ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 883         ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
 884         bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
 885             ne->exi_rootfid.fid_len);
 886         ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
 887 
 888         return (0);
 889 }
 890 
 891 void
 892 nfs_export_zone_init(nfs_globals_t *ng)
 893 {
 894         int i;
 895         nfs_export_t *ne;
 896         zone_t *zone;
 897 
 898         ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 899 
 900         rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
 901 
 902         ne->ne_globals = ng; /* "up" pointer */
 903 
 904         /*
 905          * Allocate the place holder for the public file handle, which
 906          * is all zeroes. It is initially set to the root filesystem.
 907          */
 908         ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
 909         ne->exi_public = ne->exi_root;
 910 
 911         ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
 912         ne->exi_root->exi_export.ex_pathlen = 1;  /* length of "/" */
 913         ne->exi_root->exi_export.ex_path =
 914             kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 915         ne->exi_root->exi_export.ex_path[0] = '/';
 916         ne->exi_root->exi_export.ex_path[1] = '\0';
 917 
 918         ne->exi_root->exi_count = 1;
 919         mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 920 
 921         /*
 922          * Because we cannot:
 923          *      ASSERT(curzone->zone_id == ng->nfs_zoneid);
 924          * We grab the zone pointer explicitly (like netstacks do) and
 925          * set the rootvp here.
 926          *
 927          * Subsequent exportinfo_t's that get export_link()ed to "ne" also
 928          * will backpoint to "ne" such that exi->exi_ne->exi_root->exi_vp
 929          * will get the zone's rootvp for a given exportinfo_t.
 930          */
 931         zone = zone_find_by_id_nolock(ng->nfs_zoneid);
 932         ne->exi_root->exi_vp = zone->zone_rootvp;
 933         ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 934 
 935         /*
 936          * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
 937          * because we can't correctly return errors here.
 938          */
 939 
 940         /* Initialize auth cache and auth cache lock */
 941         for (i = 0; i < AUTH_TABLESIZE; i++) {
 942                 ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 943                     KM_SLEEP);
 944                 avl_create(ne->exi_root->exi_cache[i],
 945                     nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 946                     offsetof(struct auth_cache_clnt, authc_link));
 947         }
 948         rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 949 
 950         /* setup exi_fh later, in nfs_export_get_rootfid */
 951 
 952         rw_enter(&ne->exported_lock, RW_WRITER);


1392                     strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1393                         DTRACE_PROBE(nfss__i__exported_lock2_stop);
1394                         rw_exit(&ne->exported_lock);
1395                         VN_RELE(vp);
1396                         if (dvp != NULL)
1397                                 VN_RELE(dvp);
1398                         pn_free(&lookpn);
1399                         return (EEXIST);
1400                 }
1401         }
1402         DTRACE_PROBE(nfss__i__exported_lock2_stop);
1403         rw_exit(&ne->exported_lock);
1404         pn_free(&lookpn);
1405 
1406         exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1407         exi->exi_fsid = fsid;
1408         exi->exi_fid = fid;
1409         exi->exi_vp = vp;
1410         exi->exi_count = 1;
1411         exi->exi_zoneid = crgetzoneid(cr);
1412         ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
1413         exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1414             VSW_VOLATILEDEV) ? 1 : 0;
1415         mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1416         exi->exi_dvp = dvp;
1417 
1418         /*
1419          * Initialize auth cache and auth cache lock
1420          */
1421         for (i = 0; i < AUTH_TABLESIZE; i++) {
1422                 exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1423                 avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
1424                     sizeof (struct auth_cache_clnt),
1425                     offsetof(struct auth_cache_clnt, authc_link));
1426         }
1427         rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1428 
1429         /*
1430          * Build up the template fhandle
1431          */
1432         exi->exi_fh.fh_fsid = fsid;


1862         for (i = 0; i < AUTH_TABLESIZE; i++) {
1863                 avl_destroy(exi->exi_cache[i]);
1864                 kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
1865         }
1866 
1867         kmem_free(exi, sizeof (*exi));
1868 
1869         return (error);
1870 }
1871 
1872 /*
1873  * Remove the exportinfo from the export list
1874  */
1875 void
1876 export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1877 {
1878         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1879 
1880         exp_hash_unlink(exi, fid_hash);
1881         exp_hash_unlink(exi, path_hash);
1882         ASSERT3P(exi->exi_ne, ==, ne);
1883         exi->exi_ne = NULL;
1884 }
1885 
1886 /*
1887  * Unexport an exported filesystem
1888  */
1889 static int
1890 unexport(nfs_export_t *ne, struct exportinfo *exi)
1891 {
1892         struct secinfo cursec[MAX_FLAVORS];
1893         int curcnt;
1894 
1895         rw_enter(&ne->exported_lock, RW_WRITER);
1896 
1897         /* Check if exi is still linked in the export table */
1898         if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1899                 rw_exit(&ne->exported_lock);
1900                 return (EINVAL);
1901         }
1902 
1903         mutex_enter(&nfs_exi_id_lock);


1937         rw_exit(&ne->exported_lock);
1938 
1939         /*
1940          * Need to call into the NFSv4 server and release all data
1941          * held on this particular export.  This is important since
1942          * the v4 server may be holding file locks or vnodes under
1943          * this export.
1944          */
1945         rfs4_clean_state_exi(ne, exi);
1946 
1947         /*
1948          * Notify the lock manager that the filesystem is being
1949          * unexported.
1950          */
1951         lm_unexport(exi);
1952 
1953         /*
1954          * If this was a public export, restore
1955          * the public filehandle to the root.
1956          */
1957 
1958         /*
1959          * XXX KEBE ASKS --> Should CRED() instead be
1960          * exi->exi_zone->zone_kcred?
1961          */
1962         if (exi == ne->exi_public) {
1963                 ne->exi_public = ne->exi_root;
1964 
1965                 nfslog_share_record(ne->exi_public, CRED());
1966         }
1967 
1968         if (exi->exi_export.ex_flags & EX_LOG)
1969                 nfslog_unshare_record(exi, CRED());
1970 
1971         exi_rele(exi);
1972         return (0);
1973 }
1974 
1975 /*
1976  * Get file handle system call.
1977  * Takes file name and returns a file handle for it.
1978  * Credentials must be verified before calling.
1979  */
1980 int
1981 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)


2176                         break;
2177                 }
2178 
2179                 if (v4srv)
2180                         exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2181                 else
2182                         exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
2183 
2184                 if (exi != NULL) {
2185                         /*
2186                          * Found the export info
2187                          */
2188                         break;
2189                 }
2190 
2191                 /*
2192                  * We have just failed finding a matching export.
2193                  * If we're at the root of this filesystem, then
2194                  * it's time to stop (with failure).
2195                  */
2196                 ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
2197                 if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
2198                         error = EINVAL;
2199                         break;
2200                 }
2201 
2202                 if (walk != NULL)
2203                         (*walk)++;
2204 
2205                 /*
2206                  * Now, do a ".." up vp. If dvp is supplied, use it,
2207                  * otherwise, look it up.
2208                  */
2209                 if (dvp == NULL) {
2210                         error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
2211                             NULL, NULL, NULL);
2212                         if (error)
2213                                 break;
2214                 }
2215                 VN_RELE(vp);
2216                 vp = dvp;
2217                 dvp = NULL;