Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bin/admin-upgrade: add kexec support #3362

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Makefile-libostree.am
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ endif # USE_GPGME
symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym

# Uncomment this include when adding new development symbols.
#if BUILDOPT_IS_DEVEL_BUILD
#symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
#endif
if BUILDOPT_IS_DEVEL_BUILD
symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
endif

# http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html
wl_versionscript_arg = -Wl,--version-script=
Expand Down
1 change: 1 addition & 0 deletions apidoc/ostree-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,7 @@ ostree_sysroot_repo
ostree_sysroot_get_repo
ostree_sysroot_get_staged_deployment
ostree_sysroot_init_osname
ostree_sysroot_deployment_kexec_load
ostree_sysroot_deployment_set_kargs
ostree_sysroot_deployment_set_kargs_in_place
ostree_sysroot_deployment_set_mutable
Expand Down
16 changes: 16 additions & 0 deletions man/ostree-admin-switch.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
<title>Options</title>

<variablelist>
<varlistentry>
<term><option>--reboot</option>,<option>-r</option></term>

<listitem><para>
Reboot after a successful switch.
</para></listitem>
</varlistentry>

<varlistentry>
<term><option>--kexec</option>,<option>-k</option></term>

<listitem><para>
Load new deployment into kexec after a successful switch.
</para></listitem>
</varlistentry>

<varlistentry>
<term><option>--os</option>="STATEROOT"</term>

Expand Down
8 changes: 8 additions & 0 deletions man/ostree-admin-upgrade.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
Reboot after a successful upgrade.
</para></listitem>
</varlistentry>

<varlistentry>
<term><option>--kexec</option>,<option>-k</option></term>

<listitem><para>
Load new deployment into kexec after a successful upgrade.
</para></listitem>
</varlistentry>

<varlistentry>
<term><option>--allow-downgrade</option></term>
Expand Down
5 changes: 5 additions & 0 deletions src/libostree/libostree-devel.sym
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
- uncomment the include in Makefile-libostree.am
*/

LIBOSTREE_2024.11 {
global:
ostree_sysroot_deployment_kexec_load;
} LIBOSTREE_2024.7;

/* Stub section for the stable release *after* this development one; don't
* edit this other than to update the year. This is just a copy/paste
* source. Replace $LASTSTABLE with the last stable version, and $NEWVERSION
Expand Down
61 changes: 61 additions & 0 deletions src/libostree/ostree-sysroot-deploy.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/statvfs.h>
#include <linux/kexec.h>

#ifdef HAVE_LIBMOUNT
#include <libmount.h>
Expand Down Expand Up @@ -4265,3 +4266,63 @@ ostree_sysroot_deployment_set_mutable (OstreeSysroot *self, OstreeDeployment *de

return TRUE;
}

/**
* ostree_sysroot_deployment_kexec_load
* @self: Sysroot
* @deployment: Deployment to prepare a kexec for
* @cancellable: Cancellable
* @error: Error
*
* Prepare the specified deployment for a kexec.
*/
gboolean
ostree_sysroot_deployment_kexec_load (OstreeSysroot *self, OstreeDeployment *deployment,
GCancellable *cancellable, GError **error)
{
#ifdef SYS_kexec_file_load
GLNX_AUTO_PREFIX_ERROR ("Loading kernel into kexec", error);
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
const char *kargs = ostree_bootconfig_parser_get(bootconfig, "options");
g_autofree char *deployment_dirpath = ostree_sysroot_get_deployment_dirpath (self, deployment);
glnx_autofd int deployment_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, deployment_dirpath, FALSE, &deployment_dfd, error))
return FALSE;

/* Find the kernel/initramfs in the tree */
g_autoptr (OstreeKernelLayout) kernel_layout = NULL;
if (!get_kernel_from_tree (self, deployment_dfd, &kernel_layout, cancellable, error))
return FALSE;

unsigned long flags = 0;
glnx_autofd int kernel_fd = -1;
glnx_autofd int initrd_fd = -1;

if (!glnx_openat_rdonly (kernel_layout->boot_dfd, kernel_layout->kernel_srcpath,
TRUE, &kernel_fd, error))
return FALSE;

/* initramfs is optional */
if (kernel_layout->initramfs_srcpath)
{
if (!glnx_openat_rdonly (kernel_layout->boot_dfd, kernel_layout->initramfs_srcpath,
TRUE, &initrd_fd, error))
{
return FALSE;
}
}
else
{
flags |= KEXEC_FILE_NO_INITRAMFS;
}

if (syscall (SYS_kexec_file_load, kernel_fd, initrd_fd, strlen (kargs) + 1, kargs, flags))
return glnx_throw_errno_prefix(error, "kexec_file_load");

return TRUE;
#else
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"This version of ostree is not compiled with kexec support");
return FALSE;
#endif // SYS_kexec_file_load
}
12 changes: 11 additions & 1 deletion src/libostree/ostree-sysroot-upgrader.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self, GCancellable *cance
/* Experimental flag to enable staging */
gboolean stage = (self->flags & OSTREE_SYSROOT_UPGRADER_FLAGS_STAGE) > 0
|| getenv ("OSTREE_EX_STAGE_DEPLOYMENTS") != NULL;
OstreeSysrootSimpleWriteDeploymentFlags write_deployment_flags = OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NONE;
if (stage)
{
if (!ostree_sysroot_stage_tree (self->sysroot, self->osname, self->new_revision, self->origin,
Expand All @@ -616,8 +617,15 @@ ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self, GCancellable *cance
return FALSE;

if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname, new_deployment,
self->merge_deployment, 0, cancellable, error))
self->merge_deployment, write_deployment_flags, cancellable, error))
return FALSE;


if ((self->flags & OSTREE_SYSROOT_UPGRADER_FLAGS_KEXEC) > 0)
Mstrodl marked this conversation as resolved.
Show resolved Hide resolved
{
if (!ostree_sysroot_deployment_kexec_load(self->sysroot, new_deployment, cancellable, error))
return FALSE;
}
}

return TRUE;
Expand All @@ -635,6 +643,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" },
{ 0, NULL, NULL } };
GType g_define_type_id
= g_flags_register_static (g_intern_static_string ("OstreeSysrootUpgraderFlags"), values);
Expand Down
1 change: 1 addition & 0 deletions src/libostree/ostree-sysroot-upgrader.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ typedef enum
OSTREE_SYSROOT_UPGRADER_FLAGS_NONE = (1 << 0),
OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED = (1 << 1),
OSTREE_SYSROOT_UPGRADER_FLAGS_STAGE = (1 << 2),
OSTREE_SYSROOT_UPGRADER_FLAGS_KEXEC = (1 << 3),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not opposed but do you think we still need this API flag though, versus just having callers chose to do it?

It feels like an optional secondary step, and it's basically a flag that just adds an API call that the invoking code can just run directly too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I did it this way was because the updater doesn't expose the deployment to the caller. If there's some way to do it that I'm missing though, let me know!

} OstreeSysrootUpgraderFlags;

_OSTREE_PUBLIC
Expand Down
5 changes: 5 additions & 0 deletions src/libostree/ostree-sysroot.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,9 @@ gboolean ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, const c
OstreeSysrootSimpleWriteDeploymentFlags flags,
GCancellable *cancellable, GError **error);

_OSTREE_PUBLIC
gboolean
ostree_sysroot_deployment_kexec_load (OstreeSysroot *self, OstreeDeployment *deployment,
Mstrodl marked this conversation as resolved.
Show resolved Hide resolved
GCancellable *cancellable, GError **error);

G_END_DECLS
8 changes: 7 additions & 1 deletion src/ostree/ot-admin-builtin-switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@
#include <unistd.h>

static gboolean opt_reboot;
static gboolean opt_kexec;
static char *opt_osname;

static GOptionEntry options[]
= { { "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Reboot after switching trees", NULL },
{ "kexec", 'k', 0, G_OPTION_ARG_NONE, &opt_kexec, "Stage new kernel in kexec", NULL },
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname,
"Use a different operating system root than the current one", "OSNAME" },
{ NULL } };
Expand All @@ -56,8 +58,12 @@ ot_admin_builtin_switch (int argc, char **argv, OstreeCommandInvocation *invocat

const char *new_provided_refspec = argv[1];

OstreeSysrootUpgraderFlags flags = OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED;
if (opt_kexec)
flags |= OSTREE_SYSROOT_UPGRADER_FLAGS_KEXEC;

g_autoptr (OstreeSysrootUpgrader) upgrader = ostree_sysroot_upgrader_new_for_os_with_flags (
sysroot, opt_osname, OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED, cancellable, error);
sysroot, opt_osname, flags, cancellable, error);
if (!upgrader)
return FALSE;

Expand Down
8 changes: 6 additions & 2 deletions src/ostree/ot-admin-builtin-upgrade.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <unistd.h>

static gboolean opt_reboot;
static gboolean opt_kexec;
static gboolean opt_allow_downgrade;
static gboolean opt_pull_only;
static gboolean opt_deploy_only;
Expand All @@ -42,6 +43,7 @@ static GOptionEntry options[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname,
"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 },
{ "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,
Expand Down Expand Up @@ -72,16 +74,18 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeCommandInvocation *invoca
"Cannot simultaneously specify --pull-only and --deploy-only");
return FALSE;
}
else if (opt_pull_only && opt_reboot)
else if (opt_pull_only && (opt_reboot || opt_kexec))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Cannot simultaneously specify --pull-only and --reboot");
"Cannot simultaneously specify --pull-only and --reboot or --kexec");
return FALSE;
}

OstreeSysrootUpgraderFlags flags = 0;
if (opt_stage)
flags |= OSTREE_SYSROOT_UPGRADER_FLAGS_STAGE;
if (opt_kexec)
flags |= OSTREE_SYSROOT_UPGRADER_FLAGS_KEXEC;

g_autoptr (OstreeSysrootUpgrader) upgrader = ostree_sysroot_upgrader_new_for_os_with_flags (
sysroot, opt_osname, flags, cancellable, error);
Expand Down
Loading