btrfs: use full bootloader area

Signed-off-by: Robbie Harwood <rharwood@redhat.com>
This commit is contained in:
Robbie Harwood 2022-01-06 17:42:54 +00:00
parent 46317f98bf
commit b256068060
3 changed files with 168 additions and 1 deletions

View file

@ -0,0 +1,163 @@
From 6e5b9bc2f1d2e3a10096716350fa67f48c199f5d Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 13 Dec 2021 14:25:49 +0800
Subject: [PATCH] fs/btrfs: Use full btrfs bootloader area
Up to now GRUB can only embed to the first 64 KiB before primary
superblock of btrfs, effectively limiting the GRUB core size. That
could consequently pose restrictions to feature enablement like
advanced zstd compression.
This patch attempts to utilize full unused area reserved by btrfs for
the bootloader outlined in the document [1]:
The first 1MiB on each device is unused with the exception of primary
superblock that is on the offset 64KiB and spans 4KiB.
Apart from that, adjacent sectors to superblock and first block group
are not used for embedding in case of overflow and logged access to
adjacent sectors could be useful for tracing it up.
This patch has been tested to provide out of the box support for btrfs
zstd compression with which GRUB has been installed to the partition.
[1] https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit b0f06a81c6f31b6fa20be67a96b6683bba8210c9)
---
grub-core/fs/btrfs.c | 90 +++++++++++++++++++++++++++++++++++++-------
include/grub/disk.h | 2 +
2 files changed, 79 insertions(+), 13 deletions(-)
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 4cc86e9b7..07c0ff874 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -2476,6 +2476,33 @@ grub_btrfs_label (grub_device_t device, char **label)
}
#ifdef GRUB_UTIL
+
+struct embed_region {
+ unsigned int start;
+ unsigned int secs;
+};
+
+/*
+ * https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT
+ * The first 1 MiB on each device is unused with the exception of primary
+ * superblock that is on the offset 64 KiB and spans 4 KiB.
+ */
+
+static const struct {
+ struct embed_region available;
+ struct embed_region used[6];
+} btrfs_head = {
+ .available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */
+ .used = {
+ {0, 1}, /* boot.S. */
+ {GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1}, /* Overflow guard. */
+ {GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */
+ {GRUB_DISK_KiB_TO_SECTORS (68), 1}, /* Overflow guard. */
+ {GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1}, /* Overflow guard. */
+ {0, 0} /* Array terminator. */
+ }
+};
+
static grub_err_t
grub_btrfs_embed (grub_device_t device __attribute__ ((unused)),
unsigned int *nsectors,
@@ -2483,25 +2510,62 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)),
grub_embed_type_t embed_type,
grub_disk_addr_t **sectors)
{
- unsigned i;
+ unsigned int i, j, n = 0;
+ const struct embed_region *u;
+ grub_disk_addr_t *map;
if (embed_type != GRUB_EMBED_PCBIOS)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"BtrFS currently supports only PC-BIOS embedding");
- if (64 * 2 - 1 < *nsectors)
- return grub_error (GRUB_ERR_OUT_OF_RANGE,
- N_("your core.img is unusually large. "
- "It won't fit in the embedding area"));
-
- *nsectors = 64 * 2 - 1;
- if (*nsectors > max_nsectors)
- *nsectors = max_nsectors;
- *sectors = grub_calloc (*nsectors, sizeof (**sectors));
- if (!*sectors)
+ map = grub_calloc (btrfs_head.available.secs, sizeof (*map));
+ if (map == NULL)
return grub_errno;
- for (i = 0; i < *nsectors; i++)
- (*sectors)[i] = i + 1;
+
+ /*
+ * Populating the map array so that it can be used to index if a disk
+ * address is available to embed:
+ * - 0: available,
+ * - 1: unavailable.
+ */
+ for (u = btrfs_head.used; u->secs; ++u)
+ {
+ unsigned int end = u->start + u->secs;
+
+ if (end > btrfs_head.available.secs)
+ end = btrfs_head.available.secs;
+ for (i = u->start; i < end; ++i)
+ map[i] = 1;
+ }
+
+ /* Adding up n until it matches total size of available embedding area. */
+ for (i = 0; i < btrfs_head.available.secs; ++i)
+ if (map[i] == 0)
+ n++;
+
+ if (n < *nsectors)
+ {
+ grub_free (map);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("your core.img is unusually large. "
+ "It won't fit in the embedding area"));
+ }
+
+ if (n > max_nsectors)
+ n = max_nsectors;
+
+ /*
+ * Populating the array so that it can used to index disk block address for
+ * an image file's offset to be embedded on disk (the unit is in sectors):
+ * - i: The disk block address relative to btrfs_head.available.start,
+ * - j: The offset in image file.
+ */
+ for (i = 0, j = 0; i < btrfs_head.available.secs && j < n; ++i)
+ if (map[i] == 0)
+ map[j++] = btrfs_head.available.start + i;
+
+ *nsectors = n;
+ *sectors = map;
return GRUB_ERR_NONE;
}
diff --git a/include/grub/disk.h b/include/grub/disk.h
index f95aca929..06210a704 100644
--- a/include/grub/disk.h
+++ b/include/grub/disk.h
@@ -182,6 +182,8 @@ typedef struct grub_disk_memberlist *grub_disk_memberlist_t;
/* Return value of grub_disk_native_sectors() in case disk size is unknown. */
#define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL
+#define GRUB_DISK_KiB_TO_SECTORS(x) ((x) << (10 - GRUB_DISK_SECTOR_BITS))
+
/* Convert sector number from one sector size to another. */
static inline grub_disk_addr_t
grub_convert_sector (grub_disk_addr_t sector,
--
2.34.1

View file

@ -210,3 +210,4 @@ Patch0209: 0209-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch
Patch0210: 0210-Print-module-name-on-license-check-failure.patch
Patch0211: 0211-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch
Patch0212: 0212-grub-mkconfig-restore-umask-for-grub.cfg.patch
Patch0213: 0213-fs-btrfs-Use-full-btrfs-bootloader-area.patch

View file

@ -14,7 +14,7 @@
Name: grub2
Epoch: 1
Version: 2.06
Release: 11%{?dist}
Release: 12%{?dist}
Summary: Bootloader with support for Linux, Multiboot and more
License: GPLv3+
URL: http://www.gnu.org/software/grub/
@ -523,6 +523,9 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
%endif
%changelog
* Thu Jan 06 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-12
- btrfs: use full bootloader area
* Fri Dec 10 2021 Robbie Harwood <rharwood@redhat.com> - 2.06-11
- Bump to rerun signing (no code changes)