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

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/nfs/nfs_export.c
          +++ new/usr/src/uts/common/fs/nfs/nfs_export.c
↓ open down ↓ 60 lines elided ↑ open up ↑
  61   61  
  62   62  #include <nfs/nfs.h>
  63   63  #include <nfs/export.h>
  64   64  #include <nfs/nfssys.h>
  65   65  #include <nfs/nfs_clnt.h>
  66   66  #include <nfs/nfs_acl.h>
  67   67  #include <nfs/nfs_log.h>
  68   68  #include <nfs/lm.h>
  69   69  #include <sys/sunddi.h>
  70   70  
  71      -static zone_key_t nfs_export_key;
  72      -
  73   71  /*
  74   72   * exi_id support
  75   73   *
  76   74   * exi_id_next          The next exi_id available.
  77   75   * exi_id_overflow      The exi_id_next already overflowed, so we should
  78   76   *                      thoroughly check for duplicates.
  79   77   * exi_id_tree          AVL tree indexed by exi_id.
  80   78   * nfs_exi_id_lock      Lock to protect the export ID list
  81   79   *
  82   80   * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
↓ open down ↓ 32 lines elided ↑ open up ↑
 115  113  #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
 116  114          DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
 117  115                  char *, (tag), int, (int)(flav), int, (int)(aftcnt))
 118  116  
 119  117  
 120  118  #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
 121  119  
 122  120  extern nfs_export_t *
 123  121  nfs_get_export(void)
 124  122  {
 125      -        return (zone_getspecific(nfs_export_key, curzone));
      123 +        nfs_globals_t *ng = zone_getspecific(nfssrv_zone_key, curzone);
      124 +        nfs_export_t *ne = ng->nfs_export;
      125 +        ASSERT(ne != NULL);
      126 +        return (ne);
 126  127  }
 127  128  
 128  129  static uint8_t
 129  130  xor_hash(uint8_t *data, int len)
 130  131  {
 131  132          uint8_t h = 0;
 132  133  
 133  134          while (len--)
 134  135                  h ^= *data++;
 135  136  
↓ open down ↓ 579 lines elided ↑ open up ↑
 715  716  
 716  717  /*
 717  718   * For NFS V4.
 718  719   * Add or remove the newly exported or unexported security flavors of the
 719  720   * given exportinfo from its ancestors upto the system root.
 720  721   */
 721  722  void
 722  723  srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
 723  724      int seccnt, bool_t isadd)
 724  725  {
 725      -        treenode_t *tnode = exip->exi_tree;
      726 +        treenode_t *tnode;
 726  727  
 727  728          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 728      -        ASSERT(tnode != NULL);
 729  729  
      730 +        /*
      731 +         * exi_tree can be null for the zone root
      732 +         * which means we're already at the "top"
      733 +         * and there's nothing more to "climb".
      734 +         */
      735 +        tnode = exip->exi_tree;
      736 +        if (tnode == NULL) {
      737 +                /* Should only happen for... */
      738 +                ASSERT(exip == ne->exi_root);
      739 +                return;
      740 +        }
      741 +
 730  742          if (seccnt == 0)
 731  743                  return;
 732  744  
 733  745          /*
 734  746           * If flavors are being added and the new export root isn't
 735  747           * also VROOT, its implicitly allowed flavors are inherited from
 736  748           * its pseudonode.
 737  749           * Note - for VROOT exports the implicitly allowed flavors were
 738  750           * transferred from the PSEUDO export in exportfs()
 739  751           */
↓ open down ↓ 57 lines elided ↑ open up ↑
 797  809          if ((exi)->hash_name.next) \
 798  810                  (exi)->hash_name.next->hash_name.prev = (exi); \
 799  811          *(bucket) = (exi);
 800  812  
 801  813  void
 802  814  export_link(nfs_export_t *ne, exportinfo_t *exi)
 803  815  {
 804  816          exportinfo_t **bckt;
 805  817  
 806  818          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
      819 +        ASSERT(exi->exi_zoneid == ne->ne_globals->nfs_zoneid);
 807  820  
 808  821          bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 809  822          exp_hash_link(exi, fid_hash, bckt);
 810  823  
 811  824          bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 812  825              strlen(exi->exi_export.ex_path))];
 813  826          exp_hash_link(exi, path_hash, bckt);
 814  827  }
 815  828  
 816  829  /*
↓ open down ↓ 31 lines elided ↑ open up ↑
 848  861  
 849  862                  if (exi_id_next == ret)
 850  863                          cmn_err(CE_PANIC, "exi_id exhausted");
 851  864  
 852  865                  e.exi_id = exi_id_next;
 853  866          } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
 854  867  
 855  868          return (ret);
 856  869  }
 857  870  
 858      -/*ARGSUSED*/
 859      -static void *
 860      -nfs_export_zone_init(zoneid_t zoneid)
      871 +/*
      872 + * Get the root file handle for this zone.
      873 + * Called when nfs_svc() starts
      874 + */
      875 +int
      876 +nfs_export_get_rootfh(nfs_globals_t *g)
 861  877  {
      878 +        nfs_export_t *ne = g->nfs_export;
      879 +        int err;
      880 +
      881 +        ne->exi_rootfid.fid_len = MAXFIDSZ;
      882 +        err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid);
      883 +        if (err != 0) {
      884 +                ne->exi_rootfid.fid_len = 0;
      885 +                return (err);
      886 +        }
      887 +
      888 +        /* Setup the fhandle template exi_fh */
      889 +        ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
      890 +        ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
      891 +        bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
      892 +            ne->exi_rootfid.fid_len);
      893 +        ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
      894 +
      895 +        return (0);
      896 +}
      897 +
      898 +void
      899 +nfs_export_zone_init(nfs_globals_t *ng)
      900 +{
 862  901          int i;
 863  902          nfs_export_t *ne;
 864  903  
 865  904          ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 866  905  
 867  906          rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
 868  907  
      908 +        ne->ne_globals = ng; /* "up" pointer */
      909 +
 869  910          /*
 870  911           * Allocate the place holder for the public file handle, which
 871  912           * is all zeroes. It is initially set to the root filesystem.
 872  913           */
 873  914          ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
 874  915          ne->exi_public = ne->exi_root;
 875  916  
 876  917          ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
 877  918          ne->exi_root->exi_export.ex_pathlen = 1;        /* length of "/" */
 878  919          ne->exi_root->exi_export.ex_path =
 879  920              kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 880  921          ne->exi_root->exi_export.ex_path[0] = '/';
 881  922          ne->exi_root->exi_export.ex_path[1] = '\0';
 882  923  
 883  924          ne->exi_root->exi_count = 1;
 884  925          mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 885  926  
 886      -        ne->exi_root->exi_zone = zone_find_by_id_nolock(zoneid);
 887      -        ne->exi_root->exi_vp = ne->exi_root->exi_zone->zone_rootvp;
 888      -        ne->exi_rootfid.fid_len = MAXFIDSZ;
 889      -        if (vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid) != 0) {
 890      -                mutex_destroy(&ne->exi_root->exi_lock);
 891      -                kmem_free(ne->exi_root->exi_export.ex_path,
 892      -                    ne->exi_root->exi_export.ex_pathlen + 1);
 893      -                kmem_free(ne->exi_root, sizeof (*ne->exi_root));
 894      -                return (NULL);
 895      -        }
      927 +        ASSERT(curzone->zone_id == ng->nfs_zoneid);
      928 +        ne->exi_root->exi_vp = ZONE_ROOTVP();
      929 +        ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 896  930  
      931 +        /*
      932 +         * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
      933 +         * because we can't correctly return errors here.
      934 +         */
      935 +
 897  936          /* Initialize auth cache and auth cache lock */
 898  937          for (i = 0; i < AUTH_TABLESIZE; i++) {
 899  938                  ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 900  939                      KM_SLEEP);
 901  940                  avl_create(ne->exi_root->exi_cache[i],
 902  941                      nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 903  942                      offsetof(struct auth_cache_clnt, authc_link));
 904  943          }
 905  944          rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 906  945  
 907      -        /* Setup the fhandle template */
 908      -        ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 909      -        ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
 910      -        bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
 911      -            ne->exi_rootfid.fid_len);
 912      -        ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
      946 +        /* setup exi_fh later, in nfs_export_get_rootfid */
 913  947  
 914  948          rw_enter(&ne->exported_lock, RW_WRITER);
 915  949  
 916  950          /* Publish the exportinfo in the hash table */
 917  951          export_link(ne, ne->exi_root);
 918  952  
 919  953          /* Initialize exi_id and exi_kstats */
 920  954          mutex_enter(&nfs_exi_id_lock);
 921  955          ne->exi_root->exi_id = exi_id_get_next();
 922  956          avl_add(&exi_id_tree, ne->exi_root);
 923  957          mutex_exit(&nfs_exi_id_lock);
 924  958  
 925  959          rw_exit(&ne->exported_lock);
 926  960          ne->ns_root = NULL;
 927  961  
 928      -        return (ne);
      962 +        ng->nfs_export = ne;
 929  963  }
 930  964  
 931      -/*ARGSUSED*/
 932      -static void
 933      -nfs_export_zone_fini(zoneid_t zoneid, void *data)
      965 +/*
      966 + * During zone shutdown, remove exports
      967 + */
      968 +void
      969 +nfs_export_zone_shutdown(nfs_globals_t *ng)
 934  970  {
      971 +        nfs_export_t *ne = ng->nfs_export;
      972 +        struct exportinfo *exi, *nexi;
      973 +        int i, errors;
      974 +
      975 +        rw_enter(&ne->exported_lock, RW_READER);
      976 +
      977 +        errors = 0;
      978 +        for (i = 0; i < EXPTABLESIZE; i++) {
      979 +
      980 +                exi = ne->exptable[i];
      981 +                if (exi != NULL)
      982 +                        exi_hold(exi);
      983 +
      984 +                while (exi != NULL) {
      985 +
      986 +                        /*
      987 +                         * Get and hold next export before
      988 +                         * dropping the rwlock and unexport
      989 +                         */
      990 +                        nexi = exi->fid_hash.next;
      991 +                        if (nexi != NULL)
      992 +                                exi_hold(nexi);
      993 +
      994 +                        rw_exit(&ne->exported_lock);
      995 +
      996 +                        /*
      997 +                         * Skip ne->exi_root which gets special
      998 +                         * create/destroy handling.
      999 +                         */
     1000 +                        if (exi != ne->exi_root &&
     1001 +                            unexport(ne, exi) != 0)
     1002 +                                errors++;
     1003 +                        exi_rele(exi);
     1004 +
     1005 +                        rw_enter(&ne->exported_lock, RW_READER);
     1006 +                        exi = nexi;
     1007 +                }
     1008 +        }
     1009 +        if (errors > 0) {
     1010 +                cmn_err(CE_NOTE,
     1011 +                    "NFS: failed un-exports in zone %d",
     1012 +                    (int) ng->nfs_zoneid);
     1013 +        }
     1014 +
     1015 +        rw_exit(&ne->exported_lock);
     1016 +}
     1017 +
     1018 +void
     1019 +nfs_export_zone_fini(nfs_globals_t *ng)
     1020 +{
 935 1021          int i;
 936      -        nfs_export_t *ne = data;
     1022 +        nfs_export_t *ne = ng->nfs_export;
 937 1023          struct exportinfo *exi;
 938 1024  
     1025 +        ng->nfs_export = NULL;
     1026 +
 939 1027          rw_enter(&ne->exported_lock, RW_WRITER);
 940      -        mutex_enter(&nfs_exi_id_lock);
 941 1028  
     1029 +        mutex_enter(&nfs_exi_id_lock);
 942 1030          avl_remove(&exi_id_tree, ne->exi_root);
     1031 +        mutex_exit(&nfs_exi_id_lock);
     1032 +
 943 1033          export_unlink(ne, ne->exi_root);
 944 1034  
 945      -        mutex_exit(&nfs_exi_id_lock);
 946 1035          rw_exit(&ne->exported_lock);
 947 1036  
 948 1037          /* Deallocate the place holder for the public file handle */
 949 1038          srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
 950 1039              ne->exi_root->exi_export.ex_seccnt);
 951 1040          mutex_destroy(&ne->exi_root->exi_lock);
 952 1041  
 953 1042          rw_destroy(&ne->exi_root->exi_cache_lock);
 954 1043          for (i = 0; i < AUTH_TABLESIZE; i++) {
 955 1044                  avl_destroy(ne->exi_root->exi_cache[i]);
 956 1045                  kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
 957 1046          }
 958 1047  
 959 1048          kmem_free(ne->exi_root->exi_export.ex_path,
 960 1049              ne->exi_root->exi_export.ex_pathlen + 1);
 961 1050          kmem_free(ne->exi_root, sizeof (*ne->exi_root));
 962 1051  
     1052 +        /*
     1053 +         * The shutdown hook should have left the exi_id_tree
     1054 +         * with nothing belonging to this zone.
     1055 +         */
     1056 +        mutex_enter(&nfs_exi_id_lock);
     1057 +        i = 0;
 963 1058          exi = avl_first(&exi_id_tree);
 964 1059          while (exi != NULL) {
 965      -                struct exportinfo *nexi = AVL_NEXT(&exi_id_tree, exi);
 966      -                if (zoneid == exi->exi_zoneid)
 967      -                        (void) unexport(ne, exi);
 968      -                exi = nexi;
     1060 +                if (exi->exi_zoneid == ng->nfs_zoneid)
     1061 +                        i++;
     1062 +                exi = AVL_NEXT(&exi_id_tree, exi);
 969 1063          }
 970      -
     1064 +        mutex_exit(&nfs_exi_id_lock);
     1065 +        if (i > 0) {
     1066 +                cmn_err(CE_NOTE,
     1067 +                    "NFS: zone %d has %d export IDs left after shutdown",
     1068 +                    (int) ng->nfs_zoneid, i);
     1069 +        }
 971 1070          rw_destroy(&ne->exported_lock);
 972 1071          kmem_free(ne, sizeof (*ne));
 973 1072  }
 974 1073  
 975 1074  /*
 976 1075   * Initialization routine for export routines.
 977 1076   * Should only be called once.
 978 1077   */
 979 1078  void
 980 1079  nfs_exportinit(void)
 981 1080  {
 982 1081          mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
 983 1082  
 984 1083          /* exi_id handling initialization */
 985 1084          exi_id_next = 0;
 986 1085          exi_id_overflow = FALSE;
 987 1086          avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
 988 1087              offsetof(struct exportinfo, exi_id_link));
 989 1088  
 990      -        zone_key_create(&nfs_export_key, nfs_export_zone_init,
 991      -            NULL, nfs_export_zone_fini);
 992      -
 993 1089          nfslog_init();
 994 1090  }
 995 1091  
 996 1092  /*
 997 1093   * Finalization routine for export routines.
 998 1094   */
 999 1095  void
1000 1096  nfs_exportfini(void)
1001 1097  {
1002      -        (void) zone_key_delete(nfs_export_key);
1003 1098          avl_destroy(&exi_id_tree);
1004 1099          mutex_destroy(&nfs_exi_id_lock);
1005 1100  }
1006 1101  
1007 1102  /*
1008 1103   *  Check if 2 gss mechanism identifiers are the same.
1009 1104   *
1010 1105   *  return FALSE if not the same.
1011 1106   *  return TRUE if the same.
1012 1107   */
↓ open down ↓ 823 lines elided ↑ open up ↑
1836 1931          }
1837 1932  
1838 1933          rw_exit(&ne->exported_lock);
1839 1934  
1840 1935          /*
1841 1936           * Need to call into the NFSv4 server and release all data
1842 1937           * held on this particular export.  This is important since
1843 1938           * the v4 server may be holding file locks or vnodes under
1844 1939           * this export.
1845 1940           */
1846      -        rfs4_clean_state_exi(exi);
     1941 +        rfs4_clean_state_exi(ne, exi);
1847 1942  
1848 1943          /*
1849 1944           * Notify the lock manager that the filesystem is being
1850 1945           * unexported.
1851 1946           */
1852 1947          lm_unexport(exi);
1853 1948  
1854 1949          /*
1855 1950           * If this was a public export, restore
1856 1951           * the public filehandle to the root.
↓ open down ↓ 1035 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX