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