[PATCH 3/7] arm64: hibernate: free MTE tag pages after saving

Bradley Morgan brads at mainlining.org
Tue Aug 25 13:58:35 PDT 2026


swsusp_arch_suspend() calls swsusp_mte_save_tags() to stash the
userspace MTE tags, but we only free them on a successful resume in
swsusp_mte_restore_tags(). If hibernation fails partway, the tags stay
allocated, and the next time we try to hibernate,
swsusp_mte_save_tags() warns about duplicate entries in the mte_pages
xarray.

Reproducing it is easy, just make a hibernate fail twice in a row.

| # echo test_resume > /sys/power/disk
| # echo disk > /sys/power/state
...
| PM: Cannot find swap device, try swapon -a
| PM: Cannot get swap writer
...
| # echo disk > /sys/power/state
...
| ------------[ cut here ]------------
| swsusp: save_tags: Duplicate entry
| WARNING: CPU: 0 PID: 123 at arch/arm64/kernel/hibernate.c:234 \
| swsusp_arch_suspend+0x3f0/0x5b0
...

Free the tag storage right after swsusp_save() has copied it into the
hibernation image. Where hibernation succeeds, the tags come back from
the image and get consumed by swsusp_mte_restore_tags() as before.

Fixes: ee11f332af96 ("arm64: mte: Save tags when hibernating")
Signed-off-by: Bradley Morgan <brads at mainlining.org>
---
 arch/arm64/kernel/hibernate.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
index 7bf117427777..8ac29058a839 100644
--- a/arch/arm64/kernel/hibernate.c
+++ b/arch/arm64/kernel/hibernate.c
@@ -241,14 +241,18 @@ static int save_tags(struct page *page, unsigned long pfn)
 static void swsusp_mte_free_storage(void)
 {
 	XA_STATE(xa_state, &mte_pages, 0);
+	int n = 0;
 	void *tags;
 
 	xa_lock(&mte_pages);
 	xas_for_each(&xa_state, tags, ULONG_MAX) {
 		mte_free_tag_storage(tags);
+		n++;
 	}
 	xa_unlock(&mte_pages);
 
+	pr_info("Freed %d MTE pages\n", n);
+
 	xa_destroy(&mte_pages);
 }
 
@@ -355,6 +359,12 @@ int swsusp_arch_suspend(void)
 
 		sleep_cpu = smp_processor_id();
 		ret = swsusp_save();
+
+		/*
+		 * Hibernation can still fail from here, so free the tags now,
+		 * a second attempt would warn on duplicate entries otherwise.
+		 */
+		swsusp_mte_free_storage();
 	} else {
 		/* Clean kernel core startup/idle code to PoC*/
 		dcache_clean_inval_poc((unsigned long)__mmuoff_data_start,
-- 
2.47.3



More information about the linux-arm-kernel mailing list