On Mon, Oct 07, 2024 at 09:40:40PM GMT, Vladimir 'phcoder' Serbinenko wrote: > What do you try to achieve with this that can't be achieved with using full > path? We should avoid using hidden state for directory parsing. Solaris > GRUB legacy used it for ZFS and it was a mess.
If a path is relative to the default subvolume, it cannot access files outside of the default subvolume tree. This patch enables access to files in other subvolumes by mounting them to a specific directory Thanks, Michael > > Le lun. 7 oct. 2024, 21:22, Leo Sandoval <lsand...@redhat.com> a écrit : > > > From: Michael Chang <mch...@suse.com> > > > > Signed-off-by: Michael Chang <mch...@suse.com> > > Signed-off-by: Robbie Harwood <rharw...@redhat.com> > > --- > > grub-core/fs/btrfs.c | 195 +++++++++++++++++++++++++++++++- > > grub-core/osdep/linux/getroot.c | 148 +++++++++++++++++++++++- > > include/grub/emu/getroot.h | 5 + > > util/grub-install.c | 49 ++++++++ > > 4 files changed, 392 insertions(+), 5 deletions(-) > > > > diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c > > index d47f9ab03..d44a1c73b 100644 > > --- a/grub-core/fs/btrfs.c > > +++ b/grub-core/fs/btrfs.c > > @@ -41,6 +41,7 @@ > > #include <grub/command.h> > > #include <grub/env.h> > > #include <grub/extcmd.h> > > +#include <grub/list.h> > > #include <grub/crypto.h> > > #include <grub/diskfilter.h> > > #include <grub/safemath.h> > > @@ -266,6 +267,12 @@ static grub_err_t > > grub_btrfs_read_logical (struct grub_btrfs_data *data, > > grub_disk_addr_t addr, void *buf, grub_size_t > > size, > > int recursion_depth); > > +static grub_err_t > > +get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, > > + grub_uint64_t *tree, grub_uint8_t *type); > > + > > +grub_uint64_t > > +find_mtab_subvol_tree (const char *path, char **path_in_subvol); > > > > static grub_err_t > > read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb) > > @@ -1302,9 +1309,26 @@ lookup_root_by_name(struct grub_btrfs_data *data, > > const char *path) > > grub_err_t err; > > grub_uint64_t tree = 0; > > grub_uint8_t type; > > + grub_uint64_t saved_tree; > > struct grub_btrfs_key key; > > > > + if (path[0] == '\0') > > + { > > + data->fs_tree = 0; > > + return GRUB_ERR_NONE; > > + } > > + > > + err = get_root (data, &key, &tree, &type); > > + if (err) > > + return err; > > + > > + saved_tree = data->fs_tree; > > + data->fs_tree = tree; > > + > > err = find_path (data, path, &key, &tree, &type); > > + > > + data->fs_tree = saved_tree; > > + > > if (err) > > return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", > > path); > > > > @@ -2316,11 +2340,20 @@ grub_btrfs_dir (grub_device_t device, const char > > *path, > > grub_uint64_t tree; > > grub_uint8_t type; > > grub_size_t est_size = 0; > > + char *new_path = NULL; > > > > if (!data) > > return grub_errno; > > > > - err = find_path (data, path, &key_in, &tree, &type); > > + tree = find_mtab_subvol_tree (path, &new_path); > > + > > + if (tree) > > + data->fs_tree = tree; > > + > > + err = find_path (data, new_path ? new_path : path, &key_in, &tree, > > &type); > > + if (new_path) > > + grub_free (new_path); > > + > > if (err) > > { > > grub_btrfs_unmount (data); > > @@ -2447,11 +2480,21 @@ grub_btrfs_open (struct grub_file *file, const > > char *name) > > struct grub_btrfs_inode inode; > > grub_uint8_t type; > > struct grub_btrfs_key key_in; > > + grub_uint64_t tree; > > + char *new_path = NULL; > > > > if (!data) > > return grub_errno; > > > > - err = find_path (data, name, &key_in, &data->tree, &type); > > + tree = find_mtab_subvol_tree (name, &new_path); > > + > > + if (tree) > > + data->fs_tree = tree; > > + > > + err = find_path (data, new_path ? new_path : name, &key_in, > > &data->tree, &type); > > + if (new_path) > > + grub_free (new_path); > > + > > if (err) > > { > > grub_btrfs_unmount (data); > > @@ -2686,6 +2729,150 @@ grub_cmd_btrfs_info (grub_command_t cmd > > __attribute__ ((unused)), int argc, > > return 0; > > } > > > > +struct grub_btrfs_mtab > > +{ > > + struct grub_btrfs_mtab *next; > > + struct grub_btrfs_mtab **prev; > > + char *path; > > + char *subvol; > > + grub_uint64_t tree; > > +}; > > + > > +typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t; > > + > > +static struct grub_btrfs_mtab *btrfs_mtab; > > + > > +#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab) > > +#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var), > > (next), btrfs_mtab) > > + > > +static void > > +add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree) > > +{ > > + grub_btrfs_mtab_t m = grub_malloc (sizeof (*m)); > > + > > + m->path = grub_strdup (path); > > + m->subvol = grub_strdup (subvol); > > + m->tree = tree; > > + grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m)); > > +} > > + > > +static grub_err_t > > +grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)), > > int argc, > > + char **argv) > > +{ > > + char *devname, *dirname, *subvol; > > + struct grub_btrfs_key key_in; > > + grub_uint8_t type; > > + grub_uint64_t tree; > > + grub_uint64_t saved_tree; > > + grub_err_t err; > > + struct grub_btrfs_data *data = NULL; > > + grub_device_t dev = NULL; > > + > > + if (argc < 3) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, "required <dev> <dir> and > > <subvol>"); > > + > > + devname = grub_file_get_device_name(argv[0]); > > + dev = grub_device_open (devname); > > + grub_free (devname); > > + > > + if (!dev) > > + { > > + err = grub_errno; > > + goto err_out; > > + } > > + > > + dirname = argv[1]; > > + subvol = argv[2]; > > + > > + data = grub_btrfs_mount (dev); > > + if (!data) > > + { > > + err = grub_errno; > > + goto err_out; > > + } > > + > > + err = find_path (data, dirname, &key_in, &tree, &type); > > + if (err) > > + goto err_out; > > + > > + if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) > > + { > > + err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); > > + goto err_out; > > + } > > + > > + err = get_root (data, &key_in, &tree, &type); > > + > > + if (err) > > + goto err_out; > > + > > + saved_tree = data->fs_tree; > > + data->fs_tree = tree; > > + err = find_path (data, subvol, &key_in, &tree, &type); > > + data->fs_tree = saved_tree; > > + > > + if (err) > > + goto err_out; > > + > > + if (key_in.object_id != grub_cpu_to_le64_compile_time > > (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) > > + { > > + err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", > > subvol); > > + goto err_out; > > + } > > + > > + grub_btrfs_unmount (data); > > + grub_device_close (dev); > > + add_mountpoint (dirname, subvol, tree); > > + > > + return GRUB_ERR_NONE; > > + > > +err_out: > > + > > + if (data) > > + grub_btrfs_unmount (data); > > + > > + if (dev) > > + grub_device_close (dev); > > + > > + return err; > > +} > > + > > +grub_uint64_t > > +find_mtab_subvol_tree (const char *path, char **path_in_subvol) > > +{ > > + grub_btrfs_mtab_t m, cm; > > + grub_uint64_t tree; > > + > > + if (!path || !path_in_subvol) > > + return 0; > > + > > + *path_in_subvol = NULL; > > + tree = 0; > > + cm = NULL; > > + > > + FOR_GRUB_MTAB (m) > > + { > > + if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0) > > + { > > + if (!cm) > > + cm = m; > > + else > > + if (grub_strcmp (m->path, cm->path) > 0) > > + cm = m; > > + } > > + } > > + > > + if (cm) > > + { > > + const char *s = path + grub_strlen (cm->path); > > + *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup > > (s); > > + tree = cm->tree; > > + } > > + > > + return tree; > > +} > > + > > static grub_err_t > > get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, > > grub_uint64_t objectid, grub_uint64_t offset, > > @@ -2892,6 +3079,7 @@ static struct grub_fs grub_btrfs_fs = { > > }; > > > > static grub_command_t cmd_info; > > +static grub_command_t cmd_mount_subvol; > > static grub_extcmd_t cmd_list_subvols; > > > > static char * > > @@ -2955,6 +3143,9 @@ GRUB_MOD_INIT (btrfs) > > cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, > > "DEVICE", > > "Print BtrFS info about DEVICE."); > > + cmd_mount_subvol = grub_register_command("btrfs-mount-subvol", > > grub_cmd_btrfs_mount_subvol, > > + "DEVICE DIRECTORY SUBVOL", > > + "Set btrfs DEVICE the DIRECTORY a > > mountpoint of SUBVOL."); > > cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", > > grub_cmd_btrfs_list_subvols, 0, > > "[-p|-n] [-o var] DEVICE", > > diff --git a/grub-core/osdep/linux/getroot.c > > b/grub-core/osdep/linux/getroot.c > > index 7c29b3523..74a48c030 100644 > > --- a/grub-core/osdep/linux/getroot.c > > +++ b/grub-core/osdep/linux/getroot.c > > @@ -103,6 +103,14 @@ struct btrfs_ioctl_search_key > > grub_uint32_t unused[9]; > > }; > > > > +struct btrfs_ioctl_search_header { > > + grub_uint64_t transid; > > + grub_uint64_t objectid; > > + grub_uint64_t offset; > > + grub_uint32_t type; > > + grub_uint32_t len; > > +}; > > + > > struct btrfs_ioctl_search_args { > > struct btrfs_ioctl_search_key key; > > grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key)) > > @@ -375,6 +383,109 @@ get_btrfs_fs_prefix (const char *mount_path) > > > > int use_relative_path_on_btrfs = 0; > > > > +static char * > > +get_btrfs_subvol (const char *path) > > +{ > > + struct btrfs_ioctl_ino_lookup_args args; > > + grub_uint64_t tree_id; > > + int fd = -1; > > + char *ret = NULL; > > + > > + fd = open (path, O_RDONLY); > > + > > + if (fd < 0) > > + return NULL; > > + > > + memset (&args, 0, sizeof(args)); > > + args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID; > > + > > + if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) > > + goto error; > > + > > + tree_id = args.treeid; > > + > > + while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID) > > + { > > + struct btrfs_ioctl_search_args sargs; > > + struct grub_btrfs_root_backref *br; > > + struct btrfs_ioctl_search_header *search_header; > > + char *old; > > + grub_uint16_t len; > > + grub_uint64_t inode_id; > > + > > + memset (&sargs, 0, sizeof(sargs)); > > + > > + sargs.key.tree_id = 1; > > + sargs.key.min_objectid = tree_id; > > + sargs.key.max_objectid = tree_id; > > + > > + sargs.key.min_offset = 0; > > + sargs.key.max_offset = ~0ULL; > > + sargs.key.min_transid = 0; > > + sargs.key.max_transid = ~0ULL; > > + sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; > > + sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; > > + > > + sargs.key.nr_items = 1; > > + > > + if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0) > > + goto error; > > + > > + if (sargs.key.nr_items == 0) > > + goto error; > > + > > + search_header = (struct btrfs_ioctl_search_header *)sargs.buf; > > + br = (struct grub_btrfs_root_backref *) (search_header + 1); > > + > > + len = grub_le_to_cpu16 (br->n); > > + inode_id = grub_le_to_cpu64 (br->inode_id); > > + tree_id = search_header->offset; > > + > > + old = ret; > > + ret = malloc (len + 1); > > + memcpy (ret, br->name, len); > > + ret[len] = '\0'; > > + > > + if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID) > > + { > > + char *s; > > + > > + memset(&args, 0, sizeof(args)); > > + args.treeid = search_header->offset; > > + args.objectid = inode_id; > > + > > + if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) > > + goto error; > > + > > + s = xasprintf ("%s%s", args.name, ret); > > + free (ret); > > + ret = s; > > + } > > + > > + if (old) > > + { > > + char *s = xasprintf ("%s/%s", ret, old); > > + free (ret); > > + free (old); > > + ret = s; > > + } > > + } > > + > > + close (fd); > > + return ret; > > + > > +error: > > + > > + if (fd >= 0) > > + close (fd); > > + if (ret) > > + free (ret); > > + > > + return NULL; > > +} > > + > > +void (*grub_find_root_btrfs_mount_path_hook)(const char *mount_path); > > + > > char ** > > grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) > > { > > @@ -516,12 +627,15 @@ again: > > else if (grub_strcmp (entries[i].fstype, "btrfs") == 0) > > { > > ret = grub_find_root_devices_from_btrfs (dir); > > - fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); > > if (use_relative_path_on_btrfs) > > { > > - if (fs_prefix) > > - free (fs_prefix); > > fs_prefix = xstrdup ("/"); > > + if (grub_find_root_btrfs_mount_path_hook) > > + grub_find_root_btrfs_mount_path_hook (entries[i].enc_path); > > + } > > + else > > + { > > + fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); > > } > > } > > else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) > > @@ -1147,6 +1261,34 @@ grub_util_get_grub_dev_os (const char *os_dev) > > return grub_dev; > > } > > > > + > > +char * > > +grub_util_get_btrfs_subvol (const char *path, char **mount_path) > > +{ > > + char *mp = NULL; > > + > > + if (mount_path) > > + *mount_path = NULL; > > + > > + auto void > > + mount_path_hook (const char *m) > > + { > > + mp = strdup (m); > > + } > > + > > + grub_find_root_btrfs_mount_path_hook = mount_path_hook; > > + grub_free (grub_find_root_devices_from_mountinfo (path, NULL)); > > + grub_find_root_btrfs_mount_path_hook = NULL; > > + > > + if (!mp) > > + return NULL; > > + > > + if (mount_path) > > + *mount_path = mp; > > + > > + return get_btrfs_subvol (mp); > > +} > > + > > char * > > grub_make_system_path_relative_to_its_root_os (const char *path) > > { > > diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h > > index 73fa2d34a..9c642ae3f 100644 > > --- a/include/grub/emu/getroot.h > > +++ b/include/grub/emu/getroot.h > > @@ -53,6 +53,11 @@ char ** > > grub_find_root_devices_from_mountinfo (const char *dir, char **relroot); > > #endif > > > > +#ifdef __linux__ > > +char * > > +grub_util_get_btrfs_subvol (const char *path, char **mount_path); > > +#endif > > + > > /* Devmapper functions provided by getroot_devmapper.c. */ > > void > > grub_util_pull_devmapper (const char *os_dev); > > diff --git a/util/grub-install.c b/util/grub-install.c > > index ec3ed4967..d3ec2570d 100644 > > --- a/util/grub-install.c > > +++ b/util/grub-install.c > > @@ -1615,6 +1615,55 @@ main (int argc, char *argv[]) > > prefix_drive = xasprintf ("(%s)", grub_drives[0]); > > } > > > > +#ifdef __linux__ > > + > > + if (config.is_suse_btrfs_snapshot_enabled > > + && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) > > + { > > + char *subvol = NULL; > > + char *mount_path = NULL; > > + char **rootdir_devices = NULL; > > + char *rootdir_path = grub_util_path_concat (2, "/", rootdir); > > + > > + if (grub_util_is_directory (rootdir_path)) > > + rootdir_devices = grub_guess_root_devices (rootdir_path); > > + > > + free (rootdir_path); > > + > > + if (rootdir_devices && rootdir_devices[0]) > > + if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0) > > + subvol = grub_util_get_btrfs_subvol (platdir, &mount_path); > > + > > + if (subvol && mount_path) > > + { > > + char *def_subvol; > > + > > + def_subvol = grub_util_get_btrfs_subvol ("/", NULL); > > + > > + if (def_subvol) > > + { > > + if (!load_cfg_f) > > + load_cfg_f = grub_util_fopen (load_cfg, "wb"); > > + have_load_cfg = 1; > > + > > + if (grub_strcmp (subvol, def_subvol) != 0) > > + fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n", > > mount_path, subvol); > > + free (def_subvol); > > + } > > + } > > + > > + for (curdev = rootdir_devices; *curdev; curdev++) > > + free (*curdev); > > + if (rootdir_devices) > > + free (rootdir_devices); > > + if (subvol) > > + free (subvol); > > + if (mount_path) > > + free (mount_path); > > + } > > + > > +#endif > > + > > char mkimage_target[200]; > > const char *core_name = NULL; > > > > -- > > 2.46.2 > > > > > > _______________________________________________ > > Grub-devel mailing list > > Grub-devel@gnu.org > > https://lists.gnu.org/mailman/listinfo/grub-devel > > > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > https://lists.gnu.org/mailman/listinfo/grub-devel _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel