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