mirror of
https://github.com/ostreedev/ostree.git
synced 2025-03-25 18:50:44 +03:00
sysroot-deploy: prepare for soft-reboot
This commit is contained in:
parent
d5ea852ddc
commit
45f2550d50
@ -621,6 +621,7 @@ ostree_sysroot_upgrader_get_origin
|
||||
ostree_sysroot_upgrader_dup_origin
|
||||
ostree_sysroot_upgrader_set_origin
|
||||
ostree_sysroot_upgrader_get_origin_description
|
||||
ostree_sysroot_upgrader_set_parent_mountns
|
||||
ostree_sysroot_upgrader_check_timestamps
|
||||
OstreeSysrootUpgraderPullFlags
|
||||
ostree_sysroot_upgrader_pull
|
||||
|
@ -23,6 +23,7 @@
|
||||
LIBOSTREE_2025.2 {
|
||||
global:
|
||||
ostree_sepolicy_set_null_log;
|
||||
ostree_sysroot_upgrader_set_parent_mountns;
|
||||
} LIBOSTREE_2025.1;
|
||||
|
||||
/* Stub section for the stable release *after* this development one; don't
|
||||
|
@ -4259,6 +4259,102 @@ ostree_sysroot_deployment_set_mutable (OstreeSysroot *self, OstreeDeployment *de
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_sysroot_deployment_prepare_next_root
|
||||
* @self: Sysroot
|
||||
* @deployment: Deployment to prepare /run/nextroot for
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Prepare the specified deployment for a systemd soft-reboot by creating a new
|
||||
* root with it at /run/nextroot
|
||||
*
|
||||
* Since: TODO
|
||||
*/
|
||||
gboolean
|
||||
ostree_sysroot_deployment_prepare_next_root (OstreeSysroot *self, OstreeDeployment *deployment,
|
||||
GCancellable *cancellable, GError **error)
|
||||
{
|
||||
GLNX_AUTO_PREFIX_ERROR ("Preparing /run/nextroot for a soft-reboot", error);
|
||||
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
|
||||
const char *kargs_const = ostree_bootconfig_parser_get (bootconfig, "options");
|
||||
g_autofree gchar *kargs = g_strdup (kargs_const);
|
||||
gint exit_status;
|
||||
g_autoptr (GPtrArray) args = g_ptr_array_new ();
|
||||
|
||||
/* We cannot just make a bind mount, because when the soft reboot happens, our
|
||||
current root will be unmounted, and the bind mount will break. Therefore,
|
||||
we have to recreate the mount at a different location. */
|
||||
|
||||
/* Read in mounted FSes */
|
||||
g_autofree gchar *mounts_contents = NULL;
|
||||
if (!g_file_get_contents ("/proc/self/mounts", &mounts_contents, NULL, error))
|
||||
return FALSE;
|
||||
g_auto (GStrv) mounts = g_strsplit (mounts_contents, "\n", -1);
|
||||
for (char **iter = mounts; iter && *iter; iter++)
|
||||
{
|
||||
const gchar *mount_text = *iter;
|
||||
g_auto (GStrv) mount_fields = g_strsplit (mount_text, " ", 6);
|
||||
/* Validate all 6 tokens are present */
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
if (mount_fields[i] == NULL)
|
||||
{
|
||||
ot_journal_print (LOG_WARNING, "Mount %s is missing a field at %d!", mount_text, i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only care about /sysroot */
|
||||
if (!g_str_equal (mount_fields[1], "/sysroot"))
|
||||
continue;
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, "/run/nextroot", 0755, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (mount (mount_fields[0], "/run/nextroot", mount_fields[2], MS_SILENT, NULL))
|
||||
{
|
||||
glnx_prefix_error (error, "failed to mount /run/nextroot");
|
||||
goto err_unlink;
|
||||
}
|
||||
|
||||
/* Found it, and mounted it! */
|
||||
goto end_loop;
|
||||
}
|
||||
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Couldn't find mountpoint for /sysroot!");
|
||||
return FALSE;
|
||||
|
||||
end_loop:
|
||||
|
||||
/* At this point, /sysroot is mounted at /run/nextroot, do the pivot from there: */
|
||||
g_ptr_array_add (args, "/usr/lib/ostree/ostree-prepare-root");
|
||||
g_ptr_array_add (args, "/run/nextroot");
|
||||
g_ptr_array_add (args, kargs);
|
||||
g_ptr_array_add (args, NULL);
|
||||
|
||||
if (!g_spawn_sync (NULL, (char **)args->pdata, NULL, 0, NULL, NULL, NULL, NULL, &exit_status,
|
||||
error))
|
||||
goto err_unlink;
|
||||
|
||||
if (!g_spawn_check_exit_status (exit_status, error))
|
||||
{
|
||||
glnx_prefix_error (error, "failed to prepare next root");
|
||||
goto err_unlink;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
err_unlink:
|
||||
/* We're already handling an error, not much we can do if this fails too... */
|
||||
if (unlinkat (AT_FDCWD, "/run/nextroot", AT_REMOVEDIR) < 0)
|
||||
ot_journal_print (LOG_WARNING,
|
||||
"Couldn't remove /run/nextroot while cleaning up from failed next root");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_sysroot_deployment_kexec_load
|
||||
* @self: Sysroot
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "ostree-sysroot-upgrader.h"
|
||||
#include "ostree.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
/**
|
||||
* SECTION:ostree-sysroot-upgrader
|
||||
* @title: Simple upgrade class
|
||||
@ -53,6 +55,8 @@ struct OstreeSysrootUpgrader
|
||||
char *override_csum;
|
||||
|
||||
char *new_revision;
|
||||
|
||||
int parent_mountns;
|
||||
};
|
||||
|
||||
enum
|
||||
@ -139,6 +143,8 @@ ostree_sysroot_upgrader_initable_init (GInitable *initable, GCancellable *cancel
|
||||
if (!parse_refspec (self, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
self->parent_mountns = -1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -381,6 +387,21 @@ ostree_sysroot_upgrader_get_origin_description (OstreeSysrootUpgrader *self)
|
||||
return g_key_file_get_string (self->origin, "origin", "refspec", NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_sysroot_upgrader_set_parent_mountns:
|
||||
* @self: Sysroot Upgrader
|
||||
* @mountns: FD of the parent mount NS
|
||||
*
|
||||
* Replace FD of the parent mountns
|
||||
*/
|
||||
gboolean
|
||||
ostree_sysroot_upgrader_set_parent_mountns (OstreeSysrootUpgrader *self, int mountns)
|
||||
{
|
||||
self->parent_mountns = mountns;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_sysroot_upgrader_check_timestamps:
|
||||
* @repo: Repo
|
||||
@ -628,6 +649,36 @@ ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self, GCancellable *cance
|
||||
error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((self->flags & OSTREE_SYSROOT_UPGRADER_FLAGS_SOFT_REBOOT) > 0)
|
||||
{
|
||||
/* Need to fork because setns will fail if we have threads (GIO loop) */
|
||||
pid_t child_pid = fork ();
|
||||
if (child_pid < 0)
|
||||
{
|
||||
return glnx_throw_errno_prefix (error, "fork() for parent mount ns");
|
||||
}
|
||||
|
||||
/* Hop back into the main system's mount NS so we can mount /run/nextroot */
|
||||
if (child_pid == 0)
|
||||
{
|
||||
if (self->parent_mountns >= 0 && setns (self->parent_mountns, CLONE_NEWNS))
|
||||
{
|
||||
return glnx_throw_errno_prefix (error, "Couldn't recover parent mount NS!");
|
||||
}
|
||||
if (!ostree_sysroot_deployment_prepare_next_root (self->sysroot, new_deployment,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
gint status;
|
||||
if (waitpid (child_pid, &status, 0) < 0)
|
||||
{
|
||||
return glnx_throw_errno_prefix (error, "waitpid() for mount ns child");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -645,6 +696,8 @@ ostree_sysroot_upgrader_flags_get_type (void)
|
||||
"OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED", "ignore-unconfigured" },
|
||||
{ OSTREE_SYSROOT_UPGRADER_FLAGS_STAGE, "OSTREE_SYSROOT_UPGRADER_FLAGS_STAGE", "stage" },
|
||||
{ OSTREE_SYSROOT_UPGRADER_FLAGS_KEXEC, "OSTREE_SYSROOT_UPGRADER_FLAGS_KEXEC", "kexec" },
|
||||
{ OSTREE_SYSROOT_UPGRADER_FLAGS_SOFT_REBOOT, "OSTREE_SYSROOT_UPGRADER_FLAGS_SOFT_REBOOT",
|
||||
"soft_reboot" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
GType g_define_type_id
|
||||
|
@ -45,6 +45,7 @@ typedef enum
|
||||
OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED = (1 << 1),
|
||||
OSTREE_SYSROOT_UPGRADER_FLAGS_STAGE = (1 << 2),
|
||||
OSTREE_SYSROOT_UPGRADER_FLAGS_KEXEC = (1 << 3),
|
||||
OSTREE_SYSROOT_UPGRADER_FLAGS_SOFT_REBOOT = (1 << 4),
|
||||
} OstreeSysrootUpgraderFlags;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
@ -80,6 +81,9 @@ gboolean ostree_sysroot_upgrader_set_origin (OstreeSysrootUpgrader *self, GKeyFi
|
||||
_OSTREE_PUBLIC
|
||||
char *ostree_sysroot_upgrader_get_origin_description (OstreeSysrootUpgrader *self);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_sysroot_upgrader_set_parent_mountns (OstreeSysrootUpgrader *self, int mountns);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo, const char *from_rev,
|
||||
const char *to_rev, GError **error);
|
||||
|
@ -268,6 +268,11 @@ gboolean ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, const c
|
||||
OstreeSysrootSimpleWriteDeploymentFlags flags,
|
||||
GCancellable *cancellable, GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_sysroot_deployment_prepare_next_root (OstreeSysroot *self,
|
||||
OstreeDeployment *deployment,
|
||||
GCancellable *cancellable, GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_sysroot_deployment_kexec_load (OstreeSysroot *self, OstreeDeployment *deployment,
|
||||
GCancellable *cancellable, GError **error);
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
static gboolean opt_reboot;
|
||||
static gboolean opt_kexec;
|
||||
static gboolean opt_soft_reboot;
|
||||
static gboolean opt_allow_downgrade;
|
||||
static gboolean opt_pull_only;
|
||||
static gboolean opt_deploy_only;
|
||||
@ -44,6 +45,8 @@ static GOptionEntry options[] = {
|
||||
"Use a different operating system root than the current one", "OSNAME" },
|
||||
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Reboot after a successful upgrade", NULL },
|
||||
{ "kexec", 'k', 0, G_OPTION_ARG_NONE, &opt_kexec, "Stage new kernel in kexec", NULL },
|
||||
{ "soft-reboot", 'x', 0, G_OPTION_ARG_NONE, &opt_soft_reboot,
|
||||
"Prepare nextroot for a systemd soft reboot", NULL },
|
||||
{ "allow-downgrade", 0, 0, G_OPTION_ARG_NONE, &opt_allow_downgrade,
|
||||
"Permit deployment of chronologically older trees", NULL },
|
||||
{ "override-commit", 0, 0, G_OPTION_ARG_STRING, &opt_override_commit,
|
||||
@ -86,12 +89,17 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeCommandInvocation *invoca
|
||||
flags |= OSTREE_SYSROOT_UPGRADER_FLAGS_STAGE;
|
||||
if (opt_kexec)
|
||||
flags |= OSTREE_SYSROOT_UPGRADER_FLAGS_KEXEC;
|
||||
if (opt_soft_reboot)
|
||||
flags |= OSTREE_SYSROOT_UPGRADER_FLAGS_SOFT_REBOOT;
|
||||
|
||||
g_autoptr (OstreeSysrootUpgrader) upgrader = ostree_sysroot_upgrader_new_for_os_with_flags (
|
||||
sysroot, opt_osname, flags, cancellable, error);
|
||||
if (!upgrader)
|
||||
return FALSE;
|
||||
|
||||
if (!ostree_sysroot_upgrader_set_parent_mountns (upgrader, invocation->parent_mountns))
|
||||
return FALSE;
|
||||
|
||||
g_autoptr (GKeyFile) origin = ostree_sysroot_upgrader_dup_origin (upgrader);
|
||||
if (origin != NULL)
|
||||
{
|
||||
|
@ -174,6 +174,7 @@ ostree_builtin_admin (int argc, char **argv, OstreeCommandInvocation *invocation
|
||||
g_set_prgname (prgname);
|
||||
}
|
||||
|
||||
OstreeCommandInvocation sub_invocation = { .command = subcommand };
|
||||
OstreeCommandInvocation sub_invocation = *invocation;
|
||||
sub_invocation.command = subcommand;
|
||||
return subcommand->fn (argc, argv, &sub_invocation, cancellable, error);
|
||||
}
|
||||
|
@ -288,6 +288,13 @@ ostree_run (int argc, char **argv, OstreeCommand *commands, GError **res_error)
|
||||
command++;
|
||||
}
|
||||
|
||||
int parent_mountns = open ("/proc/self/ns/mnt", O_RDONLY | O_NOCTTY | O_CLOEXEC);
|
||||
if (parent_mountns < 0)
|
||||
{
|
||||
glnx_throw_errno_prefix (&error, "open(mountns)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!command->fn)
|
||||
{
|
||||
g_autoptr (GOptionContext) context = ostree_option_context_new_with_commands (commands);
|
||||
@ -315,7 +322,8 @@ ostree_run (int argc, char **argv, OstreeCommand *commands, GError **res_error)
|
||||
prgname = g_strdup_printf ("%s %s", g_get_prgname (), command_name);
|
||||
g_set_prgname (prgname);
|
||||
#endif
|
||||
OstreeCommandInvocation invocation = { .command = command };
|
||||
OstreeCommandInvocation invocation = { .command = command, .parent_mountns = parent_mountns };
|
||||
|
||||
if (!command->fn (argc, argv, &invocation, cancellable, &error))
|
||||
goto out;
|
||||
|
||||
|
@ -61,6 +61,7 @@ typedef struct
|
||||
struct OstreeCommandInvocation
|
||||
{
|
||||
OstreeCommand *command;
|
||||
int parent_mountns;
|
||||
};
|
||||
|
||||
int ostree_main (int argc, char **argv, OstreeCommand *commands);
|
||||
|
Loading…
x
Reference in New Issue
Block a user