Print this page
patch tsoome-feedback
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/zoneadm/zfs.c
+++ new/usr/src/cmd/zoneadm/zfs.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]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2012 by Delphix. All rights reserved.
25 25 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 26 */
27 27
28 28 /*
29 29 * This file contains the functions used to support the ZFS integration
30 30 * with zones. This includes validation (e.g. zonecfg dataset), cloning,
31 31 * file system creation and destruction.
32 32 */
33 33
34 34 #include <stdio.h>
35 35 #include <errno.h>
36 36 #include <unistd.h>
37 37 #include <string.h>
38 38 #include <locale.h>
39 39 #include <libintl.h>
40 40 #include <sys/stat.h>
41 41 #include <sys/statvfs.h>
42 42 #include <libgen.h>
43 43 #include <libzonecfg.h>
44 44 #include <sys/mnttab.h>
45 45 #include <libzfs.h>
46 46 #include <sys/mntent.h>
47 47 #include <values.h>
48 48 #include <strings.h>
49 49 #include <assert.h>
50 50
51 51 #include "zoneadm.h"
52 52
53 53 libzfs_handle_t *g_zfs;
54 54
55 55 typedef struct zfs_mount_data {
56 56 char *match_name;
57 57 zfs_handle_t *match_handle;
58 58 } zfs_mount_data_t;
59 59
60 60 typedef struct zfs_snapshot_data {
61 61 char *match_name; /* zonename@SUNWzone */
62 62 int len; /* strlen of match_name */
63 63 int max; /* highest digit appended to snap name */
64 64 int num; /* number of snapshots to rename */
65 65 int cntr; /* counter for renaming snapshots */
66 66 } zfs_snapshot_data_t;
67 67
68 68 typedef struct clone_data {
69 69 zfs_handle_t *clone_zhp; /* clone dataset to promote */
70 70 time_t origin_creation; /* snapshot creation time of clone */
71 71 const char *snapshot; /* snapshot of dataset being demoted */
72 72 } clone_data_t;
73 73
74 74 /*
75 75 * A ZFS file system iterator call-back function which returns the
76 76 * zfs_handle_t for a ZFS file system on the specified mount point.
77 77 */
78 78 static int
79 79 match_mountpoint(zfs_handle_t *zhp, void *data)
80 80 {
81 81 int res;
82 82 zfs_mount_data_t *cbp;
83 83 char mp[ZFS_MAXPROPLEN];
84 84
85 85 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
86 86 zfs_close(zhp);
87 87 return (0);
88 88 }
89 89
90 90 /* First check if the dataset is mounted. */
91 91 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mp, sizeof (mp), NULL, NULL,
92 92 0, B_FALSE) != 0 || strcmp(mp, "no") == 0) {
93 93 zfs_close(zhp);
94 94 return (0);
95 95 }
96 96
97 97 /* Now check mount point. */
98 98 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
99 99 0, B_FALSE) != 0) {
100 100 zfs_close(zhp);
101 101 return (0);
102 102 }
103 103
104 104 cbp = (zfs_mount_data_t *)data;
105 105
106 106 if (strcmp(mp, "legacy") == 0) {
107 107 /* If legacy, must look in mnttab for mountpoint. */
108 108 FILE *fp;
109 109 struct mnttab entry;
110 110 const char *nm;
111 111
112 112 nm = zfs_get_name(zhp);
113 113 if ((fp = fopen(MNTTAB, "r")) == NULL) {
114 114 zfs_close(zhp);
115 115 return (0);
116 116 }
117 117
118 118 while (getmntent(fp, &entry) == 0) {
119 119 if (strcmp(nm, entry.mnt_special) == 0) {
120 120 if (strcmp(entry.mnt_mountp, cbp->match_name)
121 121 == 0) {
122 122 (void) fclose(fp);
123 123 cbp->match_handle = zhp;
124 124 return (1);
125 125 }
126 126 break;
127 127 }
128 128 }
129 129 (void) fclose(fp);
130 130
131 131 } else if (strcmp(mp, cbp->match_name) == 0) {
132 132 cbp->match_handle = zhp;
133 133 return (1);
134 134 }
135 135
136 136 /* Iterate over any nested datasets. */
137 137 res = zfs_iter_filesystems(zhp, match_mountpoint, data);
138 138 zfs_close(zhp);
139 139 return (res);
140 140 }
141 141
142 142 /*
143 143 * Get ZFS handle for the specified mount point.
144 144 */
145 145 static zfs_handle_t *
146 146 mount2zhandle(char *mountpoint)
147 147 {
148 148 zfs_mount_data_t cb;
149 149
150 150 cb.match_name = mountpoint;
151 151 cb.match_handle = NULL;
152 152 (void) zfs_iter_root(g_zfs, match_mountpoint, &cb);
153 153 return (cb.match_handle);
154 154 }
155 155
156 156 /*
157 157 * Check if there is already a file system (zfs or any other type) mounted on
158 158 * path.
159 159 */
160 160 static boolean_t
161 161 is_mountpnt(char *path)
162 162 {
163 163 FILE *fp;
164 164 struct mnttab entry;
165 165
166 166 if ((fp = fopen(MNTTAB, "r")) == NULL)
167 167 return (B_FALSE);
168 168
169 169 while (getmntent(fp, &entry) == 0) {
170 170 if (strcmp(path, entry.mnt_mountp) == 0) {
171 171 (void) fclose(fp);
172 172 return (B_TRUE);
173 173 }
174 174 }
175 175
176 176 (void) fclose(fp);
177 177 return (B_FALSE);
178 178 }
179 179
180 180 /*
181 181 * Run the brand's pre-snapshot hook before we take a ZFS snapshot of the zone.
182 182 */
183 183 static int
184 184 pre_snapshot(char *presnapbuf)
185 185 {
186 186 int status;
187 187
188 188 /* No brand-specific handler */
189 189 if (presnapbuf[0] == '\0')
190 190 return (Z_OK);
191 191
192 192 /* Run the hook */
193 193 status = do_subproc(presnapbuf);
194 194 if ((status = subproc_status(gettext("brand-specific presnapshot"),
195 195 status, B_FALSE)) != ZONE_SUBPROC_OK)
196 196 return (Z_ERR);
197 197
198 198 return (Z_OK);
199 199 }
200 200
201 201 /*
202 202 * Run the brand's post-snapshot hook after we take a ZFS snapshot of the zone.
203 203 */
204 204 static int
205 205 post_snapshot(char *postsnapbuf)
206 206 {
207 207 int status;
208 208
209 209 /* No brand-specific handler */
210 210 if (postsnapbuf[0] == '\0')
211 211 return (Z_OK);
212 212
213 213 /* Run the hook */
214 214 status = do_subproc(postsnapbuf);
215 215 if ((status = subproc_status(gettext("brand-specific postsnapshot"),
216 216 status, B_FALSE)) != ZONE_SUBPROC_OK)
217 217 return (Z_ERR);
218 218
219 219 return (Z_OK);
220 220 }
221 221
222 222 /*
223 223 * This is a ZFS snapshot iterator call-back function which returns the
224 224 * highest number of SUNWzone snapshots that have been taken.
225 225 */
226 226 static int
227 227 get_snap_max(zfs_handle_t *zhp, void *data)
228 228 {
229 229 int res;
230 230 zfs_snapshot_data_t *cbp;
231 231
232 232 if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
233 233 zfs_close(zhp);
234 234 return (0);
235 235 }
236 236
237 237 cbp = (zfs_snapshot_data_t *)data;
238 238
239 239 if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) {
240 240 char *nump;
241 241 int num;
242 242
243 243 cbp->num++;
244 244 nump = (char *)(zfs_get_name(zhp) + cbp->len);
245 245 num = atoi(nump);
246 246 if (num > cbp->max)
247 247 cbp->max = num;
248 248 }
249 249
250 250 res = zfs_iter_snapshots(zhp, get_snap_max, data);
251 251 zfs_close(zhp);
252 252 return (res);
253 253 }
254 254
255 255 /*
256 256 * Take a ZFS snapshot to be used for cloning the zone.
257 257 */
258 258 static int
259 259 take_snapshot(zfs_handle_t *zhp, char *snapshot_name, int snap_size,
260 260 char *presnapbuf, char *postsnapbuf)
261 261 {
262 262 int res;
263 263 char template[ZFS_MAXNAMELEN];
264 264 zfs_snapshot_data_t cb;
265 265
266 266 /*
267 267 * First we need to figure out the next available name for the
268 268 * zone snapshot. Look through the list of zones snapshots for
269 269 * this file system to determine the maximum snapshot name.
270 270 */
271 271 if (snprintf(template, sizeof (template), "%s@SUNWzone",
272 272 zfs_get_name(zhp)) >= sizeof (template))
273 273 return (Z_ERR);
274 274
275 275 cb.match_name = template;
276 276 cb.len = strlen(template);
277 277 cb.max = 0;
278 278
279 279 if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0)
280 280 return (Z_ERR);
281 281
282 282 cb.max++;
283 283
284 284 if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d",
285 285 zfs_get_name(zhp), cb.max) >= snap_size)
286 286 return (Z_ERR);
287 287
288 288 if (pre_snapshot(presnapbuf) != Z_OK)
289 289 return (Z_ERR);
290 290 res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE, NULL);
291 291 if (post_snapshot(postsnapbuf) != Z_OK)
292 292 return (Z_ERR);
293 293
294 294 if (res != 0)
295 295 return (Z_ERR);
296 296 return (Z_OK);
297 297 }
298 298
299 299 /*
300 300 * We are using an explicit snapshot from some earlier point in time so
301 301 * we need to validate it. Run the brand specific hook.
302 302 */
303 303 static int
304 304 validate_snapshot(char *snapshot_name, char *snap_path, char *validsnapbuf)
305 305 {
306 306 int status;
307 307 char cmdbuf[MAXPATHLEN];
308 308
309 309 /* No brand-specific handler */
310 310 if (validsnapbuf[0] == '\0')
311 311 return (Z_OK);
312 312
313 313 /* pass args - snapshot_name & snap_path */
314 314 if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %s %s", validsnapbuf,
315 315 snapshot_name, snap_path) >= sizeof (cmdbuf)) {
316 316 zerror("Command line too long");
317 317 return (Z_ERR);
318 318 }
319 319
320 320 /* Run the hook */
321 321 status = do_subproc(cmdbuf);
322 322 if ((status = subproc_status(gettext("brand-specific validatesnapshot"),
323 323 status, B_FALSE)) != ZONE_SUBPROC_OK)
324 324 return (Z_ERR);
325 325
326 326 return (Z_OK);
327 327 }
328 328
329 329 /*
330 330 * Remove the sw inventory file from inside this zonepath that we picked up out
331 331 * of the snapshot.
332 332 */
333 333 static int
334 334 clean_out_clone()
335 335 {
336 336 int err;
337 337 zone_dochandle_t handle;
338 338
339 339 if ((handle = zonecfg_init_handle()) == NULL) {
340 340 zperror(cmd_to_str(CMD_CLONE), B_TRUE);
341 341 return (Z_ERR);
342 342 }
343 343
344 344 if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
345 345 errno = err;
346 346 zperror(cmd_to_str(CMD_CLONE), B_TRUE);
347 347 zonecfg_fini_handle(handle);
348 348 return (Z_ERR);
349 349 }
350 350
351 351 zonecfg_rm_detached(handle, B_FALSE);
352 352 zonecfg_fini_handle(handle);
353 353
354 354 return (Z_OK);
355 355 }
356 356
357 357 /*
358 358 * Make a ZFS clone on zonepath from snapshot_name.
359 359 */
360 360 static int
361 361 clone_snap(char *snapshot_name, char *zonepath)
362 362 {
363 363 int res = Z_OK;
364 364 int err;
365 365 zfs_handle_t *zhp;
366 366 zfs_handle_t *clone;
367 367 nvlist_t *props = NULL;
368 368
369 369 if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL)
370 370 return (Z_NO_ENTRY);
371 371
372 372 (void) printf(gettext("Cloning snapshot %s\n"), snapshot_name);
373 373
↓ open down ↓ |
373 lines elided |
↑ open up ↑ |
374 374 /*
375 375 * We turn off zfs SHARENFS and SHARESMB properties on the
376 376 * zoneroot dataset in order to prevent the GZ from sharing
377 377 * NGZ data by accident.
378 378 */
379 379 if ((nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) ||
380 380 (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
381 381 "off") != 0) ||
382 382 (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARESMB),
383 383 "off") != 0)) {
384 - if (props != NULL)
385 - nvlist_free(props);
384 + nvlist_free(props);
386 385 (void) fprintf(stderr, gettext("could not create ZFS clone "
387 386 "%s: out of memory\n"), zonepath);
388 387 return (Z_ERR);
389 388 }
390 389
391 390 err = zfs_clone(zhp, zonepath, props);
392 391 zfs_close(zhp);
393 392
394 393 nvlist_free(props);
395 394
396 395 if (err != 0)
397 396 return (Z_ERR);
398 397
399 398 /* create the mountpoint if necessary */
400 399 if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_DATASET)) == NULL)
401 400 return (Z_ERR);
402 401
403 402 /*
404 403 * The clone has been created so we need to print a diagnostic
405 404 * message if one of the following steps fails for some reason.
406 405 */
407 406 if (zfs_mount(clone, NULL, 0) != 0) {
408 407 (void) fprintf(stderr, gettext("could not mount ZFS clone "
409 408 "%s\n"), zfs_get_name(clone));
410 409 res = Z_ERR;
411 410
412 411 } else if (clean_out_clone() != Z_OK) {
413 412 (void) fprintf(stderr, gettext("could not remove the "
414 413 "software inventory from ZFS clone %s\n"),
415 414 zfs_get_name(clone));
416 415 res = Z_ERR;
417 416 }
418 417
419 418 zfs_close(clone);
420 419 return (res);
421 420 }
422 421
423 422 /*
424 423 * This function takes a zonepath and attempts to determine what the ZFS
425 424 * file system name (not mountpoint) should be for that path. We do not
426 425 * assume that zonepath is an existing directory or ZFS fs since we use
427 426 * this function as part of the process of creating a new ZFS fs or clone.
428 427 *
429 428 * The way this works is that we look at the parent directory of the zonepath
430 429 * to see if it is a ZFS fs. If it is, we get the name of that ZFS fs and
431 430 * append the last component of the zonepath to generate the ZFS name for the
432 431 * zonepath. This matches the algorithm that ZFS uses for automatically
433 432 * mounting a new fs after it is created.
434 433 *
435 434 * Although a ZFS fs can be mounted anywhere, we don't worry about handling
436 435 * all of the complexity that a user could possibly configure with arbitrary
437 436 * mounts since there is no way to generate a ZFS name from a random path in
438 437 * the file system. We only try to handle the automatic mounts that ZFS does
439 438 * for each file system. ZFS restricts this so that a new fs must be created
440 439 * in an existing parent ZFS fs. It then automatically mounts the new fs
441 440 * directly under the mountpoint for the parent fs using the last component
442 441 * of the name as the mountpoint directory.
443 442 *
444 443 * For example:
445 444 * Name Mountpoint
446 445 * space/eng/dev/test/zone1 /project1/eng/dev/test/zone1
447 446 *
448 447 * Return Z_OK if the path mapped to a ZFS file system name, otherwise return
449 448 * Z_ERR.
450 449 */
451 450 static int
452 451 path2name(char *zonepath, char *zfs_name, int len)
453 452 {
454 453 int res;
455 454 char *bnm, *dnm, *dname, *bname;
456 455 zfs_handle_t *zhp;
457 456 struct stat stbuf;
458 457
459 458 /*
460 459 * We need two tmp strings to handle paths directly in / (e.g. /foo)
461 460 * since dirname will overwrite the first char after "/" in this case.
462 461 */
463 462 if ((bnm = strdup(zonepath)) == NULL)
464 463 return (Z_ERR);
465 464
466 465 if ((dnm = strdup(zonepath)) == NULL) {
467 466 free(bnm);
468 467 return (Z_ERR);
469 468 }
470 469
471 470 bname = basename(bnm);
472 471 dname = dirname(dnm);
473 472
474 473 /*
475 474 * This is a quick test to save iterating over all of the zfs datasets
476 475 * on the system (which can be a lot). If the parent dir is not in a
477 476 * ZFS fs, then we're done.
478 477 */
479 478 if (stat(dname, &stbuf) != 0 || !S_ISDIR(stbuf.st_mode) ||
480 479 strcmp(stbuf.st_fstype, MNTTYPE_ZFS) != 0) {
481 480 free(bnm);
482 481 free(dnm);
483 482 return (Z_ERR);
484 483 }
485 484
486 485 /* See if the parent directory is its own ZFS dataset. */
487 486 if ((zhp = mount2zhandle(dname)) == NULL) {
488 487 /*
489 488 * The parent is not a ZFS dataset so we can't automatically
490 489 * create a dataset on the given path.
491 490 */
492 491 free(bnm);
493 492 free(dnm);
494 493 return (Z_ERR);
495 494 }
496 495
497 496 res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), bname);
498 497
499 498 free(bnm);
500 499 free(dnm);
501 500 zfs_close(zhp);
502 501 if (res >= len)
503 502 return (Z_ERR);
504 503
505 504 return (Z_OK);
506 505 }
507 506
508 507 /*
509 508 * A ZFS file system iterator call-back function used to determine if the
510 509 * file system has dependents (snapshots & clones).
511 510 */
512 511 /* ARGSUSED */
513 512 static int
514 513 has_dependent(zfs_handle_t *zhp, void *data)
515 514 {
516 515 zfs_close(zhp);
517 516 return (1);
518 517 }
519 518
520 519 /*
521 520 * Given a snapshot name, get the file system path where the snapshot lives.
522 521 * A snapshot name is of the form fs_name@snap_name. For example, snapshot
523 522 * pl/zones/z1@SUNWzone1 would have a path of
524 523 * /pl/zones/z1/.zfs/snapshot/SUNWzone1.
525 524 */
526 525 static int
527 526 snap2path(char *snap_name, char *path, int len)
528 527 {
529 528 char *p;
530 529 zfs_handle_t *zhp;
531 530 char mp[ZFS_MAXPROPLEN];
532 531
533 532 if ((p = strrchr(snap_name, '@')) == NULL)
534 533 return (Z_ERR);
535 534
536 535 /* Get the file system name from the snap_name. */
537 536 *p = '\0';
538 537 zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_DATASET);
539 538 *p = '@';
540 539 if (zhp == NULL)
541 540 return (Z_ERR);
542 541
543 542 /* Get the file system mount point. */
544 543 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
545 544 0, B_FALSE) != 0) {
546 545 zfs_close(zhp);
547 546 return (Z_ERR);
548 547 }
549 548 zfs_close(zhp);
550 549
551 550 p++;
552 551 if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len)
553 552 return (Z_ERR);
554 553
555 554 return (Z_OK);
556 555 }
557 556
558 557 /*
559 558 * This callback function is used to iterate through a snapshot's dependencies
560 559 * to find a filesystem that is a direct clone of the snapshot being iterated.
561 560 */
562 561 static int
563 562 get_direct_clone(zfs_handle_t *zhp, void *data)
564 563 {
565 564 clone_data_t *cd = data;
566 565 char origin[ZFS_MAXNAMELEN];
567 566 char ds_path[ZFS_MAXNAMELEN];
568 567
569 568 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
570 569 zfs_close(zhp);
571 570 return (0);
572 571 }
573 572
574 573 (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
575 574
576 575 /* Make sure this is a direct clone of the snapshot we're iterating. */
577 576 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
578 577 NULL, 0, B_FALSE) != 0 || strcmp(origin, cd->snapshot) != 0) {
579 578 zfs_close(zhp);
580 579 return (0);
581 580 }
582 581
583 582 if (cd->clone_zhp != NULL)
584 583 zfs_close(cd->clone_zhp);
585 584
586 585 cd->clone_zhp = zhp;
587 586 return (1);
588 587 }
589 588
590 589 /*
591 590 * A ZFS file system iterator call-back function used to determine the clone
592 591 * to promote. This function finds the youngest (i.e. last one taken) snapshot
593 592 * that has a clone. If found, it returns a reference to that clone in the
594 593 * callback data.
595 594 */
596 595 static int
597 596 find_clone(zfs_handle_t *zhp, void *data)
598 597 {
599 598 clone_data_t *cd = data;
600 599 time_t snap_creation;
601 600 int zret = 0;
602 601
603 602 /* If snapshot has no clones, skip it */
604 603 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
605 604 zfs_close(zhp);
606 605 return (0);
607 606 }
608 607
609 608 cd->snapshot = zfs_get_name(zhp);
610 609
611 610 /* Get the creation time of this snapshot */
612 611 snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
613 612
614 613 /*
615 614 * If this snapshot's creation time is greater than (i.e. younger than)
616 615 * the current youngest snapshot found, iterate this snapshot to
617 616 * get the right clone.
618 617 */
619 618 if (snap_creation >= cd->origin_creation) {
620 619 /*
621 620 * Iterate the dependents of this snapshot to find a clone
622 621 * that's a direct dependent.
623 622 */
624 623 if ((zret = zfs_iter_dependents(zhp, B_FALSE, get_direct_clone,
625 624 cd)) == -1) {
626 625 zfs_close(zhp);
627 626 return (1);
628 627 } else if (zret == 1) {
629 628 /*
630 629 * Found a clone, update the origin_creation time
631 630 * in the callback data.
632 631 */
633 632 cd->origin_creation = snap_creation;
634 633 }
635 634 }
636 635
637 636 zfs_close(zhp);
638 637 return (0);
639 638 }
640 639
641 640 /*
642 641 * A ZFS file system iterator call-back function used to remove standalone
643 642 * snapshots.
644 643 */
645 644 /* ARGSUSED */
646 645 static int
647 646 rm_snap(zfs_handle_t *zhp, void *data)
648 647 {
649 648 /* If snapshot has clones, something is wrong */
650 649 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
651 650 zfs_close(zhp);
652 651 return (1);
653 652 }
654 653
655 654 if (zfs_unmount(zhp, NULL, 0) == 0) {
656 655 (void) zfs_destroy(zhp, B_FALSE);
657 656 }
658 657
659 658 zfs_close(zhp);
660 659 return (0);
661 660 }
662 661
663 662 /*
664 663 * A ZFS snapshot iterator call-back function which renames snapshots.
665 664 */
666 665 static int
667 666 rename_snap(zfs_handle_t *zhp, void *data)
668 667 {
669 668 int res;
670 669 zfs_snapshot_data_t *cbp;
671 670 char template[ZFS_MAXNAMELEN];
672 671
673 672 cbp = (zfs_snapshot_data_t *)data;
674 673
675 674 /*
676 675 * When renaming snapshots with the iterator, the iterator can see
677 676 * the same snapshot after we've renamed up in the namespace. To
678 677 * prevent this we check the count for the number of snapshots we have
679 678 * to rename and stop at that point.
680 679 */
681 680 if (cbp->cntr >= cbp->num) {
682 681 zfs_close(zhp);
683 682 return (0);
684 683 }
685 684
686 685 if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
687 686 zfs_close(zhp);
688 687 return (0);
689 688 }
690 689
691 690 /* Only rename the snapshots we automatically generate when we clone. */
692 691 if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) != 0) {
693 692 zfs_close(zhp);
694 693 return (0);
695 694 }
696 695
697 696 (void) snprintf(template, sizeof (template), "%s%d", cbp->match_name,
698 697 cbp->max++);
699 698
700 699 res = (zfs_rename(zhp, template, B_FALSE, B_FALSE) != 0);
701 700 if (res != 0)
702 701 (void) fprintf(stderr, gettext("failed to rename snapshot %s "
703 702 "to %s: %s\n"), zfs_get_name(zhp), template,
704 703 libzfs_error_description(g_zfs));
705 704
706 705 cbp->cntr++;
707 706
708 707 zfs_close(zhp);
709 708 return (res);
710 709 }
711 710
712 711 /*
713 712 * Rename the source dataset's snapshots that are automatically generated when
714 713 * we clone a zone so that there won't be a name collision when we promote the
715 714 * cloned dataset. Once the snapshots have been renamed, then promote the
716 715 * clone.
717 716 *
718 717 * The snapshot rename process gets the highest number on the snapshot names
719 718 * (the format is zonename@SUNWzoneXX where XX are digits) on both the source
720 719 * and clone datasets, then renames the source dataset snapshots starting at
721 720 * the next number.
722 721 */
723 722 static int
724 723 promote_clone(zfs_handle_t *src_zhp, zfs_handle_t *cln_zhp)
725 724 {
726 725 zfs_snapshot_data_t sd;
727 726 char nm[ZFS_MAXNAMELEN];
728 727 char template[ZFS_MAXNAMELEN];
729 728
730 729 (void) strlcpy(nm, zfs_get_name(cln_zhp), sizeof (nm));
731 730 /*
732 731 * Start by getting the clone's snapshot max which we use
733 732 * during the rename of the original dataset's snapshots.
734 733 */
735 734 (void) snprintf(template, sizeof (template), "%s@SUNWzone", nm);
736 735 sd.match_name = template;
737 736 sd.len = strlen(template);
738 737 sd.max = 0;
739 738
740 739 if (zfs_iter_snapshots(cln_zhp, get_snap_max, &sd) != 0)
741 740 return (Z_ERR);
742 741
743 742 /*
744 743 * Now make sure the source's snapshot max is at least as high as
745 744 * the clone's snapshot max.
746 745 */
747 746 (void) snprintf(template, sizeof (template), "%s@SUNWzone",
748 747 zfs_get_name(src_zhp));
749 748 sd.match_name = template;
750 749 sd.len = strlen(template);
751 750 sd.num = 0;
752 751
753 752 if (zfs_iter_snapshots(src_zhp, get_snap_max, &sd) != 0)
754 753 return (Z_ERR);
755 754
756 755 /*
757 756 * Now rename the source dataset's snapshots so there's no
758 757 * conflict when we promote the clone.
759 758 */
760 759 sd.max++;
761 760 sd.cntr = 0;
762 761 if (zfs_iter_snapshots(src_zhp, rename_snap, &sd) != 0)
763 762 return (Z_ERR);
764 763
765 764 /* close and reopen the clone dataset to get the latest info */
766 765 zfs_close(cln_zhp);
767 766 if ((cln_zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
768 767 return (Z_ERR);
769 768
770 769 if (zfs_promote(cln_zhp) != 0) {
771 770 (void) fprintf(stderr, gettext("failed to promote %s: %s\n"),
772 771 nm, libzfs_error_description(g_zfs));
773 772 return (Z_ERR);
774 773 }
775 774
776 775 zfs_close(cln_zhp);
777 776 return (Z_OK);
778 777 }
779 778
780 779 /*
781 780 * Promote the youngest clone. That clone will then become the origin of all
782 781 * of the other clones that were hanging off of the source dataset.
783 782 */
784 783 int
785 784 promote_all_clones(zfs_handle_t *zhp)
786 785 {
787 786 clone_data_t cd;
788 787 char nm[ZFS_MAXNAMELEN];
789 788
790 789 cd.clone_zhp = NULL;
791 790 cd.origin_creation = 0;
792 791 cd.snapshot = NULL;
793 792
794 793 if (zfs_iter_snapshots(zhp, find_clone, &cd) != 0) {
795 794 zfs_close(zhp);
796 795 return (Z_ERR);
797 796 }
798 797
799 798 /* Nothing to promote. */
800 799 if (cd.clone_zhp == NULL)
801 800 return (Z_OK);
802 801
803 802 /* Found the youngest clone to promote. Promote it. */
804 803 if (promote_clone(zhp, cd.clone_zhp) != 0) {
805 804 zfs_close(cd.clone_zhp);
806 805 zfs_close(zhp);
807 806 return (Z_ERR);
808 807 }
809 808
810 809 /* close and reopen the main dataset to get the latest info */
811 810 (void) strlcpy(nm, zfs_get_name(zhp), sizeof (nm));
812 811 zfs_close(zhp);
813 812 if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
814 813 return (Z_ERR);
815 814
816 815 return (Z_OK);
817 816 }
818 817
819 818 /*
820 819 * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if
821 820 * possible, or by copying the data from the snapshot to the zonepath.
822 821 */
823 822 int
824 823 clone_snapshot_zfs(char *snap_name, char *zonepath, char *validatesnap)
825 824 {
826 825 int err = Z_OK;
827 826 char clone_name[MAXPATHLEN];
828 827 char snap_path[MAXPATHLEN];
829 828
830 829 if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) {
831 830 (void) fprintf(stderr, gettext("unable to find path for %s.\n"),
832 831 snap_name);
833 832 return (Z_ERR);
834 833 }
835 834
836 835 if (validate_snapshot(snap_name, snap_path, validatesnap) != Z_OK)
837 836 return (Z_NO_ENTRY);
838 837
839 838 /*
840 839 * The zonepath cannot be ZFS cloned, try to copy the data from
841 840 * within the snapshot to the zonepath.
842 841 */
843 842 if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
844 843 if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
845 844 if (clean_out_clone() != Z_OK)
846 845 (void) fprintf(stderr,
847 846 gettext("could not remove the "
848 847 "software inventory from %s\n"), zonepath);
849 848
850 849 return (err);
851 850 }
852 851
853 852 if ((err = clone_snap(snap_name, clone_name)) != Z_OK) {
854 853 if (err != Z_NO_ENTRY) {
855 854 /*
856 855 * Cloning the snapshot failed. Fall back to trying
857 856 * to install the zone by copying from the snapshot.
858 857 */
859 858 if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
860 859 if (clean_out_clone() != Z_OK)
861 860 (void) fprintf(stderr,
862 861 gettext("could not remove the "
863 862 "software inventory from %s\n"),
864 863 zonepath);
865 864 } else {
866 865 /*
867 866 * The snapshot is unusable for some reason so restore
868 867 * the zone state to configured since we were unable to
869 868 * actually do anything about getting the zone
870 869 * installed.
871 870 */
872 871 int tmp;
873 872
874 873 if ((tmp = zone_set_state(target_zone,
875 874 ZONE_STATE_CONFIGURED)) != Z_OK) {
876 875 errno = tmp;
877 876 zperror2(target_zone,
878 877 gettext("could not set state"));
879 878 }
880 879 }
881 880 }
882 881
883 882 return (err);
884 883 }
885 884
886 885 /*
887 886 * Attempt to clone a source_zone to a target zonepath by using a ZFS clone.
888 887 */
889 888 int
890 889 clone_zfs(char *source_zonepath, char *zonepath, char *presnapbuf,
891 890 char *postsnapbuf)
892 891 {
893 892 zfs_handle_t *zhp;
894 893 char clone_name[MAXPATHLEN];
895 894 char snap_name[MAXPATHLEN];
896 895
897 896 /*
898 897 * Try to get a zfs handle for the source_zonepath. If this fails
899 898 * the source_zonepath is not ZFS so return an error.
900 899 */
901 900 if ((zhp = mount2zhandle(source_zonepath)) == NULL)
902 901 return (Z_ERR);
903 902
904 903 /*
905 904 * Check if there is a file system already mounted on zonepath. If so,
906 905 * we can't clone to the path so we should fall back to copying.
907 906 */
908 907 if (is_mountpnt(zonepath)) {
909 908 zfs_close(zhp);
910 909 (void) fprintf(stderr,
911 910 gettext("A file system is already mounted on %s,\n"
912 911 "preventing use of a ZFS clone.\n"), zonepath);
913 912 return (Z_ERR);
914 913 }
915 914
916 915 /*
917 916 * Instead of using path2name to get the clone name from the zonepath,
918 917 * we could generate a name from the source zone ZFS name. However,
919 918 * this would mean we would create the clone under the ZFS fs of the
920 919 * source instead of what the zonepath says. For example,
921 920 *
922 921 * source_zonepath zonepath
923 922 * /pl/zones/dev/z1 /pl/zones/deploy/z2
924 923 *
925 924 * We don't want the clone to be under "dev", we want it under
926 925 * "deploy", so that we can leverage the normal attribute inheritance
927 926 * that ZFS provides in the fs hierarchy.
928 927 */
929 928 if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
930 929 zfs_close(zhp);
931 930 return (Z_ERR);
932 931 }
933 932
934 933 if (take_snapshot(zhp, snap_name, sizeof (snap_name), presnapbuf,
935 934 postsnapbuf) != Z_OK) {
936 935 zfs_close(zhp);
937 936 return (Z_ERR);
938 937 }
939 938 zfs_close(zhp);
940 939
941 940 if (clone_snap(snap_name, clone_name) != Z_OK) {
942 941 /* Clean up the snapshot we just took. */
943 942 if ((zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_SNAPSHOT))
944 943 != NULL) {
945 944 if (zfs_unmount(zhp, NULL, 0) == 0)
946 945 (void) zfs_destroy(zhp, B_FALSE);
947 946 zfs_close(zhp);
948 947 }
949 948
950 949 return (Z_ERR);
951 950 }
952 951
953 952 (void) printf(gettext("Instead of copying, a ZFS clone has been "
954 953 "created for this zone.\n"));
955 954
956 955 return (Z_OK);
957 956 }
958 957
959 958 /*
960 959 * Attempt to create a ZFS file system for the specified zonepath.
961 960 * We either will successfully create a ZFS file system and get it mounted
962 961 * on the zonepath or we don't. The caller doesn't care since a regular
963 962 * directory is used for the zonepath if no ZFS file system is mounted there.
964 963 */
965 964 void
966 965 create_zfs_zonepath(char *zonepath)
967 966 {
968 967 zfs_handle_t *zhp;
969 968 char zfs_name[MAXPATHLEN];
970 969 nvlist_t *props = NULL;
971 970
972 971 if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
973 972 return;
974 973
975 974 /* Check if the dataset already exists. */
976 975 if ((zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) != NULL) {
977 976 zfs_close(zhp);
978 977 return;
979 978 }
980 979
↓ open down ↓ |
585 lines elided |
↑ open up ↑ |
981 980 /*
982 981 * We turn off zfs SHARENFS and SHARESMB properties on the
983 982 * zoneroot dataset in order to prevent the GZ from sharing
984 983 * NGZ data by accident.
985 984 */
986 985 if ((nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) ||
987 986 (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
988 987 "off") != 0) ||
989 988 (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARESMB),
990 989 "off") != 0)) {
991 - if (props != NULL)
992 - nvlist_free(props);
990 + nvlist_free(props);
993 991 (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
994 992 "out of memory\n"), zfs_name);
995 993 }
996 994
997 995 if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 ||
998 996 (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) == NULL) {
999 997 (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
1000 998 "%s\n"), zfs_name, libzfs_error_description(g_zfs));
1001 999 nvlist_free(props);
1002 1000 return;
1003 1001 }
1004 1002
1005 1003 nvlist_free(props);
1006 1004
1007 1005 if (zfs_mount(zhp, NULL, 0) != 0) {
1008 1006 (void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: "
1009 1007 "%s\n"), zfs_name, libzfs_error_description(g_zfs));
1010 1008 (void) zfs_destroy(zhp, B_FALSE);
1011 1009 } else {
1012 1010 if (chmod(zonepath, S_IRWXU) != 0) {
1013 1011 (void) fprintf(stderr, gettext("file system %s "
1014 1012 "successfully created, but chmod %o failed: %s\n"),
1015 1013 zfs_name, S_IRWXU, strerror(errno));
1016 1014 (void) destroy_zfs(zonepath);
1017 1015 } else {
1018 1016 (void) printf(gettext("A ZFS file system has been "
1019 1017 "created for this zone.\n"));
1020 1018 }
1021 1019 }
1022 1020
1023 1021 zfs_close(zhp);
1024 1022 }
1025 1023
1026 1024 /*
1027 1025 * If the zonepath is a ZFS file system, attempt to destroy it. We return Z_OK
1028 1026 * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR
1029 1027 * which means the caller should clean up the zonepath in the traditional
1030 1028 * way.
1031 1029 */
1032 1030 int
1033 1031 destroy_zfs(char *zonepath)
1034 1032 {
1035 1033 zfs_handle_t *zhp;
1036 1034 boolean_t is_clone = B_FALSE;
1037 1035 char origin[ZFS_MAXPROPLEN];
1038 1036
1039 1037 if ((zhp = mount2zhandle(zonepath)) == NULL)
1040 1038 return (Z_ERR);
1041 1039
1042 1040 if (promote_all_clones(zhp) != 0)
1043 1041 return (Z_ERR);
1044 1042
1045 1043 /* Now cleanup any snapshots remaining. */
1046 1044 if (zfs_iter_snapshots(zhp, rm_snap, NULL) != 0) {
1047 1045 zfs_close(zhp);
1048 1046 return (Z_ERR);
1049 1047 }
1050 1048
1051 1049 /*
1052 1050 * We can't destroy the file system if it has still has dependents.
1053 1051 * There shouldn't be any at this point, but we'll double check.
1054 1052 */
1055 1053 if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0) {
1056 1054 (void) fprintf(stderr, gettext("zfs destroy %s failed: the "
1057 1055 "dataset still has dependents\n"), zfs_get_name(zhp));
1058 1056 zfs_close(zhp);
1059 1057 return (Z_ERR);
1060 1058 }
1061 1059
1062 1060 /*
1063 1061 * This might be a clone. Try to get the snapshot so we can attempt
1064 1062 * to destroy that as well.
1065 1063 */
1066 1064 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
1067 1065 NULL, 0, B_FALSE) == 0)
1068 1066 is_clone = B_TRUE;
1069 1067
1070 1068 if (zfs_unmount(zhp, NULL, 0) != 0) {
1071 1069 (void) fprintf(stderr, gettext("zfs unmount %s failed: %s\n"),
1072 1070 zfs_get_name(zhp), libzfs_error_description(g_zfs));
1073 1071 zfs_close(zhp);
1074 1072 return (Z_ERR);
1075 1073 }
1076 1074
1077 1075 if (zfs_destroy(zhp, B_FALSE) != 0) {
1078 1076 /*
1079 1077 * If the destroy fails for some reason, try to remount
1080 1078 * the file system so that we can use "rm -rf" to clean up
1081 1079 * instead.
1082 1080 */
1083 1081 (void) fprintf(stderr, gettext("zfs destroy %s failed: %s\n"),
1084 1082 zfs_get_name(zhp), libzfs_error_description(g_zfs));
1085 1083 (void) zfs_mount(zhp, NULL, 0);
1086 1084 zfs_close(zhp);
1087 1085 return (Z_ERR);
1088 1086 }
1089 1087
1090 1088 /*
1091 1089 * If the zone has ever been moved then the mountpoint dir will not be
1092 1090 * cleaned up by the zfs_destroy(). To handle this case try to clean
1093 1091 * it up now but don't worry if it fails, that will be normal.
1094 1092 */
1095 1093 (void) rmdir(zonepath);
1096 1094
1097 1095 (void) printf(gettext("The ZFS file system for this zone has been "
1098 1096 "destroyed.\n"));
1099 1097
1100 1098 if (is_clone) {
1101 1099 zfs_handle_t *ohp;
1102 1100
1103 1101 /*
1104 1102 * Try to clean up the snapshot that the clone was taken from.
1105 1103 */
1106 1104 if ((ohp = zfs_open(g_zfs, origin,
1107 1105 ZFS_TYPE_SNAPSHOT)) != NULL) {
1108 1106 if (zfs_iter_dependents(ohp, B_TRUE, has_dependent,
1109 1107 NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0)
1110 1108 (void) zfs_destroy(ohp, B_FALSE);
1111 1109 zfs_close(ohp);
1112 1110 }
1113 1111 }
1114 1112
1115 1113 zfs_close(zhp);
1116 1114 return (Z_OK);
1117 1115 }
1118 1116
1119 1117 /*
1120 1118 * Return true if the path is its own zfs file system. We determine this
1121 1119 * by stat-ing the path to see if it is zfs and stat-ing the parent to see
1122 1120 * if it is a different fs.
1123 1121 */
1124 1122 boolean_t
1125 1123 is_zonepath_zfs(char *zonepath)
1126 1124 {
1127 1125 int res;
1128 1126 char *path;
1129 1127 char *parent;
1130 1128 struct statvfs64 buf1, buf2;
1131 1129
1132 1130 if (statvfs64(zonepath, &buf1) != 0)
1133 1131 return (B_FALSE);
1134 1132
1135 1133 if (strcmp(buf1.f_basetype, "zfs") != 0)
1136 1134 return (B_FALSE);
1137 1135
1138 1136 if ((path = strdup(zonepath)) == NULL)
1139 1137 return (B_FALSE);
1140 1138
1141 1139 parent = dirname(path);
1142 1140 res = statvfs64(parent, &buf2);
1143 1141 free(path);
1144 1142
1145 1143 if (res != 0)
1146 1144 return (B_FALSE);
1147 1145
1148 1146 if (buf1.f_fsid == buf2.f_fsid)
1149 1147 return (B_FALSE);
1150 1148
1151 1149 return (B_TRUE);
1152 1150 }
1153 1151
1154 1152 /*
1155 1153 * Implement the fast move of a ZFS file system by simply updating the
1156 1154 * mountpoint. Since it is file system already, we don't have the
1157 1155 * issue of cross-file system copying.
1158 1156 */
1159 1157 int
1160 1158 move_zfs(char *zonepath, char *new_zonepath)
1161 1159 {
1162 1160 int ret = Z_ERR;
1163 1161 zfs_handle_t *zhp;
1164 1162
1165 1163 if ((zhp = mount2zhandle(zonepath)) == NULL)
1166 1164 return (Z_ERR);
1167 1165
1168 1166 if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1169 1167 new_zonepath) == 0) {
1170 1168 /*
1171 1169 * Clean up the old mount point. We ignore any failure since
1172 1170 * the zone is already successfully mounted on the new path.
1173 1171 */
1174 1172 (void) rmdir(zonepath);
1175 1173 ret = Z_OK;
1176 1174 }
1177 1175
1178 1176 zfs_close(zhp);
1179 1177
1180 1178 return (ret);
1181 1179 }
1182 1180
1183 1181 /*
1184 1182 * Validate that the given dataset exists on the system, and that neither it nor
1185 1183 * its children are zvols.
1186 1184 *
1187 1185 * Note that we don't do anything with the 'zoned' property here. All
1188 1186 * management is done in zoneadmd when the zone is actually rebooted. This
1189 1187 * allows us to automatically set the zoned property even when a zone is
1190 1188 * rebooted by the administrator.
1191 1189 */
1192 1190 int
1193 1191 verify_datasets(zone_dochandle_t handle)
1194 1192 {
1195 1193 int return_code = Z_OK;
1196 1194 struct zone_dstab dstab;
1197 1195 zfs_handle_t *zhp;
1198 1196 char propbuf[ZFS_MAXPROPLEN];
1199 1197 char source[ZFS_MAXNAMELEN];
1200 1198 zprop_source_t srctype;
1201 1199
1202 1200 if (zonecfg_setdsent(handle) != Z_OK) {
1203 1201 /*
1204 1202 * TRANSLATION_NOTE
1205 1203 * zfs and dataset are literals that should not be translated.
1206 1204 */
1207 1205 (void) fprintf(stderr, gettext("could not verify zfs datasets: "
1208 1206 "unable to enumerate datasets\n"));
1209 1207 return (Z_ERR);
1210 1208 }
1211 1209
1212 1210 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
1213 1211
1214 1212 if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name,
1215 1213 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
1216 1214 (void) fprintf(stderr, gettext("could not verify zfs "
1217 1215 "dataset %s: %s\n"), dstab.zone_dataset_name,
1218 1216 libzfs_error_description(g_zfs));
1219 1217 return_code = Z_ERR;
1220 1218 continue;
1221 1219 }
1222 1220
1223 1221 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf,
1224 1222 sizeof (propbuf), &srctype, source,
1225 1223 sizeof (source), 0) == 0 &&
1226 1224 (srctype == ZPROP_SRC_INHERITED)) {
1227 1225 (void) fprintf(stderr, gettext("could not verify zfs "
1228 1226 "dataset %s: mountpoint cannot be inherited\n"),
1229 1227 dstab.zone_dataset_name);
1230 1228 return_code = Z_ERR;
1231 1229 zfs_close(zhp);
1232 1230 continue;
1233 1231 }
1234 1232
1235 1233 zfs_close(zhp);
1236 1234 }
1237 1235 (void) zonecfg_enddsent(handle);
1238 1236
1239 1237 return (return_code);
1240 1238 }
1241 1239
1242 1240 /*
1243 1241 * Verify that the ZFS dataset exists, and its mountpoint
1244 1242 * property is set to "legacy".
1245 1243 */
1246 1244 int
1247 1245 verify_fs_zfs(struct zone_fstab *fstab)
1248 1246 {
1249 1247 zfs_handle_t *zhp;
1250 1248 char propbuf[ZFS_MAXPROPLEN];
1251 1249
1252 1250 if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special,
1253 1251 ZFS_TYPE_DATASET)) == NULL) {
1254 1252 (void) fprintf(stderr, gettext("could not verify fs %s: "
1255 1253 "could not access zfs dataset '%s'\n"),
1256 1254 fstab->zone_fs_dir, fstab->zone_fs_special);
1257 1255 return (Z_ERR);
1258 1256 }
1259 1257
1260 1258 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
1261 1259 (void) fprintf(stderr, gettext("cannot verify fs %s: "
1262 1260 "'%s' is not a file system\n"),
1263 1261 fstab->zone_fs_dir, fstab->zone_fs_special);
1264 1262 zfs_close(zhp);
1265 1263 return (Z_ERR);
1266 1264 }
1267 1265
1268 1266 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
1269 1267 NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) {
1270 1268 (void) fprintf(stderr, gettext("could not verify fs %s: "
1271 1269 "zfs '%s' mountpoint is not \"legacy\"\n"),
1272 1270 fstab->zone_fs_dir, fstab->zone_fs_special);
1273 1271 zfs_close(zhp);
1274 1272 return (Z_ERR);
1275 1273 }
1276 1274
1277 1275 zfs_close(zhp);
1278 1276 return (Z_OK);
1279 1277 }
1280 1278
1281 1279 /*
1282 1280 * Destroy the specified mnttab structure that was created by mnttab_dup().
1283 1281 * NOTE: The structure's mnt_time field isn't freed.
1284 1282 */
1285 1283 static void
1286 1284 mnttab_destroy(struct mnttab *tabp)
1287 1285 {
1288 1286 assert(tabp != NULL);
1289 1287
1290 1288 free(tabp->mnt_mountp);
1291 1289 free(tabp->mnt_special);
1292 1290 free(tabp->mnt_fstype);
1293 1291 free(tabp->mnt_mntopts);
1294 1292 free(tabp);
1295 1293 }
1296 1294
1297 1295 /*
1298 1296 * Duplicate the specified mnttab structure. The mnt_mountp and mnt_time
1299 1297 * fields aren't duplicated. This function returns a pointer to the new mnttab
1300 1298 * structure or NULL if an error occurred. If an error occurs, then this
1301 1299 * function sets errno to reflect the error. mnttab structures created by
1302 1300 * this function should be destroyed via mnttab_destroy().
1303 1301 */
1304 1302 static struct mnttab *
1305 1303 mnttab_dup(const struct mnttab *srcp)
1306 1304 {
1307 1305 struct mnttab *retval;
1308 1306
1309 1307 assert(srcp != NULL);
1310 1308
1311 1309 retval = (struct mnttab *)calloc(1, sizeof (*retval));
1312 1310 if (retval == NULL) {
1313 1311 errno = ENOMEM;
1314 1312 return (NULL);
1315 1313 }
1316 1314 if (srcp->mnt_special != NULL) {
1317 1315 retval->mnt_special = strdup(srcp->mnt_special);
1318 1316 if (retval->mnt_special == NULL)
1319 1317 goto err;
1320 1318 }
1321 1319 if (srcp->mnt_fstype != NULL) {
1322 1320 retval->mnt_fstype = strdup(srcp->mnt_fstype);
1323 1321 if (retval->mnt_fstype == NULL)
1324 1322 goto err;
1325 1323 }
1326 1324 retval->mnt_mntopts = (char *)malloc(MAX_MNTOPT_STR * sizeof (char));
1327 1325 if (retval->mnt_mntopts == NULL)
1328 1326 goto err;
1329 1327 if (srcp->mnt_mntopts != NULL) {
1330 1328 if (strlcpy(retval->mnt_mntopts, srcp->mnt_mntopts,
1331 1329 MAX_MNTOPT_STR * sizeof (char)) >= MAX_MNTOPT_STR *
1332 1330 sizeof (char)) {
1333 1331 mnttab_destroy(retval);
1334 1332 errno = EOVERFLOW; /* similar to mount(2) behavior */
1335 1333 return (NULL);
1336 1334 }
1337 1335 } else {
1338 1336 retval->mnt_mntopts[0] = '\0';
1339 1337 }
1340 1338 return (retval);
1341 1339
1342 1340 err:
1343 1341 mnttab_destroy(retval);
1344 1342 errno = ENOMEM;
1345 1343 return (NULL);
1346 1344 }
1347 1345
1348 1346 /*
1349 1347 * Determine whether the specified ZFS dataset's mountpoint property is set
1350 1348 * to "legacy". If the specified dataset does not have a legacy mountpoint,
1351 1349 * then the string pointer to which the mountpoint argument points is assigned
1352 1350 * a dynamically-allocated string containing the dataset's mountpoint
1353 1351 * property. If the dataset's mountpoint property is "legacy" or a libzfs
1354 1352 * error occurs, then the string pointer to which the mountpoint argument
1355 1353 * points isn't modified.
1356 1354 *
1357 1355 * This function returns B_TRUE if it doesn't encounter any fatal errors.
1358 1356 * It returns B_FALSE if it encounters a fatal error and sets errno to the
1359 1357 * appropriate error code.
1360 1358 */
1361 1359 static boolean_t
1362 1360 get_zfs_non_legacy_mountpoint(const char *dataset_name, char **mountpoint)
1363 1361 {
1364 1362 zfs_handle_t *zhp;
1365 1363 char propbuf[ZFS_MAXPROPLEN];
1366 1364
1367 1365 assert(dataset_name != NULL);
1368 1366 assert(mountpoint != NULL);
1369 1367
1370 1368 if ((zhp = zfs_open(g_zfs, dataset_name, ZFS_TYPE_DATASET)) == NULL) {
1371 1369 errno = EINVAL;
1372 1370 return (B_FALSE);
1373 1371 }
1374 1372 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
1375 1373 NULL, NULL, 0, 0) != 0) {
1376 1374 zfs_close(zhp);
1377 1375 errno = EINVAL;
1378 1376 return (B_FALSE);
1379 1377 }
1380 1378 zfs_close(zhp);
1381 1379 if (strcmp(propbuf, "legacy") != 0) {
1382 1380 if ((*mountpoint = strdup(propbuf)) == NULL) {
1383 1381 errno = ENOMEM;
1384 1382 return (B_FALSE);
1385 1383 }
1386 1384 }
1387 1385 return (B_TRUE);
1388 1386 }
1389 1387
1390 1388
1391 1389 /*
1392 1390 * This zonecfg_find_mounts() callback records information about mounts of
1393 1391 * interest in a zonepath. It also tallies the number of zone
1394 1392 * root overlay mounts and the number of unexpected mounts found.
1395 1393 * This function outputs errors using zerror() if it finds unexpected
1396 1394 * mounts. cookiep should point to an initialized zone_mounts_t structure.
1397 1395 *
1398 1396 * This function returns zero on success and a nonzero value on failure.
1399 1397 */
1400 1398 static int
1401 1399 zone_mounts_cb(const struct mnttab *mountp, void *cookiep)
1402 1400 {
1403 1401 zone_mounts_t *mounts;
1404 1402 const char *zone_mount_dir;
1405 1403
1406 1404 assert(mountp != NULL);
1407 1405 assert(cookiep != NULL);
1408 1406
1409 1407 mounts = (zone_mounts_t *)cookiep;
1410 1408 zone_mount_dir = mountp->mnt_mountp + mounts->zonepath_len;
1411 1409 if (strcmp(zone_mount_dir, "/root") == 0) {
1412 1410 /*
1413 1411 * Check for an overlay mount. If we already detected a /root
1414 1412 * mount, then the current mount must be an overlay mount.
1415 1413 */
1416 1414 if (mounts->root_mnttab != NULL) {
1417 1415 mounts->num_root_overlay_mounts++;
1418 1416 return (0);
1419 1417 }
1420 1418
1421 1419 /*
1422 1420 * Store the root mount's mnttab information in the
1423 1421 * zone_mounts_t structure for future use.
1424 1422 */
1425 1423 if ((mounts->root_mnttab = mnttab_dup(mountp)) == NULL) {
1426 1424 zperror(cmd_to_str(CMD_MOVE), B_FALSE);
1427 1425 return (-1);
1428 1426 }
1429 1427
1430 1428 /*
1431 1429 * Determine if the filesystem is a ZFS filesystem with a
1432 1430 * non-legacy mountpoint. If it is, then set the root
1433 1431 * filesystem's mnttab's mnt_mountp field to a non-NULL
1434 1432 * value, which will serve as a flag to indicate this special
1435 1433 * condition.
1436 1434 */
1437 1435 if (strcmp(mountp->mnt_fstype, MNTTYPE_ZFS) == 0 &&
1438 1436 get_zfs_non_legacy_mountpoint(mountp->mnt_special,
1439 1437 &mounts->root_mnttab->mnt_mountp) != B_TRUE) {
1440 1438 zperror(cmd_to_str(CMD_MOVE), B_FALSE);
1441 1439 return (-1);
1442 1440 }
1443 1441 } else {
1444 1442 /*
1445 1443 * An unexpected mount was found. Notify the user.
1446 1444 */
1447 1445 if (mounts->num_unexpected_mounts == 0)
1448 1446 zerror(gettext("These file systems are mounted on "
1449 1447 "subdirectories of %s.\n"), mounts->zonepath);
1450 1448 mounts->num_unexpected_mounts++;
1451 1449 (void) zfm_print(mountp, NULL);
1452 1450 }
1453 1451 return (0);
1454 1452 }
1455 1453
1456 1454 /*
1457 1455 * Initialize the specified zone_mounts_t structure for the given zonepath.
1458 1456 * If this function succeeds, it returns zero and the specified zone_mounts_t
1459 1457 * structure contains information about mounts in the specified zonepath.
1460 1458 * The function returns a nonzero value if it fails. The zone_mounts_t
1461 1459 * structure doesn't need be destroyed via zone_mounts_destroy() if this
1462 1460 * function fails.
1463 1461 */
1464 1462 int
1465 1463 zone_mounts_init(zone_mounts_t *mounts, const char *zonepath)
1466 1464 {
1467 1465 assert(mounts != NULL);
1468 1466 assert(zonepath != NULL);
1469 1467
1470 1468 bzero(mounts, sizeof (*mounts));
1471 1469 if ((mounts->zonepath = strdup(zonepath)) == NULL) {
1472 1470 zerror(gettext("the process ran out of memory while checking "
1473 1471 "for mounts in zonepath %s."), zonepath);
1474 1472 return (-1);
1475 1473 }
1476 1474 mounts->zonepath_len = strlen(zonepath);
1477 1475 if (zonecfg_find_mounts((char *)zonepath, zone_mounts_cb, mounts) ==
1478 1476 -1) {
1479 1477 zerror(gettext("an error occurred while checking for mounts "
1480 1478 "in zonepath %s."), zonepath);
1481 1479 zone_mounts_destroy(mounts);
1482 1480 return (-1);
1483 1481 }
1484 1482 return (0);
1485 1483 }
1486 1484
1487 1485 /*
1488 1486 * Destroy the memory used by the specified zone_mounts_t structure's fields.
1489 1487 * This function doesn't free the memory occupied by the structure itself
1490 1488 * (i.e., it doesn't free the parameter).
1491 1489 */
1492 1490 void
1493 1491 zone_mounts_destroy(zone_mounts_t *mounts)
1494 1492 {
1495 1493 assert(mounts != NULL);
1496 1494
1497 1495 free(mounts->zonepath);
1498 1496 if (mounts->root_mnttab != NULL)
1499 1497 mnttab_destroy(mounts->root_mnttab);
1500 1498 }
1501 1499
1502 1500 /*
1503 1501 * Mount a moving zone's root filesystem (if it had a root filesystem mount
1504 1502 * prior to the move) using the specified zonepath. mounts should refer to
1505 1503 * the zone_mounts_t structure describing the zone's mount information.
1506 1504 *
1507 1505 * This function returns zero if the mount succeeds and a nonzero value
1508 1506 * if it doesn't.
1509 1507 */
1510 1508 int
1511 1509 zone_mount_rootfs(zone_mounts_t *mounts, const char *zonepath)
1512 1510 {
1513 1511 char zoneroot[MAXPATHLEN];
1514 1512 struct mnttab *mtab;
1515 1513 int flags;
1516 1514
1517 1515 assert(mounts != NULL);
1518 1516 assert(zonepath != NULL);
1519 1517
1520 1518 /*
1521 1519 * If there isn't a root filesystem, then don't do anything.
1522 1520 */
1523 1521 mtab = mounts->root_mnttab;
1524 1522 if (mtab == NULL)
1525 1523 return (0);
1526 1524
1527 1525 /*
1528 1526 * Determine the root filesystem's new mountpoint.
1529 1527 */
1530 1528 if (snprintf(zoneroot, sizeof (zoneroot), "%s/root", zonepath) >=
1531 1529 sizeof (zoneroot)) {
1532 1530 zerror(gettext("Zonepath %s is too long.\n"), zonepath);
1533 1531 return (-1);
1534 1532 }
1535 1533
1536 1534 /*
1537 1535 * If the root filesystem is a non-legacy ZFS filesystem (i.e., if it's
1538 1536 * mnt_mountp field is non-NULL), then make the filesystem's new
1539 1537 * mount point its mountpoint property and mount the filesystem.
1540 1538 */
1541 1539 if (mtab->mnt_mountp != NULL) {
1542 1540 zfs_handle_t *zhp;
1543 1541
1544 1542 if ((zhp = zfs_open(g_zfs, mtab->mnt_special,
1545 1543 ZFS_TYPE_DATASET)) == NULL) {
1546 1544 zerror(gettext("could not get ZFS handle for the zone's"
1547 1545 " root filesystem"));
1548 1546 return (-1);
1549 1547 }
1550 1548 if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1551 1549 zoneroot) != 0) {
1552 1550 zerror(gettext("could not modify zone's root "
1553 1551 "filesystem's mountpoint property"));
1554 1552 zfs_close(zhp);
1555 1553 return (-1);
1556 1554 }
1557 1555 if (zfs_mount(zhp, mtab->mnt_mntopts, 0) != 0) {
1558 1556 zerror(gettext("unable to mount zone root %s: %s"),
1559 1557 zoneroot, libzfs_error_description(g_zfs));
1560 1558 if (zfs_prop_set(zhp,
1561 1559 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1562 1560 mtab->mnt_mountp) != 0)
1563 1561 zerror(gettext("unable to restore zone's root "
1564 1562 "filesystem's mountpoint property"));
1565 1563 zfs_close(zhp);
1566 1564 return (-1);
1567 1565 }
1568 1566 zfs_close(zhp);
1569 1567 return (0);
1570 1568 }
1571 1569
1572 1570 /*
1573 1571 * The root filesystem is either a legacy-mounted ZFS filesystem or
1574 1572 * a non-ZFS filesystem. Use mount(2) to mount the root filesystem.
1575 1573 */
1576 1574 if (mtab->mnt_mntopts != NULL)
1577 1575 flags = MS_OPTIONSTR;
1578 1576 else
1579 1577 flags = 0;
1580 1578 if (mount(mtab->mnt_special, zoneroot, flags, mtab->mnt_fstype, NULL, 0,
1581 1579 mtab->mnt_mntopts, MAX_MNTOPT_STR * sizeof (char)) != 0) {
1582 1580 flags = errno;
1583 1581 zerror(gettext("unable to mount zone root %s: %s"), zoneroot,
1584 1582 strerror(flags));
1585 1583 return (-1);
1586 1584 }
1587 1585 return (0);
1588 1586 }
1589 1587
1590 1588 /*
1591 1589 * Unmount a moving zone's root filesystem (if such a mount exists) using the
1592 1590 * specified zonepath. mounts should refer to the zone_mounts_t structure
1593 1591 * describing the zone's mount information. If force is B_TRUE, then if the
1594 1592 * unmount fails, then the function will try to forcibly unmount the zone's root
1595 1593 * filesystem.
1596 1594 *
1597 1595 * This function returns zero if the unmount (forced or otherwise) succeeds;
1598 1596 * otherwise, it returns a nonzero value.
1599 1597 */
1600 1598 int
1601 1599 zone_unmount_rootfs(zone_mounts_t *mounts, const char *zonepath,
1602 1600 boolean_t force)
1603 1601 {
1604 1602 char zoneroot[MAXPATHLEN];
1605 1603 struct mnttab *mtab;
1606 1604 int err;
1607 1605
1608 1606 assert(mounts != NULL);
1609 1607 assert(zonepath != NULL);
1610 1608
1611 1609 /*
1612 1610 * If there isn't a root filesystem, then don't do anything.
1613 1611 */
1614 1612 mtab = mounts->root_mnttab;
1615 1613 if (mtab == NULL)
1616 1614 return (0);
1617 1615
1618 1616 /*
1619 1617 * Determine the root filesystem's mountpoint.
1620 1618 */
1621 1619 if (snprintf(zoneroot, sizeof (zoneroot), "%s/root", zonepath) >=
1622 1620 sizeof (zoneroot)) {
1623 1621 zerror(gettext("Zonepath %s is too long.\n"), zonepath);
1624 1622 return (-1);
1625 1623 }
1626 1624
1627 1625 /*
1628 1626 * If the root filesystem is a non-legacy ZFS fileystem, then unmount
1629 1627 * the filesystem via libzfs.
1630 1628 */
1631 1629 if (mtab->mnt_mountp != NULL) {
1632 1630 zfs_handle_t *zhp;
1633 1631
1634 1632 if ((zhp = zfs_open(g_zfs, mtab->mnt_special,
1635 1633 ZFS_TYPE_DATASET)) == NULL) {
1636 1634 zerror(gettext("could not get ZFS handle for the zone's"
1637 1635 " root filesystem"));
1638 1636 return (-1);
1639 1637 }
1640 1638 if (zfs_unmount(zhp, zoneroot, 0) != 0) {
1641 1639 if (force && zfs_unmount(zhp, zoneroot, MS_FORCE) ==
1642 1640 0) {
1643 1641 zfs_close(zhp);
1644 1642 return (0);
1645 1643 }
1646 1644 zerror(gettext("unable to unmount zone root %s: %s"),
1647 1645 zoneroot, libzfs_error_description(g_zfs));
1648 1646 zfs_close(zhp);
1649 1647 return (-1);
1650 1648 }
1651 1649 zfs_close(zhp);
1652 1650 return (0);
1653 1651 }
1654 1652
1655 1653 /*
1656 1654 * Use umount(2) to unmount the root filesystem. If this fails, then
1657 1655 * forcibly unmount it if the force flag is set.
1658 1656 */
1659 1657 if (umount(zoneroot) != 0) {
1660 1658 if (force && umount2(zoneroot, MS_FORCE) == 0)
1661 1659 return (0);
1662 1660 err = errno;
1663 1661 zerror(gettext("unable to unmount zone root %s: %s"), zoneroot,
1664 1662 strerror(err));
1665 1663 return (-1);
1666 1664 }
1667 1665 return (0);
1668 1666 }
1669 1667
1670 1668 int
1671 1669 init_zfs(void)
1672 1670 {
1673 1671 if ((g_zfs = libzfs_init()) == NULL) {
1674 1672 (void) fprintf(stderr, gettext("failed to initialize ZFS "
1675 1673 "library\n"));
1676 1674 return (Z_ERR);
1677 1675 }
1678 1676
1679 1677 return (Z_OK);
1680 1678 }
↓ open down ↓ |
678 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX