68 #include <nfs/lm.h>
69 #include <sys/sunddi.h>
70
71 /*
72 * exi_id support
73 *
74 * exi_id_next The next exi_id available.
75 * exi_id_overflow The exi_id_next already overflowed, so we should
76 * thoroughly check for duplicates.
77 * exi_id_tree AVL tree indexed by exi_id.
78 * nfs_exi_id_lock Lock to protect the export ID list
79 *
80 * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
81 * nfs_exi_id_lock.
82 */
83 static int exi_id_next;
84 static bool_t exi_id_overflow;
85 avl_tree_t exi_id_tree;
86 kmutex_t nfs_exi_id_lock;
87
88 static int unexport(nfs_export_t *, exportinfo_t *);
89 static void exportfree(exportinfo_t *);
90 static int loadindex(exportdata_t *);
91
92 extern void nfsauth_cache_free(exportinfo_t *);
93 extern int sec_svc_loadrootnames(int, int, caddr_t **, model_t);
94 extern void sec_svc_freerootnames(int, int, caddr_t *);
95
96 static int build_seclist_nodups(exportdata_t *, secinfo_t *, int);
97 static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
98 static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
99 static void srv_secinfo_treeclimb(nfs_export_t *, exportinfo_t *,
100 secinfo_t *, int, bool_t);
101
102 #ifdef VOLATILE_FH_TEST
103 static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
104 static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
105 static void free_volrnm_list(exportinfo_t *);
106 #endif /* VOLATILE_FH_TEST */
107
108 fhandle_t nullfh2; /* for comparing V2 filehandles */
958 mutex_enter(&nfs_exi_id_lock);
959 ne->exi_root->exi_id = exi_id_get_next();
960 avl_add(&exi_id_tree, ne->exi_root);
961 mutex_exit(&nfs_exi_id_lock);
962
963 rw_exit(&ne->exported_lock);
964 ne->ns_root = NULL;
965
966 ng->nfs_export = ne;
967 }
968
969 /*
970 * During zone shutdown, remove exports
971 */
972 void
973 nfs_export_zone_shutdown(nfs_globals_t *ng)
974 {
975 nfs_export_t *ne = ng->nfs_export;
976 struct exportinfo *exi, *nexi;
977 int i, errors;
978
979 rw_enter(&ne->exported_lock, RW_READER);
980
981 errors = 0;
982 for (i = 0; i < EXPTABLESIZE; i++) {
983
984 exi = ne->exptable[i];
985 if (exi != NULL)
986 exi_hold(exi);
987
988 while (exi != NULL) {
989
990 /*
991 * Get and hold next export before
992 * dropping the rwlock and unexport
993 */
994 nexi = exi->fid_hash.next;
995 if (nexi != NULL)
996 exi_hold(nexi);
997
998 rw_exit(&ne->exported_lock);
999
1000 /*
1001 * Skip ne->exi_root which gets special
1002 * create/destroy handling.
1003 */
1004 if (exi != ne->exi_root &&
1005 unexport(ne, exi) != 0)
1006 errors++;
1007 exi_rele(exi);
1008
1009 rw_enter(&ne->exported_lock, RW_READER);
1010 exi = nexi;
1011 }
1012 }
1013 if (errors > 0) {
1014 cmn_err(CE_NOTE, "NFS: failed un-exports in zone %d",
1015 (int)ng->nfs_zoneid);
1016 }
1017
1018 rw_exit(&ne->exported_lock);
1019 }
1020
1021 void
1022 nfs_export_zone_fini(nfs_globals_t *ng)
1023 {
1024 int i;
1025 nfs_export_t *ne = ng->nfs_export;
1026 struct exportinfo *exi;
1027
1028 ng->nfs_export = NULL;
1029
1030 rw_enter(&ne->exported_lock, RW_WRITER);
1031
1032 mutex_enter(&nfs_exi_id_lock);
1033 avl_remove(&exi_id_tree, ne->exi_root);
1034 mutex_exit(&nfs_exi_id_lock);
1035
1036 export_unlink(ne, ne->exi_root);
1037
1038 rw_exit(&ne->exported_lock);
1269
1270 /* Walk the export list looking for that pathname */
1271 rw_enter(&ne->exported_lock, RW_READER);
1272 DTRACE_PROBE(nfss__i__exported_lock1_start);
1273 for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1274 strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1275 if (ex1 != ne->exi_root && 0 ==
1276 strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1277 exi_hold(ex1);
1278 break;
1279 }
1280 }
1281 DTRACE_PROBE(nfss__i__exported_lock1_stop);
1282 rw_exit(&ne->exported_lock);
1283
1284 /* Is this an unshare? */
1285 if (STRUCT_FGETP(uap, uex) == NULL) {
1286 pn_free(&lookpn);
1287 if (ex1 == NULL)
1288 return (EINVAL);
1289 error = unexport(ne, ex1);
1290 exi_rele(ex1);
1291 return (error);
1292 }
1293
1294 /* It is a share or a re-share */
1295 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1296 FOLLOW, &dvp, &vp);
1297 if (error == EINVAL) {
1298 /*
1299 * if fname resolves to / we get EINVAL error
1300 * since we wanted the parent vnode. Try again
1301 * with NULL dvp.
1302 */
1303 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1304 FOLLOW, NULL, &vp);
1305 dvp = NULL;
1306 }
1307 if (!error && vp == NULL) {
1308 /* Last component of fname not found */
1309 if (dvp != NULL)
1869 }
1870
1871 /*
1872 * Remove the exportinfo from the export list
1873 */
1874 void
1875 export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1876 {
1877 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1878
1879 exp_hash_unlink(exi, fid_hash);
1880 exp_hash_unlink(exi, path_hash);
1881 ASSERT3P(exi->exi_ne, ==, ne);
1882 exi->exi_ne = NULL;
1883 }
1884
1885 /*
1886 * Unexport an exported filesystem
1887 */
1888 static int
1889 unexport(nfs_export_t *ne, struct exportinfo *exi)
1890 {
1891 struct secinfo cursec[MAX_FLAVORS];
1892 int curcnt;
1893
1894 rw_enter(&ne->exported_lock, RW_WRITER);
1895
1896 /* Check if exi is still linked in the export table */
1897 if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1898 rw_exit(&ne->exported_lock);
1899 return (EINVAL);
1900 }
1901
1902 mutex_enter(&nfs_exi_id_lock);
1903 avl_remove(&exi_id_tree, exi);
1904 mutex_exit(&nfs_exi_id_lock);
1905 export_unlink(ne, exi);
1906
1907 /*
1908 * Remove security flavors before treeclimb_unexport() is called
1909 * because srv_secinfo_treeclimb needs the namespace tree
1937
1938 /*
1939 * Need to call into the NFSv4 server and release all data
1940 * held on this particular export. This is important since
1941 * the v4 server may be holding file locks or vnodes under
1942 * this export.
1943 */
1944 rfs4_clean_state_exi(ne, exi);
1945
1946 /*
1947 * Notify the lock manager that the filesystem is being
1948 * unexported.
1949 */
1950 lm_unexport(exi);
1951
1952 /*
1953 * If this was a public export, restore
1954 * the public filehandle to the root.
1955 */
1956
1957 /*
1958 * XXX KEBE ASKS --> Should CRED() instead be
1959 * exi->exi_zone->zone_kcred?
1960 */
1961 if (exi == ne->exi_public) {
1962 ne->exi_public = ne->exi_root;
1963
1964 nfslog_share_record(ne->exi_public, CRED());
1965 }
1966
1967 if (exi->exi_export.ex_flags & EX_LOG)
1968 nfslog_unshare_record(exi, CRED());
1969
1970 exi_rele(exi);
1971 return (0);
1972 }
1973
1974 /*
1975 * Get file handle system call.
1976 * Takes file name and returns a file handle for it.
1977 * Credentials must be verified before calling.
1978 */
1979 int
1980 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1981 {
1982 nfs_fh3 fh;
1983 char buf[NFS3_MAXFHSIZE];
1984 char *logptr, logbuf[NFS3_MAXFHSIZE];
1985 int l = NFS3_MAXFHSIZE;
1986 vnode_t *vp;
1987 vnode_t *dvp;
1988 struct exportinfo *exi;
|
68 #include <nfs/lm.h>
69 #include <sys/sunddi.h>
70
71 /*
72 * exi_id support
73 *
74 * exi_id_next The next exi_id available.
75 * exi_id_overflow The exi_id_next already overflowed, so we should
76 * thoroughly check for duplicates.
77 * exi_id_tree AVL tree indexed by exi_id.
78 * nfs_exi_id_lock Lock to protect the export ID list
79 *
80 * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
81 * nfs_exi_id_lock.
82 */
83 static int exi_id_next;
84 static bool_t exi_id_overflow;
85 avl_tree_t exi_id_tree;
86 kmutex_t nfs_exi_id_lock;
87
88 static int unexport(nfs_export_t *, exportinfo_t *, cred_t *);
89 static void exportfree(exportinfo_t *);
90 static int loadindex(exportdata_t *);
91
92 extern void nfsauth_cache_free(exportinfo_t *);
93 extern int sec_svc_loadrootnames(int, int, caddr_t **, model_t);
94 extern void sec_svc_freerootnames(int, int, caddr_t *);
95
96 static int build_seclist_nodups(exportdata_t *, secinfo_t *, int);
97 static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
98 static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
99 static void srv_secinfo_treeclimb(nfs_export_t *, exportinfo_t *,
100 secinfo_t *, int, bool_t);
101
102 #ifdef VOLATILE_FH_TEST
103 static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
104 static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
105 static void free_volrnm_list(exportinfo_t *);
106 #endif /* VOLATILE_FH_TEST */
107
108 fhandle_t nullfh2; /* for comparing V2 filehandles */
958 mutex_enter(&nfs_exi_id_lock);
959 ne->exi_root->exi_id = exi_id_get_next();
960 avl_add(&exi_id_tree, ne->exi_root);
961 mutex_exit(&nfs_exi_id_lock);
962
963 rw_exit(&ne->exported_lock);
964 ne->ns_root = NULL;
965
966 ng->nfs_export = ne;
967 }
968
969 /*
970 * During zone shutdown, remove exports
971 */
972 void
973 nfs_export_zone_shutdown(nfs_globals_t *ng)
974 {
975 nfs_export_t *ne = ng->nfs_export;
976 struct exportinfo *exi, *nexi;
977 int i, errors;
978 zoneid_t zoneid = ng->nfs_zoneid;
979 cred_t *cr;
980
981 /*
982 * Use the zone's credential. Since this is a zone shutdown method,
983 * the zone_t should still be around for a zone_get_kcred() call.
984 */
985 cr = zone_get_kcred(zoneid);
986 VERIFY(cr != NULL);
987 rw_enter(&ne->exported_lock, RW_READER);
988
989 errors = 0;
990 for (i = 0; i < EXPTABLESIZE; i++) {
991
992 exi = ne->exptable[i];
993 if (exi != NULL)
994 exi_hold(exi);
995
996 while (exi != NULL) {
997 ASSERT3U(zoneid, ==, exi->exi_zoneid);
998 /*
999 * Get and hold next export before
1000 * dropping the rwlock and unexport
1001 */
1002 nexi = exi->fid_hash.next;
1003 if (nexi != NULL)
1004 exi_hold(nexi);
1005
1006 rw_exit(&ne->exported_lock);
1007
1008 /*
1009 * Skip ne->exi_root which gets special
1010 * create/destroy handling.
1011 */
1012 if (exi != ne->exi_root &&
1013 unexport(ne, exi, cr) != 0)
1014 errors++;
1015 exi_rele(exi);
1016
1017 rw_enter(&ne->exported_lock, RW_READER);
1018 exi = nexi;
1019 }
1020 }
1021 if (errors > 0) {
1022 cmn_err(CE_NOTE, "NFS: failed un-exports in zone %d",
1023 (int)ng->nfs_zoneid);
1024 }
1025
1026 rw_exit(&ne->exported_lock);
1027 crfree(cr);
1028 }
1029
1030 void
1031 nfs_export_zone_fini(nfs_globals_t *ng)
1032 {
1033 int i;
1034 nfs_export_t *ne = ng->nfs_export;
1035 struct exportinfo *exi;
1036
1037 ng->nfs_export = NULL;
1038
1039 rw_enter(&ne->exported_lock, RW_WRITER);
1040
1041 mutex_enter(&nfs_exi_id_lock);
1042 avl_remove(&exi_id_tree, ne->exi_root);
1043 mutex_exit(&nfs_exi_id_lock);
1044
1045 export_unlink(ne, ne->exi_root);
1046
1047 rw_exit(&ne->exported_lock);
1278
1279 /* Walk the export list looking for that pathname */
1280 rw_enter(&ne->exported_lock, RW_READER);
1281 DTRACE_PROBE(nfss__i__exported_lock1_start);
1282 for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1283 strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1284 if (ex1 != ne->exi_root && 0 ==
1285 strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1286 exi_hold(ex1);
1287 break;
1288 }
1289 }
1290 DTRACE_PROBE(nfss__i__exported_lock1_stop);
1291 rw_exit(&ne->exported_lock);
1292
1293 /* Is this an unshare? */
1294 if (STRUCT_FGETP(uap, uex) == NULL) {
1295 pn_free(&lookpn);
1296 if (ex1 == NULL)
1297 return (EINVAL);
1298 error = unexport(ne, ex1, cr);
1299 exi_rele(ex1);
1300 return (error);
1301 }
1302
1303 /* It is a share or a re-share */
1304 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1305 FOLLOW, &dvp, &vp);
1306 if (error == EINVAL) {
1307 /*
1308 * if fname resolves to / we get EINVAL error
1309 * since we wanted the parent vnode. Try again
1310 * with NULL dvp.
1311 */
1312 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1313 FOLLOW, NULL, &vp);
1314 dvp = NULL;
1315 }
1316 if (!error && vp == NULL) {
1317 /* Last component of fname not found */
1318 if (dvp != NULL)
1878 }
1879
1880 /*
1881 * Remove the exportinfo from the export list
1882 */
1883 void
1884 export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1885 {
1886 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1887
1888 exp_hash_unlink(exi, fid_hash);
1889 exp_hash_unlink(exi, path_hash);
1890 ASSERT3P(exi->exi_ne, ==, ne);
1891 exi->exi_ne = NULL;
1892 }
1893
1894 /*
1895 * Unexport an exported filesystem
1896 */
1897 static int
1898 unexport(nfs_export_t *ne, struct exportinfo *exi, cred_t *cr)
1899 {
1900 struct secinfo cursec[MAX_FLAVORS];
1901 int curcnt;
1902
1903 rw_enter(&ne->exported_lock, RW_WRITER);
1904
1905 /* Check if exi is still linked in the export table */
1906 if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1907 rw_exit(&ne->exported_lock);
1908 return (EINVAL);
1909 }
1910
1911 mutex_enter(&nfs_exi_id_lock);
1912 avl_remove(&exi_id_tree, exi);
1913 mutex_exit(&nfs_exi_id_lock);
1914 export_unlink(ne, exi);
1915
1916 /*
1917 * Remove security flavors before treeclimb_unexport() is called
1918 * because srv_secinfo_treeclimb needs the namespace tree
1946
1947 /*
1948 * Need to call into the NFSv4 server and release all data
1949 * held on this particular export. This is important since
1950 * the v4 server may be holding file locks or vnodes under
1951 * this export.
1952 */
1953 rfs4_clean_state_exi(ne, exi);
1954
1955 /*
1956 * Notify the lock manager that the filesystem is being
1957 * unexported.
1958 */
1959 lm_unexport(exi);
1960
1961 /*
1962 * If this was a public export, restore
1963 * the public filehandle to the root.
1964 */
1965
1966 if (exi == ne->exi_public) {
1967 ne->exi_public = ne->exi_root;
1968
1969 nfslog_share_record(ne->exi_public, cr);
1970 }
1971
1972 if (exi->exi_export.ex_flags & EX_LOG)
1973 nfslog_unshare_record(exi, cr);
1974
1975 exi_rele(exi);
1976 return (0);
1977 }
1978
1979 /*
1980 * Get file handle system call.
1981 * Takes file name and returns a file handle for it.
1982 * Credentials must be verified before calling.
1983 */
1984 int
1985 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1986 {
1987 nfs_fh3 fh;
1988 char buf[NFS3_MAXFHSIZE];
1989 char *logptr, logbuf[NFS3_MAXFHSIZE];
1990 int l = NFS3_MAXFHSIZE;
1991 vnode_t *vp;
1992 vnode_t *dvp;
1993 struct exportinfo *exi;
|