Re: [PATCH v1 1/4] PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page
From: Mike Rapoport
Date: Tue Sep 22 2026 - 01:55:19 EST
Hi Vincent,
On Fri, Sep 18, 2026 at 02:16:53PM +0100, Vincent Donnefort wrote:
> hibernate_map_page() is called from an atomic context. This is
> problematic for Arm BBML3 systems where the linear map may contain
> blocks and is allowed to split as splitting is a sleepable operation.
>
> Add arch hook so arm64 can define its own implementation without relying
> on the direct map.
I posted patches that remove set_direct_map usage from hibernation:
https://lore.kernel.org/all/20260917-hibernation-v1-0-7f7dfae3dbe0@xxxxxxxxxx
So I really hope this patch won't be needed :)
> Signed-off-by: Vincent Donnefort <vdonnefort@xxxxxxxxxx>
> ---
> include/linux/suspend.h | 2 ++
> kernel/power/snapshot.c | 10 ++++++----
> 2 files changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/suspend.h b/include/linux/suspend.h
> index b02876f1ae38..10fe2298d94e 100644
> --- a/include/linux/suspend.h
> +++ b/include/linux/suspend.h
> @@ -401,6 +401,8 @@ int hibernate_quiet_exec(int (*func)(void *data), void *data);
> int hibernate_resume_nonboot_cpu_disable(void);
> int arch_hibernation_header_save(void *addr, unsigned int max_size);
> int arch_hibernation_header_restore(void *addr);
> +void *hibernate_map_page(struct page *page);
> +void hibernate_unmap_page(struct page *page);
>
> #else /* CONFIG_HIBERNATION */
> static inline void register_nosave_region(unsigned long b, unsigned long e) {}
> diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
> index b209712cb2c3..b41952f1de2a 100644
> --- a/kernel/power/snapshot.c
> +++ b/kernel/power/snapshot.c
> @@ -85,7 +85,7 @@ static inline int hibernate_restore_unprotect_page(void *page_address) {return 0
> * It is still worth to have a warning here if something changes and this
> * will no longer be the case.
> */
> -static inline void hibernate_map_page(struct page *page)
> +void * __weak hibernate_map_page(struct page *page)
> {
> if (IS_ENABLED(CONFIG_ARCH_HAS_SET_DIRECT_MAP)) {
> int ret = set_direct_map_default_noflush(page);
> @@ -95,9 +95,10 @@ static inline void hibernate_map_page(struct page *page)
> } else {
> debug_pagealloc_map_pages(page, 1);
> }
> + return page_address(page);
> }
>
> -static inline void hibernate_unmap_page(struct page *page)
> +void __weak hibernate_unmap_page(struct page *page)
> {
> if (IS_ENABLED(CONFIG_ARCH_HAS_SET_DIRECT_MAP)) {
> unsigned long addr = (unsigned long)page_address(page);
> @@ -1456,8 +1457,9 @@ static bool safe_copy_page(void *dst, struct page *s_page)
> if (kernel_page_present(s_page)) {
> zeros_only = do_copy_page(dst, page_address(s_page));
> } else {
> - hibernate_map_page(s_page);
> - zeros_only = do_copy_page(dst, page_address(s_page));
> + void *src = hibernate_map_page(s_page);
> +
> + zeros_only = do_copy_page(dst, src);
> hibernate_unmap_page(s_page);
> }
> return zeros_only;
> --
> 2.55.0.1082.g2b9226bbc0-goog
>
--
Sincerely yours,
Mike.