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
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
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
}
10 changes: 9 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,13 @@ 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)
Copy link
Member

Choose a reason for hiding this comment

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

Very minor style thing, having a { is preferred on at least the outer conditional in these nested if setups.

if (!ostree_sysroot_deployment_kexec_load(self->sysroot, new_deployment, cancellable, error))
return FALSE;
}

return TRUE;
Expand All @@ -635,6 +641,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.

} 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,
Copy link
Member

Choose a reason for hiding this comment

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

When adding new API you'll need to also add this libostree-devel.sym. There's a few subtleties around this and it's probably easier if I just add a commit for you to apply to your branch, will do in a bit.

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