mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: Barebox List <barebox@lists.infradead.org>
Subject: [PATCH] partitions: gpt: refresh partition tables when necessary
Date: Fri, 28 Nov 2025 12:19:29 +0100	[thread overview]
Message-ID: <20251128111929.2463263-1-s.hauer@pengutronix.de> (raw)

The GPT alternative header must be at the end of the device. When disk
images are written to a device this often is not the case which results
in warnings:

WARNING: mmc0: GPT:Primary header thinks Alt. header is not at the end of the disk.
WARNING: mmc0: GPT:6561831 != 62160895
WARNING: mmc0: GPT:Alternate GPT header not at the end of the disk.
WARNING: mmc0: GPT:6561831 != 62160895
WARNING: mmc0: GPT: Use parted to correct GPT errors.

This patch adds support for automatically rewriting the partition table
when this happens. This behaviour is optional and needs to be enabled at
compile time with CONFIG_PARTITION_DISK_EFI_REFRESH. Also this is
runtime configurable with global.system.gpt_refresh

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/partitions/Kconfig |  14 +++++
 common/partitions/efi.c   | 108 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 119 insertions(+), 3 deletions(-)

diff --git a/common/partitions/Kconfig b/common/partitions/Kconfig
index 3bbcceedc1..1007dbbe19 100644
--- a/common/partitions/Kconfig
+++ b/common/partitions/Kconfig
@@ -24,6 +24,20 @@ config PARTITION_DISK_EFI
 	help
 	  Add support to handle partitions in GUID Partition Table style.
 
+config PARTITION_DISK_EFI_REFRESH
+	depends on PARTITION_DISK_EFI && PARTITION_MANIPULATION
+	bool "refresh GPT partition on demand"
+	help
+	  The GPT alternative header must be at the end of the device. When disk
+	  images are written to a device this often is not the case which results
+	  in warnings:
+
+	  GPT:Primary header thinks Alt. header is not at the end of the disk.
+
+	  Enable this option and set global.system.gpt_refresh to true to refresh
+	  GPT partition tables when necessary. Only erroneous partition tables will
+	  be rewritten, once fixed up partition tables will not be touched.
+
 config PARTITION_DISK_EFI_GPT_NO_FORCE
 	depends on PARTITION_DISK_EFI
 	default y
diff --git a/common/partitions/efi.c b/common/partitions/efi.c
index 88d8a2d739..9d62a63918 100644
--- a/common/partitions/efi.c
+++ b/common/partitions/efi.c
@@ -15,8 +15,10 @@
 #include <common.h>
 #include <disks.h>
 #include <init.h>
+#include <globalvar.h>
 #include <asm/unaligned.h>
 #include <crc.h>
+#include <fcntl.h>
 #include <linux/ctype.h>
 
 #include <efi/partition.h>
@@ -36,6 +38,93 @@ struct efi_partition {
 
 static const int force_gpt = IS_ENABLED(CONFIG_PARTITION_DISK_EFI_GPT_NO_FORCE);
 
+struct gpt_refresh {
+	struct block_device *blk;
+	struct list_head list;
+};
+
+static LIST_HEAD(gpt_refreshes);
+
+static unsigned int global_gpt_refresh;
+
+static int gpt_refresh_one(struct block_device *blk)
+{
+	struct partition_desc *pdesc;
+	int ret;
+
+	if (!global_gpt_refresh)
+		return 0;
+
+	ret = cdev_open(&blk->cdev, O_RDWR);
+	if (ret)
+		return ret;
+
+	pdesc = partition_table_read(blk);
+	if (!pdesc) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = partition_table_write(pdesc);
+	if (ret)
+		goto out;
+
+	ret = 0;
+
+	partition_table_free(pdesc);
+out:
+	cdev_close(&blk->cdev);
+
+	if (ret)
+		dev_err(blk->dev, "Refreshing partition table failed: %pe\n",
+			ERR_PTR(ret));
+
+	return ret;
+}
+
+static bool gpt_refresh_done;
+
+static int do_gpt_refreshes(void)
+{
+	struct gpt_refresh *r, *tmp;
+
+	if (!IS_ENABLED(CONFIG_PARTITION_DISK_EFI_REFRESH))
+		return 0;
+
+	if (!global_gpt_refresh)
+		return 0;
+
+	list_for_each_entry_safe(r, tmp, &gpt_refreshes, list) {
+		gpt_refresh_one(r->blk);
+		list_del(&r->list);
+		free(r);
+	}
+
+	gpt_refresh_done = true;
+
+	return 0;
+}
+postenvironment_initcall(do_gpt_refreshes);
+
+static void add_gpt_refresh(struct block_device *blk)
+{
+	struct gpt_refresh *r;
+
+	if (!IS_ENABLED(CONFIG_PARTITION_DISK_EFI_REFRESH))
+		return;
+
+	if (gpt_refresh_done) {
+		gpt_refresh_one(blk);
+		return;
+	}
+
+	r = xzalloc(sizeof(*r));
+
+	r->blk = blk;
+
+	list_add_tail(&r->list, &gpt_refreshes);
+}
+
 /**
 * compute_partitions_entries_size() - return the size of all partitions
 * @gpt: GPT header
@@ -288,9 +377,11 @@ is_pte_valid(const gpt_entry *pte, const u64 lastlba)
  *
  */
 static void
-compare_gpts(struct device *dev, gpt_header *pgpt, gpt_header *agpt,
+compare_gpts(struct block_device *blk, gpt_header *pgpt, gpt_header *agpt,
 	     u64 lastlba)
 {
+	struct device *dev = blk->dev;
+
 	int error_found = 0;
 	if (!pgpt || !agpt)
 		return;
@@ -374,8 +465,11 @@ compare_gpts(struct device *dev, gpt_header *pgpt, gpt_header *agpt,
 		error_found++;
 	}
 
-	if (error_found)
+	if (error_found) {
+		add_gpt_refresh(blk);
 		dev_warn(dev, "GPT: Use parted to correct GPT errors.\n");
+	}
+
 	return;
 }
 
@@ -426,7 +520,7 @@ static int find_valid_gpt(void *buf, struct block_device *blk, gpt_header **gpt,
 		goto fail;
 
 	if (IS_ENABLED(CONFIG_PARTITION_DISK_EFI_GPT_COMPARE))
-		compare_gpts(blk->dev, pgpt, agpt, lastlba);
+		compare_gpts(blk, pgpt, agpt, lastlba);
 
 	/* The good cases */
 	if (good_pgpt) {
@@ -826,8 +920,16 @@ static struct partition_parser efi_partition_parser = {
 	.name = "gpt",
 };
 
+#ifdef CONFIG_PARTITION_DISK_EFI_REFRESH
+BAREBOX_MAGICVAR(global.system.gpt_refresh, "When true, refresh GPT partitions when necessary");
+#endif
+
 static int efi_partition_init(void)
 {
+	if (IS_ENABLED(CONFIG_PARTITION_DISK_EFI_REFRESH))
+		globalvar_add_simple_bool("system.gpt_refresh",
+					  &global_gpt_refresh);
+
 	return partition_parser_register(&efi_partition_parser);
 }
 postconsole_initcall(efi_partition_init);
-- 
2.47.3




                 reply	other threads:[~2025-11-28 11:20 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251128111929.2463263-1-s.hauer@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox