On Mon, Oct 14, 2024 at 1:10 PM Leo Sandoval <lsand...@redhat.com> wrote:
>
> 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
>

LGTM. :)

Reviewed-by: Neal Gompa <ngomp...@gmail.com>



-- 
真実はいつも一つ!/ Always, there's only one truth!

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

Reply via email to