xref: /illumos-gate/usr/src/lib/libbe/common/be_mount.c (revision 19f5167c)
1f169c0eaSGlenn Lagasse /*
2f169c0eaSGlenn Lagasse  * CDDL HEADER START
3f169c0eaSGlenn Lagasse  *
4f169c0eaSGlenn Lagasse  * The contents of this file are subject to the terms of the
5f169c0eaSGlenn Lagasse  * Common Development and Distribution License (the "License").
6f169c0eaSGlenn Lagasse  * You may not use this file except in compliance with the License.
7f169c0eaSGlenn Lagasse  *
8f169c0eaSGlenn Lagasse  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f169c0eaSGlenn Lagasse  * or http://www.opensolaris.org/os/licensing.
10f169c0eaSGlenn Lagasse  * See the License for the specific language governing permissions
11f169c0eaSGlenn Lagasse  * and limitations under the License.
12f169c0eaSGlenn Lagasse  *
13f169c0eaSGlenn Lagasse  * When distributing Covered Code, include this CDDL HEADER in each
14f169c0eaSGlenn Lagasse  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f169c0eaSGlenn Lagasse  * If applicable, add the following below this CDDL HEADER, with the
16f169c0eaSGlenn Lagasse  * fields enclosed by brackets "[]" replaced with your own identifying
17f169c0eaSGlenn Lagasse  * information: Portions Copyright [yyyy] [name of copyright owner]
18f169c0eaSGlenn Lagasse  *
19f169c0eaSGlenn Lagasse  * CDDL HEADER END
20f169c0eaSGlenn Lagasse  */
21f169c0eaSGlenn Lagasse 
22f169c0eaSGlenn Lagasse /*
23f169c0eaSGlenn Lagasse  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
247e0e2549SAlexander Eremin  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
2585aac7c1SIgor Kozhukhov  * Copyright 2015 EveryCity Ltd.
269adfa60dSMatthew Ahrens  * Copyright (c) 2015 by Delphix. All rights reserved.
2789d19e00SAlexander Eremin  */
28f169c0eaSGlenn Lagasse 
29f169c0eaSGlenn Lagasse /*
30f169c0eaSGlenn Lagasse  * System includes
31f169c0eaSGlenn Lagasse  */
32f169c0eaSGlenn Lagasse #include <assert.h>
33f169c0eaSGlenn Lagasse #include <errno.h>
347e0e2549SAlexander Eremin #include <libgen.h>
35f169c0eaSGlenn Lagasse #include <libintl.h>
36f169c0eaSGlenn Lagasse #include <libnvpair.h>
37f169c0eaSGlenn Lagasse #include <libzfs.h>
38f169c0eaSGlenn Lagasse #include <stdio.h>
39f169c0eaSGlenn Lagasse #include <stdlib.h>
40f169c0eaSGlenn Lagasse #include <string.h>
41f169c0eaSGlenn Lagasse #include <sys/mntent.h>
42f169c0eaSGlenn Lagasse #include <sys/mnttab.h>
43f169c0eaSGlenn Lagasse #include <sys/mount.h>
44f169c0eaSGlenn Lagasse #include <sys/stat.h>
45f169c0eaSGlenn Lagasse #include <sys/types.h>
46f169c0eaSGlenn Lagasse #include <sys/vfstab.h>
47f169c0eaSGlenn Lagasse #include <sys/zone.h>
48f169c0eaSGlenn Lagasse #include <sys/mkdev.h>
49f169c0eaSGlenn Lagasse #include <unistd.h>
50f169c0eaSGlenn Lagasse 
51f169c0eaSGlenn Lagasse #include <libbe.h>
52f169c0eaSGlenn Lagasse #include <libbe_priv.h>
53f169c0eaSGlenn Lagasse 
54f169c0eaSGlenn Lagasse #define	BE_TMP_MNTPNT		"/tmp/.be.XXXXXX"
55f169c0eaSGlenn Lagasse 
56f169c0eaSGlenn Lagasse typedef struct dir_data {
57f169c0eaSGlenn Lagasse 	char *dir;
58f169c0eaSGlenn Lagasse 	char *ds;
59f169c0eaSGlenn Lagasse } dir_data_t;
60f169c0eaSGlenn Lagasse 
61f169c0eaSGlenn Lagasse /* Private function prototypes */
62f169c0eaSGlenn Lagasse static int be_mount_callback(zfs_handle_t *, void *);
63f169c0eaSGlenn Lagasse static int be_unmount_callback(zfs_handle_t *, void *);
64f169c0eaSGlenn Lagasse static int be_get_legacy_fs_callback(zfs_handle_t *, void *);
65f169c0eaSGlenn Lagasse static int fix_mountpoint(zfs_handle_t *);
66f169c0eaSGlenn Lagasse static int fix_mountpoint_callback(zfs_handle_t *, void *);
67f169c0eaSGlenn Lagasse static int get_mountpoint_from_vfstab(char *, const char *, char *, size_t,
68f169c0eaSGlenn Lagasse     boolean_t);
69f169c0eaSGlenn Lagasse static int loopback_mount_shared_fs(zfs_handle_t *, be_mount_data_t *);
70f169c0eaSGlenn Lagasse static int loopback_mount_zonepath(const char *, be_mount_data_t *);
71f169c0eaSGlenn Lagasse static int iter_shared_fs_callback(zfs_handle_t *, void *);
72f169c0eaSGlenn Lagasse static int zpool_shared_fs_callback(zpool_handle_t *, void *);
73f169c0eaSGlenn Lagasse static int unmount_shared_fs(be_unmount_data_t *);
74f169c0eaSGlenn Lagasse static int add_to_fs_list(be_fs_list_data_t *, const char *);
75f169c0eaSGlenn Lagasse static int be_mount_root(zfs_handle_t *, char *);
76f169c0eaSGlenn Lagasse static int be_unmount_root(zfs_handle_t *, be_unmount_data_t *);
77f169c0eaSGlenn Lagasse static int be_mount_zones(zfs_handle_t *, be_mount_data_t *);
78f169c0eaSGlenn Lagasse static int be_unmount_zones(be_unmount_data_t *);
79f169c0eaSGlenn Lagasse static int be_mount_one_zone(zfs_handle_t *, be_mount_data_t *, char *, char *,
80f169c0eaSGlenn Lagasse     char *);
81f169c0eaSGlenn Lagasse static int be_unmount_one_zone(be_unmount_data_t *, char *, char *, char *);
82f169c0eaSGlenn Lagasse static int be_get_ds_from_dir_callback(zfs_handle_t *, void *);
833a876192SAlexander Pyhalov static int mount_zfs(zfs_handle_t *, char *);
84f169c0eaSGlenn Lagasse 
85f169c0eaSGlenn Lagasse 
86f169c0eaSGlenn Lagasse /* ********************************************************************	*/
87f169c0eaSGlenn Lagasse /*			Public Functions				*/
88f169c0eaSGlenn Lagasse /* ********************************************************************	*/
89f169c0eaSGlenn Lagasse 
90f169c0eaSGlenn Lagasse /*
91f169c0eaSGlenn Lagasse  * Function:	be_mount
92f169c0eaSGlenn Lagasse  * Description:	Mounts a BE and its subordinate datasets at a given mountpoint.
93f169c0eaSGlenn Lagasse  * Parameters:
94f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
95f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
96f169c0eaSGlenn Lagasse  *
97f169c0eaSGlenn Lagasse  *			BE_ATTR_ORIG_BE_NAME		*required
98f169c0eaSGlenn Lagasse  *			BE_ATTR_MOUNTPOINT		*required
99f169c0eaSGlenn Lagasse  *			BE_ATTR_MOUNT_FLAGS		*optional
100f169c0eaSGlenn Lagasse  * Return:
101f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
102f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
103f169c0eaSGlenn Lagasse  * Scope:
104f169c0eaSGlenn Lagasse  *		Public
105f169c0eaSGlenn Lagasse  */
106f169c0eaSGlenn Lagasse int
107f169c0eaSGlenn Lagasse be_mount(nvlist_t *be_attrs)
108f169c0eaSGlenn Lagasse {
109f169c0eaSGlenn Lagasse 	char		*be_name = NULL;
110f169c0eaSGlenn Lagasse 	char		*mountpoint = NULL;
111f169c0eaSGlenn Lagasse 	uint16_t	flags = 0;
112f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
113f169c0eaSGlenn Lagasse 
114f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
115f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
116f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
117f169c0eaSGlenn Lagasse 
118f169c0eaSGlenn Lagasse 	/* Get original BE name */
119f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
120f169c0eaSGlenn Lagasse 	    != 0) {
121f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to lookup "
122f169c0eaSGlenn Lagasse 		    "BE_ATTR_ORIG_BE_NAME attribute\n"));
123f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
124f169c0eaSGlenn Lagasse 	}
125f169c0eaSGlenn Lagasse 
126f169c0eaSGlenn Lagasse 	/* Validate original BE name */
127f169c0eaSGlenn Lagasse 	if (!be_valid_be_name(be_name)) {
128f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: invalid BE name %s\n"),
129f169c0eaSGlenn Lagasse 		    be_name);
130f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
131f169c0eaSGlenn Lagasse 	}
132f169c0eaSGlenn Lagasse 
133f169c0eaSGlenn Lagasse 	/* Get mountpoint */
134f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_MOUNTPOINT, &mountpoint)
135f169c0eaSGlenn Lagasse 	    != 0) {
136f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to lookup "
137f169c0eaSGlenn Lagasse 		    "BE_ATTR_MOUNTPOINT attribute\n"));
138f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
139f169c0eaSGlenn Lagasse 	}
140f169c0eaSGlenn Lagasse 
141f169c0eaSGlenn Lagasse 	/* Get flags */
142f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
143f169c0eaSGlenn Lagasse 	    BE_ATTR_MOUNT_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
144f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to lookup "
145f169c0eaSGlenn Lagasse 		    "BE_ATTR_MOUNT_FLAGS attribute\n"));
146f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
147f169c0eaSGlenn Lagasse 	}
148f169c0eaSGlenn Lagasse 
149f169c0eaSGlenn Lagasse 	ret = _be_mount(be_name, &mountpoint, flags);
150f169c0eaSGlenn Lagasse 
151f169c0eaSGlenn Lagasse 	be_zfs_fini();
152f169c0eaSGlenn Lagasse 
153f169c0eaSGlenn Lagasse 	return (ret);
154f169c0eaSGlenn Lagasse }
155f169c0eaSGlenn Lagasse 
156f169c0eaSGlenn Lagasse /*
157f169c0eaSGlenn Lagasse  * Function:	be_unmount
158f169c0eaSGlenn Lagasse  * Description:	Unmounts a BE and its subordinate datasets.
159f169c0eaSGlenn Lagasse  * Parameters:
160f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
161f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
162f169c0eaSGlenn Lagasse  *
163f169c0eaSGlenn Lagasse  *			BE_ATTR_ORIG_BE_NAME		*required
164f169c0eaSGlenn Lagasse  *			BE_ATTR_UNMOUNT_FLAGS		*optional
165f169c0eaSGlenn Lagasse  * Return:
166f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
167f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
168f169c0eaSGlenn Lagasse  * Scope:
169f169c0eaSGlenn Lagasse  *		Public
170f169c0eaSGlenn Lagasse  */
171f169c0eaSGlenn Lagasse int
172f169c0eaSGlenn Lagasse be_unmount(nvlist_t *be_attrs)
173f169c0eaSGlenn Lagasse {
174f169c0eaSGlenn Lagasse 	char		*be_name = NULL;
17589d19e00SAlexander Eremin 	char		*be_name_mnt = NULL;
17689d19e00SAlexander Eremin 	char		*ds = NULL;
177f169c0eaSGlenn Lagasse 	uint16_t	flags = 0;
178f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
179f169c0eaSGlenn Lagasse 
180f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
181f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
182f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
183f169c0eaSGlenn Lagasse 
184f169c0eaSGlenn Lagasse 	/* Get original BE name */
185f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
186f169c0eaSGlenn Lagasse 	    != 0) {
187f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to lookup "
188f169c0eaSGlenn Lagasse 		    "BE_ATTR_ORIG_BE_NAME attribute\n"));
189f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
190f169c0eaSGlenn Lagasse 	}
191f169c0eaSGlenn Lagasse 
19289d19e00SAlexander Eremin 	/* Check if we have mountpoint argument instead of BE name */
19389d19e00SAlexander Eremin 	if (be_name[0] == '/') {
19489d19e00SAlexander Eremin 		if ((ds = be_get_ds_from_dir(be_name)) != NULL) {
19589d19e00SAlexander Eremin 			if ((be_name_mnt = strrchr(ds, '/')) != NULL) {
19689d19e00SAlexander Eremin 				be_name = be_name_mnt + 1;
19789d19e00SAlexander Eremin 			}
19889d19e00SAlexander Eremin 		} else {
19989d19e00SAlexander Eremin 			be_print_err(gettext("be_unmount: no datasets mounted "
20089d19e00SAlexander Eremin 			    "at '%s'\n"), be_name);
20189d19e00SAlexander Eremin 			return (BE_ERR_INVAL);
20289d19e00SAlexander Eremin 		}
20389d19e00SAlexander Eremin 	}
20489d19e00SAlexander Eremin 
205f169c0eaSGlenn Lagasse 	/* Validate original BE name */
206f169c0eaSGlenn Lagasse 	if (!be_valid_be_name(be_name)) {
207f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: invalid BE name %s\n"),
208f169c0eaSGlenn Lagasse 		    be_name);
209f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
210f169c0eaSGlenn Lagasse 	}
211f169c0eaSGlenn Lagasse 
212f169c0eaSGlenn Lagasse 	/* Get unmount flags */
213f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
214f169c0eaSGlenn Lagasse 	    BE_ATTR_UNMOUNT_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
215f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to loookup "
216f169c0eaSGlenn Lagasse 		    "BE_ATTR_UNMOUNT_FLAGS attribute\n"));
217f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
218f169c0eaSGlenn Lagasse 	}
219f169c0eaSGlenn Lagasse 
220f169c0eaSGlenn Lagasse 	ret = _be_unmount(be_name, flags);
221f169c0eaSGlenn Lagasse 
222f169c0eaSGlenn Lagasse 	be_zfs_fini();
223f169c0eaSGlenn Lagasse 
224f169c0eaSGlenn Lagasse 	return (ret);
225f169c0eaSGlenn Lagasse }
226f169c0eaSGlenn Lagasse 
227f169c0eaSGlenn Lagasse /* ********************************************************************	*/
228f169c0eaSGlenn Lagasse /*			Semi-Private Functions				*/
229f169c0eaSGlenn Lagasse /* ******************************************************************** */
230f169c0eaSGlenn Lagasse 
231f169c0eaSGlenn Lagasse /*
232f169c0eaSGlenn Lagasse  * Function:	_be_mount
233f169c0eaSGlenn Lagasse  * Description:	Mounts a BE.  If the altroot is not provided, this function
234f169c0eaSGlenn Lagasse  *		will generate a temporary mountpoint to mount the BE at.  It
235f169c0eaSGlenn Lagasse  *		will return this temporary mountpoint to the caller via the
236f169c0eaSGlenn Lagasse  *		altroot reference pointer passed in.  This returned value is
237f169c0eaSGlenn Lagasse  *		allocated on heap storage and is the repsonsibility of the
238f169c0eaSGlenn Lagasse  *		caller to free.
239f169c0eaSGlenn Lagasse  * Parameters:
240f169c0eaSGlenn Lagasse  *		be_name - pointer to name of BE to mount.
241f169c0eaSGlenn Lagasse  *		altroot - reference pointer to altroot of where to mount BE.
242f169c0eaSGlenn Lagasse  *		flags - flag indicating special handling for mounting the BE
243f169c0eaSGlenn Lagasse  * Return:
244f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
245f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
246f169c0eaSGlenn Lagasse  * Scope:
247f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
248f169c0eaSGlenn Lagasse  */
249f169c0eaSGlenn Lagasse int
250f169c0eaSGlenn Lagasse _be_mount(char *be_name, char **altroot, int flags)
251f169c0eaSGlenn Lagasse {
252f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
253f169c0eaSGlenn Lagasse 	be_mount_data_t	md = { 0 };
254f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp;
255f169c0eaSGlenn Lagasse 	char		obe_root_ds[MAXPATHLEN];
256f169c0eaSGlenn Lagasse 	char		*mp = NULL;
257f169c0eaSGlenn Lagasse 	char		*tmp_altroot = NULL;
258f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS, err = 0;
259f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
260f169c0eaSGlenn Lagasse 	boolean_t	gen_tmp_altroot = B_FALSE;
261f169c0eaSGlenn Lagasse 
262f169c0eaSGlenn Lagasse 	if (be_name == NULL || altroot == NULL)
263f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
264f169c0eaSGlenn Lagasse 
265f169c0eaSGlenn Lagasse 	/* Set be_name as obe_name in bt structure */
266f169c0eaSGlenn Lagasse 	bt.obe_name = be_name;
267f169c0eaSGlenn Lagasse 
268f169c0eaSGlenn Lagasse 	/* Find which zpool obe_name lives in */
269f169c0eaSGlenn Lagasse 	if ((err = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
270f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to "
271f169c0eaSGlenn Lagasse 		    "find zpool for BE (%s)\n"), bt.obe_name);
272f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_NOENT);
273f169c0eaSGlenn Lagasse 	} else if (err < 0) {
274f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: zpool_iter failed: %s\n"),
275f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
276f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
277f169c0eaSGlenn Lagasse 	}
278f169c0eaSGlenn Lagasse 
279f169c0eaSGlenn Lagasse 	/* Generate string for obe_name's root dataset */
280f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
281f169c0eaSGlenn Lagasse 	    sizeof (obe_root_ds));
282f169c0eaSGlenn Lagasse 	bt.obe_root_ds = obe_root_ds;
283f169c0eaSGlenn Lagasse 
284f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
285f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
286f169c0eaSGlenn Lagasse 	    NULL) {
287f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to "
288f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
289f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
290f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
291f169c0eaSGlenn Lagasse 	}
292f169c0eaSGlenn Lagasse 
293f169c0eaSGlenn Lagasse 	/* Make sure BE's root dataset isn't already mounted somewhere */
294f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &mp)) {
295f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
296f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: %s is already mounted "
297f169c0eaSGlenn Lagasse 		    "at %s\n"), bt.obe_name, mp != NULL ? mp : "");
298f169c0eaSGlenn Lagasse 		free(mp);
299f169c0eaSGlenn Lagasse 		return (BE_ERR_MOUNTED);
300f169c0eaSGlenn Lagasse 	}
301f169c0eaSGlenn Lagasse 
302f169c0eaSGlenn Lagasse 	/*
303f169c0eaSGlenn Lagasse 	 * Fix this BE's mountpoint if its root dataset isn't set to
304f169c0eaSGlenn Lagasse 	 * either 'legacy' or '/'.
305f169c0eaSGlenn Lagasse 	 */
306f169c0eaSGlenn Lagasse 	if ((ret = fix_mountpoint(zhp)) != BE_SUCCESS) {
307f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: mountpoint check "
308f169c0eaSGlenn Lagasse 		    "failed for %s\n"), bt.obe_root_ds);
309f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
310f169c0eaSGlenn Lagasse 		return (ret);
311f169c0eaSGlenn Lagasse 	}
312f169c0eaSGlenn Lagasse 
313f169c0eaSGlenn Lagasse 	/*
314f169c0eaSGlenn Lagasse 	 * If altroot not provided, create a temporary alternate root
315f169c0eaSGlenn Lagasse 	 * to mount on
316f169c0eaSGlenn Lagasse 	 */
317f169c0eaSGlenn Lagasse 	if (*altroot == NULL) {
318f169c0eaSGlenn Lagasse 		if ((ret = be_make_tmp_mountpoint(&tmp_altroot))
319f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
320f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_mount: failed to "
321f169c0eaSGlenn Lagasse 			    "make temporary mountpoint\n"));
322f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
323f169c0eaSGlenn Lagasse 			return (ret);
324f169c0eaSGlenn Lagasse 		}
325f169c0eaSGlenn Lagasse 		gen_tmp_altroot = B_TRUE;
326f169c0eaSGlenn Lagasse 	} else {
327f169c0eaSGlenn Lagasse 		tmp_altroot = *altroot;
328f169c0eaSGlenn Lagasse 	}
329f169c0eaSGlenn Lagasse 
3307e0e2549SAlexander Eremin 	md.altroot = tmp_altroot;
3317e0e2549SAlexander Eremin 	md.shared_fs = flags & BE_MOUNT_FLAG_SHARED_FS;
3327e0e2549SAlexander Eremin 	md.shared_rw = flags & BE_MOUNT_FLAG_SHARED_RW;
3337e0e2549SAlexander Eremin 
334f169c0eaSGlenn Lagasse 	/* Mount the BE's root file system */
3357e0e2549SAlexander Eremin 	if (getzoneid() == GLOBAL_ZONEID) {
3367e0e2549SAlexander Eremin 		if ((ret = be_mount_root(zhp, tmp_altroot)) != BE_SUCCESS) {
3377e0e2549SAlexander Eremin 			be_print_err(gettext("be_mount: failed to "
3387e0e2549SAlexander Eremin 			    "mount BE root file system\n"));
3397e0e2549SAlexander Eremin 			if (gen_tmp_altroot)
3407e0e2549SAlexander Eremin 				free(tmp_altroot);
3417e0e2549SAlexander Eremin 			ZFS_CLOSE(zhp);
3427e0e2549SAlexander Eremin 			return (ret);
3437e0e2549SAlexander Eremin 		}
3447e0e2549SAlexander Eremin 	} else {
3457e0e2549SAlexander Eremin 		/* Legacy mount the zone root dataset */
3467e0e2549SAlexander Eremin 		if ((ret = be_mount_zone_root(zhp, &md)) != BE_SUCCESS) {
3477e0e2549SAlexander Eremin 			be_print_err(gettext("be_mount: failed to "
3487e0e2549SAlexander Eremin 			    "mount BE zone root file system\n"));
3497e0e2549SAlexander Eremin 			free(md.altroot);
3507e0e2549SAlexander Eremin 			ZFS_CLOSE(zhp);
3517e0e2549SAlexander Eremin 			return (ret);
3527e0e2549SAlexander Eremin 		}
353f169c0eaSGlenn Lagasse 	}
354f169c0eaSGlenn Lagasse 
355f169c0eaSGlenn Lagasse 	/* Iterate through BE's children filesystems */
356f169c0eaSGlenn Lagasse 	if ((err = zfs_iter_filesystems(zhp, be_mount_callback,
357f169c0eaSGlenn Lagasse 	    tmp_altroot)) != 0) {
358f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to "
359f169c0eaSGlenn Lagasse 		    "mount BE (%s) on %s\n"), bt.obe_name, tmp_altroot);
360f169c0eaSGlenn Lagasse 		if (gen_tmp_altroot)
361f169c0eaSGlenn Lagasse 			free(tmp_altroot);
362f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
363f169c0eaSGlenn Lagasse 		return (err);
364f169c0eaSGlenn Lagasse 	}
365f169c0eaSGlenn Lagasse 
366f169c0eaSGlenn Lagasse 	/*
367f169c0eaSGlenn Lagasse 	 * Mount shared file systems if mount flag says so.
368f169c0eaSGlenn Lagasse 	 */
369f169c0eaSGlenn Lagasse 	if (md.shared_fs) {
370f169c0eaSGlenn Lagasse 		/*
371f169c0eaSGlenn Lagasse 		 * Mount all ZFS file systems not under the BE's root dataset
372f169c0eaSGlenn Lagasse 		 */
373f169c0eaSGlenn Lagasse 		(void) zpool_iter(g_zfs, zpool_shared_fs_callback, &md);
374f169c0eaSGlenn Lagasse 
375f169c0eaSGlenn Lagasse 		/* TODO: Mount all non-ZFS file systems - Not supported yet */
376f169c0eaSGlenn Lagasse 	}
377f169c0eaSGlenn Lagasse 
378f169c0eaSGlenn Lagasse 	/*
379f169c0eaSGlenn Lagasse 	 * If we're in the global zone and the global zone has a valid uuid,
380f169c0eaSGlenn Lagasse 	 * mount all supported non-global zones.
381f169c0eaSGlenn Lagasse 	 */
382f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID &&
383f169c0eaSGlenn Lagasse 	    !(flags & BE_MOUNT_FLAG_NO_ZONES) &&
384f169c0eaSGlenn Lagasse 	    be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
38540ccc6adSAlexander Eremin 		if (be_mount_zones(zhp, &md) != BE_SUCCESS) {
38640ccc6adSAlexander Eremin 			ret = BE_ERR_NO_MOUNTED_ZONE;
387f169c0eaSGlenn Lagasse 		}
388f169c0eaSGlenn Lagasse 	}
389f169c0eaSGlenn Lagasse 
390f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
391f169c0eaSGlenn Lagasse 
392f169c0eaSGlenn Lagasse 	/*
393f169c0eaSGlenn Lagasse 	 * If a NULL altroot was passed in, pass the generated altroot
394f169c0eaSGlenn Lagasse 	 * back to the caller in altroot.
395f169c0eaSGlenn Lagasse 	 */
39640ccc6adSAlexander Eremin 	if (gen_tmp_altroot) {
39740ccc6adSAlexander Eremin 		if (ret == BE_SUCCESS || ret == BE_ERR_NO_MOUNTED_ZONE)
39840ccc6adSAlexander Eremin 			*altroot = tmp_altroot;
39940ccc6adSAlexander Eremin 		else
40040ccc6adSAlexander Eremin 			free(tmp_altroot);
40140ccc6adSAlexander Eremin 	}
402f169c0eaSGlenn Lagasse 
40340ccc6adSAlexander Eremin 	return (ret);
404f169c0eaSGlenn Lagasse }
405f169c0eaSGlenn Lagasse 
406f169c0eaSGlenn Lagasse /*
407f169c0eaSGlenn Lagasse  * Function:	_be_unmount
408f169c0eaSGlenn Lagasse  * Description:	Unmount a BE.
409f169c0eaSGlenn Lagasse  * Parameters:
410f169c0eaSGlenn Lagasse  *		be_name - pointer to name of BE to unmount.
411f169c0eaSGlenn Lagasse  *		flags - flags for unmounting the BE.
412f169c0eaSGlenn Lagasse  * Returns:
413f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
414f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
415f169c0eaSGlenn Lagasse  * Scope:
416f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
417f169c0eaSGlenn Lagasse  */
418f169c0eaSGlenn Lagasse int
419f169c0eaSGlenn Lagasse _be_unmount(char *be_name, int flags)
420f169c0eaSGlenn Lagasse {
421f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
422f169c0eaSGlenn Lagasse 	be_unmount_data_t	ud = { 0 };
423f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp;
424f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
425f169c0eaSGlenn Lagasse 	char		obe_root_ds[MAXPATHLEN];
426f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
427f169c0eaSGlenn Lagasse 	char		*mp = NULL;
428f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
429f169c0eaSGlenn Lagasse 	int		zret = 0;
430f169c0eaSGlenn Lagasse 
431f169c0eaSGlenn Lagasse 	if (be_name == NULL)
432f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
433f169c0eaSGlenn Lagasse 
434f169c0eaSGlenn Lagasse 	/* Set be_name as obe_name in bt structure */
435f169c0eaSGlenn Lagasse 	bt.obe_name = be_name;
436f169c0eaSGlenn Lagasse 
437f169c0eaSGlenn Lagasse 	/* Find which zpool obe_name lives in */
438f169c0eaSGlenn Lagasse 	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
439f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to "
440f169c0eaSGlenn Lagasse 		    "find zpool for BE (%s)\n"), bt.obe_name);
441f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_NOENT);
442f169c0eaSGlenn Lagasse 	} else if (zret < 0) {
443f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: "
444f169c0eaSGlenn Lagasse 		    "zpool_iter failed: %s\n"),
445f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
446f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
447f169c0eaSGlenn Lagasse 		return (ret);
448f169c0eaSGlenn Lagasse 	}
449f169c0eaSGlenn Lagasse 
450f169c0eaSGlenn Lagasse 	/* Generate string for obe_name's root dataset */
451f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
452f169c0eaSGlenn Lagasse 	    sizeof (obe_root_ds));
453f169c0eaSGlenn Lagasse 	bt.obe_root_ds = obe_root_ds;
454f169c0eaSGlenn Lagasse 
455f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
456f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
457f169c0eaSGlenn Lagasse 	    NULL) {
458f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to "
459f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
460f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
461f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
462f169c0eaSGlenn Lagasse 		return (ret);
463f169c0eaSGlenn Lagasse 	}
464f169c0eaSGlenn Lagasse 
465f169c0eaSGlenn Lagasse 	/* Make sure BE's root dataset is mounted somewhere */
466f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &mp)) {
467f169c0eaSGlenn Lagasse 
468f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: "
469f169c0eaSGlenn Lagasse 		    "(%s) not mounted\n"), bt.obe_name);
470f169c0eaSGlenn Lagasse 
471f169c0eaSGlenn Lagasse 		/*
472f169c0eaSGlenn Lagasse 		 * BE is not mounted, fix this BE's mountpoint if its root
473f169c0eaSGlenn Lagasse 		 * dataset isn't set to either 'legacy' or '/'.
474f169c0eaSGlenn Lagasse 		 */
475f169c0eaSGlenn Lagasse 		if ((ret = fix_mountpoint(zhp)) != BE_SUCCESS) {
476f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_unmount: mountpoint check "
477f169c0eaSGlenn Lagasse 			    "failed for %s\n"), bt.obe_root_ds);
478f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
479f169c0eaSGlenn Lagasse 			return (ret);
480f169c0eaSGlenn Lagasse 		}
481f169c0eaSGlenn Lagasse 
482f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
48389d19e00SAlexander Eremin 		return (BE_ERR_NOTMOUNTED);
484f169c0eaSGlenn Lagasse 	}
485f169c0eaSGlenn Lagasse 
486f169c0eaSGlenn Lagasse 	/*
487f169c0eaSGlenn Lagasse 	 * If we didn't get a mountpoint from the zfs_is_mounted call,
488f169c0eaSGlenn Lagasse 	 * try and get it from its property.
489f169c0eaSGlenn Lagasse 	 */
490f169c0eaSGlenn Lagasse 	if (mp == NULL) {
491f169c0eaSGlenn Lagasse 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
492f169c0eaSGlenn Lagasse 		    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
493f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_unmount: failed to "
494f169c0eaSGlenn Lagasse 			    "get mountpoint of (%s)\n"), bt.obe_name);
495f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
496f169c0eaSGlenn Lagasse 			return (BE_ERR_ZFS);
497f169c0eaSGlenn Lagasse 		}
498f169c0eaSGlenn Lagasse 	} else {
499f169c0eaSGlenn Lagasse 		(void) strlcpy(mountpoint, mp, sizeof (mountpoint));
500f169c0eaSGlenn Lagasse 		free(mp);
501f169c0eaSGlenn Lagasse 	}
502f169c0eaSGlenn Lagasse 
503f169c0eaSGlenn Lagasse 	/* If BE mounted as current root, fail */
504f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, "/") == 0) {
505f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: "
506f169c0eaSGlenn Lagasse 		    "cannot unmount currently running BE\n"));
507f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
508f169c0eaSGlenn Lagasse 		return (BE_ERR_UMOUNT_CURR_BE);
509f169c0eaSGlenn Lagasse 	}
510f169c0eaSGlenn Lagasse 
511f169c0eaSGlenn Lagasse 	ud.altroot = mountpoint;
512f169c0eaSGlenn Lagasse 	ud.force = flags & BE_UNMOUNT_FLAG_FORCE;
513f169c0eaSGlenn Lagasse 
514f169c0eaSGlenn Lagasse 	/* Unmount all supported non-global zones if we're in the global zone */
515f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID &&
516f169c0eaSGlenn Lagasse 	    be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
517f169c0eaSGlenn Lagasse 		if ((ret = be_unmount_zones(&ud)) != BE_SUCCESS) {
518f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
519f169c0eaSGlenn Lagasse 			return (ret);
520f169c0eaSGlenn Lagasse 		}
521f169c0eaSGlenn Lagasse 	}
522f169c0eaSGlenn Lagasse 
523f169c0eaSGlenn Lagasse 	/* TODO: Unmount all non-ZFS file systems - Not supported yet */
524f169c0eaSGlenn Lagasse 
525f169c0eaSGlenn Lagasse 	/* Unmount all ZFS file systems not under the BE root dataset */
526f169c0eaSGlenn Lagasse 	if ((ret = unmount_shared_fs(&ud)) != BE_SUCCESS) {
527f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to "
528f169c0eaSGlenn Lagasse 		    "unmount shared file systems\n"));
529f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
530f169c0eaSGlenn Lagasse 		return (ret);
531f169c0eaSGlenn Lagasse 	}
532f169c0eaSGlenn Lagasse 
533f169c0eaSGlenn Lagasse 	/* Unmount all children datasets under the BE's root dataset */
534f169c0eaSGlenn Lagasse 	if ((zret = zfs_iter_filesystems(zhp, be_unmount_callback,
535f169c0eaSGlenn Lagasse 	    &ud)) != 0) {
536f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to "
537f169c0eaSGlenn Lagasse 		    "unmount BE (%s)\n"), bt.obe_name);
538f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
539f169c0eaSGlenn Lagasse 		return (zret);
540f169c0eaSGlenn Lagasse 	}
541f169c0eaSGlenn Lagasse 
542f169c0eaSGlenn Lagasse 	/* Unmount this BE's root filesystem */
5437e0e2549SAlexander Eremin 	if (getzoneid() == GLOBAL_ZONEID) {
5447e0e2549SAlexander Eremin 		if ((ret = be_unmount_root(zhp, &ud)) != BE_SUCCESS) {
5457e0e2549SAlexander Eremin 			ZFS_CLOSE(zhp);
5467e0e2549SAlexander Eremin 			return (ret);
5477e0e2549SAlexander Eremin 		}
5487e0e2549SAlexander Eremin 	} else {
5497e0e2549SAlexander Eremin 		if ((ret = be_unmount_zone_root(zhp, &ud)) != BE_SUCCESS) {
5507e0e2549SAlexander Eremin 			ZFS_CLOSE(zhp);
5517e0e2549SAlexander Eremin 			return (ret);
5527e0e2549SAlexander Eremin 		}
553f169c0eaSGlenn Lagasse 	}
554f169c0eaSGlenn Lagasse 
555f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
556f169c0eaSGlenn Lagasse 
557f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
558f169c0eaSGlenn Lagasse }
559f169c0eaSGlenn Lagasse 
560f169c0eaSGlenn Lagasse /*
561f169c0eaSGlenn Lagasse  * Function:	be_mount_zone_root
562f169c0eaSGlenn Lagasse  * Description:	Mounts the zone root dataset for a zone.
563f169c0eaSGlenn Lagasse  * Parameters:
564f169c0eaSGlenn Lagasse  *		zfs - zfs_handle_t pointer to zone root dataset
565f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer to data for zone to be mounted
566f169c0eaSGlenn Lagasse  * Returns:
567f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
568f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
569f169c0eaSGlenn Lagasse  * Scope:
570f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
571f169c0eaSGlenn Lagasse  */
572f169c0eaSGlenn Lagasse int
573f169c0eaSGlenn Lagasse be_mount_zone_root(zfs_handle_t *zhp, be_mount_data_t *md)
574f169c0eaSGlenn Lagasse {
5757e0e2549SAlexander Eremin 	struct stat buf;
576f169c0eaSGlenn Lagasse 	char	mountpoint[MAXPATHLEN];
577f169c0eaSGlenn Lagasse 	int	err = 0;
578f169c0eaSGlenn Lagasse 
579f169c0eaSGlenn Lagasse 	/* Get mountpoint property of dataset */
580f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
581f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
582f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_zone_root: failed to "
583f169c0eaSGlenn Lagasse 		    "get mountpoint property for %s: %s\n"), zfs_get_name(zhp),
584f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
585f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
586f169c0eaSGlenn Lagasse 	}
587f169c0eaSGlenn Lagasse 
588f169c0eaSGlenn Lagasse 	/*
589f169c0eaSGlenn Lagasse 	 * Make sure zone's root dataset is set to 'legacy'.  This is
590f169c0eaSGlenn Lagasse 	 * currently a requirement in this implementation of zones
591f169c0eaSGlenn Lagasse 	 * support.
592f169c0eaSGlenn Lagasse 	 */
593f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
594f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_zone_root: "
595f169c0eaSGlenn Lagasse 		    "zone root dataset mountpoint is not 'legacy'\n"));
596f169c0eaSGlenn Lagasse 		return (BE_ERR_ZONE_ROOT_NOT_LEGACY);
597f169c0eaSGlenn Lagasse 	}
598f169c0eaSGlenn Lagasse 
5997e0e2549SAlexander Eremin 	/* Create the mountpoint if it doesn't exist */
6007e0e2549SAlexander Eremin 	if (lstat(md->altroot, &buf) != 0) {
6017e0e2549SAlexander Eremin 		if (mkdirp(md->altroot, 0755) != 0) {
6027e0e2549SAlexander Eremin 			err = errno;
6037e0e2549SAlexander Eremin 			be_print_err(gettext("be_mount_zone_root: failed "
6047e0e2549SAlexander Eremin 			    "to create mountpoint %s\n"), md->altroot);
6057e0e2549SAlexander Eremin 			return (errno_to_be_err(err));
6067e0e2549SAlexander Eremin 		}
6077e0e2549SAlexander Eremin 	}
6087e0e2549SAlexander Eremin 
609f169c0eaSGlenn Lagasse 	/*
610f169c0eaSGlenn Lagasse 	 * Legacy mount the zone root dataset.
611f169c0eaSGlenn Lagasse 	 *
612f169c0eaSGlenn Lagasse 	 * As a workaround for 6176743, we mount the zone's root with the
613f169c0eaSGlenn Lagasse 	 * MS_OVERLAY option in case an alternate BE is mounted, and we're
614f169c0eaSGlenn Lagasse 	 * mounting the root for the zone from the current BE here.  When an
615f169c0eaSGlenn Lagasse 	 * alternate BE is mounted, it ties up the zone's zoneroot directory
616f169c0eaSGlenn Lagasse 	 * for the current BE since the zone's zonepath is loopback mounted
617f169c0eaSGlenn Lagasse 	 * from the current BE.
618f169c0eaSGlenn Lagasse 	 *
619f169c0eaSGlenn Lagasse 	 * TODO: The MS_OVERLAY option needs to be removed when 6176743
620f169c0eaSGlenn Lagasse 	 * is fixed.
621f169c0eaSGlenn Lagasse 	 */
622f169c0eaSGlenn Lagasse 	if (mount(zfs_get_name(zhp), md->altroot, MS_OVERLAY, MNTTYPE_ZFS,
623f169c0eaSGlenn Lagasse 	    NULL, 0, NULL, 0) != 0) {
624f169c0eaSGlenn Lagasse 		err = errno;
625f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_zone_root: failed to "
626f169c0eaSGlenn Lagasse 		    "legacy mount zone root dataset (%s) at %s\n"),
627f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), md->altroot);
628f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
629f169c0eaSGlenn Lagasse 	}
630f169c0eaSGlenn Lagasse 
631f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
632f169c0eaSGlenn Lagasse }
633f169c0eaSGlenn Lagasse 
634f169c0eaSGlenn Lagasse /*
635f169c0eaSGlenn Lagasse  * Function:	be_unmount_zone_root
636f169c0eaSGlenn Lagasse  * Description:	Unmounts the zone root dataset for a zone.
637f169c0eaSGlenn Lagasse  * Parameters:
638f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to zone root dataset
639f169c0eaSGlenn Lagasse  *		ud - be_unmount_data_t pointer to data for zone to be unmounted
640f169c0eaSGlenn Lagasse  * Returns:
641f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
642f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
643f169c0eaSGlenn Lagasse  * Scope:
644f169c0eaSGlenn Lagasse  *		Semi-private (library wise use only)
645f169c0eaSGlenn Lagasse  */
646f169c0eaSGlenn Lagasse int
647f169c0eaSGlenn Lagasse be_unmount_zone_root(zfs_handle_t *zhp, be_unmount_data_t *ud)
648f169c0eaSGlenn Lagasse {
649f169c0eaSGlenn Lagasse 	char	mountpoint[MAXPATHLEN];
650f169c0eaSGlenn Lagasse 
651f169c0eaSGlenn Lagasse 	/* Unmount the dataset */
652f169c0eaSGlenn Lagasse 	if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) {
653f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_zone_root: failed to "
654f169c0eaSGlenn Lagasse 		    "unmount zone root dataset %s: %s\n"), zfs_get_name(zhp),
655f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
656f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
657f169c0eaSGlenn Lagasse 	}
658f169c0eaSGlenn Lagasse 
659f169c0eaSGlenn Lagasse 	/* Get the current mountpoint property for the zone root dataset */
660f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
661f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
662f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_zone_root: failed to "
663f169c0eaSGlenn Lagasse 		    "get mountpoint property for zone root dataset (%s): %s\n"),
664f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
665f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
666f169c0eaSGlenn Lagasse 	}
667f169c0eaSGlenn Lagasse 
668f169c0eaSGlenn Lagasse 	/* If mountpoint not already set to 'legacy', set it to 'legacy' */
669f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
670f169c0eaSGlenn Lagasse 		if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
671f169c0eaSGlenn Lagasse 		    ZFS_MOUNTPOINT_LEGACY) != 0) {
672f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_unmount_zone_root: "
673f169c0eaSGlenn Lagasse 			    "failed to set mountpoint of zone root dataset "
674f169c0eaSGlenn Lagasse 			    "%s to 'legacy': %s\n"), zfs_get_name(zhp),
675f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
676f169c0eaSGlenn Lagasse 			return (zfs_err_to_be_err(g_zfs));
677f169c0eaSGlenn Lagasse 		}
678f169c0eaSGlenn Lagasse 	}
679f169c0eaSGlenn Lagasse 
680f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
681f169c0eaSGlenn Lagasse }
682f169c0eaSGlenn Lagasse 
683f169c0eaSGlenn Lagasse /*
684f169c0eaSGlenn Lagasse  * Function:	be_get_legacy_fs
685f169c0eaSGlenn Lagasse  * Description:	This function iterates through all non-shared file systems
686f169c0eaSGlenn Lagasse  *		of a BE and finds the ones with a legacy mountpoint.  For
687f169c0eaSGlenn Lagasse  *		those file systems, it reads the BE's vfstab to get the
688f169c0eaSGlenn Lagasse  *		mountpoint.  If found, it adds that file system to the
689f169c0eaSGlenn Lagasse  *		be_fs_list_data_t passed in.
690f169c0eaSGlenn Lagasse  *
691f169c0eaSGlenn Lagasse  *		This function can be used to gather legacy mounted file systems
692f169c0eaSGlenn Lagasse  *		for both global BEs and non-global zone BEs.  To get data for
693f169c0eaSGlenn Lagasse  *		a non-global zone BE, the zoneroot_ds and zoneroot parameters
694f169c0eaSGlenn Lagasse  *		will be specified, otherwise they should be set to NULL.
695f169c0eaSGlenn Lagasse  * Parameters:
696f169c0eaSGlenn Lagasse  *		be_name - global BE name from which to get legacy file
697f169c0eaSGlenn Lagasse  *			system list.
698f169c0eaSGlenn Lagasse  *		be_root_ds - root dataset of global BE.
699f169c0eaSGlenn Lagasse  *		zoneroot_ds - root dataset of zone.
700f169c0eaSGlenn Lagasse  *		zoneroot - zoneroot path of zone.
701f169c0eaSGlenn Lagasse  *		fld - be_fs_list_data_t pointer.
702f169c0eaSGlenn Lagasse  * Returns:
703f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
704f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
705f169c0eaSGlenn Lagasse  * Scope:
706f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
707f169c0eaSGlenn Lagasse  */
708f169c0eaSGlenn Lagasse int
709f169c0eaSGlenn Lagasse be_get_legacy_fs(char *be_name, char *be_root_ds, char *zoneroot_ds,
710f169c0eaSGlenn Lagasse     char *zoneroot, be_fs_list_data_t *fld)
711f169c0eaSGlenn Lagasse {
712f169c0eaSGlenn Lagasse 	zfs_handle_t		*zhp = NULL;
713f169c0eaSGlenn Lagasse 	char			mountpoint[MAXPATHLEN];
714f169c0eaSGlenn Lagasse 	boolean_t		mounted_here = B_FALSE;
715f169c0eaSGlenn Lagasse 	boolean_t		zone_mounted_here = B_FALSE;
716f169c0eaSGlenn Lagasse 	int			ret = BE_SUCCESS, err = 0;
717f169c0eaSGlenn Lagasse 
718f169c0eaSGlenn Lagasse 	if (be_name == NULL || be_root_ds == NULL || fld == NULL)
719f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
720f169c0eaSGlenn Lagasse 
721f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
722f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM))
723f169c0eaSGlenn Lagasse 	    == NULL) {
724f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_legacy_fs: failed to "
725f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), be_root_ds,
726f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
727f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
728f169c0eaSGlenn Lagasse 		return (ret);
729f169c0eaSGlenn Lagasse 	}
730f169c0eaSGlenn Lagasse 
731f169c0eaSGlenn Lagasse 	/* If BE is not already mounted, mount it. */
732f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &fld->altroot)) {
733f169c0eaSGlenn Lagasse 		if ((ret = _be_mount(be_name, &fld->altroot,
734f169c0eaSGlenn Lagasse 		    zoneroot_ds ? BE_MOUNT_FLAG_NULL :
735f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
736f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs: "
737f169c0eaSGlenn Lagasse 			    "failed to mount BE %s\n"), be_name);
738f169c0eaSGlenn Lagasse 			goto cleanup;
739f169c0eaSGlenn Lagasse 		}
740f169c0eaSGlenn Lagasse 
741f169c0eaSGlenn Lagasse 		mounted_here = B_TRUE;
742f169c0eaSGlenn Lagasse 	} else if (fld->altroot == NULL) {
743f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_legacy_fs: failed to "
744f169c0eaSGlenn Lagasse 		    "get altroot of mounted BE %s: %s\n"),
745f169c0eaSGlenn Lagasse 		    be_name, libzfs_error_description(g_zfs));
746f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
747f169c0eaSGlenn Lagasse 		goto cleanup;
748f169c0eaSGlenn Lagasse 	}
749f169c0eaSGlenn Lagasse 
750f169c0eaSGlenn Lagasse 	/*
751f169c0eaSGlenn Lagasse 	 * If a zone root dataset was passed in, we're wanting to get
752f169c0eaSGlenn Lagasse 	 * legacy mounted file systems for that zone, not the global
753f169c0eaSGlenn Lagasse 	 * BE.
754f169c0eaSGlenn Lagasse 	 */
755f169c0eaSGlenn Lagasse 	if (zoneroot_ds != NULL) {
756f169c0eaSGlenn Lagasse 		be_mount_data_t		zone_md = { 0 };
757f169c0eaSGlenn Lagasse 
758f169c0eaSGlenn Lagasse 		/* Close off handle to global BE's root dataset */
759f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
760f169c0eaSGlenn Lagasse 
761f169c0eaSGlenn Lagasse 		/* Get handle to zone's root dataset */
762f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, zoneroot_ds,
763f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
764f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs: failed to "
765f169c0eaSGlenn Lagasse 			    "open zone BE root dataset (%s): %s\n"),
766f169c0eaSGlenn Lagasse 			    zoneroot_ds, libzfs_error_description(g_zfs));
767f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
768f169c0eaSGlenn Lagasse 			goto cleanup;
769f169c0eaSGlenn Lagasse 		}
770f169c0eaSGlenn Lagasse 
771f169c0eaSGlenn Lagasse 		/* Make sure the zone we're looking for is mounted */
772f169c0eaSGlenn Lagasse 		if (!zfs_is_mounted(zhp, &zone_md.altroot)) {
773f169c0eaSGlenn Lagasse 			char	zone_altroot[MAXPATHLEN];
774f169c0eaSGlenn Lagasse 
775f169c0eaSGlenn Lagasse 			/* Generate alternate root path for zone */
776f169c0eaSGlenn Lagasse 			(void) snprintf(zone_altroot, sizeof (zone_altroot),
777f169c0eaSGlenn Lagasse 			    "%s%s", fld->altroot, zoneroot);
778f169c0eaSGlenn Lagasse 			if ((zone_md.altroot = strdup(zone_altroot)) == NULL) {
779f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_get_legacy_fs: "
780f169c0eaSGlenn Lagasse 				    "memory allocation failed\n"));
781f169c0eaSGlenn Lagasse 				ret = BE_ERR_NOMEM;
782f169c0eaSGlenn Lagasse 				goto cleanup;
783f169c0eaSGlenn Lagasse 			}
784f169c0eaSGlenn Lagasse 
785f169c0eaSGlenn Lagasse 			if ((ret = be_mount_zone_root(zhp, &zone_md))
786f169c0eaSGlenn Lagasse 			    != BE_SUCCESS) {
787f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_get_legacy_fs: "
788f169c0eaSGlenn Lagasse 				    "failed to mount zone root %s\n"),
789f169c0eaSGlenn Lagasse 				    zoneroot_ds);
790f169c0eaSGlenn Lagasse 				free(zone_md.altroot);
791f169c0eaSGlenn Lagasse 				zone_md.altroot = NULL;
792f169c0eaSGlenn Lagasse 				goto cleanup;
793f169c0eaSGlenn Lagasse 			}
794f169c0eaSGlenn Lagasse 			zone_mounted_here = B_TRUE;
795f169c0eaSGlenn Lagasse 		}
796f169c0eaSGlenn Lagasse 
797f169c0eaSGlenn Lagasse 		free(fld->altroot);
798f169c0eaSGlenn Lagasse 		fld->altroot = zone_md.altroot;
799f169c0eaSGlenn Lagasse 	}
800f169c0eaSGlenn Lagasse 
801f169c0eaSGlenn Lagasse 	/*
802f169c0eaSGlenn Lagasse 	 * If the root dataset is in the vfstab with a mountpoint of "/",
803f169c0eaSGlenn Lagasse 	 * add it to the list
804f169c0eaSGlenn Lagasse 	 */
805f169c0eaSGlenn Lagasse 	if (get_mountpoint_from_vfstab(fld->altroot, zfs_get_name(zhp),
806f169c0eaSGlenn Lagasse 	    mountpoint, sizeof (mountpoint), B_FALSE) == BE_SUCCESS) {
807f169c0eaSGlenn Lagasse 		if (strcmp(mountpoint, "/") == 0) {
808f169c0eaSGlenn Lagasse 			if (add_to_fs_list(fld, zfs_get_name(zhp))
809f169c0eaSGlenn Lagasse 			    != BE_SUCCESS) {
810f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_get_legacy_fs: "
811f169c0eaSGlenn Lagasse 				    "failed to add %s to fs list\n"),
812f169c0eaSGlenn Lagasse 				    zfs_get_name(zhp));
813f169c0eaSGlenn Lagasse 				ret = BE_ERR_INVAL;
814f169c0eaSGlenn Lagasse 				goto cleanup;
815f169c0eaSGlenn Lagasse 			}
816f169c0eaSGlenn Lagasse 		}
817f169c0eaSGlenn Lagasse 	}
818f169c0eaSGlenn Lagasse 
819f169c0eaSGlenn Lagasse 	/* Iterate subordinate file systems looking for legacy mounts */
820f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_get_legacy_fs_callback,
821f169c0eaSGlenn Lagasse 	    fld)) != 0) {
822f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_legacy_fs: "
823f169c0eaSGlenn Lagasse 		    "failed to iterate  %s to get legacy mounts\n"),
824f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp));
825f169c0eaSGlenn Lagasse 	}
826f169c0eaSGlenn Lagasse 
827f169c0eaSGlenn Lagasse cleanup:
828f169c0eaSGlenn Lagasse 	/* If we mounted the zone BE, unmount it */
829f169c0eaSGlenn Lagasse 	if (zone_mounted_here) {
830f169c0eaSGlenn Lagasse 		be_unmount_data_t	zone_ud = { 0 };
831f169c0eaSGlenn Lagasse 
832f169c0eaSGlenn Lagasse 		zone_ud.altroot = fld->altroot;
833f169c0eaSGlenn Lagasse 		zone_ud.force = B_TRUE;
834f169c0eaSGlenn Lagasse 		if ((err = be_unmount_zone_root(zhp, &zone_ud)) != BE_SUCCESS) {
835f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs: "
836f169c0eaSGlenn Lagasse 			    "failed to unmount zone root %s\n"),
837f169c0eaSGlenn Lagasse 			    zoneroot_ds);
838f169c0eaSGlenn Lagasse 			if (ret == BE_SUCCESS)
839f169c0eaSGlenn Lagasse 				ret = err;
840f169c0eaSGlenn Lagasse 		}
841f169c0eaSGlenn Lagasse 	}
842f169c0eaSGlenn Lagasse 
843f169c0eaSGlenn Lagasse 	/* If we mounted this BE, unmount it */
844f169c0eaSGlenn Lagasse 	if (mounted_here) {
845f169c0eaSGlenn Lagasse 		if ((err = _be_unmount(be_name, 0)) != BE_SUCCESS) {
846f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs: "
847f169c0eaSGlenn Lagasse 			    "failed to unmount %s\n"), be_name);
848f169c0eaSGlenn Lagasse 			if (ret == BE_SUCCESS)
849f169c0eaSGlenn Lagasse 				ret = err;
850f169c0eaSGlenn Lagasse 		}
851f169c0eaSGlenn Lagasse 	}
852f169c0eaSGlenn Lagasse 
853f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
854f169c0eaSGlenn Lagasse 
855f169c0eaSGlenn Lagasse 	free(fld->altroot);
856f169c0eaSGlenn Lagasse 	fld->altroot = NULL;
857f169c0eaSGlenn Lagasse 
858f169c0eaSGlenn Lagasse 	return (ret);
859f169c0eaSGlenn Lagasse }
860f169c0eaSGlenn Lagasse 
861f169c0eaSGlenn Lagasse /*
862f169c0eaSGlenn Lagasse  * Function:	be_free_fs_list
863f169c0eaSGlenn Lagasse  * Description:	Function used to free the members of a be_fs_list_data_t
864f169c0eaSGlenn Lagasse  *			structure.
865f169c0eaSGlenn Lagasse  * Parameters:
866f169c0eaSGlenn Lagasse  *		fld - be_fs_list_data_t pointer to free.
867f169c0eaSGlenn Lagasse  * Returns:
868f169c0eaSGlenn Lagasse  *		None
869f169c0eaSGlenn Lagasse  * Scope:
870f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
871f169c0eaSGlenn Lagasse  */
872f169c0eaSGlenn Lagasse void
873f169c0eaSGlenn Lagasse be_free_fs_list(be_fs_list_data_t *fld)
874f169c0eaSGlenn Lagasse {
875f169c0eaSGlenn Lagasse 	int	i;
876f169c0eaSGlenn Lagasse 
877f169c0eaSGlenn Lagasse 	if (fld == NULL)
878f169c0eaSGlenn Lagasse 		return;
879f169c0eaSGlenn Lagasse 
880f169c0eaSGlenn Lagasse 	free(fld->altroot);
881f169c0eaSGlenn Lagasse 
882f169c0eaSGlenn Lagasse 	if (fld->fs_list == NULL)
883f169c0eaSGlenn Lagasse 		return;
884f169c0eaSGlenn Lagasse 
885f169c0eaSGlenn Lagasse 	for (i = 0; i < fld->fs_num; i++)
886f169c0eaSGlenn Lagasse 		free(fld->fs_list[i]);
887f169c0eaSGlenn Lagasse 
888f169c0eaSGlenn Lagasse 	free(fld->fs_list);
889f169c0eaSGlenn Lagasse }
890f169c0eaSGlenn Lagasse 
891f169c0eaSGlenn Lagasse /*
892f169c0eaSGlenn Lagasse  * Function:	be_get_ds_from_dir(char *dir)
893f169c0eaSGlenn Lagasse  * Description:	Given a directory path, find the underlying dataset mounted
894f169c0eaSGlenn Lagasse  *		at that directory path if there is one.   The returned name
895f169c0eaSGlenn Lagasse  *		is allocated in heap storage, so the caller is responsible
896f169c0eaSGlenn Lagasse  *		for freeing it.
897f169c0eaSGlenn Lagasse  * Parameters:
898f169c0eaSGlenn Lagasse  *		dir - char pointer of directory to find.
899f169c0eaSGlenn Lagasse  * Returns:
900f169c0eaSGlenn Lagasse  *		NULL - if directory is not mounted from a dataset.
901f169c0eaSGlenn Lagasse  *		name of dataset mounted at dir.
902f169c0eaSGlenn Lagasse  * Scope:
903f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
904f169c0eaSGlenn Lagasse  */
905f169c0eaSGlenn Lagasse char *
906f169c0eaSGlenn Lagasse be_get_ds_from_dir(char *dir)
907f169c0eaSGlenn Lagasse {
908f169c0eaSGlenn Lagasse 	dir_data_t	dd = { 0 };
909f169c0eaSGlenn Lagasse 	char		resolved_dir[MAXPATHLEN];
910f169c0eaSGlenn Lagasse 
911f169c0eaSGlenn Lagasse 	/* Make sure length of dir is within the max length */
912f169c0eaSGlenn Lagasse 	if (dir == NULL || strlen(dir) >= MAXPATHLEN)
913f169c0eaSGlenn Lagasse 		return (NULL);
914f169c0eaSGlenn Lagasse 
915f169c0eaSGlenn Lagasse 	/* Resolve dir in case its lofs mounted */
916f169c0eaSGlenn Lagasse 	(void) strlcpy(resolved_dir, dir, sizeof (resolved_dir));
917f169c0eaSGlenn Lagasse 	z_resolve_lofs(resolved_dir, sizeof (resolved_dir));
918f169c0eaSGlenn Lagasse 
919f169c0eaSGlenn Lagasse 	dd.dir = resolved_dir;
920f169c0eaSGlenn Lagasse 
921f169c0eaSGlenn Lagasse 	(void) zfs_iter_root(g_zfs, be_get_ds_from_dir_callback, &dd);
922f169c0eaSGlenn Lagasse 
923f169c0eaSGlenn Lagasse 	return (dd.ds);
924f169c0eaSGlenn Lagasse }
925f169c0eaSGlenn Lagasse 
926f169c0eaSGlenn Lagasse /*
927f169c0eaSGlenn Lagasse  * Function:	be_make_tmp_mountpoint
928f169c0eaSGlenn Lagasse  * Description:	This function generates a random temporary mountpoint
929f169c0eaSGlenn Lagasse  *		and creates that mountpoint directory.  It returns the
930f169c0eaSGlenn Lagasse  *		mountpoint in heap storage, so the caller is responsible
931f169c0eaSGlenn Lagasse  *		for freeing it.
932f169c0eaSGlenn Lagasse  * Parameters:
933f169c0eaSGlenn Lagasse  *		tmp_mp - reference to pointer of where to store generated
934f169c0eaSGlenn Lagasse  *			temporary mountpoint.
935f169c0eaSGlenn Lagasse  * Returns:
936f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
937f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
938f169c0eaSGlenn Lagasse  * Scope:
939f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
940f169c0eaSGlenn Lagasse  */
941f169c0eaSGlenn Lagasse int
942f169c0eaSGlenn Lagasse be_make_tmp_mountpoint(char **tmp_mp)
943f169c0eaSGlenn Lagasse {
944f169c0eaSGlenn Lagasse 	int	err = 0;
945f169c0eaSGlenn Lagasse 
946f169c0eaSGlenn Lagasse 	if ((*tmp_mp = (char *)calloc(1, sizeof (BE_TMP_MNTPNT) + 1)) == NULL) {
947f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_make_tmp_mountpoint: "
948f169c0eaSGlenn Lagasse 		    "malloc failed\n"));
949f169c0eaSGlenn Lagasse 		return (BE_ERR_NOMEM);
950f169c0eaSGlenn Lagasse 	}
951f169c0eaSGlenn Lagasse 	(void) strlcpy(*tmp_mp, BE_TMP_MNTPNT, sizeof (BE_TMP_MNTPNT) + 1);
952f169c0eaSGlenn Lagasse 	if (mkdtemp(*tmp_mp) == NULL) {
953f169c0eaSGlenn Lagasse 		err = errno;
954f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_make_tmp_mountpoint: mkdtemp() failed "
955f169c0eaSGlenn Lagasse 		    "for %s: %s\n"), *tmp_mp, strerror(err));
956f169c0eaSGlenn Lagasse 		free(*tmp_mp);
957f169c0eaSGlenn Lagasse 		*tmp_mp = NULL;
958f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
959f169c0eaSGlenn Lagasse 	}
960f169c0eaSGlenn Lagasse 
961f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
962f169c0eaSGlenn Lagasse }
963f169c0eaSGlenn Lagasse 
964f169c0eaSGlenn Lagasse /*
965f169c0eaSGlenn Lagasse  * Function:	be_mount_pool
966f169c0eaSGlenn Lagasse  * Description: This function determines if the pool's datase is mounted
967f169c0eaSGlenn Lagasse  *		and if not it is used to mount the pool's dataset. The
968f169c0eaSGlenn Lagasse  *		function returns the current mountpoint if we are able
969f169c0eaSGlenn Lagasse  *		to mount the dataset.
970f169c0eaSGlenn Lagasse  * Parameters:
971f169c0eaSGlenn Lagasse  *		zhp - handle to the pool's dataset
972f169c0eaSGlenn Lagasse  *		tmp_mntpnt - The temporary mountpoint that the pool's
973f169c0eaSGlenn Lagasse  *			      dataset is mounted on. This is set only
974f169c0eaSGlenn Lagasse  *			      if the attempt to mount the dataset at it's
975f169c0eaSGlenn Lagasse  *			      set mountpoint fails, and we've used a
976f169c0eaSGlenn Lagasse  *			      temporary mount point for this dataset. It
977f169c0eaSGlenn Lagasse  *			      is expected that the caller will free this
978f169c0eaSGlenn Lagasse  *			      memory.
979f169c0eaSGlenn Lagasse  *		orig_mntpnt - The original mountpoint for the pool. If a
980f169c0eaSGlenn Lagasse  *			      temporary mount point was needed this will
981f169c0eaSGlenn Lagasse  *			      be used to reset the mountpoint property to
982f169c0eaSGlenn Lagasse  *			      it's original mountpoint. It is expected that
983f169c0eaSGlenn Lagasse  *			      the caller will free this memory.
984f169c0eaSGlenn Lagasse  *		pool_mounted - This flag indicates that the pool was mounted
985f169c0eaSGlenn Lagasse  *			       in this function.
986f169c0eaSGlenn Lagasse  * Returns:
987f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
988f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
989f169c0eaSGlenn Lagasse  * Scope:
990f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
991f169c0eaSGlenn Lagasse  */
992f169c0eaSGlenn Lagasse int
993f169c0eaSGlenn Lagasse be_mount_pool(
994f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp,
995f169c0eaSGlenn Lagasse 	char **tmp_mntpnt,
996f169c0eaSGlenn Lagasse 	char **orig_mntpnt,
997f169c0eaSGlenn Lagasse 	boolean_t *pool_mounted)
998f169c0eaSGlenn Lagasse {
999f169c0eaSGlenn Lagasse 
1000f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
1001f169c0eaSGlenn Lagasse 	int		ret = 0;
1002f169c0eaSGlenn Lagasse 
1003f169c0eaSGlenn Lagasse 	*tmp_mntpnt = NULL;
1004f169c0eaSGlenn Lagasse 	*orig_mntpnt = NULL;
1005f169c0eaSGlenn Lagasse 	*pool_mounted = B_FALSE;
1006f169c0eaSGlenn Lagasse 
1007f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, NULL)) {
1008f169c0eaSGlenn Lagasse 		if (zfs_mount(zhp, NULL, 0) != 0) {
1009f169c0eaSGlenn Lagasse 			if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
1010f169c0eaSGlenn Lagasse 			    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
1011f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: failed to "
1012f169c0eaSGlenn Lagasse 				    "get mountpoint of (%s): %s\n"),
1013f169c0eaSGlenn Lagasse 				    zfs_get_name(zhp),
1014f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
1015f169c0eaSGlenn Lagasse 				return (zfs_err_to_be_err(g_zfs));
1016f169c0eaSGlenn Lagasse 			}
1017f169c0eaSGlenn Lagasse 			if ((*orig_mntpnt = strdup(mountpoint)) == NULL) {
1018f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: memory "
1019f169c0eaSGlenn Lagasse 				    "allocation failed\n"));
1020f169c0eaSGlenn Lagasse 				return (BE_ERR_NOMEM);
1021f169c0eaSGlenn Lagasse 			}
1022f169c0eaSGlenn Lagasse 			/*
1023f169c0eaSGlenn Lagasse 			 * attempt to mount on a temp mountpoint
1024f169c0eaSGlenn Lagasse 			 */
1025f169c0eaSGlenn Lagasse 			if ((ret = be_make_tmp_mountpoint(tmp_mntpnt))
1026f169c0eaSGlenn Lagasse 			    != BE_SUCCESS) {
1027f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: failed "
1028f169c0eaSGlenn Lagasse 				    "to make temporary mountpoint\n"));
1029f169c0eaSGlenn Lagasse 				free(*orig_mntpnt);
1030f169c0eaSGlenn Lagasse 				*orig_mntpnt = NULL;
1031f169c0eaSGlenn Lagasse 				return (ret);
1032f169c0eaSGlenn Lagasse 			}
1033f169c0eaSGlenn Lagasse 
1034f169c0eaSGlenn Lagasse 			if (zfs_prop_set(zhp,
1035f169c0eaSGlenn Lagasse 			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1036f169c0eaSGlenn Lagasse 			    *tmp_mntpnt) != 0) {
1037f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: failed "
1038f169c0eaSGlenn Lagasse 				    "to set mountpoint of pool dataset %s to "
1039f169c0eaSGlenn Lagasse 				    "%s: %s\n"), zfs_get_name(zhp),
1040f169c0eaSGlenn Lagasse 				    *orig_mntpnt,
1041f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
1042f169c0eaSGlenn Lagasse 				free(*tmp_mntpnt);
1043f169c0eaSGlenn Lagasse 				free(*orig_mntpnt);
1044f169c0eaSGlenn Lagasse 				*orig_mntpnt = NULL;
1045f169c0eaSGlenn Lagasse 				*tmp_mntpnt = NULL;
1046f169c0eaSGlenn Lagasse 				return (zfs_err_to_be_err(g_zfs));
1047f169c0eaSGlenn Lagasse 			}
1048f169c0eaSGlenn Lagasse 
1049f169c0eaSGlenn Lagasse 			if (zfs_mount(zhp, NULL, 0) != 0) {
1050f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: failed "
1051f169c0eaSGlenn Lagasse 				    "to mount dataset %s at %s: %s\n"),
1052f169c0eaSGlenn Lagasse 				    zfs_get_name(zhp), *tmp_mntpnt,
1053f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
1054f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
1055f169c0eaSGlenn Lagasse 				if (zfs_prop_set(zhp,
1056f169c0eaSGlenn Lagasse 				    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1057f169c0eaSGlenn Lagasse 				    mountpoint) != 0) {
1058f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_mount_pool: "
1059f169c0eaSGlenn Lagasse 					    "failed to set mountpoint of pool "
1060f169c0eaSGlenn Lagasse 					    "dataset %s to %s: %s\n"),
1061f169c0eaSGlenn Lagasse 					    zfs_get_name(zhp), *tmp_mntpnt,
1062f169c0eaSGlenn Lagasse 					    libzfs_error_description(g_zfs));
1063f169c0eaSGlenn Lagasse 				}
1064f169c0eaSGlenn Lagasse 				free(*tmp_mntpnt);
1065f169c0eaSGlenn Lagasse 				free(*orig_mntpnt);
1066f169c0eaSGlenn Lagasse 				*orig_mntpnt = NULL;
1067f169c0eaSGlenn Lagasse 				*tmp_mntpnt = NULL;
1068f169c0eaSGlenn Lagasse 				return (ret);
1069f169c0eaSGlenn Lagasse 			}
1070f169c0eaSGlenn Lagasse 		}
1071f169c0eaSGlenn Lagasse 		*pool_mounted = B_TRUE;
1072f169c0eaSGlenn Lagasse 	}
1073f169c0eaSGlenn Lagasse 
1074f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1075f169c0eaSGlenn Lagasse }
1076f169c0eaSGlenn Lagasse 
1077f169c0eaSGlenn Lagasse /*
1078f169c0eaSGlenn Lagasse  * Function:	be_unmount_pool
1079f169c0eaSGlenn Lagasse  * Description: This function is used to unmount the pool's dataset if we
1080f169c0eaSGlenn Lagasse  *		mounted it previously using be_mount_pool().
1081f169c0eaSGlenn Lagasse  * Parameters:
1082f169c0eaSGlenn Lagasse  *		zhp - handle to the pool's dataset
1083f169c0eaSGlenn Lagasse  *		tmp_mntpnt - If a temprary mount point was used this will
1084f169c0eaSGlenn Lagasse  *			     be set. Since this was created in be_mount_pool
1085f169c0eaSGlenn Lagasse  *			     we will need to clean it up here.
1086f169c0eaSGlenn Lagasse  *		orig_mntpnt - The original mountpoint for the pool. This is
1087f169c0eaSGlenn Lagasse  *			      used to set the dataset mountpoint property
1088f169c0eaSGlenn Lagasse  *			      back to it's original value in the case where a
1089f169c0eaSGlenn Lagasse  *			      temporary mountpoint was used.
1090f169c0eaSGlenn Lagasse  * Returns:
1091f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1092f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1093f169c0eaSGlenn Lagasse  * Scope:
1094f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1095f169c0eaSGlenn Lagasse  */
1096f169c0eaSGlenn Lagasse int
1097f169c0eaSGlenn Lagasse be_unmount_pool(
1098f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp,
1099f169c0eaSGlenn Lagasse 	char *tmp_mntpnt,
1100f169c0eaSGlenn Lagasse 	char *orig_mntpnt)
1101f169c0eaSGlenn Lagasse {
1102f169c0eaSGlenn Lagasse 	if (zfs_unmount(zhp, NULL, 0) != 0) {
1103f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_pool: failed to "
1104f169c0eaSGlenn Lagasse 		    "unmount pool (%s): %s\n"), zfs_get_name(zhp),
1105f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1106f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1107f169c0eaSGlenn Lagasse 	}
1108f169c0eaSGlenn Lagasse 	if (orig_mntpnt != NULL) {
1109f169c0eaSGlenn Lagasse 		if (tmp_mntpnt != NULL &&
1110f169c0eaSGlenn Lagasse 		    strcmp(orig_mntpnt, tmp_mntpnt) != 0) {
1111f169c0eaSGlenn Lagasse 			(void) rmdir(tmp_mntpnt);
1112f169c0eaSGlenn Lagasse 		}
1113f169c0eaSGlenn Lagasse 		if (zfs_prop_set(zhp,
1114f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1115f169c0eaSGlenn Lagasse 		    orig_mntpnt) != 0) {
1116f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_unmount_pool: failed "
1117f169c0eaSGlenn Lagasse 			    "to set the mountpoint for dataset (%s) to "
1118f169c0eaSGlenn Lagasse 			    "%s: %s\n"), zfs_get_name(zhp), orig_mntpnt,
1119f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1120f169c0eaSGlenn Lagasse 			return (zfs_err_to_be_err(g_zfs));
1121f169c0eaSGlenn Lagasse 		}
1122f169c0eaSGlenn Lagasse 	}
1123f169c0eaSGlenn Lagasse 
1124f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1125f169c0eaSGlenn Lagasse }
1126f169c0eaSGlenn Lagasse 
1127f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1128f169c0eaSGlenn Lagasse /*			Private Functions				*/
1129f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1130f169c0eaSGlenn Lagasse 
1131f169c0eaSGlenn Lagasse /*
1132f169c0eaSGlenn Lagasse  * Function:	be_mount_callback
1133f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through all of a BE's
1134f169c0eaSGlenn Lagasse  *		subordinate file systems and to mount them accordingly.
1135f169c0eaSGlenn Lagasse  * Parameters:
1136f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current file system being
1137f169c0eaSGlenn Lagasse  *			processed.
1138f169c0eaSGlenn Lagasse  *		data - pointer to the altroot of where to mount BE.
1139f169c0eaSGlenn Lagasse  * Returns:
1140f169c0eaSGlenn Lagasse  *		0 - Success
1141f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1142f169c0eaSGlenn Lagasse  * Scope:
1143f169c0eaSGlenn Lagasse  *		Private
1144f169c0eaSGlenn Lagasse  */
1145f169c0eaSGlenn Lagasse static int
1146f169c0eaSGlenn Lagasse be_mount_callback(zfs_handle_t *zhp, void *data)
1147f169c0eaSGlenn Lagasse {
1148f169c0eaSGlenn Lagasse 	zprop_source_t	sourcetype;
1149f169c0eaSGlenn Lagasse 	const char	*fs_name = zfs_get_name(zhp);
11509adfa60dSMatthew Ahrens 	char		source[ZFS_MAX_DATASET_NAME_LEN];
1151f169c0eaSGlenn Lagasse 	char		*altroot = data;
1152f169c0eaSGlenn Lagasse 	char		zhp_mountpoint[MAXPATHLEN];
1153f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
1154f169c0eaSGlenn Lagasse 	int		ret = 0;
1155f169c0eaSGlenn Lagasse 
1156f169c0eaSGlenn Lagasse 	/* Get dataset's mountpoint and source values */
1157f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, zhp_mountpoint,
1158f169c0eaSGlenn Lagasse 	    sizeof (zhp_mountpoint), &sourcetype, source, sizeof (source),
1159f169c0eaSGlenn Lagasse 	    B_FALSE) != 0) {
1160f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_callback: failed to "
1161f169c0eaSGlenn Lagasse 		    "get mountpoint and sourcetype for %s\n"),
1162f169c0eaSGlenn Lagasse 		    fs_name);
1163f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1164f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
1165f169c0eaSGlenn Lagasse 	}
1166f169c0eaSGlenn Lagasse 
1167f169c0eaSGlenn Lagasse 	/*
1168f169c0eaSGlenn Lagasse 	 * Set this filesystem's 'canmount' property to 'noauto' just incase
11693a876192SAlexander Pyhalov 	 * it's been set 'on'.
1170f169c0eaSGlenn Lagasse 	 */
1171f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")) {
1172f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_callback: failed to "
1173f169c0eaSGlenn Lagasse 		    "set canmount to 'noauto' (%s)\n"), fs_name);
1174f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1175f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
1176f169c0eaSGlenn Lagasse 	}
1177f169c0eaSGlenn Lagasse 
1178f169c0eaSGlenn Lagasse 	/*
1179f169c0eaSGlenn Lagasse 	 * If the mountpoint is none, there's nothing to do, goto next.
1180f169c0eaSGlenn Lagasse 	 * If the mountpoint is legacy, legacy mount it with mount(2).
1181f169c0eaSGlenn Lagasse 	 * If the mountpoint is inherited, its mountpoint should
1182f169c0eaSGlenn Lagasse 	 * already be set.  If it's not, then explicitly fix-up
1183f169c0eaSGlenn Lagasse 	 * the mountpoint now by appending its explicitly set
1184f169c0eaSGlenn Lagasse 	 * mountpoint value to the BE mountpoint.
1185f169c0eaSGlenn Lagasse 	 */
1186f169c0eaSGlenn Lagasse 	if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_NONE) == 0) {
1187f169c0eaSGlenn Lagasse 		goto next;
1188f169c0eaSGlenn Lagasse 	} else if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1189f169c0eaSGlenn Lagasse 		/*
1190f169c0eaSGlenn Lagasse 		 * If the mountpoint is set to 'legacy', we need to
1191f169c0eaSGlenn Lagasse 		 * dig into this BE's vfstab to figure out where to
1192f169c0eaSGlenn Lagasse 		 * mount it, and just mount it via mount(2).
1193f169c0eaSGlenn Lagasse 		 */
1194f169c0eaSGlenn Lagasse 		if (get_mountpoint_from_vfstab(altroot, fs_name,
1195f169c0eaSGlenn Lagasse 		    mountpoint, sizeof (mountpoint), B_TRUE) == BE_SUCCESS) {
1196f169c0eaSGlenn Lagasse 
1197f169c0eaSGlenn Lagasse 			/* Legacy mount the file system */
1198f169c0eaSGlenn Lagasse 			if (mount(fs_name, mountpoint, MS_DATA,
1199f169c0eaSGlenn Lagasse 			    MNTTYPE_ZFS, NULL, 0, NULL, 0) != 0) {
1200f169c0eaSGlenn Lagasse 				be_print_err(
1201f169c0eaSGlenn Lagasse 				    gettext("be_mount_callback: "
1202f169c0eaSGlenn Lagasse 				    "failed to mount %s on %s\n"),
1203f169c0eaSGlenn Lagasse 				    fs_name, mountpoint);
1204f169c0eaSGlenn Lagasse 			}
1205f169c0eaSGlenn Lagasse 		} else {
1206f169c0eaSGlenn Lagasse 			be_print_err(
1207f169c0eaSGlenn Lagasse 			    gettext("be_mount_callback: "
1208f169c0eaSGlenn Lagasse 			    "no entry for %s in vfstab, "
1209f169c0eaSGlenn Lagasse 			    "skipping ...\n"), fs_name);
1210f169c0eaSGlenn Lagasse 		}
1211f169c0eaSGlenn Lagasse 
1212f169c0eaSGlenn Lagasse 		goto next;
1213f169c0eaSGlenn Lagasse 
12143a876192SAlexander Pyhalov 	} else if ((sourcetype & (ZPROP_SRC_INHERITED|ZPROP_SRC_LOCAL)) == 0) {
1215f169c0eaSGlenn Lagasse 		/*
12163a876192SAlexander Pyhalov 		 * Skip dataset if mountpoint is not inherited
12173a876192SAlexander Pyhalov 		 * or explicitly set.
1218f169c0eaSGlenn Lagasse 		 */
1219f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_callback: "
1220f169c0eaSGlenn Lagasse 		    "mountpoint sourcetype of %s is %d, skipping ...\n"),
1221f169c0eaSGlenn Lagasse 		    fs_name, sourcetype);
1222f169c0eaSGlenn Lagasse 
1223f169c0eaSGlenn Lagasse 		goto next;
1224f169c0eaSGlenn Lagasse 	}
1225f169c0eaSGlenn Lagasse 
1226f169c0eaSGlenn Lagasse 	/* Mount this filesystem */
12273a876192SAlexander Pyhalov 	if (mount_zfs(zhp, altroot) != 0) {
1228f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_callback: failed to "
1229f169c0eaSGlenn Lagasse 		    "mount dataset %s at %s: %s\n"), fs_name, mountpoint,
12303a876192SAlexander Pyhalov 		    strerror(errno));
1231f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1232f169c0eaSGlenn Lagasse 		return (BE_ERR_MOUNT);
1233f169c0eaSGlenn Lagasse 	}
1234f169c0eaSGlenn Lagasse 
1235f169c0eaSGlenn Lagasse next:
1236f169c0eaSGlenn Lagasse 	/* Iterate through this dataset's children and mount them */
1237f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_mount_callback,
1238f169c0eaSGlenn Lagasse 	    altroot)) != 0) {
1239f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1240f169c0eaSGlenn Lagasse 		return (ret);
1241f169c0eaSGlenn Lagasse 	}
1242f169c0eaSGlenn Lagasse 
1243f169c0eaSGlenn Lagasse 
1244f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1245f169c0eaSGlenn Lagasse 	return (0);
1246f169c0eaSGlenn Lagasse }
1247f169c0eaSGlenn Lagasse 
1248f169c0eaSGlenn Lagasse /*
1249f169c0eaSGlenn Lagasse  * Function:	be_unmount_callback
1250f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through all of a BE's
1251f169c0eaSGlenn Lagasse  *		subordinate file systems and to unmount them.
1252f169c0eaSGlenn Lagasse  * Parameters:
1253f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current file system being
1254f169c0eaSGlenn Lagasse  *			processed.
1255f169c0eaSGlenn Lagasse  *		data - pointer to the mountpoint of where BE is mounted.
1256f169c0eaSGlenn Lagasse  * Returns:
1257f169c0eaSGlenn Lagasse  *		0 - Success
1258f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1259f169c0eaSGlenn Lagasse  * Scope:
1260f169c0eaSGlenn Lagasse  *		Private
1261f169c0eaSGlenn Lagasse  */
1262f169c0eaSGlenn Lagasse static int
1263f169c0eaSGlenn Lagasse be_unmount_callback(zfs_handle_t *zhp, void *data)
1264f169c0eaSGlenn Lagasse {
1265f169c0eaSGlenn Lagasse 	be_unmount_data_t	*ud = data;
1266f169c0eaSGlenn Lagasse 	zprop_source_t	sourcetype;
1267f169c0eaSGlenn Lagasse 	const char	*fs_name = zfs_get_name(zhp);
12689adfa60dSMatthew Ahrens 	char		source[ZFS_MAX_DATASET_NAME_LEN];
1269f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
1270f169c0eaSGlenn Lagasse 	char		*zhp_mountpoint;
1271f169c0eaSGlenn Lagasse 	int		ret = 0;
1272f169c0eaSGlenn Lagasse 
1273f169c0eaSGlenn Lagasse 	/* Iterate down this dataset's children first */
1274f169c0eaSGlenn Lagasse 	if (zfs_iter_filesystems(zhp, be_unmount_callback, ud)) {
1275f169c0eaSGlenn Lagasse 		ret = BE_ERR_UMOUNT;
1276f169c0eaSGlenn Lagasse 		goto done;
1277f169c0eaSGlenn Lagasse 	}
1278f169c0eaSGlenn Lagasse 
1279f169c0eaSGlenn Lagasse 	/* Is dataset even mounted ? */
1280f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, NULL))
1281f169c0eaSGlenn Lagasse 		goto done;
1282f169c0eaSGlenn Lagasse 
1283f169c0eaSGlenn Lagasse 	/* Unmount this file system */
1284f169c0eaSGlenn Lagasse 	if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) {
1285f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_callback: "
1286f169c0eaSGlenn Lagasse 		    "failed to unmount %s: %s\n"), fs_name,
1287f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1288f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1289f169c0eaSGlenn Lagasse 		goto done;
1290f169c0eaSGlenn Lagasse 	}
1291f169c0eaSGlenn Lagasse 
1292f169c0eaSGlenn Lagasse 	/* Get dataset's current mountpoint and source value */
1293f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
1294f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), &sourcetype, source, sizeof (source),
1295f169c0eaSGlenn Lagasse 	    B_FALSE) != 0) {
1296f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_callback: "
1297f169c0eaSGlenn Lagasse 		    "failed to get mountpoint and sourcetype for %s: %s\n"),
1298f169c0eaSGlenn Lagasse 		    fs_name, libzfs_error_description(g_zfs));
1299f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1300f169c0eaSGlenn Lagasse 		goto done;
1301f169c0eaSGlenn Lagasse 	}
1302f169c0eaSGlenn Lagasse 
1303f169c0eaSGlenn Lagasse 	if (sourcetype & ZPROP_SRC_INHERITED) {
1304f169c0eaSGlenn Lagasse 		/*
1305f169c0eaSGlenn Lagasse 		 * If the mountpoint is inherited we don't need to
1306f169c0eaSGlenn Lagasse 		 * do anything.  When its parent gets processed
1307f169c0eaSGlenn Lagasse 		 * its mountpoint will be set accordingly.
1308f169c0eaSGlenn Lagasse 		 */
1309f169c0eaSGlenn Lagasse 		goto done;
1310f169c0eaSGlenn Lagasse 	} else if (sourcetype & ZPROP_SRC_LOCAL) {
1311f169c0eaSGlenn Lagasse 
1312f169c0eaSGlenn Lagasse 		if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1313f169c0eaSGlenn Lagasse 			/*
1314f169c0eaSGlenn Lagasse 			 * If the mountpoint is set to 'legacy', its already
1315f169c0eaSGlenn Lagasse 			 * been unmounted (from above call to zfs_unmount), and
1316f169c0eaSGlenn Lagasse 			 * we don't need to do anything else with it.
1317f169c0eaSGlenn Lagasse 			 */
1318f169c0eaSGlenn Lagasse 			goto done;
1319f169c0eaSGlenn Lagasse 
1320f169c0eaSGlenn Lagasse 		} else {
1321f169c0eaSGlenn Lagasse 			/*
1322f169c0eaSGlenn Lagasse 			 * Else process dataset with explicitly set mountpoint.
1323f169c0eaSGlenn Lagasse 			 */
1324f169c0eaSGlenn Lagasse 
1325f169c0eaSGlenn Lagasse 			/*
1326f169c0eaSGlenn Lagasse 			 * Get this dataset's mountpoint relative to
1327f169c0eaSGlenn Lagasse 			 * the BE's mountpoint.
1328f169c0eaSGlenn Lagasse 			 */
1329f169c0eaSGlenn Lagasse 			if ((strncmp(mountpoint, ud->altroot,
1330f169c0eaSGlenn Lagasse 			    strlen(ud->altroot)) == 0) &&
1331f169c0eaSGlenn Lagasse 			    (mountpoint[strlen(ud->altroot)] == '/')) {
1332f169c0eaSGlenn Lagasse 
1333f169c0eaSGlenn Lagasse 				zhp_mountpoint = mountpoint +
1334f169c0eaSGlenn Lagasse 				    strlen(ud->altroot);
1335f169c0eaSGlenn Lagasse 
1336f169c0eaSGlenn Lagasse 				/* Set this dataset's mountpoint value */
1337f169c0eaSGlenn Lagasse 				if (zfs_prop_set(zhp,
1338f169c0eaSGlenn Lagasse 				    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1339f169c0eaSGlenn Lagasse 				    zhp_mountpoint)) {
1340f169c0eaSGlenn Lagasse 					be_print_err(
1341f169c0eaSGlenn Lagasse 					    gettext("be_unmount_callback: "
1342f169c0eaSGlenn Lagasse 					    "failed to set mountpoint for "
1343f169c0eaSGlenn Lagasse 					    "%s to %s: %s\n"), fs_name,
1344f169c0eaSGlenn Lagasse 					    zhp_mountpoint,
1345f169c0eaSGlenn Lagasse 					    libzfs_error_description(g_zfs));
1346f169c0eaSGlenn Lagasse 					ret = zfs_err_to_be_err(g_zfs);
1347f169c0eaSGlenn Lagasse 				}
1348f169c0eaSGlenn Lagasse 			} else {
1349f169c0eaSGlenn Lagasse 				/*
13503a876192SAlexander Pyhalov 				 * Nothing to do, mountpoint shouldn't be
13513a876192SAlexander Pyhalov 				 * corrected.
1352f169c0eaSGlenn Lagasse 				 */
13533a876192SAlexander Pyhalov 				goto done;
1354f169c0eaSGlenn Lagasse 			}
1355f169c0eaSGlenn Lagasse 		}
1356f169c0eaSGlenn Lagasse 	} else {
1357f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_callback: "
1358f169c0eaSGlenn Lagasse 		    "mountpoint sourcetype of %s is %d, skipping ...\n"),
1359f169c0eaSGlenn Lagasse 		    fs_name, sourcetype);
1360f169c0eaSGlenn Lagasse 		ret = BE_ERR_ZFS;
1361f169c0eaSGlenn Lagasse 	}
1362f169c0eaSGlenn Lagasse 
1363f169c0eaSGlenn Lagasse done:
1364f169c0eaSGlenn Lagasse 	/* Set this filesystem's 'canmount' property to 'noauto' */
1365f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")) {
1366f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_callback: "
1367f169c0eaSGlenn Lagasse 		    "failed to set canmount to 'noauto' (%s)\n"), fs_name);
1368f169c0eaSGlenn Lagasse 		if (ret == 0)
1369f169c0eaSGlenn Lagasse 			ret = BE_ERR_ZFS;
1370f169c0eaSGlenn Lagasse 	}
1371f169c0eaSGlenn Lagasse 
1372f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1373f169c0eaSGlenn Lagasse 	return (ret);
1374f169c0eaSGlenn Lagasse }
1375f169c0eaSGlenn Lagasse 
1376f169c0eaSGlenn Lagasse /*
1377f169c0eaSGlenn Lagasse  * Function:	be_get_legacy_fs_callback
1378f169c0eaSGlenn Lagasse  * Description:	The callback function is used to iterate through all
1379f169c0eaSGlenn Lagasse  *		non-shared file systems of a BE, finding ones that have
1380f169c0eaSGlenn Lagasse  *		a legacy mountpoint and an entry in the BE's vfstab.
1381f169c0eaSGlenn Lagasse  *		It adds these file systems to the callback data.
1382f169c0eaSGlenn Lagasse  * Parameters:
1383f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current file system being
1384f169c0eaSGlenn Lagasse  *			processed.
1385f169c0eaSGlenn Lagasse  *		data - be_fs_list_data_t pointer
1386f169c0eaSGlenn Lagasse  * Returns:
1387f169c0eaSGlenn Lagasse  *		0 - Success
1388f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1389f169c0eaSGlenn Lagasse  * Scope:
1390f169c0eaSGlenn Lagasse  *		Private
1391f169c0eaSGlenn Lagasse  */
1392f169c0eaSGlenn Lagasse static int
1393f169c0eaSGlenn Lagasse be_get_legacy_fs_callback(zfs_handle_t *zhp, void *data)
1394f169c0eaSGlenn Lagasse {
1395f169c0eaSGlenn Lagasse 	be_fs_list_data_t	*fld = data;
1396f169c0eaSGlenn Lagasse 	const char		*fs_name = zfs_get_name(zhp);
1397f169c0eaSGlenn Lagasse 	char			zhp_mountpoint[MAXPATHLEN];
1398f169c0eaSGlenn Lagasse 	char			mountpoint[MAXPATHLEN];
1399f169c0eaSGlenn Lagasse 	int			ret = 0;
1400f169c0eaSGlenn Lagasse 
1401f169c0eaSGlenn Lagasse 	/* Get this dataset's mountpoint property */
1402f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, zhp_mountpoint,
1403f169c0eaSGlenn Lagasse 	    sizeof (zhp_mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
1404f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_legacy_fs_callback: "
1405f169c0eaSGlenn Lagasse 		    "failed to get mountpoint for %s: %s\n"),
1406f169c0eaSGlenn Lagasse 		    fs_name, libzfs_error_description(g_zfs));
1407f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1408f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1409f169c0eaSGlenn Lagasse 		return (ret);
1410f169c0eaSGlenn Lagasse 	}
1411f169c0eaSGlenn Lagasse 
1412f169c0eaSGlenn Lagasse 	/*
1413f169c0eaSGlenn Lagasse 	 * If mountpoint is legacy, try to get its mountpoint from this BE's
1414f169c0eaSGlenn Lagasse 	 * vfstab.  If it exists in the vfstab, add this file system to the
1415f169c0eaSGlenn Lagasse 	 * callback data.
1416f169c0eaSGlenn Lagasse 	 */
1417f169c0eaSGlenn Lagasse 	if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1418f169c0eaSGlenn Lagasse 		if (get_mountpoint_from_vfstab(fld->altroot, fs_name,
1419f169c0eaSGlenn Lagasse 		    mountpoint, sizeof (mountpoint), B_FALSE) != BE_SUCCESS) {
1420f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs_callback: "
1421f169c0eaSGlenn Lagasse 			    "no entry for %s in vfstab, "
1422f169c0eaSGlenn Lagasse 			    "skipping ...\n"), fs_name);
1423f169c0eaSGlenn Lagasse 
1424f169c0eaSGlenn Lagasse 			goto next;
1425f169c0eaSGlenn Lagasse 		}
1426f169c0eaSGlenn Lagasse 
1427f169c0eaSGlenn Lagasse 		/* Record file system into the callback data. */
1428f169c0eaSGlenn Lagasse 		if (add_to_fs_list(fld, zfs_get_name(zhp)) != BE_SUCCESS) {
1429f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs_callback: "
1430f169c0eaSGlenn Lagasse 			    "failed to add %s to fs list\n"), mountpoint);
1431f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1432f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
1433f169c0eaSGlenn Lagasse 		}
1434f169c0eaSGlenn Lagasse 	}
1435f169c0eaSGlenn Lagasse 
1436f169c0eaSGlenn Lagasse next:
1437f169c0eaSGlenn Lagasse 	/* Iterate through this dataset's children file systems */
1438f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_get_legacy_fs_callback,
1439f169c0eaSGlenn Lagasse 	    fld)) != 0) {
1440f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1441f169c0eaSGlenn Lagasse 		return (ret);
1442f169c0eaSGlenn Lagasse 	}
1443f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1444f169c0eaSGlenn Lagasse 	return (0);
1445f169c0eaSGlenn Lagasse }
1446f169c0eaSGlenn Lagasse 
1447f169c0eaSGlenn Lagasse /*
1448f169c0eaSGlenn Lagasse  * Function:	add_to_fs_list
1449f169c0eaSGlenn Lagasse  * Description:	Function used to add a file system to the fs_list array in
1450f169c0eaSGlenn Lagasse  *			a be_fs_list_data_t structure.
1451f169c0eaSGlenn Lagasse  * Parameters:
1452f169c0eaSGlenn Lagasse  *		fld - be_fs_list_data_t pointer
1453f169c0eaSGlenn Lagasse  *		fs - file system to add
1454f169c0eaSGlenn Lagasse  * Returns:
1455f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1456f169c0eaSGlenn Lagasse  *		1 - Failure
1457f169c0eaSGlenn Lagasse  * Scope:
1458f169c0eaSGlenn Lagasse  *		Private
1459f169c0eaSGlenn Lagasse  */
1460f169c0eaSGlenn Lagasse static int
1461f169c0eaSGlenn Lagasse add_to_fs_list(be_fs_list_data_t *fld, const char *fs)
1462f169c0eaSGlenn Lagasse {
1463f169c0eaSGlenn Lagasse 	if (fld == NULL || fs == NULL)
1464f169c0eaSGlenn Lagasse 		return (1);
1465f169c0eaSGlenn Lagasse 
1466f169c0eaSGlenn Lagasse 	if ((fld->fs_list = (char **)realloc(fld->fs_list,
1467f169c0eaSGlenn Lagasse 	    sizeof (char *)*(fld->fs_num + 1))) == NULL) {
1468f169c0eaSGlenn Lagasse 		be_print_err(gettext("add_to_fs_list: "
1469f169c0eaSGlenn Lagasse 		    "memory allocation failed\n"));
1470f169c0eaSGlenn Lagasse 		return (1);
1471f169c0eaSGlenn Lagasse 	}
1472f169c0eaSGlenn Lagasse 
1473f169c0eaSGlenn Lagasse 	if ((fld->fs_list[fld->fs_num++] = strdup(fs)) == NULL) {
1474f169c0eaSGlenn Lagasse 		be_print_err(gettext("add_to_fs_list: "
1475f169c0eaSGlenn Lagasse 		    "memory allocation failed\n"));
1476f169c0eaSGlenn Lagasse 		return (1);
1477f169c0eaSGlenn Lagasse 	}
1478f169c0eaSGlenn Lagasse 
1479f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1480f169c0eaSGlenn Lagasse }
1481f169c0eaSGlenn Lagasse 
1482f169c0eaSGlenn Lagasse /*
1483f169c0eaSGlenn Lagasse  * Function:	zpool_shared_fs_callback
1484f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through all existing pools
1485f169c0eaSGlenn Lagasse  *		to find and mount all shared filesystems.  This function
1486f169c0eaSGlenn Lagasse  *		processes the pool's "pool data" dataset, then uses
1487f169c0eaSGlenn Lagasse  *		iter_shared_fs_callback to iterate through the pool's
1488f169c0eaSGlenn Lagasse  *		datasets.
1489f169c0eaSGlenn Lagasse  * Parameters:
1490f169c0eaSGlenn Lagasse  *		zlp - zpool_handle_t pointer to the current pool being
1491f169c0eaSGlenn Lagasse  *			looked at.
1492f169c0eaSGlenn Lagasse  *		data - be_mount_data_t pointer
1493f169c0eaSGlenn Lagasse  * Returns:
1494f169c0eaSGlenn Lagasse  *		0 - Success
1495f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1496f169c0eaSGlenn Lagasse  * Scope:
1497f169c0eaSGlenn Lagasse  *		Private
1498f169c0eaSGlenn Lagasse  */
1499f169c0eaSGlenn Lagasse static int
1500f169c0eaSGlenn Lagasse zpool_shared_fs_callback(zpool_handle_t *zlp, void *data)
1501f169c0eaSGlenn Lagasse {
1502f169c0eaSGlenn Lagasse 	be_mount_data_t	*md = data;
1503f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1504f169c0eaSGlenn Lagasse 	const char	*zpool = zpool_get_name(zlp);
1505f169c0eaSGlenn Lagasse 	int		ret = 0;
1506f169c0eaSGlenn Lagasse 
1507f169c0eaSGlenn Lagasse 	/*
1508f169c0eaSGlenn Lagasse 	 * Get handle to pool's "pool data" dataset
1509f169c0eaSGlenn Lagasse 	 */
1510f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, zpool, ZFS_TYPE_FILESYSTEM)) == NULL) {
1511f169c0eaSGlenn Lagasse 		be_print_err(gettext("zpool_shared_fs: "
1512f169c0eaSGlenn Lagasse 		    "failed to open pool dataset %s: %s\n"), zpool,
1513f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1514f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1515f169c0eaSGlenn Lagasse 		zpool_close(zlp);
1516f169c0eaSGlenn Lagasse 		return (ret);
1517f169c0eaSGlenn Lagasse 	}
1518f169c0eaSGlenn Lagasse 
1519f169c0eaSGlenn Lagasse 	/* Process this pool's "pool data" dataset */
1520f169c0eaSGlenn Lagasse 	(void) loopback_mount_shared_fs(zhp, md);
1521f169c0eaSGlenn Lagasse 
1522f169c0eaSGlenn Lagasse 	/* Interate through this pool's children */
1523f169c0eaSGlenn Lagasse 	(void) zfs_iter_filesystems(zhp, iter_shared_fs_callback, md);
1524f169c0eaSGlenn Lagasse 
1525f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1526f169c0eaSGlenn Lagasse 	zpool_close(zlp);
1527f169c0eaSGlenn Lagasse 
1528f169c0eaSGlenn Lagasse 	return (0);
1529f169c0eaSGlenn Lagasse }
1530f169c0eaSGlenn Lagasse 
1531f169c0eaSGlenn Lagasse /*
1532f169c0eaSGlenn Lagasse  * Function:	iter_shared_fs_callback
1533f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through a pool's datasets
1534f169c0eaSGlenn Lagasse  *		to find and mount all shared filesystems.  It makes sure to
1535f169c0eaSGlenn Lagasse  *		find the BE container dataset of the pool, if it exists, and
1536f169c0eaSGlenn Lagasse  *		does not process and iterate down that path.
1537f169c0eaSGlenn Lagasse  *
1538f169c0eaSGlenn Lagasse  *		Note - This function iterates linearly down the
1539f169c0eaSGlenn Lagasse  *		hierarchical dataset paths and mounts things as it goes
1540f169c0eaSGlenn Lagasse  *		along.  It does not make sure that something deeper down
1541f169c0eaSGlenn Lagasse  *		a dataset path has an interim mountpoint for something
1542f169c0eaSGlenn Lagasse  *		processed earlier.
1543f169c0eaSGlenn Lagasse  *
1544f169c0eaSGlenn Lagasse  * Parameters:
1545f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to the current dataset being
1546f169c0eaSGlenn Lagasse  *			processed.
1547f169c0eaSGlenn Lagasse  *		data - be_mount_data_t pointer
1548f169c0eaSGlenn Lagasse  * Returns:
1549f169c0eaSGlenn Lagasse  *		0 - Success
1550f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1551f169c0eaSGlenn Lagasse  * Scope:
1552f169c0eaSGlenn Lagasse  *		Private
1553f169c0eaSGlenn Lagasse  */
1554f169c0eaSGlenn Lagasse static int
1555f169c0eaSGlenn Lagasse iter_shared_fs_callback(zfs_handle_t *zhp, void *data)
1556f169c0eaSGlenn Lagasse {
1557f169c0eaSGlenn Lagasse 	be_mount_data_t	*md = data;
1558f169c0eaSGlenn Lagasse 	const char	*name = zfs_get_name(zhp);
1559f169c0eaSGlenn Lagasse 	char		container_ds[MAXPATHLEN];
1560f169c0eaSGlenn Lagasse 	char		tmp_name[MAXPATHLEN];
1561f169c0eaSGlenn Lagasse 	char		*pool;
1562f169c0eaSGlenn Lagasse 
1563f169c0eaSGlenn Lagasse 	/* Get the pool's name */
1564f169c0eaSGlenn Lagasse 	(void) strlcpy(tmp_name, name, sizeof (tmp_name));
1565f169c0eaSGlenn Lagasse 	pool = strtok(tmp_name, "/");
1566f169c0eaSGlenn Lagasse 
1567f169c0eaSGlenn Lagasse 	if (pool) {
1568f169c0eaSGlenn Lagasse 		/* Get the name of this pool's container dataset */
1569f169c0eaSGlenn Lagasse 		be_make_container_ds(pool, container_ds,
1570f169c0eaSGlenn Lagasse 		    sizeof (container_ds));
1571f169c0eaSGlenn Lagasse 
1572f169c0eaSGlenn Lagasse 		/*
1573f169c0eaSGlenn Lagasse 		 * If what we're processing is this pool's BE container
1574f169c0eaSGlenn Lagasse 		 * dataset, skip it.
1575f169c0eaSGlenn Lagasse 		 */
1576f169c0eaSGlenn Lagasse 		if (strcmp(name, container_ds) == 0) {
1577f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1578f169c0eaSGlenn Lagasse 			return (0);
1579f169c0eaSGlenn Lagasse 		}
1580f169c0eaSGlenn Lagasse 	} else {
1581f169c0eaSGlenn Lagasse 		/* Getting the pool name failed, return error */
1582f169c0eaSGlenn Lagasse 		be_print_err(gettext("iter_shared_fs_callback: "
1583f169c0eaSGlenn Lagasse 		    "failed to get pool name from %s\n"), name);
1584f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1585f169c0eaSGlenn Lagasse 		return (BE_ERR_POOL_NOENT);
1586f169c0eaSGlenn Lagasse 	}
1587f169c0eaSGlenn Lagasse 
1588f169c0eaSGlenn Lagasse 	/* Mount this shared filesystem */
1589f169c0eaSGlenn Lagasse 	(void) loopback_mount_shared_fs(zhp, md);
1590f169c0eaSGlenn Lagasse 
1591f169c0eaSGlenn Lagasse 	/* Iterate this dataset's children file systems */
1592f169c0eaSGlenn Lagasse 	(void) zfs_iter_filesystems(zhp, iter_shared_fs_callback, md);
1593f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1594f169c0eaSGlenn Lagasse 
1595f169c0eaSGlenn Lagasse 	return (0);
1596f169c0eaSGlenn Lagasse }
1597f169c0eaSGlenn Lagasse 
1598f169c0eaSGlenn Lagasse /*
1599f169c0eaSGlenn Lagasse  * Function:	loopback_mount_shared_fs
1600f169c0eaSGlenn Lagasse  * Description:	This function loopback mounts a file system into the altroot
1601f169c0eaSGlenn Lagasse  *		area of the BE being mounted.  Since these are shared file
1602f169c0eaSGlenn Lagasse  *		systems, they are expected to be already mounted for the
1603f169c0eaSGlenn Lagasse  *		current BE, and this function just loopback mounts them into
1604f169c0eaSGlenn Lagasse  *		the BE mountpoint.  If they are not mounted for the current
1605f169c0eaSGlenn Lagasse  *		live system, they are skipped and not mounted into the BE
1606f169c0eaSGlenn Lagasse  *		we're mounting.
1607f169c0eaSGlenn Lagasse  * Parameters:
1608f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to the dataset to loopback mount
1609f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer
1610f169c0eaSGlenn Lagasse  * Returns:
1611f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1612f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1613f169c0eaSGlenn Lagasse  * Scope:
1614f169c0eaSGlenn Lagasse  *		Private
1615f169c0eaSGlenn Lagasse  */
1616f169c0eaSGlenn Lagasse static int
1617f169c0eaSGlenn Lagasse loopback_mount_shared_fs(zfs_handle_t *zhp, be_mount_data_t *md)
1618f169c0eaSGlenn Lagasse {
1619f169c0eaSGlenn Lagasse 	char		zhp_mountpoint[MAXPATHLEN];
1620f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
1621f169c0eaSGlenn Lagasse 	char		*mp = NULL;
1622f169c0eaSGlenn Lagasse 	char		optstr[MAX_MNTOPT_STR];
1623f169c0eaSGlenn Lagasse 	int		mflag = MS_OPTIONSTR;
1624f169c0eaSGlenn Lagasse 	int		err;
1625f169c0eaSGlenn Lagasse 
1626f169c0eaSGlenn Lagasse 	/*
1627f169c0eaSGlenn Lagasse 	 * Check if file system is currently mounted and not delegated
1628f169c0eaSGlenn Lagasse 	 * to a non-global zone (if we're in the global zone)
1629f169c0eaSGlenn Lagasse 	 */
1630f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &mp) && (getzoneid() != GLOBAL_ZONEID ||
1631f169c0eaSGlenn Lagasse 	    !zfs_prop_get_int(zhp, ZFS_PROP_ZONED))) {
1632f169c0eaSGlenn Lagasse 		/*
1633f169c0eaSGlenn Lagasse 		 * If we didn't get a mountpoint from the zfs_is_mounted call,
1634f169c0eaSGlenn Lagasse 		 * get it from the mountpoint property.
1635f169c0eaSGlenn Lagasse 		 */
1636f169c0eaSGlenn Lagasse 		if (mp == NULL) {
1637f169c0eaSGlenn Lagasse 			if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
1638f169c0eaSGlenn Lagasse 			    zhp_mountpoint, sizeof (zhp_mountpoint), NULL,
1639f169c0eaSGlenn Lagasse 			    NULL, 0, B_FALSE) != 0) {
1640f169c0eaSGlenn Lagasse 				be_print_err(
1641f169c0eaSGlenn Lagasse 				    gettext("loopback_mount_shared_fs: "
1642f169c0eaSGlenn Lagasse 				    "failed to get mountpoint property\n"));
1643f169c0eaSGlenn Lagasse 				return (BE_ERR_ZFS);
1644f169c0eaSGlenn Lagasse 			}
1645f169c0eaSGlenn Lagasse 		} else {
1646f169c0eaSGlenn Lagasse 			(void) strlcpy(zhp_mountpoint, mp,
1647f169c0eaSGlenn Lagasse 			    sizeof (zhp_mountpoint));
1648f169c0eaSGlenn Lagasse 			free(mp);
1649f169c0eaSGlenn Lagasse 		}
1650f169c0eaSGlenn Lagasse 
1651f169c0eaSGlenn Lagasse 		(void) snprintf(mountpoint, sizeof (mountpoint), "%s%s",
1652f169c0eaSGlenn Lagasse 		    md->altroot, zhp_mountpoint);
1653f169c0eaSGlenn Lagasse 
1654f169c0eaSGlenn Lagasse 		/* Mount it read-only if read-write was not requested */
1655f169c0eaSGlenn Lagasse 		if (!md->shared_rw) {
1656f169c0eaSGlenn Lagasse 			mflag |= MS_RDONLY;
1657f169c0eaSGlenn Lagasse 		}
1658f169c0eaSGlenn Lagasse 
1659f169c0eaSGlenn Lagasse 		/* Add the "nosub" option to the mount options string */
1660f169c0eaSGlenn Lagasse 		(void) strlcpy(optstr, MNTOPT_NOSUB, sizeof (optstr));
1661f169c0eaSGlenn Lagasse 
1662f169c0eaSGlenn Lagasse 		/* Loopback mount this dataset at the altroot */
1663f169c0eaSGlenn Lagasse 		if (mount(zhp_mountpoint, mountpoint, mflag, MNTTYPE_LOFS,
1664f169c0eaSGlenn Lagasse 		    NULL, 0, optstr, sizeof (optstr)) != 0) {
1665f169c0eaSGlenn Lagasse 			err = errno;
1666f169c0eaSGlenn Lagasse 			be_print_err(gettext("loopback_mount_shared_fs: "
1667f169c0eaSGlenn Lagasse 			    "failed to loopback mount %s at %s: %s\n"),
1668f169c0eaSGlenn Lagasse 			    zhp_mountpoint, mountpoint, strerror(err));
1669f169c0eaSGlenn Lagasse 			return (BE_ERR_MOUNT);
1670f169c0eaSGlenn Lagasse 		}
1671f169c0eaSGlenn Lagasse 	}
1672f169c0eaSGlenn Lagasse 
1673f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1674f169c0eaSGlenn Lagasse }
1675f169c0eaSGlenn Lagasse 
1676f169c0eaSGlenn Lagasse /*
1677f169c0eaSGlenn Lagasse  * Function:	loopback_mount_zonepath
1678f169c0eaSGlenn Lagasse  * Description:	This function loopback mounts a zonepath into the altroot
167940ccc6adSAlexander Eremin  *		area of the BE being mounted.
1680f169c0eaSGlenn Lagasse  * Parameters:
1681f169c0eaSGlenn Lagasse  *		zonepath - pointer to zone path in the current BE
1682f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer
1683f169c0eaSGlenn Lagasse  * Returns:
1684f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1685f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1686f169c0eaSGlenn Lagasse  * Scope:
1687f169c0eaSGlenn Lagasse  *		Private
1688f169c0eaSGlenn Lagasse  */
1689f169c0eaSGlenn Lagasse static int
1690f169c0eaSGlenn Lagasse loopback_mount_zonepath(const char *zonepath, be_mount_data_t *md)
1691f169c0eaSGlenn Lagasse {
1692f169c0eaSGlenn Lagasse 	FILE		*fp = (FILE *)NULL;
1693f169c0eaSGlenn Lagasse 	struct stat	st;
1694f169c0eaSGlenn Lagasse 	char		*p;
1695f169c0eaSGlenn Lagasse 	char		*p1;
1696f169c0eaSGlenn Lagasse 	char		*parent_dir;
1697f169c0eaSGlenn Lagasse 	struct extmnttab	extmtab;
1698f169c0eaSGlenn Lagasse 	dev_t		dev = NODEV;
1699f169c0eaSGlenn Lagasse 	char		*parentmnt;
1700f169c0eaSGlenn Lagasse 	char		alt_parentmnt[MAXPATHLEN];
1701f169c0eaSGlenn Lagasse 	struct mnttab	mntref;
1702f169c0eaSGlenn Lagasse 	char		altzonepath[MAXPATHLEN];
1703f169c0eaSGlenn Lagasse 	char		optstr[MAX_MNTOPT_STR];
1704f169c0eaSGlenn Lagasse 	int		mflag = MS_OPTIONSTR;
1705f169c0eaSGlenn Lagasse 	int		ret;
1706f169c0eaSGlenn Lagasse 	int		err;
1707f169c0eaSGlenn Lagasse 
1708f169c0eaSGlenn Lagasse 	fp = fopen(MNTTAB, "r");
1709f169c0eaSGlenn Lagasse 	if (fp == NULL) {
1710f169c0eaSGlenn Lagasse 		err = errno;
1711f169c0eaSGlenn Lagasse 		be_print_err(gettext("loopback_mount_zonepath: "
1712f169c0eaSGlenn Lagasse 		    "failed to open /etc/mnttab\n"));
1713f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
1714f169c0eaSGlenn Lagasse 	}
1715f169c0eaSGlenn Lagasse 
1716f169c0eaSGlenn Lagasse 	/*
1717f169c0eaSGlenn Lagasse 	 * before attempting the loopback mount of zonepath under altroot,
1718f169c0eaSGlenn Lagasse 	 * we need to make sure that all intermediate file systems in the
1719f169c0eaSGlenn Lagasse 	 * zone path are also mounted under altroot
1720f169c0eaSGlenn Lagasse 	 */
1721f169c0eaSGlenn Lagasse 
1722f169c0eaSGlenn Lagasse 	/* get the parent directory for zonepath */
1723f169c0eaSGlenn Lagasse 	p = strrchr(zonepath, '/');
1724f169c0eaSGlenn Lagasse 	if (p != NULL && p != zonepath) {
1725f169c0eaSGlenn Lagasse 		if ((parent_dir = (char *)calloc(sizeof (char),
1726f169c0eaSGlenn Lagasse 		    p - zonepath + 1)) == NULL) {
1727f169c0eaSGlenn Lagasse 			ret = BE_ERR_NOMEM;
1728f169c0eaSGlenn Lagasse 			goto done;
1729f169c0eaSGlenn Lagasse 		}
1730f169c0eaSGlenn Lagasse 		(void) strlcpy(parent_dir, zonepath, p - zonepath + 1);
1731f169c0eaSGlenn Lagasse 		if (stat(parent_dir, &st) < 0) {
1732f169c0eaSGlenn Lagasse 			ret = errno_to_be_err(errno);
1733f169c0eaSGlenn Lagasse 			be_print_err(gettext("loopback_mount_zonepath: "
1734f169c0eaSGlenn Lagasse 			    "failed to stat %s"),
1735f169c0eaSGlenn Lagasse 			    parent_dir);
1736f169c0eaSGlenn Lagasse 			free(parent_dir);
1737f169c0eaSGlenn Lagasse 			goto done;
1738f169c0eaSGlenn Lagasse 		}
1739f169c0eaSGlenn Lagasse 		free(parent_dir);
1740f169c0eaSGlenn Lagasse 
1741f169c0eaSGlenn Lagasse 		/*
1742f169c0eaSGlenn Lagasse 		 * After the above stat call, st.st_dev contains ID of the
1743f169c0eaSGlenn Lagasse 		 * device over which parent dir resides.
1744f169c0eaSGlenn Lagasse 		 * Now, search mnttab and find mount point of parent dir device.
1745f169c0eaSGlenn Lagasse 		 */
1746f169c0eaSGlenn Lagasse 
1747f169c0eaSGlenn Lagasse 		resetmnttab(fp);
1748f169c0eaSGlenn Lagasse 		while (getextmntent(fp, &extmtab, sizeof (extmtab)) == 0) {
1749f169c0eaSGlenn Lagasse 			dev = makedev(extmtab.mnt_major, extmtab.mnt_minor);
1750f169c0eaSGlenn Lagasse 			if (st.st_dev == dev && strcmp(extmtab.mnt_fstype,
1751f169c0eaSGlenn Lagasse 			    MNTTYPE_ZFS) == 0) {
1752f169c0eaSGlenn Lagasse 				p1 = strchr(extmtab.mnt_special, '/');
1753f169c0eaSGlenn Lagasse 				if (p1 == NULL || strncmp(p1 + 1,
1754f169c0eaSGlenn Lagasse 				    BE_CONTAINER_DS_NAME, 4) != 0 ||
1755f169c0eaSGlenn Lagasse 				    (*(p1 + 5) != '/' && *(p1 + 5) != '\0')) {
1756f169c0eaSGlenn Lagasse 					/*
1757f169c0eaSGlenn Lagasse 					 * if parent dir is in a shared file
1758f169c0eaSGlenn Lagasse 					 * system, check whether it is already
1759f169c0eaSGlenn Lagasse 					 * loopback mounted under altroot or
1760f169c0eaSGlenn Lagasse 					 * not.  It would have been mounted
1761f169c0eaSGlenn Lagasse 					 * already under altroot if it is in
1762f169c0eaSGlenn Lagasse 					 * a non-shared filesystem.
1763f169c0eaSGlenn Lagasse 					 */
1764f169c0eaSGlenn Lagasse 					parentmnt = strdup(extmtab.mnt_mountp);
1765f169c0eaSGlenn Lagasse 					(void) snprintf(alt_parentmnt,
1766f169c0eaSGlenn Lagasse 					    sizeof (alt_parentmnt), "%s%s",
1767f169c0eaSGlenn Lagasse 					    md->altroot, parentmnt);
1768f169c0eaSGlenn Lagasse 					mntref.mnt_mountp = alt_parentmnt;
1769f169c0eaSGlenn Lagasse 					mntref.mnt_special = parentmnt;
1770f169c0eaSGlenn Lagasse 					mntref.mnt_fstype = MNTTYPE_LOFS;
1771f169c0eaSGlenn Lagasse 					mntref.mnt_mntopts = NULL;
1772f169c0eaSGlenn Lagasse 					mntref.mnt_time = NULL;
1773f169c0eaSGlenn Lagasse 					resetmnttab(fp);
1774f169c0eaSGlenn Lagasse 					if (getmntany(fp, (struct mnttab *)
1775f169c0eaSGlenn Lagasse 					    &extmtab, &mntref) != 0) {
1776f169c0eaSGlenn Lagasse 						ret = loopback_mount_zonepath(
1777f169c0eaSGlenn Lagasse 						    parentmnt, md);
1778f169c0eaSGlenn Lagasse 						if (ret != BE_SUCCESS) {
1779f169c0eaSGlenn Lagasse 							free(parentmnt);
1780f169c0eaSGlenn Lagasse 							goto done;
1781f169c0eaSGlenn Lagasse 						}
1782f169c0eaSGlenn Lagasse 					}
1783f169c0eaSGlenn Lagasse 					free(parentmnt);
1784f169c0eaSGlenn Lagasse 				}
1785f169c0eaSGlenn Lagasse 				break;
1786f169c0eaSGlenn Lagasse 			}
1787f169c0eaSGlenn Lagasse 		}
1788f169c0eaSGlenn Lagasse 	}
1789f169c0eaSGlenn Lagasse 
1790f169c0eaSGlenn Lagasse 
1791f169c0eaSGlenn Lagasse 	if (!md->shared_rw) {
1792f169c0eaSGlenn Lagasse 		mflag |= MS_RDONLY;
1793f169c0eaSGlenn Lagasse 	}
1794f169c0eaSGlenn Lagasse 
1795f169c0eaSGlenn Lagasse 	(void) snprintf(altzonepath, sizeof (altzonepath), "%s%s",
1796f169c0eaSGlenn Lagasse 	    md->altroot, zonepath);
1797f169c0eaSGlenn Lagasse 
1798f169c0eaSGlenn Lagasse 	/* Add the "nosub" option to the mount options string */
1799f169c0eaSGlenn Lagasse 	(void) strlcpy(optstr, MNTOPT_NOSUB, sizeof (optstr));
1800f169c0eaSGlenn Lagasse 
1801f169c0eaSGlenn Lagasse 	/* Loopback mount this dataset at the altroot */
1802f169c0eaSGlenn Lagasse 	if (mount(zonepath, altzonepath, mflag, MNTTYPE_LOFS,
1803f169c0eaSGlenn Lagasse 	    NULL, 0, optstr, sizeof (optstr)) != 0) {
1804f169c0eaSGlenn Lagasse 		err = errno;
1805f169c0eaSGlenn Lagasse 		be_print_err(gettext("loopback_mount_zonepath: "
1806f169c0eaSGlenn Lagasse 		    "failed to loopback mount %s at %s: %s\n"),
1807f169c0eaSGlenn Lagasse 		    zonepath, altzonepath, strerror(err));
1808f169c0eaSGlenn Lagasse 		ret = BE_ERR_MOUNT;
1809f169c0eaSGlenn Lagasse 		goto done;
1810f169c0eaSGlenn Lagasse 	}
1811f169c0eaSGlenn Lagasse 	ret = BE_SUCCESS;
1812f169c0eaSGlenn Lagasse 
1813f169c0eaSGlenn Lagasse done :
1814f169c0eaSGlenn Lagasse 	(void) fclose(fp);
1815f169c0eaSGlenn Lagasse 	return (ret);
1816f169c0eaSGlenn Lagasse }
1817f169c0eaSGlenn Lagasse 
1818f169c0eaSGlenn Lagasse /*
1819f169c0eaSGlenn Lagasse  * Function:	unmount_shared_fs
1820f169c0eaSGlenn Lagasse  * Description:	This function iterates through the mnttab and finds all
1821f169c0eaSGlenn Lagasse  *		loopback mount entries that reside within the altroot of
1822f169c0eaSGlenn Lagasse  *		where the BE is mounted, and unmounts it.
1823f169c0eaSGlenn Lagasse  * Parameters:
1824f169c0eaSGlenn Lagasse  *		ud - be_unmount_data_t pointer
1825f169c0eaSGlenn Lagasse  * Returns:
1826f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1827f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1828f169c0eaSGlenn Lagasse  * Scope:
1829f169c0eaSGlenn Lagasse  *		Private
1830f169c0eaSGlenn Lagasse  */
1831f169c0eaSGlenn Lagasse static int
1832f169c0eaSGlenn Lagasse unmount_shared_fs(be_unmount_data_t *ud)
1833f169c0eaSGlenn Lagasse {
1834f169c0eaSGlenn Lagasse 	FILE		*fp = NULL;
1835f169c0eaSGlenn Lagasse 	struct mnttab	*table = NULL;
1836f169c0eaSGlenn Lagasse 	struct mnttab	ent;
1837f169c0eaSGlenn Lagasse 	struct mnttab	*entp = NULL;
1838f169c0eaSGlenn Lagasse 	size_t		size = 0;
1839f169c0eaSGlenn Lagasse 	int		read_chunk = 32;
1840f169c0eaSGlenn Lagasse 	int		i;
1841f169c0eaSGlenn Lagasse 	int		altroot_len;
1842f169c0eaSGlenn Lagasse 	int		err = 0;
1843f169c0eaSGlenn Lagasse 
1844f169c0eaSGlenn Lagasse 	errno = 0;
1845f169c0eaSGlenn Lagasse 
1846f169c0eaSGlenn Lagasse 	/* Read in the mnttab into a table */
1847f169c0eaSGlenn Lagasse 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
1848f169c0eaSGlenn Lagasse 		err = errno;
1849f169c0eaSGlenn Lagasse 		be_print_err(gettext("unmount_shared_fs: "
1850f169c0eaSGlenn Lagasse 		    "failed to open mnttab\n"));
1851f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
1852f169c0eaSGlenn Lagasse 	}
1853f169c0eaSGlenn Lagasse 
1854f169c0eaSGlenn Lagasse 	while (getmntent(fp, &ent) == 0) {
1855f169c0eaSGlenn Lagasse 		if (size % read_chunk == 0) {
1856f169c0eaSGlenn Lagasse 			table = (struct mnttab *)realloc(table,
1857f169c0eaSGlenn Lagasse 			    (size + read_chunk) * sizeof (ent));
1858f169c0eaSGlenn Lagasse 		}
1859f169c0eaSGlenn Lagasse 		entp = &table[size++];
1860f169c0eaSGlenn Lagasse 
1861f169c0eaSGlenn Lagasse 		/*
1862f169c0eaSGlenn Lagasse 		 * Copy over the current mnttab entry into our table,
1863f169c0eaSGlenn Lagasse 		 * copying only the fields that we care about.
1864f169c0eaSGlenn Lagasse 		 */
1865f169c0eaSGlenn Lagasse 		(void) memset(entp, 0, sizeof (*entp));
1866f169c0eaSGlenn Lagasse 		if ((entp->mnt_mountp = strdup(ent.mnt_mountp)) == NULL ||
1867f169c0eaSGlenn Lagasse 		    (entp->mnt_fstype = strdup(ent.mnt_fstype)) == NULL) {
1868f169c0eaSGlenn Lagasse 			be_print_err(gettext("unmount_shared_fs: "
1869f169c0eaSGlenn Lagasse 			    "memory allocation failed\n"));
1870f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
1871f169c0eaSGlenn Lagasse 		}
1872f169c0eaSGlenn Lagasse 	}
1873f169c0eaSGlenn Lagasse 	(void) fclose(fp);
1874f169c0eaSGlenn Lagasse 
1875f169c0eaSGlenn Lagasse 	/*
1876f169c0eaSGlenn Lagasse 	 * Process the mnttab entries in reverse order, looking for
1877f169c0eaSGlenn Lagasse 	 * loopback mount entries mounted under our altroot.
1878f169c0eaSGlenn Lagasse 	 */
1879f169c0eaSGlenn Lagasse 	altroot_len = strlen(ud->altroot);
1880f169c0eaSGlenn Lagasse 	for (i = size; i > 0; i--) {
1881f169c0eaSGlenn Lagasse 		entp = &table[i - 1];
1882f169c0eaSGlenn Lagasse 
1883f169c0eaSGlenn Lagasse 		/* If not of type lofs, skip */
1884f169c0eaSGlenn Lagasse 		if (strcmp(entp->mnt_fstype, MNTTYPE_LOFS) != 0)
1885f169c0eaSGlenn Lagasse 			continue;
1886f169c0eaSGlenn Lagasse 
1887f169c0eaSGlenn Lagasse 		/* If inside the altroot, unmount it */
1888f169c0eaSGlenn Lagasse 		if (strncmp(entp->mnt_mountp, ud->altroot, altroot_len) == 0 &&
1889f169c0eaSGlenn Lagasse 		    entp->mnt_mountp[altroot_len] == '/') {
1890f169c0eaSGlenn Lagasse 			if (umount(entp->mnt_mountp) != 0) {
1891f169c0eaSGlenn Lagasse 				err = errno;
1892f169c0eaSGlenn Lagasse 				if (err == EBUSY) {
1893f169c0eaSGlenn Lagasse 					(void) sleep(1);
1894f169c0eaSGlenn Lagasse 					err = errno = 0;
1895f169c0eaSGlenn Lagasse 					if (umount(entp->mnt_mountp) != 0)
1896f169c0eaSGlenn Lagasse 						err = errno;
1897f169c0eaSGlenn Lagasse 				}
1898f169c0eaSGlenn Lagasse 				if (err != 0) {
1899f169c0eaSGlenn Lagasse 					be_print_err(gettext(
1900f169c0eaSGlenn Lagasse 					    "unmount_shared_fs: "
1901f169c0eaSGlenn Lagasse 					    "failed to unmount shared file "
1902f169c0eaSGlenn Lagasse 					    "system %s: %s\n"),
1903f169c0eaSGlenn Lagasse 					    entp->mnt_mountp, strerror(err));
1904f169c0eaSGlenn Lagasse 					return (errno_to_be_err(err));
1905f169c0eaSGlenn Lagasse 				}
1906f169c0eaSGlenn Lagasse 			}
1907f169c0eaSGlenn Lagasse 		}
1908f169c0eaSGlenn Lagasse 	}
1909f169c0eaSGlenn Lagasse 
1910f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1911f169c0eaSGlenn Lagasse }
1912f169c0eaSGlenn Lagasse 
1913f169c0eaSGlenn Lagasse /*
1914f169c0eaSGlenn Lagasse  * Function:	get_mountpoint_from_vfstab
1915f169c0eaSGlenn Lagasse  * Description:	This function digs into the vfstab in the given altroot,
1916f169c0eaSGlenn Lagasse  *		and searches for an entry for the fs passed in.  If found,
1917f169c0eaSGlenn Lagasse  *		it returns the mountpoint of that fs in the mountpoint
1918f169c0eaSGlenn Lagasse  *		buffer passed in.  If the get_alt_mountpoint flag is set,
1919f169c0eaSGlenn Lagasse  *		it returns the mountpoint with the altroot prepended.
1920f169c0eaSGlenn Lagasse  * Parameters:
1921f169c0eaSGlenn Lagasse  *		altroot - pointer to the alternate root location
1922f169c0eaSGlenn Lagasse  *		fs - pointer to the file system name to look for in the
1923f169c0eaSGlenn Lagasse  *			vfstab in altroot
1924f169c0eaSGlenn Lagasse  *		mountpoint - pointer to buffer of where the mountpoint of
1925f169c0eaSGlenn Lagasse  *			fs will be returned.
1926f169c0eaSGlenn Lagasse  *		size_mp - size of mountpoint argument
1927f169c0eaSGlenn Lagasse  *		get_alt_mountpoint - flag to indicate whether or not the
1928f169c0eaSGlenn Lagasse  *			mountpoint should be populated with the altroot
1929f169c0eaSGlenn Lagasse  *			prepended.
1930f169c0eaSGlenn Lagasse  * Returns:
1931f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1932f169c0eaSGlenn Lagasse  *		1 - Failure
1933f169c0eaSGlenn Lagasse  * Scope:
1934f169c0eaSGlenn Lagasse  *		Private
1935f169c0eaSGlenn Lagasse  */
1936f169c0eaSGlenn Lagasse static int
1937f169c0eaSGlenn Lagasse get_mountpoint_from_vfstab(char *altroot, const char *fs, char *mountpoint,
1938f169c0eaSGlenn Lagasse     size_t size_mp, boolean_t get_alt_mountpoint)
1939f169c0eaSGlenn Lagasse {
1940f169c0eaSGlenn Lagasse 	struct vfstab	vp;
1941f169c0eaSGlenn Lagasse 	FILE		*fp = NULL;
1942f169c0eaSGlenn Lagasse 	char		alt_vfstab[MAXPATHLEN];
1943f169c0eaSGlenn Lagasse 
1944f169c0eaSGlenn Lagasse 	/* Generate path to alternate root vfstab */
1945f169c0eaSGlenn Lagasse 	(void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
1946f169c0eaSGlenn Lagasse 	    altroot);
1947f169c0eaSGlenn Lagasse 
1948f169c0eaSGlenn Lagasse 	/* Open alternate root vfstab */
1949f169c0eaSGlenn Lagasse 	if ((fp = fopen(alt_vfstab, "r")) == NULL) {
1950f169c0eaSGlenn Lagasse 		be_print_err(gettext("get_mountpoint_from_vfstab: "
1951f169c0eaSGlenn Lagasse 		    "failed to open vfstab (%s)\n"), alt_vfstab);
1952f169c0eaSGlenn Lagasse 		return (1);
1953f169c0eaSGlenn Lagasse 	}
1954f169c0eaSGlenn Lagasse 
1955f169c0eaSGlenn Lagasse 	if (getvfsspec(fp, &vp, (char *)fs) == 0) {
1956f169c0eaSGlenn Lagasse 		/*
1957f169c0eaSGlenn Lagasse 		 * Found entry for fs, grab its mountpoint.
1958f169c0eaSGlenn Lagasse 		 * If the flag to prepend the altroot into the mountpoint
1959f169c0eaSGlenn Lagasse 		 * is set, prepend it.  Otherwise, just return the mountpoint.
1960f169c0eaSGlenn Lagasse 		 */
1961f169c0eaSGlenn Lagasse 		if (get_alt_mountpoint) {
1962f169c0eaSGlenn Lagasse 			(void) snprintf(mountpoint, size_mp, "%s%s", altroot,
1963f169c0eaSGlenn Lagasse 			    vp.vfs_mountp);
1964f169c0eaSGlenn Lagasse 		} else {
1965f169c0eaSGlenn Lagasse 			(void) strlcpy(mountpoint, vp.vfs_mountp, size_mp);
1966f169c0eaSGlenn Lagasse 		}
1967f169c0eaSGlenn Lagasse 	} else {
1968f169c0eaSGlenn Lagasse 		(void) fclose(fp);
1969f169c0eaSGlenn Lagasse 		return (1);
1970f169c0eaSGlenn Lagasse 	}
1971f169c0eaSGlenn Lagasse 
1972f169c0eaSGlenn Lagasse 	(void) fclose(fp);
1973f169c0eaSGlenn Lagasse 
1974f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1975f169c0eaSGlenn Lagasse }
1976f169c0eaSGlenn Lagasse 
1977f169c0eaSGlenn Lagasse /*
1978f169c0eaSGlenn Lagasse  * Function:	fix_mountpoint_callback
1979f169c0eaSGlenn Lagasse  * Description:	This callback function is used to iterate through a BE's
1980f169c0eaSGlenn Lagasse  *		children filesystems to check if its mountpoint is currently
1981f169c0eaSGlenn Lagasse  *		set to be mounted at some specified altroot.  If so, fix it by
1982f169c0eaSGlenn Lagasse  *		removing altroot from the beginning of its mountpoint.
1983f169c0eaSGlenn Lagasse  *
1984f169c0eaSGlenn Lagasse  *		Note - There's no way to tell if a child filesystem's
1985f169c0eaSGlenn Lagasse  *		mountpoint isn't broken, and just happens to begin with
1986f169c0eaSGlenn Lagasse  *		the altroot we're looking for.  In this case, this function
1987f169c0eaSGlenn Lagasse  *		will errantly remove the altroot portion from the beginning
1988f169c0eaSGlenn Lagasse  *		of this filesystem's mountpoint.
1989f169c0eaSGlenn Lagasse  *
1990f169c0eaSGlenn Lagasse  * Parameters:
1991f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to filesystem being processed.
1992f169c0eaSGlenn Lagasse  *		data - altroot of where BE is to be mounted.
1993f169c0eaSGlenn Lagasse  * Returns:
1994f169c0eaSGlenn Lagasse  *		0 - Success
1995f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1996f169c0eaSGlenn Lagasse  * Scope:
1997f169c0eaSGlenn Lagasse  *		Private
1998f169c0eaSGlenn Lagasse  */
1999f169c0eaSGlenn Lagasse static int
2000f169c0eaSGlenn Lagasse fix_mountpoint_callback(zfs_handle_t *zhp, void *data)
2001f169c0eaSGlenn Lagasse {
2002f169c0eaSGlenn Lagasse 	zprop_source_t	sourcetype;
20039adfa60dSMatthew Ahrens 	char		source[ZFS_MAX_DATASET_NAME_LEN];
2004f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
2005f169c0eaSGlenn Lagasse 	char		*zhp_mountpoint = NULL;
2006f169c0eaSGlenn Lagasse 	char		*altroot = data;
2007f169c0eaSGlenn Lagasse 	int		ret = 0;
2008f169c0eaSGlenn Lagasse 
2009f169c0eaSGlenn Lagasse 	/* Get dataset's mountpoint and source values */
2010f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2011f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), &sourcetype, source, sizeof (source),
2012f169c0eaSGlenn Lagasse 	    B_FALSE) != 0) {
2013f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint_callback: "
2014f169c0eaSGlenn Lagasse 		    "failed to get mountpoint and sourcetype for %s\n"),
2015f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp));
2016f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2017f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
2018f169c0eaSGlenn Lagasse 	}
2019f169c0eaSGlenn Lagasse 
2020f169c0eaSGlenn Lagasse 	/*
2021f169c0eaSGlenn Lagasse 	 * If the mountpoint is not inherited and the mountpoint is not
2022f169c0eaSGlenn Lagasse 	 * 'legacy', this file system potentially needs its mountpoint
2023f169c0eaSGlenn Lagasse 	 * fixed.
2024f169c0eaSGlenn Lagasse 	 */
2025f169c0eaSGlenn Lagasse 	if (!(sourcetype & ZPROP_SRC_INHERITED) &&
2026f169c0eaSGlenn Lagasse 	    strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
2027f169c0eaSGlenn Lagasse 
2028f169c0eaSGlenn Lagasse 		/*
2029f169c0eaSGlenn Lagasse 		 * Check if this file system's current mountpoint is
2030f169c0eaSGlenn Lagasse 		 * under the altroot we're fixing it against.
2031f169c0eaSGlenn Lagasse 		 */
2032f169c0eaSGlenn Lagasse 		if (strncmp(mountpoint, altroot, strlen(altroot)) == 0 &&
2033f169c0eaSGlenn Lagasse 		    mountpoint[strlen(altroot)] == '/') {
2034f169c0eaSGlenn Lagasse 
2035f169c0eaSGlenn Lagasse 			/*
2036f169c0eaSGlenn Lagasse 			 * Get this dataset's mountpoint relative to the
2037f169c0eaSGlenn Lagasse 			 * altroot.
2038f169c0eaSGlenn Lagasse 			 */
2039f169c0eaSGlenn Lagasse 			zhp_mountpoint = mountpoint + strlen(altroot);
2040f169c0eaSGlenn Lagasse 
2041f169c0eaSGlenn Lagasse 			/* Fix this dataset's mountpoint value */
2042f169c0eaSGlenn Lagasse 			if (zfs_prop_set(zhp,
2043f169c0eaSGlenn Lagasse 			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2044f169c0eaSGlenn Lagasse 			    zhp_mountpoint)) {
2045f169c0eaSGlenn Lagasse 				be_print_err(gettext("fix_mountpoint_callback: "
2046f169c0eaSGlenn Lagasse 				    "failed to set mountpoint for %s to "
2047f169c0eaSGlenn Lagasse 				    "%s: %s\n"), zfs_get_name(zhp),
2048f169c0eaSGlenn Lagasse 				    zhp_mountpoint,
2049f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
2050f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
2051f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
2052f169c0eaSGlenn Lagasse 				return (ret);
2053f169c0eaSGlenn Lagasse 			}
2054f169c0eaSGlenn Lagasse 		}
2055f169c0eaSGlenn Lagasse 	}
2056f169c0eaSGlenn Lagasse 
2057f169c0eaSGlenn Lagasse 	/* Iterate through this dataset's children and fix them */
2058f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, fix_mountpoint_callback,
2059f169c0eaSGlenn Lagasse 	    altroot)) != 0) {
2060f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2061f169c0eaSGlenn Lagasse 		return (ret);
2062f169c0eaSGlenn Lagasse 	}
2063f169c0eaSGlenn Lagasse 
2064f169c0eaSGlenn Lagasse 
2065f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2066f169c0eaSGlenn Lagasse 	return (0);
2067f169c0eaSGlenn Lagasse }
2068f169c0eaSGlenn Lagasse 
2069f169c0eaSGlenn Lagasse /*
2070f169c0eaSGlenn Lagasse  * Function:	be_mount_root
2071f169c0eaSGlenn Lagasse  * Description:	This function mounts the root dataset of a BE at the
2072f169c0eaSGlenn Lagasse  *		specified altroot.
2073f169c0eaSGlenn Lagasse  * Parameters:
2074f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to root dataset of a BE that is
2075f169c0eaSGlenn Lagasse  *		to be mounted at altroot.
2076f169c0eaSGlenn Lagasse  *		altroot - location of where to mount the BE root.
2077f169c0eaSGlenn Lagasse  * Return:
2078f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2079f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2080f169c0eaSGlenn Lagasse  * Scope:
2081f169c0eaSGlenn Lagasse  *		Private
2082f169c0eaSGlenn Lagasse  */
2083f169c0eaSGlenn Lagasse static int
2084f169c0eaSGlenn Lagasse be_mount_root(zfs_handle_t *zhp, char *altroot)
2085f169c0eaSGlenn Lagasse {
2086f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
2087f169c0eaSGlenn Lagasse 
2088f169c0eaSGlenn Lagasse 	/* Get mountpoint property of dataset */
2089f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2090f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
2091f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_root: failed to "
2092f169c0eaSGlenn Lagasse 		    "get mountpoint property for %s: %s\n"), zfs_get_name(zhp),
2093f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2094f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2095f169c0eaSGlenn Lagasse 	}
2096f169c0eaSGlenn Lagasse 
2097f169c0eaSGlenn Lagasse 	/*
2098f169c0eaSGlenn Lagasse 	 * Set the canmount property for the BE's root dataset to 'noauto' just
20993a876192SAlexander Pyhalov 	 * in case it's been set to 'on'.
2100f169c0eaSGlenn Lagasse 	 */
2101f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")
2102f169c0eaSGlenn Lagasse 	    != 0) {
2103f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_root: failed to "
2104f169c0eaSGlenn Lagasse 		    "set canmount property to 'noauto' (%s): %s\n"),
2105f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
2106f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2107f169c0eaSGlenn Lagasse 	}
2108f169c0eaSGlenn Lagasse 
2109f169c0eaSGlenn Lagasse 	/* Mount the BE's root filesystem */
21103a876192SAlexander Pyhalov 	if (mount_zfs(zhp, altroot) != 0) {
2111f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_root: failed to "
2112f169c0eaSGlenn Lagasse 		    "mount dataset %s at %s: %s\n"), zfs_get_name(zhp),
21133a876192SAlexander Pyhalov 		    altroot, strerror(errno));
21143a876192SAlexander Pyhalov 		return (BE_ERR_ZFS);
2115f169c0eaSGlenn Lagasse 	}
2116f169c0eaSGlenn Lagasse 
2117f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
2118f169c0eaSGlenn Lagasse }
2119f169c0eaSGlenn Lagasse 
2120f169c0eaSGlenn Lagasse /*
2121f169c0eaSGlenn Lagasse  * Function:	be_unmount_root
2122f169c0eaSGlenn Lagasse  * Description:	This function unmounts the root dataset of a BE, but before
2123f169c0eaSGlenn Lagasse  *		unmounting, it looks at the BE's vfstab to determine
2124f169c0eaSGlenn Lagasse  *		if the root dataset mountpoint should be left as 'legacy'
2125f169c0eaSGlenn Lagasse  *		or '/'.  If the vfstab contains an entry for this root
2126f169c0eaSGlenn Lagasse  *		dataset with a mountpoint of '/', it sets the mountpoint
2127f169c0eaSGlenn Lagasse  *		property to 'legacy'.
2128f169c0eaSGlenn Lagasse  *
2129f169c0eaSGlenn Lagasse  * Parameters:
2130f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer of the BE root dataset that
2131f169c0eaSGlenn Lagasse  *		is currently mounted.
2132f169c0eaSGlenn Lagasse  *		ud - be_unmount_data_t pointer providing unmount data
2133f169c0eaSGlenn Lagasse  *		for the given BE root dataset.
2134f169c0eaSGlenn Lagasse  * Returns:
2135f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2136f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2137f169c0eaSGlenn Lagasse  * Scope:
2138f169c0eaSGlenn Lagasse  *		Private
2139f169c0eaSGlenn Lagasse  */
2140f169c0eaSGlenn Lagasse static int
2141f169c0eaSGlenn Lagasse be_unmount_root(zfs_handle_t *zhp, be_unmount_data_t *ud)
2142f169c0eaSGlenn Lagasse {
2143f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
2144f169c0eaSGlenn Lagasse 	boolean_t	is_legacy = B_FALSE;
2145f169c0eaSGlenn Lagasse 
2146f169c0eaSGlenn Lagasse 	/* See if this is a legacy mounted root */
2147f169c0eaSGlenn Lagasse 	if (get_mountpoint_from_vfstab(ud->altroot, zfs_get_name(zhp),
2148f169c0eaSGlenn Lagasse 	    mountpoint, sizeof (mountpoint), B_FALSE) == BE_SUCCESS &&
2149f169c0eaSGlenn Lagasse 	    strcmp(mountpoint, "/") == 0) {
2150f169c0eaSGlenn Lagasse 		is_legacy = B_TRUE;
2151f169c0eaSGlenn Lagasse 	}
2152f169c0eaSGlenn Lagasse 
2153f169c0eaSGlenn Lagasse 	/* Unmount the dataset */
2154f169c0eaSGlenn Lagasse 	if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) {
2155f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_root: failed to "
2156f169c0eaSGlenn Lagasse 		    "unmount BE root dataset %s: %s\n"), zfs_get_name(zhp),
2157f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2158f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2159f169c0eaSGlenn Lagasse 	}
2160f169c0eaSGlenn Lagasse 
2161f169c0eaSGlenn Lagasse 	/* Set canmount property for this BE's root filesystem to noauto */
2162f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")
2163f169c0eaSGlenn Lagasse 	    != 0) {
2164f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_root: failed to "
2165f169c0eaSGlenn Lagasse 		    "set canmount property for %s to 'noauto': %s\n"),
2166f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
2167f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2168f169c0eaSGlenn Lagasse 	}
2169f169c0eaSGlenn Lagasse 
2170f169c0eaSGlenn Lagasse 	/*
2171f169c0eaSGlenn Lagasse 	 * Set mountpoint for BE's root dataset back to '/', or 'legacy'
2172f169c0eaSGlenn Lagasse 	 * if its a legacy mounted root.
2173f169c0eaSGlenn Lagasse 	 */
2174f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2175f169c0eaSGlenn Lagasse 	    is_legacy ? ZFS_MOUNTPOINT_LEGACY : "/") != 0) {
2176f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_root: failed to "
2177f169c0eaSGlenn Lagasse 		    "set mountpoint of %s to %s\n"), zfs_get_name(zhp),
2178f169c0eaSGlenn Lagasse 		    is_legacy ? ZFS_MOUNTPOINT_LEGACY : "/");
2179f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2180f169c0eaSGlenn Lagasse 	}
2181f169c0eaSGlenn Lagasse 
2182f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
2183f169c0eaSGlenn Lagasse }
2184f169c0eaSGlenn Lagasse 
2185f169c0eaSGlenn Lagasse /*
2186f169c0eaSGlenn Lagasse  * Function:	fix_mountpoint
2187f169c0eaSGlenn Lagasse  * Description:	This function checks the mountpoint of an unmounted BE to make
2188f169c0eaSGlenn Lagasse  *		sure that it is set to either 'legacy' or '/'.  If it's not,
2189f169c0eaSGlenn Lagasse  *		then we're in a situation where an unmounted BE has some random
2190f169c0eaSGlenn Lagasse  *		mountpoint set for it.  (This could happen if the system was
2191f169c0eaSGlenn Lagasse  *		rebooted while an inactive BE was mounted).  This function
2192f169c0eaSGlenn Lagasse  *		attempts to fix its mountpoints.
2193f169c0eaSGlenn Lagasse  * Parameters:
2194f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to root dataset of the BE
2195f169c0eaSGlenn Lagasse  *		whose mountpoint needs to be checked.
2196f169c0eaSGlenn Lagasse  * Return:
2197f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2198f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2199f169c0eaSGlenn Lagasse  * Scope:
2200f169c0eaSGlenn Lagasse  *		Private
2201f169c0eaSGlenn Lagasse  */
2202f169c0eaSGlenn Lagasse static int
2203f169c0eaSGlenn Lagasse fix_mountpoint(zfs_handle_t *zhp)
2204f169c0eaSGlenn Lagasse {
2205f169c0eaSGlenn Lagasse 	be_unmount_data_t	ud = { 0 };
2206f169c0eaSGlenn Lagasse 	char	*altroot = NULL;
2207f169c0eaSGlenn Lagasse 	char	mountpoint[MAXPATHLEN];
2208f169c0eaSGlenn Lagasse 	int	ret = BE_SUCCESS;
2209f169c0eaSGlenn Lagasse 
2210f169c0eaSGlenn Lagasse 	/*
2211f169c0eaSGlenn Lagasse 	 * Record what this BE's root dataset mountpoint property is currently
2212f169c0eaSGlenn Lagasse 	 * set to.
2213f169c0eaSGlenn Lagasse 	 */
2214f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2215f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
2216f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint: failed to get "
2217f169c0eaSGlenn Lagasse 		    "mountpoint property of (%s): %s\n"), zfs_get_name(zhp),
2218f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2219f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
2220f169c0eaSGlenn Lagasse 	}
2221f169c0eaSGlenn Lagasse 
2222f169c0eaSGlenn Lagasse 	/*
2223f169c0eaSGlenn Lagasse 	 * If the root dataset mountpoint is set to 'legacy' or '/', we're okay.
2224f169c0eaSGlenn Lagasse 	 */
2225f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0 ||
2226f169c0eaSGlenn Lagasse 	    strcmp(mountpoint, "/") == 0) {
2227f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2228f169c0eaSGlenn Lagasse 	}
2229f169c0eaSGlenn Lagasse 
2230f169c0eaSGlenn Lagasse 	/*
2231f169c0eaSGlenn Lagasse 	 * Iterate through this BE's children datasets and fix
2232f169c0eaSGlenn Lagasse 	 * them if they need fixing.
2233f169c0eaSGlenn Lagasse 	 */
2234f169c0eaSGlenn Lagasse 	if (zfs_iter_filesystems(zhp, fix_mountpoint_callback, mountpoint)
2235f169c0eaSGlenn Lagasse 	    != 0) {
2236f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
2237f169c0eaSGlenn Lagasse 	}
2238f169c0eaSGlenn Lagasse 
2239f169c0eaSGlenn Lagasse 	/*
2240f169c0eaSGlenn Lagasse 	 * The process of mounting and unmounting the root file system
2241f169c0eaSGlenn Lagasse 	 * will fix its mountpoint to correctly be either 'legacy' or '/'
2242f169c0eaSGlenn Lagasse 	 * since be_unmount_root will do the right thing by looking at
2243f169c0eaSGlenn Lagasse 	 * its vfstab.
2244f169c0eaSGlenn Lagasse 	 */
2245f169c0eaSGlenn Lagasse 
2246f169c0eaSGlenn Lagasse 	/* Generate temporary altroot to mount the root file system */
2247f169c0eaSGlenn Lagasse 	if ((ret = be_make_tmp_mountpoint(&altroot)) != BE_SUCCESS) {
2248f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint: failed to "
2249f169c0eaSGlenn Lagasse 		    "make temporary mountpoint\n"));
2250f169c0eaSGlenn Lagasse 		return (ret);
2251f169c0eaSGlenn Lagasse 	}
2252f169c0eaSGlenn Lagasse 
2253f169c0eaSGlenn Lagasse 	/* Mount and unmount the root. */
2254f169c0eaSGlenn Lagasse 	if ((ret = be_mount_root(zhp, altroot)) != BE_SUCCESS) {
2255f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint: failed to "
2256f169c0eaSGlenn Lagasse 		    "mount BE root file system\n"));
2257f169c0eaSGlenn Lagasse 		goto cleanup;
2258f169c0eaSGlenn Lagasse 	}
2259f169c0eaSGlenn Lagasse 	ud.altroot = altroot;
2260f169c0eaSGlenn Lagasse 	if ((ret = be_unmount_root(zhp, &ud)) != BE_SUCCESS) {
2261f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint: failed to "
2262f169c0eaSGlenn Lagasse 		    "unmount BE root file system\n"));
2263f169c0eaSGlenn Lagasse 		goto cleanup;
2264f169c0eaSGlenn Lagasse 	}
2265f169c0eaSGlenn Lagasse 
2266f169c0eaSGlenn Lagasse cleanup:
2267f169c0eaSGlenn Lagasse 	free(altroot);
2268f169c0eaSGlenn Lagasse 
2269f169c0eaSGlenn Lagasse 	return (ret);
2270f169c0eaSGlenn Lagasse }
2271f169c0eaSGlenn Lagasse 
2272f169c0eaSGlenn Lagasse /*
2273f169c0eaSGlenn Lagasse  * Function:	be_mount_zones
2274f169c0eaSGlenn Lagasse  * Description:	This function finds all supported non-global zones in the
2275f169c0eaSGlenn Lagasse  *		given global BE and mounts them with respect to where the
2276f169c0eaSGlenn Lagasse  *		global BE is currently mounted.  The global BE datasets
2277f169c0eaSGlenn Lagasse  *		(including its shared datasets) are expected to already
2278f169c0eaSGlenn Lagasse  *		be mounted.
2279f169c0eaSGlenn Lagasse  * Parameters:
2280f169c0eaSGlenn Lagasse  *		be_zhp - zfs_handle_t pointer to the root dataset of the
2281f169c0eaSGlenn Lagasse  *			global BE.
2282f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer to data for global BE.
2283f169c0eaSGlenn Lagasse  * Returns:
2284f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2285f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2286f169c0eaSGlenn Lagasse  * Scope:
2287f169c0eaSGlenn Lagasse  *		Private
2288f169c0eaSGlenn Lagasse  */
2289f169c0eaSGlenn Lagasse static int
2290f169c0eaSGlenn Lagasse be_mount_zones(zfs_handle_t *be_zhp, be_mount_data_t *md)
2291f169c0eaSGlenn Lagasse {
2292f169c0eaSGlenn Lagasse 	zoneBrandList_t	*brands = NULL;
2293f169c0eaSGlenn Lagasse 	zoneList_t	zlst = NULL;
2294f169c0eaSGlenn Lagasse 	char		*zonename = NULL;
2295f169c0eaSGlenn Lagasse 	char		*zonepath = NULL;
2296f169c0eaSGlenn Lagasse 	char		*zonepath_ds = NULL;
2297f169c0eaSGlenn Lagasse 	int		k;
2298f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
2299f169c0eaSGlenn Lagasse 
2300f169c0eaSGlenn Lagasse 	z_set_zone_root(md->altroot);
2301f169c0eaSGlenn Lagasse 
2302f169c0eaSGlenn Lagasse 	if ((brands = be_get_supported_brandlist()) == NULL) {
2303f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_zones: "
2304f169c0eaSGlenn Lagasse 		    "no supported brands\n"));
2305f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2306f169c0eaSGlenn Lagasse 	}
2307f169c0eaSGlenn Lagasse 
2308f169c0eaSGlenn Lagasse 	zlst = z_get_nonglobal_zone_list_by_brand(brands);
2309f169c0eaSGlenn Lagasse 	if (zlst == NULL) {
2310f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
2311f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2312f169c0eaSGlenn Lagasse 	}
2313f169c0eaSGlenn Lagasse 
2314f169c0eaSGlenn Lagasse 	for (k = 0; (zonename = z_zlist_get_zonename(zlst, k)) != NULL; k++) {
2315f169c0eaSGlenn Lagasse 		if (z_zlist_get_current_state(zlst, k) ==
2316f169c0eaSGlenn Lagasse 		    ZONE_STATE_INSTALLED) {
2317f169c0eaSGlenn Lagasse 			zonepath = z_zlist_get_zonepath(zlst, k);
2318f169c0eaSGlenn Lagasse 
2319f169c0eaSGlenn Lagasse 			/*
2320f169c0eaSGlenn Lagasse 			 * Get the dataset of this zonepath in current BE.
2321f169c0eaSGlenn Lagasse 			 * If its not a dataset, skip it.
2322f169c0eaSGlenn Lagasse 			 */
2323f169c0eaSGlenn Lagasse 			if ((zonepath_ds = be_get_ds_from_dir(zonepath))
2324f169c0eaSGlenn Lagasse 			    == NULL)
2325f169c0eaSGlenn Lagasse 				continue;
2326f169c0eaSGlenn Lagasse 
2327f169c0eaSGlenn Lagasse 			/*
2328f169c0eaSGlenn Lagasse 			 * Check if this zone is supported based on
2329f169c0eaSGlenn Lagasse 			 * the dataset of its zonepath
2330f169c0eaSGlenn Lagasse 			 */
2331f169c0eaSGlenn Lagasse 			if (!be_zone_supported(zonepath_ds)) {
2332f169c0eaSGlenn Lagasse 				free(zonepath_ds);
2333f169c0eaSGlenn Lagasse 				zonepath_ds = NULL;
2334f169c0eaSGlenn Lagasse 				continue;
2335f169c0eaSGlenn Lagasse 			}
2336f169c0eaSGlenn Lagasse 
2337f169c0eaSGlenn Lagasse 			/*
2338f169c0eaSGlenn Lagasse 			 * if BE's shared file systems are already mounted,
2339f169c0eaSGlenn Lagasse 			 * zone path dataset would have already been lofs
2340f169c0eaSGlenn Lagasse 			 * mounted under altroot. Otherwise, we need to do
2341f169c0eaSGlenn Lagasse 			 * it here.
2342f169c0eaSGlenn Lagasse 			 */
2343f169c0eaSGlenn Lagasse 			if (!md->shared_fs) {
2344f169c0eaSGlenn Lagasse 				ret = loopback_mount_zonepath(zonepath, md);
2345f169c0eaSGlenn Lagasse 				if (ret != BE_SUCCESS)
2346f169c0eaSGlenn Lagasse 					goto done;
2347f169c0eaSGlenn Lagasse 			}
2348f169c0eaSGlenn Lagasse 
2349f169c0eaSGlenn Lagasse 
2350f169c0eaSGlenn Lagasse 			/* Mount this zone */
2351f169c0eaSGlenn Lagasse 			ret = be_mount_one_zone(be_zhp, md, zonename,
2352f169c0eaSGlenn Lagasse 			    zonepath, zonepath_ds);
2353f169c0eaSGlenn Lagasse 
2354f169c0eaSGlenn Lagasse 			free(zonepath_ds);
2355f169c0eaSGlenn Lagasse 			zonepath_ds = NULL;
2356f169c0eaSGlenn Lagasse 
2357f169c0eaSGlenn Lagasse 			if (ret != BE_SUCCESS) {
2358f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_zones: "
2359f169c0eaSGlenn Lagasse 				    "failed to mount zone %s under "
2360f169c0eaSGlenn Lagasse 				    "altroot %s\n"), zonename, md->altroot);
2361f169c0eaSGlenn Lagasse 				goto done;
2362f169c0eaSGlenn Lagasse 			}
2363f169c0eaSGlenn Lagasse 		}
2364f169c0eaSGlenn Lagasse 	}
2365f169c0eaSGlenn Lagasse 
2366f169c0eaSGlenn Lagasse done:
2367f169c0eaSGlenn Lagasse 	z_free_brand_list(brands);
2368f169c0eaSGlenn Lagasse 	z_free_zone_list(zlst);
2369f169c0eaSGlenn Lagasse 	/*
2370f169c0eaSGlenn Lagasse 	 * libinstzones caches mnttab and uses cached version for resolving lofs
2371f169c0eaSGlenn Lagasse 	 * mounts when we call z_resolve_lofs. It creates the cached version
2372f169c0eaSGlenn Lagasse 	 * when the first call to z_resolve_lofs happens. So, library's cached
2373f169c0eaSGlenn Lagasse 	 * mnttab doesn't contain entries for lofs mounts created in the above
2374f169c0eaSGlenn Lagasse 	 * loop. Because of this, subsequent calls to z_resolve_lofs would fail
2375f169c0eaSGlenn Lagasse 	 * to resolve these lofs mounts. So, here we destroy library's cached
2376f169c0eaSGlenn Lagasse 	 * mnttab to force its recreation when the next call to z_resolve_lofs
2377f169c0eaSGlenn Lagasse 	 * happens.
2378f169c0eaSGlenn Lagasse 	 */
2379f169c0eaSGlenn Lagasse 	z_destroyMountTable();
2380f169c0eaSGlenn Lagasse 	return (ret);
2381f169c0eaSGlenn Lagasse }
2382f169c0eaSGlenn Lagasse 
2383f169c0eaSGlenn Lagasse /*
2384f169c0eaSGlenn Lagasse  * Function:	be_unmount_zones
2385f169c0eaSGlenn Lagasse  * Description:	This function finds all supported non-global zones in the
2386f169c0eaSGlenn Lagasse  *		given mounted global BE and unmounts them.
2387f169c0eaSGlenn Lagasse  * Parameters:
2388f169c0eaSGlenn Lagasse  *		ud - unmount_data_t pointer data for the global BE.
2389f169c0eaSGlenn Lagasse  * Returns:
2390f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2391f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2392f169c0eaSGlenn Lagasse  * Scope:
2393f169c0eaSGlenn Lagasse  *		Private
2394f169c0eaSGlenn Lagasse  */
2395f169c0eaSGlenn Lagasse static int
2396f169c0eaSGlenn Lagasse be_unmount_zones(be_unmount_data_t *ud)
2397f169c0eaSGlenn Lagasse {
2398f169c0eaSGlenn Lagasse 	zoneBrandList_t		*brands = NULL;
2399f169c0eaSGlenn Lagasse 	zoneList_t		zlst = NULL;
2400f169c0eaSGlenn Lagasse 	char			*zonename = NULL;
2401f169c0eaSGlenn Lagasse 	char			*zonepath = NULL;
2402f169c0eaSGlenn Lagasse 	char			alt_zonepath[MAXPATHLEN];
2403f169c0eaSGlenn Lagasse 	char			*zonepath_ds = NULL;
2404f169c0eaSGlenn Lagasse 	int			k;
2405f169c0eaSGlenn Lagasse 	int			ret = BE_SUCCESS;
2406f169c0eaSGlenn Lagasse 
2407f169c0eaSGlenn Lagasse 	z_set_zone_root(ud->altroot);
2408f169c0eaSGlenn Lagasse 
2409f169c0eaSGlenn Lagasse 	if ((brands = be_get_supported_brandlist()) == NULL) {
2410f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_zones: "
2411f169c0eaSGlenn Lagasse 		    "no supported brands\n"));
2412f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2413f169c0eaSGlenn Lagasse 	}
2414f169c0eaSGlenn Lagasse 
2415f169c0eaSGlenn Lagasse 	zlst = z_get_nonglobal_zone_list_by_brand(brands);
2416f169c0eaSGlenn Lagasse 	if (zlst == NULL) {
2417f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
2418f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2419f169c0eaSGlenn Lagasse 	}
2420f169c0eaSGlenn Lagasse 
2421f169c0eaSGlenn Lagasse 	for (k = 0; (zonename = z_zlist_get_zonename(zlst, k)) != NULL; k++) {
2422f169c0eaSGlenn Lagasse 		if (z_zlist_get_current_state(zlst, k) ==
2423f169c0eaSGlenn Lagasse 		    ZONE_STATE_INSTALLED) {
2424f169c0eaSGlenn Lagasse 			zonepath = z_zlist_get_zonepath(zlst, k);
2425f169c0eaSGlenn Lagasse 
2426f169c0eaSGlenn Lagasse 			/* Build zone's zonepath wrt the global BE altroot */
2427f169c0eaSGlenn Lagasse 			(void) snprintf(alt_zonepath, sizeof (alt_zonepath),
2428f169c0eaSGlenn Lagasse 			    "%s%s", ud->altroot, zonepath);
2429f169c0eaSGlenn Lagasse 
2430f169c0eaSGlenn Lagasse 			/*
2431f169c0eaSGlenn Lagasse 			 * Get the dataset of this zonepath.  If its not
2432f169c0eaSGlenn Lagasse 			 * a dataset, skip it.
2433f169c0eaSGlenn Lagasse 			 */
2434f169c0eaSGlenn Lagasse 			if ((zonepath_ds = be_get_ds_from_dir(alt_zonepath))
2435f169c0eaSGlenn Lagasse 			    == NULL)
2436f169c0eaSGlenn Lagasse 				continue;
2437f169c0eaSGlenn Lagasse 
2438f169c0eaSGlenn Lagasse 			/*
2439f169c0eaSGlenn Lagasse 			 * Check if this zone is supported based on the
2440f169c0eaSGlenn Lagasse 			 * dataset of its zonepath.
2441f169c0eaSGlenn Lagasse 			 */
2442f169c0eaSGlenn Lagasse 			if (!be_zone_supported(zonepath_ds)) {
2443f169c0eaSGlenn Lagasse 				free(zonepath_ds);
2444f169c0eaSGlenn Lagasse 				zonepath_ds = NULL;
2445f169c0eaSGlenn Lagasse 				continue;
2446f169c0eaSGlenn Lagasse 			}
2447f169c0eaSGlenn Lagasse 
2448f169c0eaSGlenn Lagasse 			/* Unmount this zone */
2449f169c0eaSGlenn Lagasse 			ret = be_unmount_one_zone(ud, zonename, zonepath,
2450f169c0eaSGlenn Lagasse 			    zonepath_ds);
2451f169c0eaSGlenn Lagasse 
2452f169c0eaSGlenn Lagasse 			free(zonepath_ds);
2453f169c0eaSGlenn Lagasse 			zonepath_ds = NULL;
2454f169c0eaSGlenn Lagasse 
2455f169c0eaSGlenn Lagasse 			if (ret != BE_SUCCESS) {
2456f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_unmount_zones:"
2457f169c0eaSGlenn Lagasse 				    " failed to unmount zone %s from "
2458f169c0eaSGlenn Lagasse 				    "altroot %s\n"), zonename, ud->altroot);
2459f169c0eaSGlenn Lagasse 				goto done;
2460f169c0eaSGlenn Lagasse 			}
2461f169c0eaSGlenn Lagasse 		}
2462f169c0eaSGlenn Lagasse 	}
2463f169c0eaSGlenn Lagasse 
2464f169c0eaSGlenn Lagasse done:
2465f169c0eaSGlenn Lagasse 	z_free_brand_list(brands);
2466f169c0eaSGlenn Lagasse 	z_free_zone_list(zlst);
2467f169c0eaSGlenn Lagasse 	return (ret);
2468f169c0eaSGlenn Lagasse }
2469f169c0eaSGlenn Lagasse 
2470f169c0eaSGlenn Lagasse /*
2471f169c0eaSGlenn Lagasse  * Function:	be_mount_one_zone
2472f169c0eaSGlenn Lagasse  * Description:	This function is called to mount one zone for a given
2473f169c0eaSGlenn Lagasse  *		global BE.
2474f169c0eaSGlenn Lagasse  * Parameters:
2475f169c0eaSGlenn Lagasse  *		be_zhp - zfs_handle_t pointer to the root dataset of the
2476f169c0eaSGlenn Lagasse  *			global BE
2477f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer to data for global BE
2478f169c0eaSGlenn Lagasse  *		zonename - name of zone to mount
2479f169c0eaSGlenn Lagasse  *		zonepath - zonepath of zone to mount
2480f169c0eaSGlenn Lagasse  *		zonepath_ds - dataset for the zonepath
2481f169c0eaSGlenn Lagasse  * Returns:
2482f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2483f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2484f169c0eaSGlenn Lagasse  * Scope:
2485f169c0eaSGlenn Lagasse  *		Private
2486f169c0eaSGlenn Lagasse  */
2487f169c0eaSGlenn Lagasse static int
2488f169c0eaSGlenn Lagasse be_mount_one_zone(zfs_handle_t *be_zhp, be_mount_data_t *md, char *zonename,
2489f169c0eaSGlenn Lagasse     char *zonepath, char *zonepath_ds)
2490f169c0eaSGlenn Lagasse {
2491f169c0eaSGlenn Lagasse 	be_mount_data_t	zone_md = { 0 };
2492f169c0eaSGlenn Lagasse 	zfs_handle_t	*zone_zhp = NULL;
2493f169c0eaSGlenn Lagasse 	char		zone_altroot[MAXPATHLEN];
2494f169c0eaSGlenn Lagasse 	char		zoneroot[MAXPATHLEN];
2495f169c0eaSGlenn Lagasse 	char		zoneroot_ds[MAXPATHLEN];
2496f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
2497f169c0eaSGlenn Lagasse 
2498f169c0eaSGlenn Lagasse 	/* Find the active zone root dataset for this zone for this BE */
2499f169c0eaSGlenn Lagasse 	if ((ret = be_find_active_zone_root(be_zhp, zonepath_ds, zoneroot_ds,
2500f169c0eaSGlenn Lagasse 	    sizeof (zoneroot_ds))) == BE_ERR_ZONE_NO_ACTIVE_ROOT) {
2501f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: did not "
2502f169c0eaSGlenn Lagasse 		    "find active zone root for zone %s, skipping ...\n"),
2503f169c0eaSGlenn Lagasse 		    zonename);
2504f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2505f169c0eaSGlenn Lagasse 	} else if (ret != BE_SUCCESS) {
2506f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: failed to "
2507f169c0eaSGlenn Lagasse 		    "find active zone root for zone %s\n"), zonename);
2508f169c0eaSGlenn Lagasse 		return (ret);
2509f169c0eaSGlenn Lagasse 	}
2510f169c0eaSGlenn Lagasse 
2511f169c0eaSGlenn Lagasse 	/* Get handle to active zoneroot dataset */
2512f169c0eaSGlenn Lagasse 	if ((zone_zhp = zfs_open(g_zfs, zoneroot_ds, ZFS_TYPE_FILESYSTEM))
2513f169c0eaSGlenn Lagasse 	    == NULL) {
2514f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: failed to "
2515f169c0eaSGlenn Lagasse 		    "open zone root dataset (%s): %s\n"), zoneroot_ds,
2516f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2517f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2518f169c0eaSGlenn Lagasse 	}
2519f169c0eaSGlenn Lagasse 
2520f169c0eaSGlenn Lagasse 	/* Generate string for zone's altroot path */
2521f169c0eaSGlenn Lagasse 	be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2522f169c0eaSGlenn Lagasse 	(void) strlcpy(zone_altroot, md->altroot, sizeof (zone_altroot));
2523f169c0eaSGlenn Lagasse 	(void) strlcat(zone_altroot, zoneroot, sizeof (zone_altroot));
2524f169c0eaSGlenn Lagasse 
2525f169c0eaSGlenn Lagasse 	/* Build mount_data for the zone */
2526f169c0eaSGlenn Lagasse 	zone_md.altroot = zone_altroot;
2527f169c0eaSGlenn Lagasse 	zone_md.shared_fs = md->shared_fs;
2528f169c0eaSGlenn Lagasse 	zone_md.shared_rw = md->shared_rw;
2529f169c0eaSGlenn Lagasse 
2530f169c0eaSGlenn Lagasse 	/* Mount the zone's root file system */
2531f169c0eaSGlenn Lagasse 	if ((ret = be_mount_zone_root(zone_zhp, &zone_md)) != BE_SUCCESS) {
2532f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: failed to "
2533f169c0eaSGlenn Lagasse 		    "mount zone root file system at %s\n"), zone_altroot);
2534f169c0eaSGlenn Lagasse 		goto done;
2535f169c0eaSGlenn Lagasse 	}
2536f169c0eaSGlenn Lagasse 
2537f169c0eaSGlenn Lagasse 	/* Iterate through zone's children filesystems */
2538f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zone_zhp, be_mount_callback,
2539f169c0eaSGlenn Lagasse 	    zone_altroot)) != 0) {
2540f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: failed to "
2541f169c0eaSGlenn Lagasse 		    "mount zone subordinate file systems at %s\n"),
2542f169c0eaSGlenn Lagasse 		    zone_altroot);
2543f169c0eaSGlenn Lagasse 		goto done;
2544f169c0eaSGlenn Lagasse 	}
2545f169c0eaSGlenn Lagasse 
2546f169c0eaSGlenn Lagasse 	/* TODO: Mount all shared file systems for this zone */
2547f169c0eaSGlenn Lagasse 
2548f169c0eaSGlenn Lagasse done:
2549f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zone_zhp);
2550f169c0eaSGlenn Lagasse 	return (ret);
2551f169c0eaSGlenn Lagasse }
2552f169c0eaSGlenn Lagasse 
2553f169c0eaSGlenn Lagasse /*
2554f169c0eaSGlenn Lagasse  * Function:	be_unmount_one_zone
2555f169c0eaSGlenn Lagasse  * Description:	This function unmount one zone for a give global BE.
2556f169c0eaSGlenn Lagasse  * Parameters:
2557f169c0eaSGlenn Lagasse  *		ud - be_unmount_data_t pointer to data for global BE
2558f169c0eaSGlenn Lagasse  *		zonename - name of zone to unmount
2559f169c0eaSGlenn Lagasse  *		zonepath - zonepath of the zone to unmount
2560f169c0eaSGlenn Lagasse  *		zonepath_ds - dataset for the zonepath
2561f169c0eaSGlenn Lagasse  * Returns:
2562f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2563f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2564f169c0eaSGlenn Lagasse  * Scope:
2565f169c0eaSGlenn Lagasse  *		Private
2566f169c0eaSGlenn Lagasse  */
2567f169c0eaSGlenn Lagasse static int
2568f169c0eaSGlenn Lagasse be_unmount_one_zone(be_unmount_data_t *ud, char *zonename, char *zonepath,
2569f169c0eaSGlenn Lagasse     char *zonepath_ds)
2570f169c0eaSGlenn Lagasse {
2571f169c0eaSGlenn Lagasse 	be_unmount_data_t	zone_ud = { 0 };
2572f169c0eaSGlenn Lagasse 	zfs_handle_t	*zone_zhp = NULL;
2573f169c0eaSGlenn Lagasse 	char		zone_altroot[MAXPATHLEN];
2574f169c0eaSGlenn Lagasse 	char		zoneroot[MAXPATHLEN];
2575f169c0eaSGlenn Lagasse 	char		zoneroot_ds[MAXPATHLEN];
2576f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
2577f169c0eaSGlenn Lagasse 
2578f169c0eaSGlenn Lagasse 	/* Generate string for zone's alternate root path */
2579f169c0eaSGlenn Lagasse 	be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2580f169c0eaSGlenn Lagasse 	(void) strlcpy(zone_altroot, ud->altroot, sizeof (zone_altroot));
2581f169c0eaSGlenn Lagasse 	(void) strlcat(zone_altroot, zoneroot, sizeof (zone_altroot));
2582f169c0eaSGlenn Lagasse 
2583f169c0eaSGlenn Lagasse 	/* Build be_unmount_data for zone */
2584f169c0eaSGlenn Lagasse 	zone_ud.altroot = zone_altroot;
2585f169c0eaSGlenn Lagasse 	zone_ud.force = ud->force;
2586f169c0eaSGlenn Lagasse 
2587f169c0eaSGlenn Lagasse 	/* Find the mounted zone root dataset for this zone for this BE */
2588f169c0eaSGlenn Lagasse 	if ((ret = be_find_mounted_zone_root(zone_altroot, zonepath_ds,
2589f169c0eaSGlenn Lagasse 	    zoneroot_ds, sizeof (zoneroot_ds))) == BE_ERR_NO_MOUNTED_ZONE) {
2590f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: did not "
2591f169c0eaSGlenn Lagasse 		    "find any zone root mounted for zone %s\n"), zonename);
2592f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2593f169c0eaSGlenn Lagasse 	} else if (ret != BE_SUCCESS) {
2594f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: failed to "
2595f169c0eaSGlenn Lagasse 		    "find mounted zone root for zone %s\n"), zonename);
2596f169c0eaSGlenn Lagasse 		return (ret);
2597f169c0eaSGlenn Lagasse 	}
2598f169c0eaSGlenn Lagasse 
2599f169c0eaSGlenn Lagasse 	/* Get handle to zoneroot dataset mounted for this BE */
2600f169c0eaSGlenn Lagasse 	if ((zone_zhp = zfs_open(g_zfs, zoneroot_ds, ZFS_TYPE_FILESYSTEM))
2601f169c0eaSGlenn Lagasse 	    == NULL) {
2602f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: failed to "
2603f169c0eaSGlenn Lagasse 		    "open mounted zone root dataset (%s): %s\n"), zoneroot_ds,
2604f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2605f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2606f169c0eaSGlenn Lagasse 	}
2607f169c0eaSGlenn Lagasse 
2608f169c0eaSGlenn Lagasse 	/* TODO: Unmount all shared file systems for this zone */
2609f169c0eaSGlenn Lagasse 
2610f169c0eaSGlenn Lagasse 	/* Iterate through zone's children filesystems and unmount them */
2611f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zone_zhp, be_unmount_callback,
2612f169c0eaSGlenn Lagasse 	    &zone_ud)) != 0) {
2613f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: failed to "
2614f169c0eaSGlenn Lagasse 		    "unmount zone subordinate file systems at %s\n"),
2615f169c0eaSGlenn Lagasse 		    zone_altroot);
2616f169c0eaSGlenn Lagasse 		goto done;
2617f169c0eaSGlenn Lagasse 	}
2618f169c0eaSGlenn Lagasse 
2619f169c0eaSGlenn Lagasse 	/* Unmount the zone's root filesystem */
2620f169c0eaSGlenn Lagasse 	if ((ret = be_unmount_zone_root(zone_zhp, &zone_ud)) != BE_SUCCESS) {
2621f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: failed to "
2622f169c0eaSGlenn Lagasse 		    "unmount zone root file system at %s\n"), zone_altroot);
2623f169c0eaSGlenn Lagasse 		goto done;
2624f169c0eaSGlenn Lagasse 	}
2625f169c0eaSGlenn Lagasse 
2626f169c0eaSGlenn Lagasse done:
2627f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zone_zhp);
2628f169c0eaSGlenn Lagasse 	return (ret);
2629f169c0eaSGlenn Lagasse }
2630f169c0eaSGlenn Lagasse 
2631f169c0eaSGlenn Lagasse /*
2632f169c0eaSGlenn Lagasse  * Function:	be_get_ds_from_dir_callback
2633f169c0eaSGlenn Lagasse  * Description:	This is a callback function used to iterate all datasets
2634f169c0eaSGlenn Lagasse  *		to find the one that is currently mounted at the directory
2635f169c0eaSGlenn Lagasse  *		being searched for.  If matched, the name of the dataset is
2636f169c0eaSGlenn Lagasse  *		returned in heap storage, so the caller is responsible for
2637f169c0eaSGlenn Lagasse  *		freeing it.
2638f169c0eaSGlenn Lagasse  * Parameters:
2639f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current dataset being processed.
2640f169c0eaSGlenn Lagasse  *		data - dir_data_t pointer providing name of directory being
2641f169c0eaSGlenn Lagasse  *			searched for.
2642f169c0eaSGlenn Lagasse  * Returns:
2643f169c0eaSGlenn Lagasse  *		1 - This dataset is mounted at directory being searched for.
2644f169c0eaSGlenn Lagasse  *		0 - This dataset is not mounted at directory being searched for.
2645f169c0eaSGlenn Lagasse  * Scope:
2646f169c0eaSGlenn Lagasse  *		Private
2647f169c0eaSGlenn Lagasse  */
2648f169c0eaSGlenn Lagasse static int
2649f169c0eaSGlenn Lagasse be_get_ds_from_dir_callback(zfs_handle_t *zhp, void *data)
2650f169c0eaSGlenn Lagasse {
2651f169c0eaSGlenn Lagasse 	dir_data_t	*dd = data;
2652f169c0eaSGlenn Lagasse 	char		*mp = NULL;
2653f169c0eaSGlenn Lagasse 	int		zret = 0;
2654f169c0eaSGlenn Lagasse 
2655f169c0eaSGlenn Lagasse 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2656f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2657f169c0eaSGlenn Lagasse 		return (0);
2658f169c0eaSGlenn Lagasse 	}
2659f169c0eaSGlenn Lagasse 
2660f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &mp) && mp != NULL &&
2661f169c0eaSGlenn Lagasse 	    strcmp(mp, dd->dir) == 0) {
2662f169c0eaSGlenn Lagasse 		if ((dd->ds = strdup(zfs_get_name(zhp))) == NULL) {
2663f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_ds_from_dir_callback: "
2664f169c0eaSGlenn Lagasse 			    "memory allocation failed\n"));
2665f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2666f169c0eaSGlenn Lagasse 			return (0);
2667f169c0eaSGlenn Lagasse 		}
2668f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2669f169c0eaSGlenn Lagasse 		return (1);
2670f169c0eaSGlenn Lagasse 	}
2671f169c0eaSGlenn Lagasse 
2672f169c0eaSGlenn Lagasse 	zret = zfs_iter_filesystems(zhp, be_get_ds_from_dir_callback, dd);
2673f169c0eaSGlenn Lagasse 
2674f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2675f169c0eaSGlenn Lagasse 
2676f169c0eaSGlenn Lagasse 	return (zret);
2677f169c0eaSGlenn Lagasse }
26783a876192SAlexander Pyhalov 
26793a876192SAlexander Pyhalov /*
26803a876192SAlexander Pyhalov  * Function:    mount_zfs
26813a876192SAlexander Pyhalov  * Description: This is a function to mount zfs filesystem to alternative
26823a876192SAlexander Pyhalov  *              root without changing zfs mountpoint property. Logic is
26833a876192SAlexander Pyhalov  *              similar to zfs_mount.
26843a876192SAlexander Pyhalov  * Parameters:
26853a876192SAlexander Pyhalov  *              zhp - zfs_handle_t pointer to current dataset being processed.
26863a876192SAlexander Pyhalov  *              altroot - char pointer to current alternative root.
26873a876192SAlexander Pyhalov  * Returns:
26883a876192SAlexander Pyhalov  *              BE_SUCCESS - Success
26893a876192SAlexander Pyhalov  *              be_errno_t - Failure
26903a876192SAlexander Pyhalov  * Scope:
26913a876192SAlexander Pyhalov  *              Private
26923a876192SAlexander Pyhalov  */
26933a876192SAlexander Pyhalov static int
26943a876192SAlexander Pyhalov mount_zfs(zfs_handle_t *zhp, char *altroot)
26953a876192SAlexander Pyhalov {
26963a876192SAlexander Pyhalov 	int	flags = 0;
26973a876192SAlexander Pyhalov 	char	mountpoint[MAXPATHLEN];
26983a876192SAlexander Pyhalov 	char	real_mountpoint[MAXPATHLEN];
26993a876192SAlexander Pyhalov 	char	source[MAXNAMELEN];
2700*19f5167cSToomas Soome 	char	optstr[MAX_MNTOPT_STR];
27013a876192SAlexander Pyhalov 	zprop_source_t	sourcetype;
27023a876192SAlexander Pyhalov 	struct stat	buf;
27033a876192SAlexander Pyhalov 
2704*19f5167cSToomas Soome 	optstr[0] = '\0';
2705*19f5167cSToomas Soome 
27063a876192SAlexander Pyhalov 	/* Get dataset's mountpoint and source values */
27073a876192SAlexander Pyhalov 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
27083a876192SAlexander Pyhalov 	    sizeof (mountpoint), &sourcetype, source, sizeof (source),
27093a876192SAlexander Pyhalov 	    B_FALSE) != 0) {
27103a876192SAlexander Pyhalov 		be_print_err(gettext("mount_zfs: "
27113a876192SAlexander Pyhalov 		    "failed to get mountpoint and sourcetype for %s\n"),
27123a876192SAlexander Pyhalov 		    zfs_get_name(zhp));
27133a876192SAlexander Pyhalov 		ZFS_CLOSE(zhp);
27143a876192SAlexander Pyhalov 		return (BE_ERR_ZFS);
27153a876192SAlexander Pyhalov 	}
27163a876192SAlexander Pyhalov 
27173a876192SAlexander Pyhalov 	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0 ||
27183a876192SAlexander Pyhalov 	    strcmp(mountpoint, "/") == 0) {
27193a876192SAlexander Pyhalov 	/*
27203a876192SAlexander Pyhalov 	 * We are called  only from be_mount_root or be_mount_callback
27213a876192SAlexander Pyhalov 	 * when mountpoint != LEGACY
27223a876192SAlexander Pyhalov 	 */
27233a876192SAlexander Pyhalov 		mountpoint[0] = '\0';
27243a876192SAlexander Pyhalov 	}
27253a876192SAlexander Pyhalov 
27263a876192SAlexander Pyhalov 	(void) snprintf(real_mountpoint, MAXPATHLEN, "%s%s", altroot,
27273a876192SAlexander Pyhalov 	    mountpoint);
27283a876192SAlexander Pyhalov 
27293a876192SAlexander Pyhalov 	if (zpool_get_prop_int(zfs_get_pool_handle(zhp), ZPOOL_PROP_READONLY,
27303a876192SAlexander Pyhalov 	    NULL))
27313a876192SAlexander Pyhalov 		flags |= MS_RDONLY;
27323a876192SAlexander Pyhalov 
27333a876192SAlexander Pyhalov 	/* Create the directory if it doesn't already exist */
27343a876192SAlexander Pyhalov 	if (lstat(real_mountpoint, &buf) != 0) {
27353a876192SAlexander Pyhalov 		if (mkdirp(real_mountpoint, 0755) != 0) {
27363a876192SAlexander Pyhalov 			be_print_err(gettext("mount_zfs: "
27373a876192SAlexander Pyhalov 			    "failed to create mountpoint for %s\n"),
27383a876192SAlexander Pyhalov 			    zfs_get_name(zhp));
27393a876192SAlexander Pyhalov 			ZFS_CLOSE(zhp);
27403a876192SAlexander Pyhalov 			return (BE_ERR_ZFS);
27413a876192SAlexander Pyhalov 		}
27423a876192SAlexander Pyhalov 	}
27433a876192SAlexander Pyhalov 
2744*19f5167cSToomas Soome 	if (mount(zfs_get_name(zhp), real_mountpoint, MS_OPTIONSTR | flags,
2745*19f5167cSToomas Soome 	    MNTTYPE_ZFS, NULL, 0, optstr, sizeof (optstr))) {
27463a876192SAlexander Pyhalov 		be_print_err(gettext("mount_zfs: failed to "
27473a876192SAlexander Pyhalov 		    "mount dataset %s at %s\n"), zfs_get_name(zhp),
27483a876192SAlexander Pyhalov 		    real_mountpoint);
27493a876192SAlexander Pyhalov 		return (BE_ERR_ZFS);
27503a876192SAlexander Pyhalov 	}
27513a876192SAlexander Pyhalov 
27523a876192SAlexander Pyhalov 	return (BE_SUCCESS);
27533a876192SAlexander Pyhalov }
2754