676 * Done. Update curdata.
677 * Free up the existing secinfo list in curdata and
678 * set the new value.
679 */
680 curdata->ex_seccnt = tcnt;
681 curdata->ex_secinfo = msec;
682 }
683
684 /*
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 #ifdef DEBUG
697 zone_t *zone = NULL;
698 #endif
699
700 for (;;) {
701 tnode = tnode->tree_parent;
702 #ifdef DEBUG
703 if (zone == NULL && tnode->tree_exi != NULL)
704 zone = tnode->tree_exi->exi_zone;
705 #endif
706 if (TREE_ROOT(tnode)) {
707 ASSERT3P(zone, ==, tnode->tree_exi->exi_zone);
708 exi_ret = tnode->tree_exi;
709 break;
710 }
711 }
712
713 ASSERT(exi_ret); /* Every visible should have its home exportinfo */
714 return (exi_ret);
715 }
716
717 /*
718 * For NFS V4.
719 * Add or remove the newly exported or unexported security flavors of the
720 * given exportinfo from its ancestors upto the system root.
721 */
722 static void
723 srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
724 int seccnt, bool_t isadd)
725 {
726 treenode_t *tnode;
727
728 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
729 ASSERT3U(exip->exi_zoneid, ==, curzone->zone_id);
730
731 /*
732 * exi_tree can be null for the zone root
733 * which means we're already at the "top"
734 * and there's nothing more to "climb".
735 */
736 tnode = exip->exi_tree;
737 if (tnode == NULL) {
738 /* Should only happen for... */
739 ASSERT(exip == ne->exi_root);
740 return;
741 }
742
743 if (seccnt == 0)
744 return;
745
746 /*
747 * If flavors are being added and the new export root isn't
748 * also VROOT, its implicitly allowed flavors are inherited from
749 * its pseudonode.
750 * Note - for VROOT exports the implicitly allowed flavors were
751 * transferred from the PSEUDO export in exportfs()
752 */
753 if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
754 !VN_IS_CURZONEROOT(exip->exi_vp) &&
755 tnode->tree_vis->vis_seccnt > 0) {
756 srv_secinfo_add(&exip->exi_export.ex_secinfo,
757 &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
758 tnode->tree_vis->vis_seccnt, FALSE);
759 }
760
761 /*
762 * Move to parent node and propagate sec flavor
763 * to exportinfo and to visible structures.
764 */
765 tnode = tnode->tree_parent;
766
767 while (tnode != NULL) {
768
769 /* If there is exportinfo, update it */
770 if (tnode->tree_exi != NULL) {
771 secinfo_t **pxsec =
772 &tnode->tree_exi->exi_export.ex_secinfo;
773 int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
774 int is_pseudo = PSEUDO(tnode->tree_exi);
807 (exi)->hash_name.bckt = (bucket); \
808 (exi)->hash_name.prev = NULL; \
809 (exi)->hash_name.next = *(bucket); \
810 if ((exi)->hash_name.next) \
811 (exi)->hash_name.next->hash_name.prev = (exi); \
812 *(bucket) = (exi);
813
814 void
815 export_link(nfs_export_t *ne, exportinfo_t *exi)
816 {
817 exportinfo_t **bckt;
818
819 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
820
821 bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
822 exp_hash_link(exi, fid_hash, bckt);
823
824 bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
825 strlen(exi->exi_export.ex_path))];
826 exp_hash_link(exi, path_hash, bckt);
827 }
828
829 /*
830 * Helper functions for exi_id handling
831 */
832 static int
833 exi_id_compar(const void *v1, const void *v2)
834 {
835 const struct exportinfo *e1 = v1;
836 const struct exportinfo *e2 = v2;
837
838 if (e1->exi_id < e2->exi_id)
839 return (-1);
840 if (e1->exi_id > e2->exi_id)
841 return (1);
842
843 return (0);
844 }
845
846 int
913 * is all zeroes. It is initially set to the root filesystem.
914 */
915 ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
916 ne->exi_public = ne->exi_root;
917
918 ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
919 ne->exi_root->exi_export.ex_pathlen = 1; /* length of "/" */
920 ne->exi_root->exi_export.ex_path =
921 kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
922 ne->exi_root->exi_export.ex_path[0] = '/';
923 ne->exi_root->exi_export.ex_path[1] = '\0';
924
925 ne->exi_root->exi_count = 1;
926 mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
927
928 /*
929 * Because we cannot:
930 * ASSERT(curzone->zone_id == ng->nfs_zoneid);
931 * We grab the zone pointer explicitly (like netstacks do) and
932 * set the rootvp here.
933 */
934 zone = zone_find_by_id_nolock(ng->nfs_zoneid);
935 ne->exi_root->exi_vp = zone->zone_rootvp;
936 ne->exi_root->exi_zone = zone; /* XXX KEBE SAYS lose me, and... */
937 /* ne->exi_root->exi_zoneid = ng->nfs_zoneid; */ /* use me instead! */
938
939 /*
940 * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
941 * because we can't correctly return errors here.
942 */
943
944 /* Initialize auth cache and auth cache lock */
945 for (i = 0; i < AUTH_TABLESIZE; i++) {
946 ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
947 KM_SLEEP);
948 avl_create(ne->exi_root->exi_cache[i],
949 nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
950 offsetof(struct auth_cache_clnt, authc_link));
951 }
952 rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
953
954 /* setup exi_fh later, in nfs_export_get_rootfid */
955
956 rw_enter(&ne->exported_lock, RW_WRITER);
957
1395 VN_CMP(ex2->exi_vp, vp) &&
1396 strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1397 DTRACE_PROBE(nfss__i__exported_lock2_stop);
1398 rw_exit(&ne->exported_lock);
1399 VN_RELE(vp);
1400 if (dvp != NULL)
1401 VN_RELE(dvp);
1402 pn_free(&lookpn);
1403 return (EEXIST);
1404 }
1405 }
1406 DTRACE_PROBE(nfss__i__exported_lock2_stop);
1407 rw_exit(&ne->exported_lock);
1408 pn_free(&lookpn);
1409
1410 exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1411 exi->exi_fsid = fsid;
1412 exi->exi_fid = fid;
1413 exi->exi_vp = vp;
1414 exi->exi_count = 1;
1415 exi->exi_zone = crgetzone(cr);
1416 ASSERT(exi->exi_zone != NULL); /* XXX KEBE ASKS... */
1417 ASSERT3P(exi->exi_zone, ==, curzone); /* ... are these legit? */
1418 exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1419 VSW_VOLATILEDEV) ? 1 : 0;
1420 mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1421 exi->exi_dvp = dvp;
1422
1423 /*
1424 * Initialize auth cache and auth cache lock
1425 */
1426 for (i = 0; i < AUTH_TABLESIZE; i++) {
1427 exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1428 avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
1429 sizeof (struct auth_cache_clnt),
1430 offsetof(struct auth_cache_clnt, authc_link));
1431 }
1432 rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1433
1434 /*
1435 * Build up the template fhandle
1436 */
1437 exi->exi_fh.fh_fsid = fsid;
1867 for (i = 0; i < AUTH_TABLESIZE; i++) {
1868 avl_destroy(exi->exi_cache[i]);
1869 kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
1870 }
1871
1872 kmem_free(exi, sizeof (*exi));
1873
1874 return (error);
1875 }
1876
1877 /*
1878 * Remove the exportinfo from the export list
1879 */
1880 void
1881 export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1882 {
1883 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1884
1885 exp_hash_unlink(exi, fid_hash);
1886 exp_hash_unlink(exi, path_hash);
1887 }
1888
1889 /*
1890 * Unexport an exported filesystem
1891 */
1892 static int
1893 unexport(nfs_export_t *ne, struct exportinfo *exi)
1894 {
1895 struct secinfo cursec[MAX_FLAVORS];
1896 int curcnt;
1897
1898 rw_enter(&ne->exported_lock, RW_WRITER);
1899
1900 /* Check if exi is still linked in the export table */
1901 if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1902 rw_exit(&ne->exported_lock);
1903 return (EINVAL);
1904 }
1905
1906 mutex_enter(&nfs_exi_id_lock);
1911 /*
1912 * Remove security flavors before treeclimb_unexport() is called
1913 * because srv_secinfo_treeclimb needs the namespace tree
1914 */
1915 curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1916 srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1917
1918 /*
1919 * If there's a visible list, then need to leave
1920 * a pseudo export here to retain the visible list
1921 * for paths to exports below.
1922 */
1923 if (exi->exi_visible != NULL) {
1924 struct exportinfo *newexi;
1925
1926 newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1927 exi->exi_visible, &exi->exi_export);
1928 exi->exi_visible = NULL;
1929
1930 /* interconnect the existing treenode with the new exportinfo */
1931 newexi->exi_zone = exi->exi_zone; /* XXX KEBE SAYS LOSE ME */
1932 newexi->exi_tree = exi->exi_tree;
1933 newexi->exi_tree->tree_exi = newexi;
1934
1935 /* Update the change timestamp */
1936 tree_update_change(ne, exi->exi_tree, NULL);
1937 } else {
1938 treeclimb_unexport(ne, exi);
1939 }
1940
1941 rw_exit(&ne->exported_lock);
1942
1943 /*
1944 * Need to call into the NFSv4 server and release all data
1945 * held on this particular export. This is important since
1946 * the v4 server may be holding file locks or vnodes under
1947 * this export.
1948 */
1949 rfs4_clean_state_exi(ne, exi);
1950
1951 /*
|
676 * Done. Update curdata.
677 * Free up the existing secinfo list in curdata and
678 * set the new value.
679 */
680 curdata->ex_seccnt = tcnt;
681 curdata->ex_secinfo = msec;
682 }
683
684 /*
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);
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
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);
953
1391 VN_CMP(ex2->exi_vp, vp) &&
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);
1908 /*
1909 * Remove security flavors before treeclimb_unexport() is called
1910 * because srv_secinfo_treeclimb needs the namespace tree
1911 */
1912 curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1913 srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1914
1915 /*
1916 * If there's a visible list, then need to leave
1917 * a pseudo export here to retain the visible list
1918 * for paths to exports below.
1919 */
1920 if (exi->exi_visible != NULL) {
1921 struct exportinfo *newexi;
1922
1923 newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1924 exi->exi_visible, &exi->exi_export);
1925 exi->exi_visible = NULL;
1926
1927 /* interconnect the existing treenode with the new exportinfo */
1928 newexi->exi_tree = exi->exi_tree;
1929 newexi->exi_tree->tree_exi = newexi;
1930
1931 /* Update the change timestamp */
1932 tree_update_change(ne, exi->exi_tree, NULL);
1933 } else {
1934 treeclimb_unexport(ne, exi);
1935 }
1936
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 /*
|