summaryrefslogtreecommitdiff
path: root/usr/src/cmd/zoneadm/zoneadm.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/zoneadm/zoneadm.c')
-rw-r--r--usr/src/cmd/zoneadm/zoneadm.c95
1 files changed, 74 insertions, 21 deletions
diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c
index 058de1e7ed..af08db8d70 100644
--- a/usr/src/cmd/zoneadm/zoneadm.c
+++ b/usr/src/cmd/zoneadm/zoneadm.c
@@ -3488,9 +3488,9 @@ copy_zone(char *src, char *dst)
}
/* ARGSUSED */
-static int
-zfm_print(const char *p, void *r) {
- zerror(" %s\n", p);
+int
+zfm_print(const struct mnttab *p, void *r) {
+ zerror(" %s\n", p->mnt_mountp);
return (0);
}
@@ -3951,12 +3951,14 @@ move_func(int argc, char *argv[])
zone_dochandle_t handle;
boolean_t fast;
boolean_t is_zfs = B_FALSE;
+ boolean_t root_fs_mounted = B_FALSE;
struct dirent *dp;
DIR *dirp;
boolean_t empty = B_TRUE;
boolean_t revert;
struct stat zonepath_buf;
struct stat new_zonepath_buf;
+ zone_mounts_t mounts;
if (zonecfg_in_alt_root()) {
zerror(gettext("cannot move zone in alternate root"));
@@ -4033,13 +4035,20 @@ move_func(int argc, char *argv[])
return (Z_ERR);
}
- /* Don't move the zone if anything is still mounted there */
- if (zonecfg_find_mounts(zonepath, NULL, NULL)) {
- zerror(gettext("These file systems are mounted on "
- "subdirectories of %s.\n"), zonepath);
- (void) zonecfg_find_mounts(zonepath, zfm_print, NULL);
+ /*
+ * Collect information about mounts within the zone's zonepath.
+ * Overlay mounts on the zone's root directory are erroneous.
+ * Bail if we encounter any unexpected mounts.
+ */
+ if (zone_mounts_init(&mounts, zonepath) != 0)
return (Z_ERR);
+ if (mounts.num_root_overlay_mounts != 0) {
+ zerror(gettext("%d overlay mount(s) detected on %s/root."),
+ mounts.num_root_overlay_mounts, zonepath);
+ goto err_and_mounts_destroy;
}
+ if (mounts.num_unexpected_mounts != 0)
+ goto err_and_mounts_destroy;
/*
* Check if we are moving in the same file system and can do a fast
@@ -4049,24 +4058,29 @@ move_func(int argc, char *argv[])
if ((handle = zonecfg_init_handle()) == NULL) {
zperror(cmd_to_str(CMD_MOVE), B_TRUE);
- return (Z_ERR);
+ goto err_and_mounts_destroy;
}
if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
errno = err;
zperror(cmd_to_str(CMD_MOVE), B_TRUE);
- zonecfg_fini_handle(handle);
- return (Z_ERR);
+ goto err_and_fini_handle;
}
if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) {
zerror(gettext("another %s may have an operation in progress."),
"zoneadm");
- zonecfg_fini_handle(handle);
- return (Z_ERR);
+ goto err_and_fini_handle;
}
/*
+ * Unmount the zone's root filesystem before we move the zone's
+ * zonepath.
+ */
+ if (zone_unmount_rootfs(&mounts, zonepath, B_FALSE) != 0)
+ goto err_and_rele_lockfile;
+
+ /*
* We're making some file system changes now so we have to clean up
* the file system before we are done. This will either clean up the
* new zonepath if the zonecfg update failed or it will clean up the
@@ -4088,9 +4102,8 @@ move_func(int argc, char *argv[])
if (rmdir(new_zonepath) != 0) {
zperror(gettext("could not rmdir new zone path"),
B_FALSE);
- zonecfg_fini_handle(handle);
- zonecfg_release_lock_file(target_zone, lockfd);
- return (Z_ERR);
+ (void) zone_mount_rootfs(&mounts, zonepath);
+ goto err_and_rele_lockfile;
}
if (rename(zonepath, new_zonepath) != 0) {
@@ -4100,9 +4113,8 @@ move_func(int argc, char *argv[])
* so just return from this error.
*/
zperror(gettext("could not move zone"), B_FALSE);
- zonecfg_fini_handle(handle);
- zonecfg_release_lock_file(target_zone, lockfd);
- return (Z_ERR);
+ (void) zone_mount_rootfs(&mounts, zonepath);
+ goto err_and_rele_lockfile;
}
} else {
@@ -4125,6 +4137,16 @@ move_func(int argc, char *argv[])
goto done;
}
+ /*
+ * Mount the zone's root filesystem in the new zonepath if there was
+ * a root mount prior to the move.
+ */
+ if (zone_mount_rootfs(&mounts, new_zonepath) != 0) {
+ err = Z_ERR;
+ goto done;
+ }
+ root_fs_mounted = B_TRUE;
+
if ((err = zonecfg_set_zonepath(handle, new_zonepath)) != Z_OK) {
errno = err;
zperror(gettext("could not set new zonepath"), B_TRUE);
@@ -4149,6 +4171,24 @@ done:
* or we clean up the old zonepath if everything is ok.
*/
if (revert) {
+ /*
+ * Check for the unlikely scenario in which the zone's
+ * zonepath and its root file system moved but libzonecfg
+ * couldn't save the new zonepath to the zone's configuration
+ * file. The mounted root filesystem must be unmounted before
+ * zoneadm restores the zone's zonepath.
+ */
+ if (root_fs_mounted && zone_unmount_rootfs(&mounts,
+ new_zonepath, B_TRUE) != 0) {
+ /*
+ * We can't forcibly unmount the zone's root file system
+ * from the new zonepath. Bail!
+ */
+ zerror(gettext("fatal error: cannot unmount %s/root\n"),
+ new_zonepath);
+ goto err_and_mounts_destroy;
+ }
+
/* The zonecfg update failed, cleanup the new zonepath. */
if (is_zfs) {
if (move_zfs(new_zonepath, zonepath) == Z_ERR) {
@@ -4158,8 +4198,9 @@ done:
/*
* err is already != Z_OK since we're reverting
*/
+ } else {
+ (void) zone_mount_rootfs(&mounts, zonepath);
}
-
} else if (fast) {
if (rename(new_zonepath, zonepath) != 0) {
zperror(gettext("could not restore zonepath"),
@@ -4167,6 +4208,8 @@ done:
/*
* err is already != Z_OK since we're reverting
*/
+ } else {
+ (void) zone_mount_rootfs(&mounts, zonepath);
}
} else {
(void) printf(gettext("Cleaning up zonepath %s..."),
@@ -4187,8 +4230,9 @@ done:
*/
err = Z_ERR;
}
- }
+ (void) zone_mount_rootfs(&mounts, zonepath);
+ }
} else {
/* The move was successful, cleanup the old zonepath. */
if (!is_zfs && !fast) {
@@ -4206,7 +4250,16 @@ done:
}
}
+ zone_mounts_destroy(&mounts);
return ((err == Z_OK) ? Z_OK : Z_ERR);
+
+err_and_rele_lockfile:
+ zonecfg_release_lock_file(target_zone, lockfd);
+err_and_fini_handle:
+ zonecfg_fini_handle(handle);
+err_and_mounts_destroy:
+ zone_mounts_destroy(&mounts);
+ return (Z_ERR);
}
/* ARGSUSED */