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
be_mount(nvlist_t * be_attrs)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
be_unmount(nvlist_t * be_attrs)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
_be_mount(char * be_name,char ** altroot,int flags)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
_be_unmount(char * be_name,int flags)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
be_mount_zone_root(zfs_handle_t * zhp,be_mount_data_t * md)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 	/*
610