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