From: Ard Biesheuvel <ard.biesheuvel@linaro.org> To: linux-arm-kernel@lists.infradead.org Cc: mark.rutland@arm.com, linux-efi@vger.kernel.org, Ard Biesheuvel <ard.biesheuvel@linaro.org>, marc.zyngier@arm.com, bhsharma@redhat.com, will.deacon@arm.com Subject: [PATCH 4/4] efi: reduce the amount of memblock reservations for persistent allocations Date: Tue, 6 Nov 2018 12:37:32 +0100 [thread overview] Message-ID: <20181106113732.16351-5-ard.biesheuvel@linaro.org> (raw) In-Reply-To: <20181106113732.16351-1-ard.biesheuvel@linaro.org> The current implementation of efi_mem_reserve_persistent() is rather naive, in the sense that for each invocation, it creates a separate linked list entry to describe the reservation. Since the linked list entries themselves need to persist across subsequent kexec reboots, every reservation created this way results in two memblock_reserve() calls at the next boot. On arm64 systems with 100s of CPUs, this may result in a excessive number of memblock reservations, and needless fragmentation. So instead, make use of the newly updated struct linux_efi_memreserve layout to put multiple reservations into a single linked list entry. This should get rid of the numerous tiny memblock reservations, and effectively cut the total number of reservations in half on arm64 systems with many CPUs. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> --- drivers/firmware/efi/efi.c | 29 ++++++++++++++------ include/linux/efi.h | 3 ++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 85d2ec532816..2ca5a59f7568 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -978,22 +978,35 @@ static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock); int efi_mem_reserve_persistent(phys_addr_t addr, u64 size) { struct linux_efi_memreserve *rsv, *parent; - int rsvsize = EFI_MEMRESERVE_SIZE(1); + unsigned long prsv; + int index; if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR) return -ENODEV; - rsv = kmalloc(rsvsize, GFP_KERNEL); - if (!rsv) - return -ENOMEM; - parent = memremap(efi.mem_reserve, sizeof(*rsv), MEMREMAP_WB); - if (!parent) { - kfree(rsv); + if (!parent) return -ENOMEM; + + /* first try to find a slot in an existing linked list entry */ + for (prsv = parent->next; prsv; prsv = rsv->next) { + rsv = __va(prsv); + index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size); + if (index < rsv->size) { + rsv->entry[index].base = addr; + rsv->entry[index].size = size; + + memunmap(parent); + return 0; + } } - rsv->size = 1; + /* no slot found - allocate a new linked list entry */ + rsv = (struct linux_efi_memreserve *)__get_free_page(GFP_KERNEL); + if (!rsv) + return -ENOMEM; + + rsv->size = EFI_MEMRESERVE_COUNT(PAGE_SIZE); atomic_set(&rsv->count, 1); rsv->entry[0].base = addr; rsv->entry[0].size = size; diff --git a/include/linux/efi.h b/include/linux/efi.h index dfce82b2ca8a..1a1a081f7244 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1727,4 +1727,7 @@ struct linux_efi_memreserve { #define EFI_MEMRESERVE_SIZE(count) (sizeof(struct linux_efi_memreserve) + \ (count) * sizeof(((struct linux_efi_memreserve *)0)->entry[0])) +#define EFI_MEMRESERVE_COUNT(size) (((size) - sizeof(struct linux_efi_memreserve)) \ + / sizeof(((struct linux_efi_memreserve *)0)->entry[0])) + #endif /* _LINUX_EFI_H */ -- 2.19.1
WARNING: multiple messages have this Message-ID (diff)
From: ard.biesheuvel@linaro.org (Ard Biesheuvel) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 4/4] efi: reduce the amount of memblock reservations for persistent allocations Date: Tue, 6 Nov 2018 12:37:32 +0100 [thread overview] Message-ID: <20181106113732.16351-5-ard.biesheuvel@linaro.org> (raw) In-Reply-To: <20181106113732.16351-1-ard.biesheuvel@linaro.org> The current implementation of efi_mem_reserve_persistent() is rather naive, in the sense that for each invocation, it creates a separate linked list entry to describe the reservation. Since the linked list entries themselves need to persist across subsequent kexec reboots, every reservation created this way results in two memblock_reserve() calls at the next boot. On arm64 systems with 100s of CPUs, this may result in a excessive number of memblock reservations, and needless fragmentation. So instead, make use of the newly updated struct linux_efi_memreserve layout to put multiple reservations into a single linked list entry. This should get rid of the numerous tiny memblock reservations, and effectively cut the total number of reservations in half on arm64 systems with many CPUs. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> --- drivers/firmware/efi/efi.c | 29 ++++++++++++++------ include/linux/efi.h | 3 ++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 85d2ec532816..2ca5a59f7568 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -978,22 +978,35 @@ static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock); int efi_mem_reserve_persistent(phys_addr_t addr, u64 size) { struct linux_efi_memreserve *rsv, *parent; - int rsvsize = EFI_MEMRESERVE_SIZE(1); + unsigned long prsv; + int index; if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR) return -ENODEV; - rsv = kmalloc(rsvsize, GFP_KERNEL); - if (!rsv) - return -ENOMEM; - parent = memremap(efi.mem_reserve, sizeof(*rsv), MEMREMAP_WB); - if (!parent) { - kfree(rsv); + if (!parent) return -ENOMEM; + + /* first try to find a slot in an existing linked list entry */ + for (prsv = parent->next; prsv; prsv = rsv->next) { + rsv = __va(prsv); + index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size); + if (index < rsv->size) { + rsv->entry[index].base = addr; + rsv->entry[index].size = size; + + memunmap(parent); + return 0; + } } - rsv->size = 1; + /* no slot found - allocate a new linked list entry */ + rsv = (struct linux_efi_memreserve *)__get_free_page(GFP_KERNEL); + if (!rsv) + return -ENOMEM; + + rsv->size = EFI_MEMRESERVE_COUNT(PAGE_SIZE); atomic_set(&rsv->count, 1); rsv->entry[0].base = addr; rsv->entry[0].size = size; diff --git a/include/linux/efi.h b/include/linux/efi.h index dfce82b2ca8a..1a1a081f7244 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1727,4 +1727,7 @@ struct linux_efi_memreserve { #define EFI_MEMRESERVE_SIZE(count) (sizeof(struct linux_efi_memreserve) + \ (count) * sizeof(((struct linux_efi_memreserve *)0)->entry[0])) +#define EFI_MEMRESERVE_COUNT(size) (((size) - sizeof(struct linux_efi_memreserve)) \ + / sizeof(((struct linux_efi_memreserve *)0)->entry[0])) + #endif /* _LINUX_EFI_H */ -- 2.19.1
next prev parent reply other threads:[~2018-11-06 11:37 UTC|newest] Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-11-06 11:37 [PATCH 0/4] arm/efi: fix memblock reallocation crash due to persistent reservations Ard Biesheuvel 2018-11-06 11:37 ` Ard Biesheuvel 2018-11-06 11:37 ` [PATCH 1/4] arm64: memblock: don't permit memblock resizing until linear mapping is up Ard Biesheuvel 2018-11-06 11:37 ` Ard Biesheuvel 2018-11-06 21:22 ` Will Deacon 2018-11-06 21:22 ` Will Deacon 2018-11-06 11:37 ` [PATCH 2/4] efi/arm: defer persistent reservations until after paging_init() Ard Biesheuvel 2018-11-06 11:37 ` Ard Biesheuvel 2018-11-06 19:02 ` Ard Biesheuvel 2018-11-06 19:02 ` Ard Biesheuvel 2018-11-06 19:08 ` Russell King - ARM Linux 2018-11-06 19:08 ` Russell King - ARM Linux 2018-11-06 20:06 ` Ard Biesheuvel 2018-11-06 20:06 ` Ard Biesheuvel 2018-11-06 23:49 ` Russell King - ARM Linux 2018-11-06 23:49 ` Russell King - ARM Linux 2018-11-07 9:51 ` Marc Zyngier 2018-11-07 9:51 ` Marc Zyngier 2018-11-07 9:58 ` Russell King - ARM Linux 2018-11-07 9:58 ` Russell King - ARM Linux 2018-11-07 10:04 ` Ard Biesheuvel 2018-11-07 10:04 ` Ard Biesheuvel 2018-11-07 10:24 ` Russell King - ARM Linux 2018-11-07 10:24 ` Russell King - ARM Linux 2018-11-06 11:37 ` [PATCH 3/4] efi: permit multiple entries in persistent memreserve data structure Ard Biesheuvel 2018-11-06 11:37 ` Ard Biesheuvel 2018-11-06 11:37 ` Ard Biesheuvel [this message] 2018-11-06 11:37 ` [PATCH 4/4] efi: reduce the amount of memblock reservations for persistent allocations Ard Biesheuvel 2018-11-06 18:27 ` [PATCH 0/4] arm/efi: fix memblock reallocation crash due to persistent reservations Marc Zyngier 2018-11-06 18:27 ` Marc Zyngier 2018-11-06 19:01 ` Ard Biesheuvel 2018-11-06 19:01 ` Ard Biesheuvel 2018-11-06 19:40 ` Marc Zyngier 2018-11-06 19:40 ` Marc Zyngier 2018-11-06 21:34 ` Will Deacon 2018-11-06 21:34 ` Will Deacon 2018-11-06 21:39 ` Ard Biesheuvel 2018-11-06 21:39 ` Ard Biesheuvel 2018-11-06 21:46 ` Will Deacon 2018-11-06 21:46 ` Will Deacon
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20181106113732.16351-5-ard.biesheuvel@linaro.org \ --to=ard.biesheuvel@linaro.org \ --cc=bhsharma@redhat.com \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-efi@vger.kernel.org \ --cc=marc.zyngier@arm.com \ --cc=mark.rutland@arm.com \ --cc=will.deacon@arm.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.