From: Michael Chang <mch...@suse.com>

This patch enables the use of a relative path to the btrfs default subvolume by
setting the environment variable btrfs_relative_path=[y1]. In contrast to using
an absolute path from the toplevel root, which always reads files consistently
from a fixed location, the relative path allows grub to follow changes in the
default subvolume, which might occur as a consequence of a rollback operation.

The btrfs_relative_path environment variable is available but not enabled by
default, so the default path remains aligned with the upstream definition. For
systems that do not require btrfs rollback or booting from snapshots, an
absolute path is preferred, as it makes path handling consistent with other
non-btrfs filesystems and allows file access throughout the filesystem
regardless of subvolumes, etc.

Signed-off-by: Michael Chang <mch...@suse.com>
Signed-off-by: Robbie Harwood <rharw...@redhat.com>
---
 grub-core/fs/btrfs.c | 107 ++++++++++++++++++++++++++++++-------------
 1 file changed, 76 insertions(+), 31 deletions(-)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 14e38a4df..d47f9ab03 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -1335,6 +1335,7 @@ grub_btrfs_mount (grub_device_t dev)
 {
   struct grub_btrfs_data *data;
   grub_err_t err;
+  const char *relpath = grub_env_get ("btrfs_relative_path");
 
   if (!dev->disk)
     {
@@ -1365,11 +1366,14 @@ grub_btrfs_mount (grub_device_t dev)
   data->devices_attached[0].dev = dev;
   data->devices_attached[0].id = data->sblock.this_device.device_id;
 
-  err = btrfs_handle_subvol (data);
-  if (err)
+  if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
     {
-      grub_free (data);
-      return NULL;
+      err = btrfs_handle_subvol (data);
+      if (err)
+      {
+        grub_free (data);
+        return NULL;
+      }
     }
 
   return data;
@@ -1966,24 +1970,39 @@ find_path (struct grub_btrfs_data *data,
   grub_size_t allocated = 0;
   struct grub_btrfs_dir_item *direl = NULL;
   struct grub_btrfs_key key_out;
+  int follow_default;
   const char *ctoken;
   grub_size_t ctokenlen;
   char *path_alloc = NULL;
   char *origpath = NULL;
   unsigned symlinks_max = 32;
+  const char *relpath = grub_env_get ("btrfs_relative_path");
 
+  follow_default = 0;
   origpath = grub_strdup (path);
   if (!origpath)
     return grub_errno;
 
-  if (data->fs_tree)
+  if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
     {
-      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
-      *tree = data->fs_tree;
-      /* This is a tree root, so everything starts at objectid 256 */
-      key->object_id = grub_cpu_to_le64_compile_time 
(GRUB_BTRFS_OBJECT_ID_CHUNK);
-      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
-      key->offset = 0;
+      if (data->fs_tree)
+        {
+          *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+          *tree = data->fs_tree;
+          /* This is a tree root, so everything starts at objectid 256 */
+          key->object_id = grub_cpu_to_le64_compile_time 
(GRUB_BTRFS_OBJECT_ID_CHUNK);
+          key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+          key->offset = 0;
+        }
+      else
+        {
+          *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+          *tree = data->sblock.root_tree;
+          key->object_id = data->sblock.root_dir_objectid;
+          key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+          key->offset = 0;
+          follow_default = 1;
+        }
     }
   else
     {
@@ -1994,15 +2013,23 @@ find_path (struct grub_btrfs_data *data,
 
   while (1)
     {
-      while (path[0] == '/')
-       path++;
-      if (!path[0])
-       break;
-      slash = grub_strchr (path, '/');
-      if (!slash)
-       slash = path + grub_strlen (path);
-      ctoken = path;
-      ctokenlen = slash - path;
+      if (!follow_default)
+       {
+         while (path[0] == '/')
+           path++;
+         if (!path[0])
+           break;
+         slash = grub_strchr (path, '/');
+         if (!slash)
+           slash = path + grub_strlen (path);
+         ctoken = path;
+         ctokenlen = slash - path;
+       }
+      else
+       {
+         ctoken = "default";
+         ctokenlen = sizeof ("default") - 1;
+       }
 
       if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
        {
@@ -2013,7 +2040,9 @@ find_path (struct grub_btrfs_data *data,
 
       if (ctokenlen == 1 && ctoken[0] == '.')
        {
-         path = slash;
+         if (!follow_default)
+           path = slash;
+         follow_default = 0;
          continue;
        }
       if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.')
@@ -2044,8 +2073,9 @@ find_path (struct grub_btrfs_data *data,
          *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
          key->object_id = key_out.offset;
 
-         path = slash;
-
+         if (!follow_default)
+           path = slash;
+         follow_default = 0;
          continue;
        }
 
@@ -2114,7 +2144,9 @@ find_path (struct grub_btrfs_data *data,
          return err;
        }
 
-      path = slash;
+      if (!follow_default)
+       path = slash;
+      follow_default = 0;
       if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK)
        {
          struct grub_btrfs_inode inode;
@@ -2164,14 +2196,26 @@ find_path (struct grub_btrfs_data *data,
          path = path_alloc = tmp;
          if (path[0] == '/')
            {
-             if (data->fs_tree)
+              if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
                {
-                 *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
-                 *tree = data->fs_tree;
-                 /* This is a tree root, so everything starts at objectid 256 
*/
-                 key->object_id = grub_cpu_to_le64_compile_time 
(GRUB_BTRFS_OBJECT_ID_CHUNK);
-                 key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
-                 key->offset = 0;
+                 if (data->fs_tree)
+                   {
+                     *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+                     *tree = data->fs_tree;
+                     /* This is a tree root, so everything starts at objectid 
256 */
+                     key->object_id = grub_cpu_to_le64_compile_time 
(GRUB_BTRFS_OBJECT_ID_CHUNK);
+                     key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+                     key->offset = 0;
+                   }
+                 else
+                   {
+                     *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+                     *tree = data->sblock.root_tree;
+                     key->object_id = data->sblock.root_dir_objectid;
+                     key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+                     key->offset = 0;
+                     follow_default = 1;
+                   }
                }
              else
                {
@@ -2922,6 +2966,7 @@ GRUB_MOD_INIT (btrfs)
                                subvolid_set_env);
   grub_env_export ("btrfs_subvol");
   grub_env_export ("btrfs_subvolid");
+  grub_env_export ("btrfs_relative_path");
 }
 
 GRUB_MOD_FINI (btrfs)
-- 
2.46.2


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to