1
0
mirror of https://github.com/systemd/systemd synced 2026-03-14 17:14:49 +01:00

Compare commits

..

No commits in common. "5a35a6d9d44bc6ca21d6bc9d8bb20beab956da99" and "503a788332bda768fbcad485f8d51ee46f9e8c2f" have entirely different histories.

7 changed files with 57 additions and 148 deletions

View File

@ -125,17 +125,6 @@
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
<varlistentry>
<term><option>-x</option></term>
<term><option>--ephemeral</option></term>
<listitem><para>If specified, the VM is run with a temporary snapshot of its file system that is removed
immediately when the VM terminates. Only works with <option>--image=</option> currently.
Note that <option>--ephemeral</option> will not work with <option>--extra-drive=</option>.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
</variablelist>
</refsect2>

View File

@ -107,7 +107,6 @@
#include "shift-uid.h"
#include "signal-util.h"
#include "siphash24.h"
#include "snapshot-util.h"
#include "socket-util.h"
#include "stat-util.h"
#include "stdio-util.h"
@ -5916,7 +5915,7 @@ static int do_cleanup(void) {
}
static int run(int argc, char *argv[]) {
bool remove_image = false, veth_created = false;
bool remove_directory = false, remove_image = false, veth_created = false;
_cleanup_close_ int master = -EBADF, userns_fd = -EBADF, mount_fd = -EBADF;
_cleanup_fdset_free_ FDSet *fds = NULL;
int r, ret = EXIT_SUCCESS;
@ -5924,7 +5923,6 @@ static int run(int argc, char *argv[]) {
struct ExposeArgs expose_args = {};
_cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
_cleanup_(rmdir_and_freep) char *rootdir = NULL;
_cleanup_(rm_rf_subvolume_and_freep) char *snapshot_dir = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
@ -6066,27 +6064,63 @@ static int run(int argc, char *argv[]) {
}
if (arg_ephemeral) {
_cleanup_free_ char *np = NULL;
r = chase_and_update(&arg_directory, 0);
if (r < 0)
goto finish;
r = create_ephemeral_snapshot(
arg_directory,
arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
arg_read_only,
&tree_global_lock,
&tree_local_lock,
&snapshot_dir);
/* If the specified path is a mount point we generate the new snapshot immediately
* inside it under a random name. However if the specified is not a mount point we
* create the new snapshot in the parent directory, just next to it. */
r = path_is_mount_point(arg_directory);
if (r < 0) {
log_error_errno(r, "Failed to create ephemeral snapshot: %m");
log_error_errno(r, "Failed to determine whether directory %s is mount point: %m", arg_directory);
goto finish;
}
if (r > 0)
r = tempfn_random_child(arg_directory, "machine.", &np);
else
r = tempfn_random(arg_directory, "machine.", &np);
if (r < 0) {
log_error_errno(r, "Failed to generate name for directory snapshot: %m");
goto finish;
}
r = free_and_strdup(&arg_directory, snapshot_dir);
/* We take an exclusive lock on this image, since it's our private, ephemeral copy
* only owned by us and no one else. */
r = image_path_lock(
arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
np,
LOCK_EX|LOCK_NB,
arg_privileged ? &tree_global_lock : NULL,
&tree_local_lock);
if (r < 0) {
log_oom();
log_error_errno(r, "Failed to lock %s: %m", np);
goto finish;
}
{
BLOCK_SIGNALS(SIGINT);
r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_directory, AT_FDCWD, np,
(arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
BTRFS_SNAPSHOT_FALLBACK_COPY |
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
BTRFS_SNAPSHOT_RECURSIVE |
BTRFS_SNAPSHOT_QUOTA |
BTRFS_SNAPSHOT_SIGINT);
}
if (r == -EINTR) {
log_error_errno(r, "Interrupted while copying file system tree to %s, removed again.", np);
goto finish;
}
if (r < 0) {
log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory);
goto finish;
}
free_and_replace(arg_directory, np);
remove_directory = true;
} else {
r = chase_and_update(&arg_directory, arg_template ? CHASE_NONEXISTENT : 0);
if (r < 0)
@ -6437,6 +6471,14 @@ finish:
pager_close();
if (remove_directory && arg_directory) {
int k;
k = rm_rf(arg_directory, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
if (k < 0)
log_warning_errno(k, "Cannot remove '%s', ignoring: %m", arg_directory);
}
if (remove_image && arg_image) {
if (unlink(arg_image) < 0)
log_warning_errno(errno, "Can't remove image file '%s', ignoring: %m", arg_image);

View File

@ -177,7 +177,6 @@ shared_sources = files(
'sleep-config.c',
'smack-util.c',
'smbios11.c',
'snapshot-util.c',
'socket-label.c',
'socket-netlink.c',
'specifier.c',

View File

@ -1,65 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/file.h>
#include "alloc-util.h"
#include "btrfs-util.h"
#include "discover-image.h"
#include "log.h"
#include "mountpoint-util.h"
#include "snapshot-util.h"
#include "signal-util.h"
#include "tmpfile-util.h"
int create_ephemeral_snapshot(
const char *directory,
RuntimeScope scope,
bool read_only,
LockFile *tree_global_lock,
LockFile *tree_local_lock,
char **ret_new_path) {
_cleanup_free_ char *np = NULL;
int r;
/* If the specified path is a mount point we generate the new snapshot immediately
* inside it under a random name. However if the specified is not a mount point we
* create the new snapshot in the parent directory, just next to it. */
r = path_is_mount_point(directory);
if (r < 0)
return log_debug_errno(r, "Failed to determine whether directory %s is mount point: %m", directory);
if (r > 0)
r = tempfn_random_child(directory, "snapshot.", &np);
else
r = tempfn_random(directory, "snapshot.", &np);
if (r < 0)
return log_debug_errno(r, "Failed to generate name for directory snapshot: %m");
/* We take an exclusive lock on this image, since it's our private, ephemeral copy
* only owned by us and no one else. */
r = image_path_lock(
scope,
np,
LOCK_EX|LOCK_NB,
scope == RUNTIME_SCOPE_SYSTEM ? tree_global_lock : NULL,
tree_local_lock);
if (r < 0)
return log_debug_errno(r, "Failed to lock %s: %m", np);
{
BLOCK_SIGNALS(SIGINT);
r = btrfs_subvol_snapshot_at(AT_FDCWD, directory, AT_FDCWD, np,
(read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
BTRFS_SNAPSHOT_FALLBACK_COPY |
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
BTRFS_SNAPSHOT_RECURSIVE |
BTRFS_SNAPSHOT_QUOTA |
BTRFS_SNAPSHOT_SIGINT);
}
if (r < 0)
return log_debug_errno(r, "Failed to create snapshot %s from %s: %m", np, directory);
*ret_new_path = TAKE_PTR(np);
return 0;
}

View File

@ -1,21 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "runtime-scope.h"
/* create_ephemeral_snapshot - create a snapshot of the given directory.
*
* It will use a btrfs snapshot when available with fallback to traditional dir copy. It will set the global
* and local lock files based on the passed runtime scope. On success the new directory path is returned via
* `ret_new_path`.
*
* The caller is responsible for the cleanup of the directory, using `_cleanup_(rm_rf_subvolume_and_freep)`
* is recommended.
*/
int create_ephemeral_snapshot(
const char *directory,
RuntimeScope scope,
bool read_only,
LockFile *tree_global_lock,
LockFile *tree_local_lock,
char **ret_new_path);

View File

@ -35,7 +35,6 @@ typedef enum SettingsMask {
SETTING_START_MODE = UINT64_C(1) << 0,
SETTING_MACHINE_ID = UINT64_C(1) << 6,
SETTING_BIND_MOUNTS = UINT64_C(1) << 11,
SETTING_EPHEMERAL = UINT64_C(1) << 24,
SETTING_DIRECTORY = UINT64_C(1) << 26,
SETTING_CREDENTIALS = UINT64_C(1) << 30,
_SETTING_FORCE_ENUM_WIDTH = UINT64_MAX

View File

@ -62,7 +62,6 @@
#include "random-util.h"
#include "rm-rf.h"
#include "signal-util.h"
#include "snapshot-util.h"
#include "socket-util.h"
#include "stat-util.h"
#include "stdio-util.h"
@ -146,7 +145,6 @@ static char **arg_bind_user = NULL;
static char *arg_bind_user_shell = NULL;
static bool arg_bind_user_shell_copy = false;
static char **arg_bind_user_groups = NULL;
static bool arg_ephemeral = false;
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
@ -192,7 +190,6 @@ static int help(void) {
" --system Interact with system manager\n"
"\n%3$sImage:%4$s\n"
" -D --directory=PATH Root directory for the VM\n"
" -x --ephemeral Run VM with snapshot of the disk or directory\n"
" -i --image=FILE|DEVICE Root file system disk image or device for the VM\n"
" --image-format=FORMAT Specify disk image format (raw, qcow2; default: raw)\n"
"\n%3$sHost Configuration:%4$s\n"
@ -330,7 +327,6 @@ static int parse_argv(int argc, char *argv[]) {
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "image", required_argument, NULL, 'i' },
{ "image-format", required_argument, NULL, ARG_IMAGE_FORMAT },
{ "ephemeral", no_argument, NULL, 'x' },
{ "directory", required_argument, NULL, 'D' },
{ "machine", required_argument, NULL, 'M' },
{ "slice", required_argument, NULL, 'S' },
@ -386,7 +382,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argv);
optind = 0;
while ((c = getopt_long(argc, argv, "+hD:i:xM:nqs:G:S:", options, NULL)) >= 0)
while ((c = getopt_long(argc, argv, "+hD:i:M:nqs:G:S:", options, NULL)) >= 0)
switch (c) {
case 'h':
return help();
@ -433,10 +429,6 @@ static int parse_argv(int argc, char *argv[]) {
}
break;
case 'x':
arg_ephemeral = true;
break;
case ARG_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
@ -802,9 +794,6 @@ static int parse_argv(int argc, char *argv[]) {
if (!strv_isempty(arg_bind_user_groups) && strv_isempty(arg_bind_user))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --bind-user-group= without --bind-user=");
if (arg_ephemeral && arg_extra_drives.n_drives > 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --ephemeral with --extra-drive=");
if (argc > optind) {
arg_kernel_cmdline_extra = strv_copy(argv + optind);
if (!arg_kernel_cmdline_extra)
@ -1854,8 +1843,6 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
_cleanup_(ovmf_config_freep) OvmfConfig *ovmf_config = NULL;
_cleanup_free_ char *qemu_binary = NULL, *mem = NULL, *kernel = NULL;
_cleanup_(rm_rf_physical_and_freep) char *ssh_private_key_path = NULL, *ssh_public_key_path = NULL;
_cleanup_(rm_rf_subvolume_and_freep) char *snapshot_directory = NULL;
_cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
_cleanup_close_ int notify_sock_fd = -EBADF;
_cleanup_strv_free_ char **cmdline = NULL;
_cleanup_free_ int *pass_fds = NULL;
@ -2332,8 +2319,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
if (!escaped_image)
return log_oom();
if (strv_extendf(&cmdline, "if=none,id=vmspawn,file=%s,format=%s,discard=%s,snapshot=%s",
escaped_image, image_format_to_string(arg_image_format), on_off(arg_discard_disk), on_off(arg_ephemeral)) < 0)
if (strv_extendf(&cmdline, "if=none,id=vmspawn,file=%s,format=%s,discard=%s", escaped_image, image_format_to_string(arg_image_format), on_off(arg_discard_disk)) < 0)
return log_oom();
_cleanup_free_ char *image_fn = NULL;
@ -2380,21 +2366,6 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
if (!GREEDY_REALLOC(children, n_children + 1))
return log_oom();
if (arg_ephemeral) {
r = create_ephemeral_snapshot(arg_directory,
arg_runtime_scope,
/* read-only */ false,
&tree_global_lock,
&tree_local_lock,
&snapshot_directory);
if (r < 0)
return r;
arg_directory = strdup(snapshot_directory);
if (!arg_directory)
return log_oom();
}
r = start_virtiofsd(
unit,
arg_directory,
@ -3094,11 +3065,6 @@ static int determine_names(void) {
if (r < 0)
return log_error_errno(r, "Failed to extract file name from '%s': %m", arg_directory);
}
/* Add a random suffix when this is an ephemeral machine, so that we can run many
* instances at once without manually having to specify -M each time. */
if (arg_ephemeral)
if (strextendf(&arg_machine, "-%016" PRIx64, random_u64()) < 0)
return log_oom();
hostname_cleanup(arg_machine);
if (!hostname_is_valid(arg_machine, 0))