From nobody Thu Sep 24 20:04:06 2026 Received: from lgeamrelo11.lge.com (lgeamrelo11.lge.com [156.147.23.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9656347ACC0 for ; Mon, 21 Sep 2026 10:44:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=156.147.23.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789987494; cv=none; b=nHKG7P3MgikHWt01z4i5g725kWlpyEXbMpLaB+k7z+3mCLCcuGP5SpIg5rk7tyFPaXq+MooXr0WjkjEB8FjfzAExXLN1MB33JaC6RNM1ZknSOwkzREmfAXfjpdgT7rkbp7R9k3CpwXtFT4Q8JjvDTJEH+vfMRIIDKAZAOtxs0JM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789987494; c=relaxed/simple; bh=QjartXcLa5zeQ/M0u7+w32mROV/UGTDcThe2MZzZvvk=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=rnMaafxhYXv56Kq4jXTk7jEVvmAoQ2tdrBdacUK1JAD21fuXPWV0Q5S3zvE7zZR1h3pJVkaszhbRZE3LGlssxIp3MiVEZa/cuWw8OJjFZXCkkQxY3qA6LIzGB3+OOzULDmJhFzcRpC8vRjjPt1fp93Pn0kBoVFbxG6d3w+I0pnY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lge.com; spf=pass smtp.mailfrom=lge.com; arc=none smtp.client-ip=156.147.23.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=lge.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=lge.com Received: from unknown (HELO lgeamrelo04.lge.com) (156.147.1.127) by 156.147.23.51 with ESMTP; 21 Sep 2026 19:14:47 +0900 X-Original-SENDERIP: 156.147.1.127 X-Original-MAILFROM: trieu2.huynh@lge.com Received: from unknown (HELO trieu2-huynh-trieuhpn-ubuntu24.bee-live.svc.cluster.local) (10.159.39.43) by 156.147.1.127 with ESMTP; 21 Sep 2026 19:14:47 +0900 X-Original-SENDERIP: 10.159.39.43 X-Original-MAILFROM: trieu2.huynh@lge.com From: Nhat-Trieu Huynh-Pham To: rafael@kernel.org Cc: pavel@kernel.org, lenb@kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, Nhat-Trieu Huynh-Pham Subject: [PATCH] PM: hibernate: exclude unusable free pages from image preallocation Date: Mon, 21 Sep 2026 19:14:46 +0900 Message-ID: <20260921101446.1193565-1-trieu2.huynh@lge.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" hibernate_preallocate_memory() derives the number of page frames to preallocate for the image from the per-zone NR_FREE_PAGES counters. Those counters count every free pageblock regardless of its migratetype, including MIGRATE_HIGHATOMIC and MIGRATE_CMA pageblocks. Such pages are free from the buddy allocator's point of view, but they cannot be used by the order-0, non-movable, non-reserve GFP_KERNEL allocations with which the image is preallocated (GFP_IMAGE =3D GFP_KERNEL|__GFP_NOWARN). (*) Reported free vs usable free: The mm subsystem already accounts for this in __zone_watermark_unusable_free(). For order-0 GFP_KERNEL neither ALLOC_RESERVES nor ALLOC_CMA is set, so the allocator subtracts the high-order atomic reserve and the free CMA pages from the free count before checking the watermarks. The hibernation preallocation, however, computes its target from the unadjusted NR_FREE_PAGES value, so it asks for about half of the unusable pages more than the allocator can deliver. On arm64 (no CONFIG_HIGHMEM) the highmem fallback in the failure path is a no-op, hence even a small shortfall aborts hibernation, see [3] for example. (*) Why those pages are not usable by GFP_KERNEL: (**) CMA is reserved for movable allocations, so GFP_KERNEL has no ALLOC_CMA, and MIGRATE_CMA is not in the unmovable fallback list. Free CMA pages are therefore never handed to these allocations. (**) The high-order atomic reserve is only handed out to atomic, order > 0, __GFP_HIGH allocations (ALLOC_HIGHATOMIC), which GFP_KERNEL order-0 is not. These pages can be unreserved under memory pressure, but only all but one pageblock per zone and only after an allocation has already failed, so counting them as available still overestimates what the preallocation can obtain without failing first. Excluding them is conservative. (*) Consequence of not excluding the unusable pages: With M =3D managed, S =3D saveable, F =3D free, U =3D highatomic + CMA and R =3D reclaimable, count =3D S + F - totalreserve and alloc is about count / 2, while the allocator can actually provide about (F - U) + R pages. The shortfall is therefore inflated by exactly U compared with the usable memory. From, with U =3D 11430 unusable free pages (5120 highatomic + 6310 CMA), the preallocation target is inflated by about U / 2 =3D 5715 pages, while the allocator ends up 1247 pages short and hibernation is aborted even though the system is able to create the image. (*) What changes after excluding the unusable pages: Subtract U from the per-zone free accounting used to compute count and avail_normal. Then count' =3D count - U and, since max_size is roughly count / 2, max_size' =3D max_size - U / 2 and alloc' =3D alloc - U / 2. max_size' remains well above minimum_image_size() in practice, so the resulting image is effectively unchanged while hibernation no longer aborts unnecessarily. Testing =3D=3D=3D=3D=3D=3D=3D (*) SA6155P running on AAOS with S2D feature (*) backport locally on GKI 6.1 References =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D [1] commit f27ce0e14088 ("page_alloc: consider highatomic reserve in watermark = fast") [2] commit ac3f3b0a5551 ("mm: page_alloc: unreserve highatomic page blocks befo= re oom") [3] Example of an abort: Mem-Info: free:344621 free_pcp:931 free_cma:6310 DMA32 free:973864kB reserved_highatomic:8192KB free_cma:25240kB Normal free:404620kB reserved_highatomic:12288KB free_cma:0kB PM: hibernation: Image allocation is 1247 pages short Signed-off-by: Nhat-Trieu Huynh-Pham --- kernel/power/snapshot.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index b209712cb2c3..fd6164aea272 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1867,11 +1867,32 @@ int hibernate_preallocate_memory(void) highmem =3D save_highmem; size =3D 0; for_each_populated_zone(zone) { + unsigned long free, unusable; + size +=3D snapshot_additional_pages(zone); + + /* + * Pages reserved for high-order atomic allocations + * (MIGRATE_HIGHATOMIC) and free CMA pages cannot be used by + * the order-0 non-movable GFP_KERNEL allocations that + * preallocate the image, so do not count them as available. + * This mirrors __zone_watermark_unusable_free(). + */ + free =3D zone_page_state(zone, NR_FREE_PAGES); + unusable =3D zone->nr_reserved_highatomic; +#ifdef CONFIG_CMA + unusable +=3D zone_page_state(zone, NR_FREE_CMA_PAGES); +#endif + /* + * nr_reserved_highatomic counts whole reserved pageblocks, + * so it can exceed the actual free pages. + */ + unusable =3D min(unusable, free); + if (is_highmem(zone)) - highmem +=3D zone_page_state(zone, NR_FREE_PAGES); + highmem +=3D free - unusable; else - count +=3D zone_page_state(zone, NR_FREE_PAGES); + count +=3D free - unusable; } avail_normal =3D count; count +=3D highmem; --=20 2.43.0