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