File grub2-btrfs-filter-non-subvol-mount.patch of Package grub2
From a1fbb752dd800c0aaaacc60bce33bf696f45d1a4 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Thu, 20 Mar 2025 15:08:14 +0800
Subject: [PATCH] osdep/linux: skip non-subvolume btrfs mount points
To apply the new btrfs snapshot to '/boot', 'transactional-update apply'
mounts '/boot' to the snapshot with 'mount --rbind'. For example, a new
snapshot 9 is created in '/@/.snapshots/9/snapshot', and 't-u apply'
bind-mounts '/boot' to '/@/.snapshots/9/snapshot/boot'. Then such entry
will be created in /proc/self/mountinfo:
537 62 0:64 /@/.snapshots/9/snapshot/boot /boot rw,relatime shared:486 - btrfs /dev/mapper/luks rw,seclabel,space_cache=v2,subvolid=276,subvol=/@/.snapshots/9/snapshot
This mount point is only temporary and will be gone after reboot.
However, this made 'grub2-mkrelpath -r /boot/grub2' to treat '/boot' as
a legit btrfs subvolume and return '/grub2' rather than '/boot/grub2'.
To filter out the bind-mount entries, the btrfs subvolume check is
introduced to check if the given mount point is a real subvolume or not.
If it's a btrfs subvolume, we should take it into consideration when
producing the relative path. Otherwise, skip the mount point.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/osdep/linux/getroot.c | 39 ++++++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
index d63f19f18..b6c2ff9c3 100644
--- a/grub-core/osdep/linux/getroot.c
+++ b/grub-core/osdep/linux/getroot.c
@@ -20,6 +20,7 @@
#include <config.h>
#include <sys/stat.h>
+#include <sys/statfs.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
@@ -484,6 +485,33 @@ error:
return NULL;
}
+#define BTRFS_SUPER_MAGIC 0x9123683e
+#define BTRFS_FIRST_FREE_OBJECTID 256ULL
+
+static bool
+is_btrfs_subvolume (char *mnt_path)
+{
+ struct statfs sfs;
+ struct stat st;
+ int ret;
+
+ ret = statfs (mnt_path, &sfs);
+ if (ret != 0)
+ return false;
+
+ if (sfs.f_type != BTRFS_SUPER_MAGIC)
+ return false;
+
+ ret = stat(mnt_path, &st);
+ if (ret != 0)
+ return false;
+
+ if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode))
+ return false;
+
+ return true;
+}
+
static char *grub_btrfs_mount_path;
char **
@@ -626,9 +654,17 @@ again:
}
else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
{
- ret = grub_find_root_devices_from_btrfs (dir);
if (use_relative_path_on_btrfs)
{
+ /* 'transactional-update apply' mounts '/boot' to the newly
+ created snapshot with 'mount --rbind', and this creates a
+ non-subvolume btrfs mount point. Such mount point will be
+ gone after reboot. Skip those mount points to produce the
+ correct relative path. (bsc#1239674) */
+ if (!is_btrfs_subvolume (entries[i].enc_path))
+ continue;
+
+ ret = grub_find_root_devices_from_btrfs (dir);
fs_prefix = xstrdup ("/");
if (grub_btrfs_mount_path)
@@ -637,6 +673,7 @@ again:
}
else
{
+ ret = grub_find_root_devices_from_btrfs (dir);
fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
}
}
--
2.43.0