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