diff --git a/man/ostree-admin-switch.xml b/man/ostree-admin-switch.xml
index 6795c49b97..12848c9046 100644
--- a/man/ostree-admin-switch.xml
+++ b/man/ostree-admin-switch.xml
@@ -65,6 +65,22 @@ License along with this library. If not, see .
Options
+
+ --reboot ,-r
+
+
+ Reboot after a successful switch.
+
+
+
+
+ --kexec ,-k
+
+
+ Load new deployment into kexec after a successful switch.
+
+
+
--os ="STATEROOT"
diff --git a/man/ostree-admin-upgrade.xml b/man/ostree-admin-upgrade.xml
index ccf7a65bd2..38645af903 100644
--- a/man/ostree-admin-upgrade.xml
+++ b/man/ostree-admin-upgrade.xml
@@ -111,6 +111,14 @@ License along with this library. If not, see .
Reboot after a successful upgrade.
+
+
+ --kexec ,-k
+
+
+ Load new deployment into kexec after a successful upgrade.
+
+
--allow-downgrade
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
index 953b6523d0..e3e333a1d4 100644
--- a/src/libostree/ostree-sysroot-deploy.c
+++ b/src/libostree/ostree-sysroot-deploy.c
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#ifdef HAVE_LIBMOUNT
#include
@@ -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
+}
diff --git a/src/libostree/ostree-sysroot-upgrader.c b/src/libostree/ostree-sysroot-upgrader.c
index 94654c8668..bff9bde128 100644
--- a/src/libostree/ostree-sysroot-upgrader.c
+++ b/src/libostree/ostree-sysroot-upgrader.c
@@ -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,
@@ -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)
+ if (!ostree_sysroot_deployment_kexec_load(self->sysroot, new_deployment, cancellable, error))
+ return FALSE;
}
return TRUE;
@@ -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);
diff --git a/src/libostree/ostree-sysroot-upgrader.h b/src/libostree/ostree-sysroot-upgrader.h
index 5d1e8c2aa5..5e2f5ed8a8 100644
--- a/src/libostree/ostree-sysroot-upgrader.h
+++ b/src/libostree/ostree-sysroot-upgrader.h
@@ -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),
} OstreeSysrootUpgraderFlags;
_OSTREE_PUBLIC
diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h
index 3c23f8dd5a..73c2a408ac 100644
--- a/src/libostree/ostree-sysroot.h
+++ b/src/libostree/ostree-sysroot.h
@@ -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,
+ GCancellable *cancellable, GError **error);
+
G_END_DECLS
diff --git a/src/ostree/ot-admin-builtin-switch.c b/src/ostree/ot-admin-builtin-switch.c
index 592673639f..c8a5461227 100644
--- a/src/ostree/ot-admin-builtin-switch.c
+++ b/src/ostree/ot-admin-builtin-switch.c
@@ -29,10 +29,12 @@
#include
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 } };
@@ -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;
diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c
index 96b1575995..4c9dbbedf2 100644
--- a/src/ostree/ot-admin-builtin-upgrade.c
+++ b/src/ostree/ot-admin-builtin-upgrade.c
@@ -31,6 +31,7 @@
#include
static gboolean opt_reboot;
+static gboolean opt_kexec;
static gboolean opt_allow_downgrade;
static gboolean opt_pull_only;
static gboolean opt_deploy_only;
@@ -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,
@@ -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);