[PATCH v1 1/4] PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page

Mike Rapoport rppt at kernel.org
Mon Sep 21 22:55:03 PDT 2026


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@kernel.org
 
So I really hope this patch won't be needed :)

> Signed-off-by: Vincent Donnefort <vdonnefort at google.com>
> ---
>  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.



More information about the linux-arm-kernel mailing list