xref: /freebsd-src/sys/contrib/openzfs/module/os/linux/spl/spl-zone.c (revision 7a7741af18d6c8a804cc643cb7ecda9d730c6aa6)
11f1e2261SMartin Matuska /*
21f1e2261SMartin Matuska  * Copyright (c) 2021 Klara Systems, Inc.
31f1e2261SMartin Matuska  * All rights reserved.
41f1e2261SMartin Matuska  *
51f1e2261SMartin Matuska  * Redistribution and use in source and binary forms, with or without
61f1e2261SMartin Matuska  * modification, are permitted provided that the following conditions
71f1e2261SMartin Matuska  * are met:
81f1e2261SMartin Matuska  * 1. Redistributions of source code must retain the above copyright
91f1e2261SMartin Matuska  *    notice, this list of conditions and the following disclaimer.
101f1e2261SMartin Matuska  * 2. Redistributions in binary form must reproduce the above copyright
111f1e2261SMartin Matuska  *    notice, this list of conditions and the following disclaimer in the
121f1e2261SMartin Matuska  *    documentation and/or other materials provided with the distribution.
131f1e2261SMartin Matuska  *
141f1e2261SMartin Matuska  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
151f1e2261SMartin Matuska  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161f1e2261SMartin Matuska  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171f1e2261SMartin Matuska  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
181f1e2261SMartin Matuska  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191f1e2261SMartin Matuska  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201f1e2261SMartin Matuska  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211f1e2261SMartin Matuska  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221f1e2261SMartin Matuska  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231f1e2261SMartin Matuska  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241f1e2261SMartin Matuska  * SUCH DAMAGE.
251f1e2261SMartin Matuska  */
261f1e2261SMartin Matuska 
271f1e2261SMartin Matuska #include <sys/types.h>
281f1e2261SMartin Matuska #include <sys/sysmacros.h>
291f1e2261SMartin Matuska #include <sys/kmem.h>
301f1e2261SMartin Matuska #include <linux/file.h>
311f1e2261SMartin Matuska #include <linux/magic.h>
321f1e2261SMartin Matuska #include <sys/zone.h>
33fd45b686SMartin Matuska #include <sys/string.h>
341f1e2261SMartin Matuska 
351f1e2261SMartin Matuska #if defined(CONFIG_USER_NS)
361f1e2261SMartin Matuska #include <linux/statfs.h>
371f1e2261SMartin Matuska #include <linux/proc_ns.h>
381f1e2261SMartin Matuska #endif
391f1e2261SMartin Matuska 
40dbd5678dSMartin Matuska #include <sys/mutex.h>
41dbd5678dSMartin Matuska 
421f1e2261SMartin Matuska static kmutex_t zone_datasets_lock;
431f1e2261SMartin Matuska static struct list_head zone_datasets;
441f1e2261SMartin Matuska 
451f1e2261SMartin Matuska typedef struct zone_datasets {
461f1e2261SMartin Matuska 	struct list_head zds_list;	/* zone_datasets linkage */
471f1e2261SMartin Matuska 	struct user_namespace *zds_userns; /* namespace reference */
481f1e2261SMartin Matuska 	struct list_head zds_datasets;	/* datasets for the namespace */
491f1e2261SMartin Matuska } zone_datasets_t;
501f1e2261SMartin Matuska 
511f1e2261SMartin Matuska typedef struct zone_dataset {
521f1e2261SMartin Matuska 	struct list_head zd_list;	/* zone_dataset linkage */
531f1e2261SMartin Matuska 	size_t zd_dsnamelen;		/* length of name */
5415f0b8c3SMartin Matuska 	char zd_dsname[];		/* name of the member dataset */
551f1e2261SMartin Matuska } zone_dataset_t;
561f1e2261SMartin Matuska 
57*7a7741afSMartin Matuska #ifdef CONFIG_USER_NS
581f1e2261SMartin Matuska /*
591f1e2261SMartin Matuska  * Returns:
601f1e2261SMartin Matuska  * - 0 on success
611f1e2261SMartin Matuska  * - EBADF if it cannot open the provided file descriptor
621f1e2261SMartin Matuska  * - ENOTTY if the file itself is a not a user namespace file. We want to
631f1e2261SMartin Matuska  *   intercept this error in the ZFS layer. We cannot just return one of the
641f1e2261SMartin Matuska  *   ZFS_ERR_* errors here as we want to preserve the seperation of the ZFS
651f1e2261SMartin Matuska  *   and the SPL layers.
661f1e2261SMartin Matuska  */
671f1e2261SMartin Matuska static int
681f1e2261SMartin Matuska user_ns_get(int fd, struct user_namespace **userns)
691f1e2261SMartin Matuska {
701f1e2261SMartin Matuska 	struct kstatfs st;
711f1e2261SMartin Matuska 	struct file *nsfile;
721f1e2261SMartin Matuska 	struct ns_common *ns;
731f1e2261SMartin Matuska 	int error;
741f1e2261SMartin Matuska 
751f1e2261SMartin Matuska 	if ((nsfile = fget(fd)) == NULL)
761f1e2261SMartin Matuska 		return (EBADF);
771f1e2261SMartin Matuska 	if (vfs_statfs(&nsfile->f_path, &st) != 0) {
781f1e2261SMartin Matuska 		error = ENOTTY;
791f1e2261SMartin Matuska 		goto done;
801f1e2261SMartin Matuska 	}
811f1e2261SMartin Matuska 	if (st.f_type != NSFS_MAGIC) {
821f1e2261SMartin Matuska 		error = ENOTTY;
831f1e2261SMartin Matuska 		goto done;
841f1e2261SMartin Matuska 	}
851f1e2261SMartin Matuska 	ns = get_proc_ns(file_inode(nsfile));
861f1e2261SMartin Matuska 	if (ns->ops->type != CLONE_NEWUSER) {
871f1e2261SMartin Matuska 		error = ENOTTY;
881f1e2261SMartin Matuska 		goto done;
891f1e2261SMartin Matuska 	}
901f1e2261SMartin Matuska 	*userns = container_of(ns, struct user_namespace, ns);
911f1e2261SMartin Matuska 
921f1e2261SMartin Matuska 	error = 0;
931f1e2261SMartin Matuska done:
941f1e2261SMartin Matuska 	fput(nsfile);
951f1e2261SMartin Matuska 
961f1e2261SMartin Matuska 	return (error);
971f1e2261SMartin Matuska }
98*7a7741afSMartin Matuska #endif /* CONFIG_USER_NS */
991f1e2261SMartin Matuska 
1001f1e2261SMartin Matuska static unsigned int
1011f1e2261SMartin Matuska user_ns_zoneid(struct user_namespace *user_ns)
1021f1e2261SMartin Matuska {
1031f1e2261SMartin Matuska 	unsigned int r;
1041f1e2261SMartin Matuska 
1051f1e2261SMartin Matuska 	r = user_ns->ns.inum;
1061f1e2261SMartin Matuska 
1071f1e2261SMartin Matuska 	return (r);
1081f1e2261SMartin Matuska }
1091f1e2261SMartin Matuska 
1101f1e2261SMartin Matuska static struct zone_datasets *
1111f1e2261SMartin Matuska zone_datasets_lookup(unsigned int nsinum)
1121f1e2261SMartin Matuska {
1131f1e2261SMartin Matuska 	zone_datasets_t *zds;
1141f1e2261SMartin Matuska 
1151f1e2261SMartin Matuska 	list_for_each_entry(zds, &zone_datasets, zds_list) {
1161f1e2261SMartin Matuska 		if (user_ns_zoneid(zds->zds_userns) == nsinum)
1171f1e2261SMartin Matuska 			return (zds);
1181f1e2261SMartin Matuska 	}
1191f1e2261SMartin Matuska 	return (NULL);
1201f1e2261SMartin Matuska }
1211f1e2261SMartin Matuska 
122*7a7741afSMartin Matuska #ifdef CONFIG_USER_NS
1231f1e2261SMartin Matuska static struct zone_dataset *
1241f1e2261SMartin Matuska zone_dataset_lookup(zone_datasets_t *zds, const char *dataset, size_t dsnamelen)
1251f1e2261SMartin Matuska {
1261f1e2261SMartin Matuska 	zone_dataset_t *zd;
1271f1e2261SMartin Matuska 
1281f1e2261SMartin Matuska 	list_for_each_entry(zd, &zds->zds_datasets, zd_list) {
1291f1e2261SMartin Matuska 		if (zd->zd_dsnamelen != dsnamelen)
1301f1e2261SMartin Matuska 			continue;
1311f1e2261SMartin Matuska 		if (strncmp(zd->zd_dsname, dataset, dsnamelen) == 0)
1321f1e2261SMartin Matuska 			return (zd);
1331f1e2261SMartin Matuska 	}
1341f1e2261SMartin Matuska 
1351f1e2261SMartin Matuska 	return (NULL);
1361f1e2261SMartin Matuska }
1371f1e2261SMartin Matuska 
1381f1e2261SMartin Matuska static int
1391f1e2261SMartin Matuska zone_dataset_cred_check(cred_t *cred)
1401f1e2261SMartin Matuska {
1411f1e2261SMartin Matuska 
1421f1e2261SMartin Matuska 	if (!uid_eq(cred->uid, GLOBAL_ROOT_UID))
1431f1e2261SMartin Matuska 		return (EPERM);
1441f1e2261SMartin Matuska 
1451f1e2261SMartin Matuska 	return (0);
1461f1e2261SMartin Matuska }
147*7a7741afSMartin Matuska #endif /* CONFIG_USER_NS */
1481f1e2261SMartin Matuska 
1491f1e2261SMartin Matuska static int
1501f1e2261SMartin Matuska zone_dataset_name_check(const char *dataset, size_t *dsnamelen)
1511f1e2261SMartin Matuska {
1521f1e2261SMartin Matuska 
1531f1e2261SMartin Matuska 	if (dataset[0] == '\0' || dataset[0] == '/')
1541f1e2261SMartin Matuska 		return (ENOENT);
1551f1e2261SMartin Matuska 
1561f1e2261SMartin Matuska 	*dsnamelen = strlen(dataset);
1571f1e2261SMartin Matuska 	/* Ignore trailing slash, if supplied. */
1581f1e2261SMartin Matuska 	if (dataset[*dsnamelen - 1] == '/')
1591f1e2261SMartin Matuska 		(*dsnamelen)--;
1601f1e2261SMartin Matuska 
1611f1e2261SMartin Matuska 	return (0);
1621f1e2261SMartin Matuska }
1631f1e2261SMartin Matuska 
1641f1e2261SMartin Matuska int
1651f1e2261SMartin Matuska zone_dataset_attach(cred_t *cred, const char *dataset, int userns_fd)
1661f1e2261SMartin Matuska {
167*7a7741afSMartin Matuska #ifdef CONFIG_USER_NS
1681f1e2261SMartin Matuska 	struct user_namespace *userns;
1691f1e2261SMartin Matuska 	zone_datasets_t *zds;
1701f1e2261SMartin Matuska 	zone_dataset_t *zd;
1711f1e2261SMartin Matuska 	int error;
1721f1e2261SMartin Matuska 	size_t dsnamelen;
1731f1e2261SMartin Matuska 
1741f1e2261SMartin Matuska 	if ((error = zone_dataset_cred_check(cred)) != 0)
1751f1e2261SMartin Matuska 		return (error);
1761f1e2261SMartin Matuska 	if ((error = zone_dataset_name_check(dataset, &dsnamelen)) != 0)
1771f1e2261SMartin Matuska 		return (error);
1781f1e2261SMartin Matuska 	if ((error = user_ns_get(userns_fd, &userns)) != 0)
1791f1e2261SMartin Matuska 		return (error);
1801f1e2261SMartin Matuska 
1811f1e2261SMartin Matuska 	mutex_enter(&zone_datasets_lock);
1821f1e2261SMartin Matuska 	zds = zone_datasets_lookup(user_ns_zoneid(userns));
1831f1e2261SMartin Matuska 	if (zds == NULL) {
1841f1e2261SMartin Matuska 		zds = kmem_alloc(sizeof (zone_datasets_t), KM_SLEEP);
1851f1e2261SMartin Matuska 		INIT_LIST_HEAD(&zds->zds_list);
1861f1e2261SMartin Matuska 		INIT_LIST_HEAD(&zds->zds_datasets);
1871f1e2261SMartin Matuska 		zds->zds_userns = userns;
1881f1e2261SMartin Matuska 		/*
1891f1e2261SMartin Matuska 		 * Lock the namespace by incresing its refcount to prevent
1901f1e2261SMartin Matuska 		 * the namespace ID from being reused.
1911f1e2261SMartin Matuska 		 */
1921f1e2261SMartin Matuska 		get_user_ns(userns);
1931f1e2261SMartin Matuska 		list_add_tail(&zds->zds_list, &zone_datasets);
1941f1e2261SMartin Matuska 	} else {
1951f1e2261SMartin Matuska 		zd = zone_dataset_lookup(zds, dataset, dsnamelen);
1961f1e2261SMartin Matuska 		if (zd != NULL) {
1971f1e2261SMartin Matuska 			mutex_exit(&zone_datasets_lock);
1981f1e2261SMartin Matuska 			return (EEXIST);
1991f1e2261SMartin Matuska 		}
2001f1e2261SMartin Matuska 	}
2011f1e2261SMartin Matuska 
2021f1e2261SMartin Matuska 	zd = kmem_alloc(sizeof (zone_dataset_t) + dsnamelen + 1, KM_SLEEP);
2031f1e2261SMartin Matuska 	zd->zd_dsnamelen = dsnamelen;
204be181ee2SMartin Matuska 	strlcpy(zd->zd_dsname, dataset, dsnamelen + 1);
2051f1e2261SMartin Matuska 	INIT_LIST_HEAD(&zd->zd_list);
2061f1e2261SMartin Matuska 	list_add_tail(&zd->zd_list, &zds->zds_datasets);
2071f1e2261SMartin Matuska 
2081f1e2261SMartin Matuska 	mutex_exit(&zone_datasets_lock);
2091f1e2261SMartin Matuska 	return (0);
2101f1e2261SMartin Matuska #else
2111f1e2261SMartin Matuska 	return (ENXIO);
212*7a7741afSMartin Matuska #endif /* CONFIG_USER_NS */
2131f1e2261SMartin Matuska }
2141f1e2261SMartin Matuska EXPORT_SYMBOL(zone_dataset_attach);
2151f1e2261SMartin Matuska 
2161f1e2261SMartin Matuska int
2171f1e2261SMartin Matuska zone_dataset_detach(cred_t *cred, const char *dataset, int userns_fd)
2181f1e2261SMartin Matuska {
219*7a7741afSMartin Matuska #ifdef CONFIG_USER_NS
2201f1e2261SMartin Matuska 	struct user_namespace *userns;
2211f1e2261SMartin Matuska 	zone_datasets_t *zds;
2221f1e2261SMartin Matuska 	zone_dataset_t *zd;
2231f1e2261SMartin Matuska 	int error;
2241f1e2261SMartin Matuska 	size_t dsnamelen;
2251f1e2261SMartin Matuska 
2261f1e2261SMartin Matuska 	if ((error = zone_dataset_cred_check(cred)) != 0)
2271f1e2261SMartin Matuska 		return (error);
2281f1e2261SMartin Matuska 	if ((error = zone_dataset_name_check(dataset, &dsnamelen)) != 0)
2291f1e2261SMartin Matuska 		return (error);
2301f1e2261SMartin Matuska 	if ((error = user_ns_get(userns_fd, &userns)) != 0)
2311f1e2261SMartin Matuska 		return (error);
2321f1e2261SMartin Matuska 
2331f1e2261SMartin Matuska 	mutex_enter(&zone_datasets_lock);
2341f1e2261SMartin Matuska 	zds = zone_datasets_lookup(user_ns_zoneid(userns));
2351f1e2261SMartin Matuska 	if (zds != NULL)
2361f1e2261SMartin Matuska 		zd = zone_dataset_lookup(zds, dataset, dsnamelen);
2371f1e2261SMartin Matuska 	if (zds == NULL || zd == NULL) {
2381f1e2261SMartin Matuska 		mutex_exit(&zone_datasets_lock);
2391f1e2261SMartin Matuska 		return (ENOENT);
2401f1e2261SMartin Matuska 	}
2411f1e2261SMartin Matuska 
2421f1e2261SMartin Matuska 	list_del(&zd->zd_list);
2431f1e2261SMartin Matuska 	kmem_free(zd, sizeof (*zd) + zd->zd_dsnamelen + 1);
2441f1e2261SMartin Matuska 
2451f1e2261SMartin Matuska 	/* Prune the namespace entry if it has no more delegations. */
2461f1e2261SMartin Matuska 	if (list_empty(&zds->zds_datasets)) {
2471f1e2261SMartin Matuska 		/*
2481f1e2261SMartin Matuska 		 * Decrease the refcount now that the namespace is no longer
2491f1e2261SMartin Matuska 		 * used. It is no longer necessary to prevent the namespace ID
2501f1e2261SMartin Matuska 		 * from being reused.
2511f1e2261SMartin Matuska 		 */
2521f1e2261SMartin Matuska 		put_user_ns(userns);
2531f1e2261SMartin Matuska 		list_del(&zds->zds_list);
2541f1e2261SMartin Matuska 		kmem_free(zds, sizeof (*zds));
2551f1e2261SMartin Matuska 	}
2561f1e2261SMartin Matuska 
2571f1e2261SMartin Matuska 	mutex_exit(&zone_datasets_lock);
2581f1e2261SMartin Matuska 	return (0);
2591f1e2261SMartin Matuska #else
2601f1e2261SMartin Matuska 	return (ENXIO);
261*7a7741afSMartin Matuska #endif /* CONFIG_USER_NS */
2621f1e2261SMartin Matuska }
2631f1e2261SMartin Matuska EXPORT_SYMBOL(zone_dataset_detach);
2641f1e2261SMartin Matuska 
2651f1e2261SMartin Matuska /*
2661f1e2261SMartin Matuska  * A dataset is visible if:
2671f1e2261SMartin Matuska  * - It is a parent of a namespace entry.
2681f1e2261SMartin Matuska  * - It is one of the namespace entries.
2691f1e2261SMartin Matuska  * - It is a child of a namespace entry.
2701f1e2261SMartin Matuska  *
2711f1e2261SMartin Matuska  * A dataset is writable if:
2721f1e2261SMartin Matuska  * - It is one of the namespace entries.
2731f1e2261SMartin Matuska  * - It is a child of a namespace entry.
2741f1e2261SMartin Matuska  *
2751f1e2261SMartin Matuska  * The parent datasets of namespace entries are visible and
2761f1e2261SMartin Matuska  * read-only to provide a path back to the root of the pool.
2771f1e2261SMartin Matuska  */
2781f1e2261SMartin Matuska int
2791f1e2261SMartin Matuska zone_dataset_visible(const char *dataset, int *write)
2801f1e2261SMartin Matuska {
2811f1e2261SMartin Matuska 	zone_datasets_t *zds;
2821f1e2261SMartin Matuska 	zone_dataset_t *zd;
2831f1e2261SMartin Matuska 	size_t dsnamelen, zd_len;
2841f1e2261SMartin Matuska 	int visible;
2851f1e2261SMartin Matuska 
2861f1e2261SMartin Matuska 	/* Default to read-only, in case visible is returned. */
2871f1e2261SMartin Matuska 	if (write != NULL)
2881f1e2261SMartin Matuska 		*write = 0;
2891f1e2261SMartin Matuska 	if (zone_dataset_name_check(dataset, &dsnamelen) != 0)
2901f1e2261SMartin Matuska 		return (0);
2911f1e2261SMartin Matuska 	if (INGLOBALZONE(curproc)) {
2921f1e2261SMartin Matuska 		if (write != NULL)
2931f1e2261SMartin Matuska 			*write = 1;
2941f1e2261SMartin Matuska 		return (1);
2951f1e2261SMartin Matuska 	}
2961f1e2261SMartin Matuska 
2971f1e2261SMartin Matuska 	mutex_enter(&zone_datasets_lock);
2981f1e2261SMartin Matuska 	zds = zone_datasets_lookup(crgetzoneid(curproc->cred));
2991f1e2261SMartin Matuska 	if (zds == NULL) {
3001f1e2261SMartin Matuska 		mutex_exit(&zone_datasets_lock);
3011f1e2261SMartin Matuska 		return (0);
3021f1e2261SMartin Matuska 	}
3031f1e2261SMartin Matuska 
3041f1e2261SMartin Matuska 	visible = 0;
3051f1e2261SMartin Matuska 	list_for_each_entry(zd, &zds->zds_datasets, zd_list) {
3061f1e2261SMartin Matuska 		zd_len = strlen(zd->zd_dsname);
3071f1e2261SMartin Matuska 		if (zd_len > dsnamelen) {
3081f1e2261SMartin Matuska 			/*
3091f1e2261SMartin Matuska 			 * The name of the namespace entry is longer than that
3101f1e2261SMartin Matuska 			 * of the dataset, so it could be that the dataset is a
3111f1e2261SMartin Matuska 			 * parent of the namespace entry.
3121f1e2261SMartin Matuska 			 */
3131f1e2261SMartin Matuska 			visible = memcmp(zd->zd_dsname, dataset,
3141f1e2261SMartin Matuska 			    dsnamelen) == 0 &&
3151f1e2261SMartin Matuska 			    zd->zd_dsname[dsnamelen] == '/';
3161f1e2261SMartin Matuska 			if (visible)
3171f1e2261SMartin Matuska 				break;
3181f1e2261SMartin Matuska 		} else if (zd_len == dsnamelen) {
3191f1e2261SMartin Matuska 			/*
3201f1e2261SMartin Matuska 			 * The name of the namespace entry is as long as that
3211f1e2261SMartin Matuska 			 * of the dataset, so perhaps the dataset itself is the
3221f1e2261SMartin Matuska 			 * namespace entry.
3231f1e2261SMartin Matuska 			 */
3241f1e2261SMartin Matuska 			visible = memcmp(zd->zd_dsname, dataset, zd_len) == 0;
3251f1e2261SMartin Matuska 			if (visible) {
3261f1e2261SMartin Matuska 				if (write != NULL)
3271f1e2261SMartin Matuska 					*write = 1;
3281f1e2261SMartin Matuska 				break;
3291f1e2261SMartin Matuska 			}
3301f1e2261SMartin Matuska 		} else {
3311f1e2261SMartin Matuska 			/*
3321f1e2261SMartin Matuska 			 * The name of the namespace entry is shorter than that
3331f1e2261SMartin Matuska 			 * of the dataset, so perhaps the dataset is a child of
3341f1e2261SMartin Matuska 			 * the namespace entry.
3351f1e2261SMartin Matuska 			 */
3361f1e2261SMartin Matuska 			visible = memcmp(zd->zd_dsname, dataset,
3371f1e2261SMartin Matuska 			    zd_len) == 0 && dataset[zd_len] == '/';
3381f1e2261SMartin Matuska 			if (visible) {
3391f1e2261SMartin Matuska 				if (write != NULL)
3401f1e2261SMartin Matuska 					*write = 1;
3411f1e2261SMartin Matuska 				break;
3421f1e2261SMartin Matuska 			}
3431f1e2261SMartin Matuska 		}
3441f1e2261SMartin Matuska 	}
3451f1e2261SMartin Matuska 
3461f1e2261SMartin Matuska 	mutex_exit(&zone_datasets_lock);
3471f1e2261SMartin Matuska 	return (visible);
3481f1e2261SMartin Matuska }
3491f1e2261SMartin Matuska EXPORT_SYMBOL(zone_dataset_visible);
3501f1e2261SMartin Matuska 
3511f1e2261SMartin Matuska unsigned int
3521f1e2261SMartin Matuska global_zoneid(void)
3531f1e2261SMartin Matuska {
3541f1e2261SMartin Matuska 	unsigned int z = 0;
3551f1e2261SMartin Matuska 
3561f1e2261SMartin Matuska #if defined(CONFIG_USER_NS)
3571f1e2261SMartin Matuska 	z = user_ns_zoneid(&init_user_ns);
3581f1e2261SMartin Matuska #endif
3591f1e2261SMartin Matuska 
3601f1e2261SMartin Matuska 	return (z);
3611f1e2261SMartin Matuska }
3621f1e2261SMartin Matuska EXPORT_SYMBOL(global_zoneid);
3631f1e2261SMartin Matuska 
3641f1e2261SMartin Matuska unsigned int
3651f1e2261SMartin Matuska crgetzoneid(const cred_t *cr)
3661f1e2261SMartin Matuska {
3671f1e2261SMartin Matuska 	unsigned int r = 0;
3681f1e2261SMartin Matuska 
3691f1e2261SMartin Matuska #if defined(CONFIG_USER_NS)
3701f1e2261SMartin Matuska 	r = user_ns_zoneid(cr->user_ns);
3711f1e2261SMartin Matuska #endif
3721f1e2261SMartin Matuska 
3731f1e2261SMartin Matuska 	return (r);
3741f1e2261SMartin Matuska }
3751f1e2261SMartin Matuska EXPORT_SYMBOL(crgetzoneid);
3761f1e2261SMartin Matuska 
3771f1e2261SMartin Matuska boolean_t
3781f1e2261SMartin Matuska inglobalzone(proc_t *proc)
3791f1e2261SMartin Matuska {
3801f1e2261SMartin Matuska #if defined(CONFIG_USER_NS)
3811f1e2261SMartin Matuska 	return (proc->cred->user_ns == &init_user_ns);
3821f1e2261SMartin Matuska #else
3831f1e2261SMartin Matuska 	return (B_TRUE);
3841f1e2261SMartin Matuska #endif
3851f1e2261SMartin Matuska }
3861f1e2261SMartin Matuska EXPORT_SYMBOL(inglobalzone);
3871f1e2261SMartin Matuska 
3881f1e2261SMartin Matuska int
3891f1e2261SMartin Matuska spl_zone_init(void)
3901f1e2261SMartin Matuska {
3911f1e2261SMartin Matuska 	mutex_init(&zone_datasets_lock, NULL, MUTEX_DEFAULT, NULL);
3921f1e2261SMartin Matuska 	INIT_LIST_HEAD(&zone_datasets);
3931f1e2261SMartin Matuska 	return (0);
3941f1e2261SMartin Matuska }
3951f1e2261SMartin Matuska 
3961f1e2261SMartin Matuska void
3971f1e2261SMartin Matuska spl_zone_fini(void)
3981f1e2261SMartin Matuska {
3991f1e2261SMartin Matuska 	zone_datasets_t *zds;
4001f1e2261SMartin Matuska 	zone_dataset_t *zd;
4011f1e2261SMartin Matuska 
4021f1e2261SMartin Matuska 	/*
4031f1e2261SMartin Matuska 	 * It would be better to assert an empty zone_datasets, but since
4041f1e2261SMartin Matuska 	 * there's no automatic mechanism for cleaning them up if the user
4051f1e2261SMartin Matuska 	 * namespace is destroyed, just do it here, since spl is about to go
4061f1e2261SMartin Matuska 	 * out of context.
4071f1e2261SMartin Matuska 	 */
4081f1e2261SMartin Matuska 	while (!list_empty(&zone_datasets)) {
4091f1e2261SMartin Matuska 		zds = list_entry(zone_datasets.next, zone_datasets_t, zds_list);
4101f1e2261SMartin Matuska 		while (!list_empty(&zds->zds_datasets)) {
4111f1e2261SMartin Matuska 			zd = list_entry(zds->zds_datasets.next,
4121f1e2261SMartin Matuska 			    zone_dataset_t, zd_list);
4131f1e2261SMartin Matuska 			list_del(&zd->zd_list);
4141f1e2261SMartin Matuska 			kmem_free(zd, sizeof (*zd) + zd->zd_dsnamelen + 1);
4151f1e2261SMartin Matuska 		}
416c7046f76SMartin Matuska 		put_user_ns(zds->zds_userns);
4171f1e2261SMartin Matuska 		list_del(&zds->zds_list);
4181f1e2261SMartin Matuska 		kmem_free(zds, sizeof (*zds));
4191f1e2261SMartin Matuska 	}
4201f1e2261SMartin Matuska 	mutex_destroy(&zone_datasets_lock);
4211f1e2261SMartin Matuska }
422