grub2/0081-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
Javier Martinez Canillas e1531466e1
Update to grub 2.04
This change updates grub to the 2.04 release. The new release changed how
grub is built, so the bootstrap and bootstrap.conf files have to be added
to the dist-git. Also, the gitignore file changed so it has to be updated.

Since the patches have been forward ported to 2.04, there's no need for a
logic to maintain a patch with the delta between the release and the grub
master branch. So the release-to-master.patch is dropped and no longer is
updated by the do-rebase script.

Also since gnulib isn't part of the grub repository anymore and cloned by
the boostrap tool, a gnulib tarball is included as other source file and
copied before calling the bootstrap tool. That way grub can be built even
in builders that only have access to the sources lookaside cache.

Resolves: rhbz#1727279

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
2019-08-15 08:04:53 +02:00

273 lines
7.3 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Thu, 11 May 2017 08:56:57 +0000
Subject: [PATCH] Grub not working correctly with btrfs snapshots (bsc#1026511)
---
grub-core/fs/btrfs.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 238 insertions(+)
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 69c30e62354..ba99d04f8ed 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -2867,6 +2867,238 @@ out:
return 0;
}
+static grub_err_t
+grub_btrfs_get_parent_subvol_path (struct grub_btrfs_data *data,
+ grub_uint64_t child_id,
+ const char *child_path,
+ grub_uint64_t *parent_id,
+ char **path_out)
+{
+ grub_uint64_t fs_root = 0;
+ struct grub_btrfs_key key_in = {
+ .object_id = child_id,
+ .type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF,
+ .offset = 0,
+ }, key_out;
+ struct grub_btrfs_root_ref *ref;
+ char *buf;
+ struct grub_btrfs_leaf_descriptor desc;
+ grub_size_t elemsize;
+ grub_disk_addr_t elemaddr;
+ grub_err_t err;
+ char *parent_path;
+
+ *parent_id = 0;
+ *path_out = 0;
+
+ err = lower_bound(data, &key_in, &key_out, data->sblock.root_tree,
+ &elemaddr, &elemsize, &desc, 0);
+ if (err)
+ return err;
+
+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF || elemaddr == 0)
+ next(data, &desc, &elemaddr, &elemsize, &key_out);
+
+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF)
+ {
+ free_iterator(&desc);
+ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root backrefs"));
+ }
+
+ buf = grub_malloc(elemsize + 1);
+ if (!buf)
+ {
+ free_iterator(&desc);
+ return grub_errno;
+ }
+
+ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0);
+ if (err)
+ {
+ grub_free(buf);
+ free_iterator(&desc);
+ return err;
+ }
+
+ buf[elemsize] = 0;
+ ref = (struct grub_btrfs_root_ref *)buf;
+
+ err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset),
+ 0, &fs_root);
+ if (err)
+ {
+ grub_free(buf);
+ free_iterator(&desc);
+ return err;
+ }
+
+ find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path);
+
+ if (child_path)
+ {
+ *path_out = grub_xasprintf ("%s/%s", parent_path, child_path);
+ grub_free (parent_path);
+ }
+ else
+ *path_out = parent_path;
+
+ *parent_id = grub_le_to_cpu64 (key_out.offset);
+
+ grub_free(buf);
+ free_iterator(&desc);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_btrfs_get_default_subvolume_id (struct grub_btrfs_data *data, grub_uint64_t *id)
+{
+ grub_err_t err;
+ grub_disk_addr_t elemaddr;
+ grub_size_t elemsize;
+ struct grub_btrfs_key key, key_out;
+ struct grub_btrfs_dir_item *direl = NULL;
+ const char *ctoken = "default";
+ grub_size_t ctokenlen = sizeof ("default") - 1;
+
+ *id = 0;
+ key.object_id = data->sblock.root_dir_objectid;
+ key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+ key.offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen));
+ err = lower_bound (data, &key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize,
+ NULL, 0);
+ if (err)
+ return err;
+
+ if (key_cmp (&key, &key_out) != 0)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
+
+ struct grub_btrfs_dir_item *cdirel;
+ direl = grub_malloc (elemsize + 1);
+ err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0);
+ if (err)
+ {
+ grub_free (direl);
+ return err;
+ }
+ for (cdirel = direl;
+ (grub_uint8_t *) cdirel - (grub_uint8_t *) direl
+ < (grub_ssize_t) elemsize;
+ cdirel = (void *) ((grub_uint8_t *) (direl + 1)
+ + grub_le_to_cpu16 (cdirel->n)
+ + grub_le_to_cpu16 (cdirel->m)))
+ {
+ if (ctokenlen == grub_le_to_cpu16 (cdirel->n)
+ && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0)
+ break;
+ }
+ if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl
+ >= (grub_ssize_t) elemsize)
+ {
+ grub_free (direl);
+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
+ return err;
+ }
+
+ if (cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM)
+ {
+ grub_free (direl);
+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
+ return err;
+ }
+
+ *id = grub_le_to_cpu64 (cdirel->key.object_id);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt,
+ int argc, char **argv)
+{
+ char *devname;
+ grub_device_t dev;
+ struct grub_btrfs_data *data;
+ grub_err_t err;
+ grub_uint64_t id;
+ char *subvol = NULL;
+ grub_uint64_t subvolid = 0;
+ char *varname = NULL;
+ char *output = NULL;
+ int path_only = ctxt->state[1].set;
+ int num_only = ctxt->state[2].set;
+
+ if (ctxt->state[0].set)
+ varname = ctxt->state[0].arg;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
+
+ devname = grub_file_get_device_name(argv[0]);
+ if (!devname)
+ return grub_errno;
+
+ dev = grub_device_open (devname);
+ grub_free (devname);
+ if (!dev)
+ return grub_errno;
+
+ data = grub_btrfs_mount(dev);
+ if (!data)
+ {
+ grub_device_close (dev);
+ grub_dprintf ("btrfs", "failed to open fs\n");
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+
+ err = grub_btrfs_get_default_subvolume_id (data, &subvolid);
+ if (err)
+ {
+ grub_btrfs_unmount (data);
+ grub_device_close (dev);
+ return err;
+ }
+
+ id = subvolid;
+ while (id != GRUB_BTRFS_ROOT_VOL_OBJECTID)
+ {
+ grub_uint64_t parent_id;
+ char *path_out;
+
+ err = grub_btrfs_get_parent_subvol_path (data, grub_cpu_to_le64 (id), subvol, &parent_id, &path_out);
+ if (err)
+ {
+ grub_btrfs_unmount (data);
+ grub_device_close (dev);
+ return err;
+ }
+
+ if (subvol)
+ grub_free (subvol);
+ subvol = path_out;
+ id = parent_id;
+ }
+
+ if (num_only && path_only)
+ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol);
+ else if (num_only)
+ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T, subvolid);
+ else
+ output = grub_xasprintf ("/%s", subvol);
+
+ if (varname)
+ grub_env_set(varname, output);
+ else
+ grub_printf ("%s\n", output);
+
+ grub_free (output);
+ grub_free (subvol);
+
+ grub_btrfs_unmount (data);
+ grub_device_close (dev);
+
+ return GRUB_ERR_NONE;
+}
+
static struct grub_fs grub_btrfs_fs = {
.name = "btrfs",
.fs_dir = grub_btrfs_dir,
@@ -2885,6 +3117,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 grub_extcmd_t cmd_get_default_subvol;
static char *
subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)),
@@ -2955,6 +3188,11 @@ GRUB_MOD_INIT (btrfs)
"[-p|-n] [-o var] DEVICE",
"Print list of BtrFS subvolumes on "
"DEVICE.", options);
+ cmd_get_default_subvol = grub_register_extcmd("btrfs-get-default-subvol",
+ grub_cmd_btrfs_get_default_subvol, 0,
+ "[-p|-n] [-o var] DEVICE",
+ "Print default BtrFS subvolume on "
+ "DEVICE.", options);
grub_register_variable_hook ("btrfs_subvol", subvol_get_env,
subvol_set_env);
grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,