mirror of
https://github.com/ostreedev/ostree.git
synced 2025-01-31 05:47:40 +03:00
Track deployment root/inode from prepare root
When we added composefs, it broke the logic for detecting the booted deployment which was previously a direct (device, inode) comparison. So the code there started looking at `etc`. However, that in turns breaks with `etc.transient = true` enabled. Fix all of this by tracking the real deployment directory's (device,inode) that we found in `ostree-prepare-root`, and inject it into the extensible metadata we have in `/run/ostree-booted` which is designed exactly to pass state between the initramfs and the real root. Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
parent
da89214065
commit
525a57d21d
@ -74,8 +74,9 @@ struct OstreeSysroot
|
||||
/* The device/inode for / and /etc, used to detect booted deployment */
|
||||
dev_t root_device;
|
||||
ino_t root_inode;
|
||||
dev_t etc_device;
|
||||
ino_t etc_inode;
|
||||
|
||||
// The parsed data from /run/ostree
|
||||
GVariantDict *run_ostree_metadata;
|
||||
|
||||
gboolean is_physical; /* TRUE if we're pointed at physical storage root and not a deployment */
|
||||
GPtrArray *deployments;
|
||||
|
@ -83,6 +83,7 @@ ostree_sysroot_finalize (GObject *object)
|
||||
|
||||
g_clear_object (&self->path);
|
||||
g_clear_object (&self->repo);
|
||||
g_clear_pointer (&self->run_ostree_metadata, g_variant_dict_unref);
|
||||
g_clear_pointer (&self->deployments, g_ptr_array_unref);
|
||||
g_clear_object (&self->booted_deployment);
|
||||
g_clear_object (&self->staged_deployment);
|
||||
@ -808,26 +809,35 @@ parse_deployment (OstreeSysroot *self, const char *boot_link, OstreeDeployment *
|
||||
if (looking_for_booted_deployment)
|
||||
{
|
||||
struct stat stbuf;
|
||||
struct stat etc_stbuf = {};
|
||||
if (!glnx_fstat (deployment_dfd, &stbuf, error))
|
||||
return FALSE;
|
||||
|
||||
/* We look for either the root or the etc subdir of the
|
||||
* deployment. We need to do this, because when using composefs,
|
||||
* the root is not a bind mount of the deploy dir, but the etc
|
||||
* dir is.
|
||||
/* ostree-prepare-root records the (device, inode) pair of the underlying real deployment
|
||||
* directory (before we might have mounted a composefs or overlayfs on top).
|
||||
*
|
||||
* Because this parser is operating outside the mounted namespace, we compare against
|
||||
* that backing directory.
|
||||
*/
|
||||
|
||||
if (!glnx_fstatat_allow_noent (deployment_dfd, "etc", &etc_stbuf, 0, error))
|
||||
return FALSE;
|
||||
g_assert (self->run_ostree_metadata);
|
||||
guint64 expected_root_dev = 0;
|
||||
guint64 expected_root_inode = 0;
|
||||
if (!g_variant_dict_lookup (self->run_ostree_metadata,
|
||||
OTCORE_RUN_BOOTED_KEY_BACKING_ROOTDEVINO, "(tt)",
|
||||
&expected_root_dev, &expected_root_inode))
|
||||
{
|
||||
g_debug ("Missing %s", OTCORE_RUN_BOOTED_KEY_BACKING_ROOTDEVINO);
|
||||
expected_root_dev = (guint64)self->root_device;
|
||||
expected_root_inode = (guint64)self->root_inode;
|
||||
}
|
||||
else
|
||||
g_debug ("Target rootdev key %s found", OTCORE_RUN_BOOTED_KEY_BACKING_ROOTDEVINO);
|
||||
|
||||
/* A bit ugly, we're assigning to a sysroot-owned variable from deep in
|
||||
* this parsing code. But eh, if something fails the sysroot state can't
|
||||
* be relied on anyways.
|
||||
*/
|
||||
is_booted_deployment
|
||||
= (stbuf.st_dev == self->root_device && stbuf.st_ino == self->root_inode)
|
||||
|| (etc_stbuf.st_dev == self->etc_device && etc_stbuf.st_ino == self->etc_inode);
|
||||
= stbuf.st_dev == expected_root_dev && stbuf.st_ino == expected_root_inode;
|
||||
}
|
||||
|
||||
g_autoptr (OstreeDeployment) ret_deployment
|
||||
@ -1016,10 +1026,21 @@ ostree_sysroot_initialize (OstreeSysroot *self, GError **error)
|
||||
* we'll use it to sanity check that we found a booted deployment for example.
|
||||
* Second, we also find out whether sysroot == /.
|
||||
*/
|
||||
if (!glnx_fstatat_allow_noent (AT_FDCWD, OSTREE_PATH_BOOTED, NULL, 0, error))
|
||||
glnx_autofd int booted_state_fd = -1;
|
||||
if (!ot_openat_ignore_enoent (AT_FDCWD, OSTREE_PATH_BOOTED, &booted_state_fd, error))
|
||||
return FALSE;
|
||||
const gboolean ostree_booted = (errno == 0);
|
||||
const gboolean ostree_booted = booted_state_fd != -1;
|
||||
|
||||
if (booted_state_fd != -1)
|
||||
{
|
||||
g_autoptr (GVariant) ostree_run_metadata_v = NULL;
|
||||
if (!ot_variant_read_fd (booted_state_fd, 0, G_VARIANT_TYPE_VARDICT, TRUE,
|
||||
&ostree_run_metadata_v, error))
|
||||
return glnx_prefix_error (error, "failed to read %s", OTCORE_RUN_BOOTED);
|
||||
self->run_ostree_metadata = g_variant_dict_new (ostree_run_metadata_v);
|
||||
}
|
||||
|
||||
// Gather the root device/inode
|
||||
{
|
||||
struct stat root_stbuf;
|
||||
if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error))
|
||||
@ -1028,17 +1049,6 @@ ostree_sysroot_initialize (OstreeSysroot *self, GError **error)
|
||||
self->root_inode = root_stbuf.st_ino;
|
||||
}
|
||||
|
||||
{
|
||||
struct stat etc_stbuf;
|
||||
if (!glnx_fstatat_allow_noent (AT_FDCWD, "/etc", &etc_stbuf, 0, error))
|
||||
return FALSE;
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
self->etc_device = etc_stbuf.st_dev;
|
||||
self->etc_inode = etc_stbuf.st_ino;
|
||||
}
|
||||
}
|
||||
|
||||
struct stat self_stbuf;
|
||||
if (!glnx_fstatat (AT_FDCWD, gs_file_get_path_cached (self->path), &self_stbuf, 0, error))
|
||||
return FALSE;
|
||||
@ -1047,6 +1057,7 @@ ostree_sysroot_initialize (OstreeSysroot *self, GError **error)
|
||||
= (self->root_device == self_stbuf.st_dev && self->root_inode == self_stbuf.st_ino);
|
||||
|
||||
self->root_is_ostree_booted = (ostree_booted && root_is_sysroot);
|
||||
g_debug ("root_is_ostree_booted: %d", self->root_is_ostree_booted);
|
||||
self->loadstate = OSTREE_SYSROOT_LOAD_STATE_INIT;
|
||||
}
|
||||
|
||||
|
@ -82,5 +82,7 @@ GKeyFile *otcore_load_config (int rootfs, const char *filename, GError **error);
|
||||
#define OTCORE_RUN_BOOTED_KEY_ROOT_TRANSIENT "root.transient"
|
||||
// This key will be present if the sysroot-ro flag was found
|
||||
#define OTCORE_RUN_BOOTED_KEY_SYSROOT_RO "sysroot-ro"
|
||||
// Always holds the (device, inode) pair of the booted deployment
|
||||
#define OTCORE_RUN_BOOTED_KEY_BACKING_ROOTDEVINO "backing-root-device-inode"
|
||||
|
||||
#define OTCORE_RUN_BOOTED_KEY_TRANSIENT_ETC "transient-etc"
|
||||
|
@ -430,6 +430,15 @@ main (int argc, char *argv[])
|
||||
GVariantBuilder metadata_builder;
|
||||
g_variant_builder_init (&metadata_builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
|
||||
/* Record the underlying plain deployment directory (device,inode) pair
|
||||
* so that it can be later checked by the sysroot code to figure out
|
||||
* which deployment was booted.
|
||||
*/
|
||||
if (lstat (".", &stbuf) < 0)
|
||||
err (EXIT_FAILURE, "lstat deploy_root");
|
||||
g_variant_builder_add (&metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_BACKING_ROOTDEVINO,
|
||||
g_variant_new ("(tt)", (guint64)stbuf.st_dev, (guint64)stbuf.st_ino));
|
||||
|
||||
// Tracks if we did successfully enable it at runtime
|
||||
bool using_composefs = false;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user