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