From a1fbb752dd800c0aaaacc60bce33bf696f45d1a4 Mon Sep 17 00:00:00 2001 From: Gary Lin 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 --- 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 #include +#include #include #include #include @@ -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