From patchwork Mon Oct 14 10:58:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Roberts X-Patchwork-Id: 13834682 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 84190D1A43B for ; Mon, 14 Oct 2024 11:00:14 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 1D5696B009C; Mon, 14 Oct 2024 07:00:14 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 185846B009D; Mon, 14 Oct 2024 07:00:14 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 026916B009E; Mon, 14 Oct 2024 07:00:13 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id D7F786B009C for ; Mon, 14 Oct 2024 07:00:13 -0400 (EDT) Received: from smtpin03.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id D3C8240D8B for ; Mon, 14 Oct 2024 11:00:08 +0000 (UTC) X-FDA: 82671913296.03.9982227 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by imf26.hostedemail.com (Postfix) with ESMTP id 84CEF14001B for ; Mon, 14 Oct 2024 11:00:07 +0000 (UTC) Authentication-Results: imf26.hostedemail.com; dkim=none; spf=pass (imf26.hostedemail.com: domain of ryan.roberts@arm.com designates 217.140.110.172 as permitted sender) smtp.mailfrom=ryan.roberts@arm.com; dmarc=pass (policy=none) header.from=arm.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1728903470; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=S61ImBLZUPZT81QYOovWzbBNwho35ypnuFAVdu44m+A=; b=flg0tX/Kv0/npYSKE/WnMJOvDVCujka34pdWA8UKdh/LACTr9PMDEGDDSRSt771XD0fipf i1nC8bZoH9IkSn5monK2FzQXHN8fFKrLFWblxBqeiR0crLfnMSod7zGWJAX7kxSosMnXvA u5oHCd8SWZn/fFzlGypEIr67qV0abU4= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1728903470; a=rsa-sha256; cv=none; b=gxho8t2V475rnip/Pkf/oYX3XVm8QhhsQS6hvpvg0D02SkU+2ppZ3yLpUYWtHx5BcsWrEv ijbjwD98HCbfj9/4psubj1I4qFu6B8y33cNMwWNzQxO+5z9C3Mm3h8bB43jwA0vkRF4Tod QdMa616kLhMrzLPCZ7/fQppPYHeD79Q= ARC-Authentication-Results: i=1; imf26.hostedemail.com; dkim=none; spf=pass (imf26.hostedemail.com: domain of ryan.roberts@arm.com designates 217.140.110.172 as permitted sender) smtp.mailfrom=ryan.roberts@arm.com; dmarc=pass (policy=none) header.from=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 15DE8168F; Mon, 14 Oct 2024 04:00:41 -0700 (PDT) Received: from e125769.cambridge.arm.com (e125769.cambridge.arm.com [10.1.196.27]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id EC2633F51B; Mon, 14 Oct 2024 04:00:08 -0700 (PDT) From: Ryan Roberts To: Andrew Morton , Anshuman Khandual , Ard Biesheuvel , Catalin Marinas , David Hildenbrand , Greg Marsden , Ivan Ivanov , Kalesh Singh , Marc Zyngier , Mark Rutland , Matthias Brugger , Miroslav Benes , Will Deacon Cc: Ryan Roberts , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pm@vger.kernel.org Subject: [RFC PATCH v1 14/57] pm/hibernate: Remove PAGE_SIZE compile-time constant assumption Date: Mon, 14 Oct 2024 11:58:21 +0100 Message-ID: <20241014105912.3207374-14-ryan.roberts@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241014105912.3207374-1-ryan.roberts@arm.com> References: <20241014105514.3206191-1-ryan.roberts@arm.com> <20241014105912.3207374-1-ryan.roberts@arm.com> MIME-Version: 1.0 X-Rspam-User: X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: 84CEF14001B X-Stat-Signature: pmpmjr5zpn9r3phrjtxctuppd7cdtowj X-HE-Tag: 1728903607-589818 X-HE-Meta: U2FsdGVkX1/1Ka1uE14V59PtOxr46wczpy93k7jS/xsz72QH+8zMaS9ONMe2MfX1CJkQYXQWhe+jgF7jZyddKBvIdzgTfYWdqXNCOKfjlG1B+grEb8m2a3fcEkgHcw12vxI4iMBZ9fFjA5aheBMbHE79muGe7h+fQjz/9mB1rHYY3R1vdBHEM3Ls8AeB5WvhNE3ySgEPio+mhtUmxd2H6eQ7mIOaOPl6IBmY7Zvz1swl1owq32ce3+XsYWy3D+22ufEXhOiL3vYXJLGevpAwz8U83VcSo/8JeFTMV22metHUEy8uQr4wu+dFf1UMKh3zmy0A03mEdgF43AOSWuYdNW210VmD2cDKIC9fId20SQSzX17pdNe1r16cLRShLOCnNwQNoNBBnrye+9mFaOpyQUcP203wXgT46cp2ti2aixLrJAUrsFWmZOn3ypULqiLTxa4HD6+dUWPyTCpaBxYUChvrr3h2e4GcpUJbigXePnqV6WSpUQ6sc+9ocxmwY2a5ULzzl2LNAiK8gFs2lfiG7gnOcvpuCB1S9k8ALljwhQHYCQnML78d90nqbVYXNRHntDo2josJyyfT8ybrAR2+4j3SGFM/Je5M2FTIMuJMTrqsYOP12bfT0+F64PiRFMeEwjKkFAXOFuiFixtQbwD0w0xSMOONIBzQxcw47G71pBpE7x//aqyKMUqDIEuNBgD8qv+zuHVw8lLfcgqLI5NDxZ/urm1bAe2uEPxEZ09SwjGZk7zOyfMjx+W4aGlUWL/vcIRlCJdDYgTen5UZwjR/sHKE8ZSWyh7C9Q0T8U4GcVbQIQhdlBkPOzrxgaUhLvcKPYGpqm/yhIcgZQQlHIhYZMA9OiXu3lqYiixpL2w15lnX9O3S7CAxUmUz1W+c/MCqc+5tne8a2w3RCtS1kHmUKGPeJmUKnJDVMdlBWywJGeDI02zkQLTBTHcTcW5nvcIdQ78xjmGCbIlZX3IX1z7 XYQPkfPi Nqyud7bQtyzfmAHGY26nUC0GTNnOJKzbCjqhQOuBSg+ez7vTPrCcJOls+lgwtCO6Ih6q2owU2KbwAVTo9sqnqyXe+0Rk/xh7eJktu/6ADGFf9doW/bss8zEgyeSLussGSj7uuoQSI8dUL5pWyd/gKlFH1i17WT+liZCzyHjSjnbqXk4FYdMnPYE0efAb4YSQhJBBaw/qIH16KCs/VPbfMmmZ7vHnH8JnvHkMY X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: To prepare for supporting boot-time page size selection, refactor code to remove assumptions about PAGE_SIZE being compile-time constant. Code intended to be equivalent when compile-time page size is active. "struct linked_page", "struct swap_map_page" and "struct swsusp_header" were all previously sized to be exactly PAGE_SIZE. Refactor those structures to remove the padding, then superimpose them on a page at runtime. "struct cmp_data" and "struct dec_data" previously contained embedded "unc" and "cmp" arrays, who's sizes were derived from PAGE_SIZE. We can't use flexible array approach here since there are 2 arrays in the structure, so convert to pointers and define an allocator and deallocator for each struct. Signed-off-by: Ryan Roberts --- ***NOTE*** Any confused maintainers may want to read the cover note here for context: https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/ kernel/power/power.h | 2 +- kernel/power/snapshot.c | 2 +- kernel/power/swap.c | 129 +++++++++++++++++++++++++++++++++------- 3 files changed, 108 insertions(+), 25 deletions(-) diff --git a/kernel/power/power.h b/kernel/power/power.h index de0e6b1077f23..74af2eb8d48a4 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -16,7 +16,7 @@ struct swsusp_info { unsigned long image_pages; unsigned long pages; unsigned long size; -} __aligned(PAGE_SIZE); +} __aligned(PAGE_SIZE_MAX); #ifdef CONFIG_HIBERNATION /* kernel/power/snapshot.c */ diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 405eddbda4fc5..144e92f786e35 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -155,7 +155,7 @@ struct pbe *restore_pblist; struct linked_page { struct linked_page *next; - char data[LINKED_PAGE_DATA_SIZE]; + char data[]; } __packed; /* diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 82b884b67152f..ffd4c864acfa2 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -59,6 +59,7 @@ static bool clean_pages_on_decompress; */ #define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(sector_t) - 1) +#define NEXT_SWAP_INDEX MAP_PAGE_ENTRIES /* * Number of free pages that are not high. @@ -78,8 +79,11 @@ static inline unsigned long reqd_free_pages(void) } struct swap_map_page { - sector_t entries[MAP_PAGE_ENTRIES]; - sector_t next_swap; + /* + * A PAGE_SIZE structure with (PAGE_SIZE / sizeof(sector_t)) entries. + * The last entry, [NEXT_SWAP_INDEX], is `.next_swap`. + */ + sector_t entries[1]; }; struct swap_map_page_list { @@ -103,8 +107,6 @@ struct swap_map_handle { }; struct swsusp_header { - char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) - - sizeof(u32) - sizeof(u32)]; u32 hw_sig; u32 crc32; sector_t image; @@ -113,6 +115,7 @@ struct swsusp_header { char sig[10]; } __packed; +static char *swsusp_header_pg; static struct swsusp_header *swsusp_header; /* @@ -315,7 +318,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags) { int error; - hib_submit_io(REQ_OP_READ, swsusp_resume_block, swsusp_header, NULL); + hib_submit_io(REQ_OP_READ, swsusp_resume_block, swsusp_header_pg, NULL); if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) || !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) { memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10); @@ -329,7 +332,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags) if (flags & SF_CRC32_MODE) swsusp_header->crc32 = handle->crc32; error = hib_submit_io(REQ_OP_WRITE | REQ_SYNC, - swsusp_resume_block, swsusp_header, NULL); + swsusp_resume_block, swsusp_header_pg, NULL); } else { pr_err("Swap header not found!\n"); error = -ENODEV; @@ -466,7 +469,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, offset = alloc_swapdev_block(root_swap); if (!offset) return -ENOSPC; - handle->cur->next_swap = offset; + handle->cur->entries[NEXT_SWAP_INDEX] = offset; error = write_page(handle->cur, handle->cur_swap, hb); if (error) goto out; @@ -643,8 +646,8 @@ struct cmp_data { wait_queue_head_t done; /* compression done */ size_t unc_len; /* uncompressed length */ size_t cmp_len; /* compressed length */ - unsigned char unc[UNC_SIZE]; /* uncompressed buffer */ - unsigned char cmp[CMP_SIZE]; /* compressed buffer */ + unsigned char *unc; /* uncompressed buffer */ + unsigned char *cmp; /* compressed buffer */ }; /* Indicates the image size after compression */ @@ -683,6 +686,45 @@ static int compress_threadfn(void *data) return 0; } +static void free_cmp_data(struct cmp_data *data, unsigned nr_threads) +{ + int i; + + if (!data) + return; + + for (i = 0; i < nr_threads; i++) { + vfree(data[i].unc); + vfree(data[i].cmp); + } + + vfree(data); +} + +static struct cmp_data *alloc_cmp_data(unsigned nr_threads) +{ + struct cmp_data *data = NULL; + int i = -1; + + data = vzalloc(array_size(nr_threads, sizeof(*data))); + if (!data) + goto fail; + + for (i = 0; i < nr_threads; i++) { + data[i].unc = vzalloc(UNC_SIZE); + if (!data[i].unc) + goto fail; + data[i].cmp = vzalloc(CMP_SIZE); + if (!data[i].cmp) + goto fail; + } + + return data; +fail: + free_cmp_data(data, nr_threads); + return NULL; +} + /** * save_compressed_image - Save the suspend image data after compression. * @handle: Swap map handle to use for saving the image. @@ -724,7 +766,7 @@ static int save_compressed_image(struct swap_map_handle *handle, goto out_clean; } - data = vzalloc(array_size(nr_threads, sizeof(*data))); + data = alloc_cmp_data(nr_threads); if (!data) { pr_err("Failed to allocate %s data\n", hib_comp_algo); ret = -ENOMEM; @@ -902,7 +944,7 @@ static int save_compressed_image(struct swap_map_handle *handle, if (data[thr].cc) crypto_free_comp(data[thr].cc); } - vfree(data); + free_cmp_data(data, nr_threads); } if (page) free_page((unsigned long)page); @@ -1036,7 +1078,7 @@ static int get_swap_reader(struct swap_map_handle *handle, release_swap_reader(handle); return error; } - offset = tmp->map->next_swap; + offset = tmp->map->entries[NEXT_SWAP_INDEX]; } handle->k = 0; handle->cur = handle->maps->map; @@ -1150,8 +1192,8 @@ struct dec_data { wait_queue_head_t done; /* decompression done */ size_t unc_len; /* uncompressed length */ size_t cmp_len; /* compressed length */ - unsigned char unc[UNC_SIZE]; /* uncompressed buffer */ - unsigned char cmp[CMP_SIZE]; /* compressed buffer */ + unsigned char *unc; /* uncompressed buffer */ + unsigned char *cmp; /* compressed buffer */ }; /* @@ -1189,6 +1231,45 @@ static int decompress_threadfn(void *data) return 0; } +static void free_dec_data(struct dec_data *data, unsigned nr_threads) +{ + int i; + + if (!data) + return; + + for (i = 0; i < nr_threads; i++) { + vfree(data[i].unc); + vfree(data[i].cmp); + } + + vfree(data); +} + +static struct dec_data *alloc_dec_data(unsigned nr_threads) +{ + struct dec_data *data = NULL; + int i = -1; + + data = vzalloc(array_size(nr_threads, sizeof(*data))); + if (!data) + goto fail; + + for (i = 0; i < nr_threads; i++) { + data[i].unc = vzalloc(UNC_SIZE); + if (!data[i].unc) + goto fail; + data[i].cmp = vzalloc(CMP_SIZE); + if (!data[i].cmp) + goto fail; + } + + return data; +fail: + free_dec_data(data, nr_threads); + return NULL; +} + /** * load_compressed_image - Load compressed image data and decompress it. * @handle: Swap map handle to use for loading data. @@ -1231,7 +1312,7 @@ static int load_compressed_image(struct swap_map_handle *handle, goto out_clean; } - data = vzalloc(array_size(nr_threads, sizeof(*data))); + data = alloc_dec_data(nr_threads); if (!data) { pr_err("Failed to allocate %s data\n", hib_comp_algo); ret = -ENOMEM; @@ -1510,7 +1591,7 @@ static int load_compressed_image(struct swap_map_handle *handle, if (data[thr].cc) crypto_free_comp(data[thr].cc); } - vfree(data); + free_dec_data(data, nr_threads); } vfree(page); @@ -1569,9 +1650,9 @@ int swsusp_check(bool exclusive) hib_resume_bdev_file = bdev_file_open_by_dev(swsusp_resume_device, BLK_OPEN_READ, holder, NULL); if (!IS_ERR(hib_resume_bdev_file)) { - clear_page(swsusp_header); + clear_page(swsusp_header_pg); error = hib_submit_io(REQ_OP_READ, swsusp_resume_block, - swsusp_header, NULL); + swsusp_header_pg, NULL); if (error) goto put; @@ -1581,7 +1662,7 @@ int swsusp_check(bool exclusive) /* Reset swap signature now */ error = hib_submit_io(REQ_OP_WRITE | REQ_SYNC, swsusp_resume_block, - swsusp_header, NULL); + swsusp_header_pg, NULL); } else { error = -EINVAL; } @@ -1631,12 +1712,12 @@ int swsusp_unmark(void) int error; hib_submit_io(REQ_OP_READ, swsusp_resume_block, - swsusp_header, NULL); + swsusp_header_pg, NULL); if (!memcmp(HIBERNATE_SIG,swsusp_header->sig, 10)) { memcpy(swsusp_header->sig,swsusp_header->orig_sig, 10); error = hib_submit_io(REQ_OP_WRITE | REQ_SYNC, swsusp_resume_block, - swsusp_header, NULL); + swsusp_header_pg, NULL); } else { pr_err("Cannot find swsusp signature!\n"); error = -ENODEV; @@ -1653,9 +1734,11 @@ int swsusp_unmark(void) static int __init swsusp_header_init(void) { - swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL); - if (!swsusp_header) + swsusp_header_pg = (char *)__get_free_page(GFP_KERNEL); + if (!swsusp_header_pg) panic("Could not allocate memory for swsusp_header\n"); + swsusp_header = (struct swsusp_header *)(swsusp_header_pg + + PAGE_SIZE - sizeof(struct swsusp_header)); return 0; }