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

openSUSE Build Service is sponsored by