Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1705849 > unrolled thread
| Started by | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| First post | 2017-08-07 22:50 +0200 |
| Last post | 2017-08-11 17:30 +0200 |
| Articles | 20 on this page of 29 — 5 participants |
Back to article view | Back to linux.kernel
[v6 00/15] complete deferred page initialization Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-08-07 22:50 +0200
[v6 09/15] sparc64: optimized struct page zeroing Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-08-07 22:50 +0200
Re: [v6 09/15] sparc64: optimized struct page zeroing Michal Hocko <mhocko@kernel.org> - 2017-08-11 15:00 +0200
Re: [v6 09/15] sparc64: optimized struct page zeroing Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-11 18:10 +0200
[v6 08/15] mm: zero struct pages during initialization Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-08-07 22:50 +0200
Re: [v6 08/15] mm: zero struct pages during initialization Michal Hocko <mhocko@kernel.org> - 2017-08-11 15:00 +0200
Re: [v6 08/15] mm: zero struct pages during initialization Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-11 18:10 +0200
[v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-08-07 22:50 +0200
Re: [v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw Michal Hocko <mhocko@kernel.org> - 2017-08-11 14:50 +0200
Re: [v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw Michal Hocko <mhocko@kernel.org> - 2017-08-11 18:10 +0200
Re: [v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-11 18:30 +0200
Re: [v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-11 18:10 +0200
[v6 10/15] x86/kasan: explicitly zero kasan shadow memory Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-08-07 22:50 +0200
[v6 05/15] mm: don't accessed uninitialized struct pages Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-08-07 22:50 +0200
Re: [v6 05/15] mm: don't accessed uninitialized struct pages Michal Hocko <mhocko@kernel.org> - 2017-08-11 11:40 +0200
Re: [v6 05/15] mm: don't accessed uninitialized struct pages Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-11 18:00 +0200
[v6 11/15] arm64/kasan: explicitly zero kasan shadow memory Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-08-07 22:50 +0200
Re: [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory Will Deacon <will.deacon@arm.com> - 2017-08-08 11:10 +0200
Re: [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-08 14:00 +0200
Re: [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory Will Deacon <will.deacon@arm.com> - 2017-08-08 14:40 +0200
Re: [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-08 15:00 +0200
RE: [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory David Laight <David.Laight@ACULAB.COM> - 2017-08-08 15:20 +0200
Re: [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-08 15:40 +0200
[v6 13/15] mm: stop zeroing memory during allocation in vmemmap Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-08-07 22:50 +0200
Re: [v6 13/15] mm: stop zeroing memory during allocation in vmemmap Michal Hocko <mhocko@kernel.org> - 2017-08-11 15:10 +0200
Re: [v6 13/15] mm: stop zeroing memory during allocation in vmemmap Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-11 18:20 +0200
Re: [v6 00/15] complete deferred page initialization Michal Hocko <mhocko@kernel.org> - 2017-08-11 10:00 +0200
Re: [v6 00/15] complete deferred page initialization Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-08-11 17:20 +0200
Re: [v6 00/15] complete deferred page initialization Michal Hocko <mhocko@kernel.org> - 2017-08-11 17:30 +0200
Page 1 of 2 [1] 2 Next page →
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-07 22:50 +0200 |
| Subject | [v6 00/15] complete deferred page initialization |
| Message-ID | <ubX8m-5vB-5@gated-at.bofh.it> |
Changelog:
v6 - v4
- Fixed ARM64 + kasan code, as reported by Ard Biesheuvel
- Tested ARM64 code in qemu and found few more issues, that I fixed in this
iteration
- Added page roundup/rounddown to x86 and arm zeroing routines to zero the
whole allocated range, instead of only provided address range.
- Addressed SPARC related comment from Sam Ravnborg
- Fixed section mismatch warnings related to memblock_discard().
v5 - v4
- Fixed build issues reported by kbuild on various configurations
v4 - v3
- Rewrote code to zero sturct pages in __init_single_page() as
suggested by Michal Hocko
- Added code to handle issues related to accessing struct page
memory before they are initialized.
v3 - v2
- Addressed David Miller comments about one change per patch:
* Splited changes to platforms into 4 patches
* Made "do not zero vmemmap_buf" as a separate patch
v2 - v1
- Per request, added s390 to deferred "struct page" zeroing
- Collected performance data on x86 which proofs the importance to
keep memset() as prefetch (see below).
SMP machines can benefit from the DEFERRED_STRUCT_PAGE_INIT config option,
which defers initializing struct pages until all cpus have been started so
it can be done in parallel.
However, this feature is sub-optimal, because the deferred page
initialization code expects that the struct pages have already been zeroed,
and the zeroing is done early in boot with a single thread only. Also, we
access that memory and set flags before struct pages are initialized. All
of this is fixed in this patchset.
In this work we do the following:
- Never read access struct page until it was initialized
- Never set any fields in struct pages before they are initialized
- Zero struct page at the beginning of struct page initialization
Performance improvements on x86 machine with 8 nodes:
Intel(R) Xeon(R) CPU E7-8895 v3 @ 2.60GHz
Single threaded struct page init: 7.6s/T improvement
Deferred struct page init: 10.2s/T improvement
Pavel Tatashin (15):
x86/mm: reserve only exiting low pages
x86/mm: setting fields in deferred pages
sparc64/mm: setting fields in deferred pages
mm: discard memblock data later
mm: don't accessed uninitialized struct pages
sparc64: simplify vmemmap_populate
mm: defining memblock_virt_alloc_try_nid_raw
mm: zero struct pages during initialization
sparc64: optimized struct page zeroing
x86/kasan: explicitly zero kasan shadow memory
arm64/kasan: explicitly zero kasan shadow memory
mm: explicitly zero pagetable memory
mm: stop zeroing memory during allocation in vmemmap
mm: optimize early system hash allocations
mm: debug for raw alloctor
arch/arm64/mm/kasan_init.c | 42 ++++++++++
arch/sparc/include/asm/pgtable_64.h | 30 +++++++
arch/sparc/mm/init_64.c | 31 +++-----
arch/x86/kernel/setup.c | 5 +-
arch/x86/mm/init_64.c | 9 ++-
arch/x86/mm/kasan_init_64.c | 67 ++++++++++++++++
include/linux/bootmem.h | 27 +++++++
include/linux/memblock.h | 9 ++-
include/linux/mm.h | 9 +++
mm/memblock.c | 152 ++++++++++++++++++++++++++++--------
mm/nobootmem.c | 16 ----
mm/page_alloc.c | 31 +++++---
mm/sparse-vmemmap.c | 10 ++-
mm/sparse.c | 6 +-
14 files changed, 356 insertions(+), 88 deletions(-)
--
2.14.0
[toc] | [next] | [standalone]
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-07 22:50 +0200 |
| Subject | [v6 09/15] sparc64: optimized struct page zeroing |
| Message-ID | <ubX8n-5vB-35@gated-at.bofh.it> |
| In reply to | #1705849 |
Add an optimized mm_zero_struct_page(), so struct page's are zeroed without
calling memset(). We do eight to tent regular stores based on the size of
struct page. Compiler optimizes out the conditions of switch() statement.
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Reviewed-by: Bob Picco <bob.picco@oracle.com>
---
arch/sparc/include/asm/pgtable_64.h | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 6fbd931f0570..cee5cc7ccc51 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -230,6 +230,36 @@ extern unsigned long _PAGE_ALL_SZ_BITS;
extern struct page *mem_map_zero;
#define ZERO_PAGE(vaddr) (mem_map_zero)
+/* This macro must be updated when the size of struct page grows above 80
+ * or reduces below 64.
+ * The idea that compiler optimizes out switch() statement, and only
+ * leaves clrx instructions
+ */
+#define mm_zero_struct_page(pp) do { \
+ unsigned long *_pp = (void *)(pp); \
+ \
+ /* Check that struct page is either 64, 72, or 80 bytes */ \
+ BUILD_BUG_ON(sizeof(struct page) & 7); \
+ BUILD_BUG_ON(sizeof(struct page) < 64); \
+ BUILD_BUG_ON(sizeof(struct page) > 80); \
+ \
+ switch (sizeof(struct page)) { \
+ case 80: \
+ _pp[9] = 0; /* fallthrough */ \
+ case 72: \
+ _pp[8] = 0; /* fallthrough */ \
+ default: \
+ _pp[7] = 0; \
+ _pp[6] = 0; \
+ _pp[5] = 0; \
+ _pp[4] = 0; \
+ _pp[3] = 0; \
+ _pp[2] = 0; \
+ _pp[1] = 0; \
+ _pp[0] = 0; \
+ } \
+} while (0)
+
/* PFNs are real physical page numbers. However, mem_map only begins to record
* per-page information starting at pfn_base. This is to handle systems where
* the first physical page in the machine is at some huge physical address,
--
2.14.0
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-08-11 15:00 +0200 |
| Subject | Re: [v6 09/15] sparc64: optimized struct page zeroing |
| Message-ID | <udhHI-3D8-29@gated-at.bofh.it> |
| In reply to | #1705850 |
On Mon 07-08-17 16:38:43, Pavel Tatashin wrote:
> Add an optimized mm_zero_struct_page(), so struct page's are zeroed without
> calling memset(). We do eight to tent regular stores based on the size of
> struct page. Compiler optimizes out the conditions of switch() statement.
Again, this doesn't explain why we need this. You have mentioned those
reasons in some previous emails but be explicit here please.
> Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
> Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
> Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
> Reviewed-by: Bob Picco <bob.picco@oracle.com>
> ---
> arch/sparc/include/asm/pgtable_64.h | 30 ++++++++++++++++++++++++++++++
> 1 file changed, 30 insertions(+)
>
> diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
> index 6fbd931f0570..cee5cc7ccc51 100644
> --- a/arch/sparc/include/asm/pgtable_64.h
> +++ b/arch/sparc/include/asm/pgtable_64.h
> @@ -230,6 +230,36 @@ extern unsigned long _PAGE_ALL_SZ_BITS;
> extern struct page *mem_map_zero;
> #define ZERO_PAGE(vaddr) (mem_map_zero)
>
> +/* This macro must be updated when the size of struct page grows above 80
> + * or reduces below 64.
> + * The idea that compiler optimizes out switch() statement, and only
> + * leaves clrx instructions
> + */
> +#define mm_zero_struct_page(pp) do { \
> + unsigned long *_pp = (void *)(pp); \
> + \
> + /* Check that struct page is either 64, 72, or 80 bytes */ \
> + BUILD_BUG_ON(sizeof(struct page) & 7); \
> + BUILD_BUG_ON(sizeof(struct page) < 64); \
> + BUILD_BUG_ON(sizeof(struct page) > 80); \
> + \
> + switch (sizeof(struct page)) { \
> + case 80: \
> + _pp[9] = 0; /* fallthrough */ \
> + case 72: \
> + _pp[8] = 0; /* fallthrough */ \
> + default: \
> + _pp[7] = 0; \
> + _pp[6] = 0; \
> + _pp[5] = 0; \
> + _pp[4] = 0; \
> + _pp[3] = 0; \
> + _pp[2] = 0; \
> + _pp[1] = 0; \
> + _pp[0] = 0; \
> + } \
> +} while (0)
> +
> /* PFNs are real physical page numbers. However, mem_map only begins to record
> * per-page information starting at pfn_base. This is to handle systems where
> * the first physical page in the machine is at some huge physical address,
> --
> 2.14.0
--
Michal Hocko
SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-11 18:10 +0200 |
| Subject | Re: [v6 09/15] sparc64: optimized struct page zeroing |
| Message-ID | <udkFA-5H8-21@gated-at.bofh.it> |
| In reply to | #1709584 |
>> Add an optimized mm_zero_struct_page(), so struct page's are zeroed without >> calling memset(). We do eight to tent regular stores based on the size of >> struct page. Compiler optimizes out the conditions of switch() statement. > > Again, this doesn't explain why we need this. You have mentioned those > reasons in some previous emails but be explicit here please. > I will add performance data to this patch as well. Thank you, Pasha
[toc] | [prev] | [next] | [standalone]
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-07 22:50 +0200 |
| Subject | [v6 08/15] mm: zero struct pages during initialization |
| Message-ID | <ubX8n-5vB-37@gated-at.bofh.it> |
| In reply to | #1705849 |
Add struct page zeroing as a part of initialization of other fields in
__init_single_page().
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Reviewed-by: Bob Picco <bob.picco@oracle.com>
---
include/linux/mm.h | 9 +++++++++
mm/page_alloc.c | 1 +
2 files changed, 10 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 46b9ac5e8569..183ac5e733db 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -93,6 +93,15 @@ extern int mmap_rnd_compat_bits __read_mostly;
#define mm_forbids_zeropage(X) (0)
#endif
+/*
+ * On some architectures it is expensive to call memset() for small sizes.
+ * Those architectures should provide their own implementation of "struct page"
+ * zeroing by defining this macro in <asm/pgtable.h>.
+ */
+#ifndef mm_zero_struct_page
+#define mm_zero_struct_page(pp) ((void)memset((pp), 0, sizeof(struct page)))
+#endif
+
/*
* Default maximum number of active map areas, this limits the number of vmas
* per mm struct. Users can overwrite this number by sysctl but there is a
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 983de0a8047b..4d32c1fa4c6c 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1168,6 +1168,7 @@ static void free_one_page(struct zone *zone,
static void __meminit __init_single_page(struct page *page, unsigned long pfn,
unsigned long zone, int nid)
{
+ mm_zero_struct_page(page);
set_page_links(page, zone, nid, pfn);
init_page_count(page);
page_mapcount_reset(page);
--
2.14.0
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-08-11 15:00 +0200 |
| Subject | Re: [v6 08/15] mm: zero struct pages during initialization |
| Message-ID | <udhHH-3D8-1@gated-at.bofh.it> |
| In reply to | #1705851 |
On Mon 07-08-17 16:38:42, Pavel Tatashin wrote:
> Add struct page zeroing as a part of initialization of other fields in
> __init_single_page().
I believe this deserves much more detailed explanation why this is safe.
What actually prevents any pfn walker from seeing an uninitialized
struct page? Please make your assumptions explicit in the commit log so
that we can check them independently.
Also this is done with some purpose which is the perfmance, right? You
have mentioned that in the cover letter but if somebody is going to read
through git logs this wouldn't be obvious from the specific commit.
So add that information here as well. Especially numbers will be
interesting.
As a sidenote, this will need some more followups for memory hotplug
after my recent changes which are not merged yet but I will take care of
that.
> Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
> Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
> Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
> Reviewed-by: Bob Picco <bob.picco@oracle.com>
After the relevant information is added feel free add
Acked-by: Michal Hocko <mhocko@suse.com>
> ---
> include/linux/mm.h | 9 +++++++++
> mm/page_alloc.c | 1 +
> 2 files changed, 10 insertions(+)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 46b9ac5e8569..183ac5e733db 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -93,6 +93,15 @@ extern int mmap_rnd_compat_bits __read_mostly;
> #define mm_forbids_zeropage(X) (0)
> #endif
>
> +/*
> + * On some architectures it is expensive to call memset() for small sizes.
> + * Those architectures should provide their own implementation of "struct page"
> + * zeroing by defining this macro in <asm/pgtable.h>.
> + */
> +#ifndef mm_zero_struct_page
> +#define mm_zero_struct_page(pp) ((void)memset((pp), 0, sizeof(struct page)))
> +#endif
> +
> /*
> * Default maximum number of active map areas, this limits the number of vmas
> * per mm struct. Users can overwrite this number by sysctl but there is a
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 983de0a8047b..4d32c1fa4c6c 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -1168,6 +1168,7 @@ static void free_one_page(struct zone *zone,
> static void __meminit __init_single_page(struct page *page, unsigned long pfn,
> unsigned long zone, int nid)
> {
> + mm_zero_struct_page(page);
> set_page_links(page, zone, nid, pfn);
> init_page_count(page);
> page_mapcount_reset(page);
> --
> 2.14.0
--
Michal Hocko
SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-11 18:10 +0200 |
| Subject | Re: [v6 08/15] mm: zero struct pages during initialization |
| Message-ID | <udkFz-5H8-7@gated-at.bofh.it> |
| In reply to | #1709575 |
> I believe this deserves much more detailed explanation why this is safe. > What actually prevents any pfn walker from seeing an uninitialized > struct page? Please make your assumptions explicit in the commit log so > that we can check them independently. There is nothing prevents pfn walkers from walk over any struct pages deferred and non-deferred. However, during boot before deferred pages are initialized we have just a few places that do that, and all of those cases are fixed in this patchset. > Also this is done with some purpose which is the perfmance, right? You > have mentioned that in the cover letter but if somebody is going to read > through git logs this wouldn't be obvious from the specific commit. > So add that information here as well. Especially numbers will be > interesting. I will add more performance data to this patch comment.
[toc] | [prev] | [next] | [standalone]
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-07 22:50 +0200 |
| Subject | [v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw |
| Message-ID | <ubX8n-5vB-39@gated-at.bofh.it> |
| In reply to | #1705849 |
A new variant of memblock_virt_alloc_* allocations:
memblock_virt_alloc_try_nid_raw()
- Does not zero the allocated memory
- Does not panic if request cannot be satisfied
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Reviewed-by: Bob Picco <bob.picco@oracle.com>
---
include/linux/bootmem.h | 27 +++++++++++++++++++++++++
mm/memblock.c | 53 ++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 73 insertions(+), 7 deletions(-)
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index e223d91b6439..ea30b3987282 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -160,6 +160,9 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,
#define BOOTMEM_ALLOC_ANYWHERE (~(phys_addr_t)0)
/* FIXME: Move to memblock.h at a point where we remove nobootmem.c */
+void *memblock_virt_alloc_try_nid_raw(phys_addr_t size, phys_addr_t align,
+ phys_addr_t min_addr,
+ phys_addr_t max_addr, int nid);
void *memblock_virt_alloc_try_nid_nopanic(phys_addr_t size,
phys_addr_t align, phys_addr_t min_addr,
phys_addr_t max_addr, int nid);
@@ -176,6 +179,14 @@ static inline void * __init memblock_virt_alloc(
NUMA_NO_NODE);
}
+static inline void * __init memblock_virt_alloc_raw(
+ phys_addr_t size, phys_addr_t align)
+{
+ return memblock_virt_alloc_try_nid_raw(size, align, BOOTMEM_LOW_LIMIT,
+ BOOTMEM_ALLOC_ACCESSIBLE,
+ NUMA_NO_NODE);
+}
+
static inline void * __init memblock_virt_alloc_nopanic(
phys_addr_t size, phys_addr_t align)
{
@@ -257,6 +268,14 @@ static inline void * __init memblock_virt_alloc(
return __alloc_bootmem(size, align, BOOTMEM_LOW_LIMIT);
}
+static inline void * __init memblock_virt_alloc_raw(
+ phys_addr_t size, phys_addr_t align)
+{
+ if (!align)
+ align = SMP_CACHE_BYTES;
+ return __alloc_bootmem_nopanic(size, align, BOOTMEM_LOW_LIMIT);
+}
+
static inline void * __init memblock_virt_alloc_nopanic(
phys_addr_t size, phys_addr_t align)
{
@@ -309,6 +328,14 @@ static inline void * __init memblock_virt_alloc_try_nid(phys_addr_t size,
min_addr);
}
+static inline void * __init memblock_virt_alloc_try_nid_raw(
+ phys_addr_t size, phys_addr_t align,
+ phys_addr_t min_addr, phys_addr_t max_addr, int nid)
+{
+ return ___alloc_bootmem_node_nopanic(NODE_DATA(nid), size, align,
+ min_addr, max_addr);
+}
+
static inline void * __init memblock_virt_alloc_try_nid_nopanic(
phys_addr_t size, phys_addr_t align,
phys_addr_t min_addr, phys_addr_t max_addr, int nid)
diff --git a/mm/memblock.c b/mm/memblock.c
index 08f449acfdd1..3fbf3bcb52d9 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1327,7 +1327,6 @@ static void * __init memblock_virt_alloc_internal(
return NULL;
done:
ptr = phys_to_virt(alloc);
- memset(ptr, 0, size);
/*
* The min_count is set to 0 so that bootmem allocated blocks
@@ -1340,6 +1339,38 @@ static void * __init memblock_virt_alloc_internal(
return ptr;
}
+/**
+ * memblock_virt_alloc_try_nid_raw - allocate boot memory block without zeroing
+ * memory and without panicking
+ * @size: size of memory block to be allocated in bytes
+ * @align: alignment of the region and block's size
+ * @min_addr: the lower bound of the memory region from where the allocation
+ * is preferred (phys address)
+ * @max_addr: the upper bound of the memory region from where the allocation
+ * is preferred (phys address), or %BOOTMEM_ALLOC_ACCESSIBLE to
+ * allocate only from memory limited by memblock.current_limit value
+ * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
+ *
+ * Public function, provides additional debug information (including caller
+ * info), if enabled. Does not zero allocated memory, does not panic if request
+ * cannot be satisfied.
+ *
+ * RETURNS:
+ * Virtual address of allocated memory block on success, NULL on failure.
+ */
+void * __init memblock_virt_alloc_try_nid_raw(
+ phys_addr_t size, phys_addr_t align,
+ phys_addr_t min_addr, phys_addr_t max_addr,
+ int nid)
+{
+ memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx %pF\n",
+ __func__, (u64)size, (u64)align, nid, (u64)min_addr,
+ (u64)max_addr, (void *)_RET_IP_);
+
+ return memblock_virt_alloc_internal(size, align,
+ min_addr, max_addr, nid);
+}
+
/**
* memblock_virt_alloc_try_nid_nopanic - allocate boot memory block
* @size: size of memory block to be allocated in bytes
@@ -1351,8 +1382,8 @@ static void * __init memblock_virt_alloc_internal(
* allocate only from memory limited by memblock.current_limit value
* @nid: nid of the free area to find, %NUMA_NO_NODE for any node
*
- * Public version of _memblock_virt_alloc_try_nid_nopanic() which provides
- * additional debug information (including caller info), if enabled.
+ * Public function, provides additional debug information (including caller
+ * info), if enabled. This function zeroes the allocated memory.
*
* RETURNS:
* Virtual address of allocated memory block on success, NULL on failure.
@@ -1362,11 +1393,17 @@ void * __init memblock_virt_alloc_try_nid_nopanic(
phys_addr_t min_addr, phys_addr_t max_addr,
int nid)
{
+ void *ptr;
+
memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx %pF\n",
__func__, (u64)size, (u64)align, nid, (u64)min_addr,
(u64)max_addr, (void *)_RET_IP_);
- return memblock_virt_alloc_internal(size, align, min_addr,
- max_addr, nid);
+
+ ptr = memblock_virt_alloc_internal(size, align,
+ min_addr, max_addr, nid);
+ if (ptr)
+ memset(ptr, 0, size);
+ return ptr;
}
/**
@@ -1380,7 +1417,7 @@ void * __init memblock_virt_alloc_try_nid_nopanic(
* allocate only from memory limited by memblock.current_limit value
* @nid: nid of the free area to find, %NUMA_NO_NODE for any node
*
- * Public panicking version of _memblock_virt_alloc_try_nid_nopanic()
+ * Public panicking version of memblock_virt_alloc_try_nid_nopanic()
* which provides debug information (including caller info), if enabled,
* and panics if the request can not be satisfied.
*
@@ -1399,8 +1436,10 @@ void * __init memblock_virt_alloc_try_nid(
(u64)max_addr, (void *)_RET_IP_);
ptr = memblock_virt_alloc_internal(size, align,
min_addr, max_addr, nid);
- if (ptr)
+ if (ptr) {
+ memset(ptr, 0, size);
return ptr;
+ }
panic("%s: Failed to allocate %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx\n",
__func__, (u64)size, (u64)align, nid, (u64)min_addr,
--
2.14.0
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-08-11 14:50 +0200 |
| Subject | Re: [v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw |
| Message-ID | <udhy1-3zT-3@gated-at.bofh.it> |
| In reply to | #1705853 |
On Mon 07-08-17 16:38:41, Pavel Tatashin wrote:
> A new variant of memblock_virt_alloc_* allocations:
> memblock_virt_alloc_try_nid_raw()
> - Does not zero the allocated memory
> - Does not panic if request cannot be satisfied
OK, this looks good but I would not introduce memblock_virt_alloc_raw
here because we do not have any users. Please move that to "mm: optimize
early system hash allocations" which actually uses the API. It would be
easier to review it that way.
> Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
> Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
> Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
> Reviewed-by: Bob Picco <bob.picco@oracle.com>
other than that
Acked-by: Michal Hocko <mhocko@suse.com>
> ---
> include/linux/bootmem.h | 27 +++++++++++++++++++++++++
> mm/memblock.c | 53 ++++++++++++++++++++++++++++++++++++++++++-------
> 2 files changed, 73 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
> index e223d91b6439..ea30b3987282 100644
> --- a/include/linux/bootmem.h
> +++ b/include/linux/bootmem.h
> @@ -160,6 +160,9 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,
> #define BOOTMEM_ALLOC_ANYWHERE (~(phys_addr_t)0)
>
> /* FIXME: Move to memblock.h at a point where we remove nobootmem.c */
> +void *memblock_virt_alloc_try_nid_raw(phys_addr_t size, phys_addr_t align,
> + phys_addr_t min_addr,
> + phys_addr_t max_addr, int nid);
> void *memblock_virt_alloc_try_nid_nopanic(phys_addr_t size,
> phys_addr_t align, phys_addr_t min_addr,
> phys_addr_t max_addr, int nid);
> @@ -176,6 +179,14 @@ static inline void * __init memblock_virt_alloc(
> NUMA_NO_NODE);
> }
>
> +static inline void * __init memblock_virt_alloc_raw(
> + phys_addr_t size, phys_addr_t align)
> +{
> + return memblock_virt_alloc_try_nid_raw(size, align, BOOTMEM_LOW_LIMIT,
> + BOOTMEM_ALLOC_ACCESSIBLE,
> + NUMA_NO_NODE);
> +}
> +
> static inline void * __init memblock_virt_alloc_nopanic(
> phys_addr_t size, phys_addr_t align)
> {
> @@ -257,6 +268,14 @@ static inline void * __init memblock_virt_alloc(
> return __alloc_bootmem(size, align, BOOTMEM_LOW_LIMIT);
> }
>
> +static inline void * __init memblock_virt_alloc_raw(
> + phys_addr_t size, phys_addr_t align)
> +{
> + if (!align)
> + align = SMP_CACHE_BYTES;
> + return __alloc_bootmem_nopanic(size, align, BOOTMEM_LOW_LIMIT);
> +}
> +
> static inline void * __init memblock_virt_alloc_nopanic(
> phys_addr_t size, phys_addr_t align)
> {
> @@ -309,6 +328,14 @@ static inline void * __init memblock_virt_alloc_try_nid(phys_addr_t size,
> min_addr);
> }
>
> +static inline void * __init memblock_virt_alloc_try_nid_raw(
> + phys_addr_t size, phys_addr_t align,
> + phys_addr_t min_addr, phys_addr_t max_addr, int nid)
> +{
> + return ___alloc_bootmem_node_nopanic(NODE_DATA(nid), size, align,
> + min_addr, max_addr);
> +}
> +
> static inline void * __init memblock_virt_alloc_try_nid_nopanic(
> phys_addr_t size, phys_addr_t align,
> phys_addr_t min_addr, phys_addr_t max_addr, int nid)
> diff --git a/mm/memblock.c b/mm/memblock.c
> index 08f449acfdd1..3fbf3bcb52d9 100644
> --- a/mm/memblock.c
> +++ b/mm/memblock.c
> @@ -1327,7 +1327,6 @@ static void * __init memblock_virt_alloc_internal(
> return NULL;
> done:
> ptr = phys_to_virt(alloc);
> - memset(ptr, 0, size);
>
> /*
> * The min_count is set to 0 so that bootmem allocated blocks
> @@ -1340,6 +1339,38 @@ static void * __init memblock_virt_alloc_internal(
> return ptr;
> }
>
> +/**
> + * memblock_virt_alloc_try_nid_raw - allocate boot memory block without zeroing
> + * memory and without panicking
> + * @size: size of memory block to be allocated in bytes
> + * @align: alignment of the region and block's size
> + * @min_addr: the lower bound of the memory region from where the allocation
> + * is preferred (phys address)
> + * @max_addr: the upper bound of the memory region from where the allocation
> + * is preferred (phys address), or %BOOTMEM_ALLOC_ACCESSIBLE to
> + * allocate only from memory limited by memblock.current_limit value
> + * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
> + *
> + * Public function, provides additional debug information (including caller
> + * info), if enabled. Does not zero allocated memory, does not panic if request
> + * cannot be satisfied.
> + *
> + * RETURNS:
> + * Virtual address of allocated memory block on success, NULL on failure.
> + */
> +void * __init memblock_virt_alloc_try_nid_raw(
> + phys_addr_t size, phys_addr_t align,
> + phys_addr_t min_addr, phys_addr_t max_addr,
> + int nid)
> +{
> + memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx %pF\n",
> + __func__, (u64)size, (u64)align, nid, (u64)min_addr,
> + (u64)max_addr, (void *)_RET_IP_);
> +
> + return memblock_virt_alloc_internal(size, align,
> + min_addr, max_addr, nid);
> +}
> +
> /**
> * memblock_virt_alloc_try_nid_nopanic - allocate boot memory block
> * @size: size of memory block to be allocated in bytes
> @@ -1351,8 +1382,8 @@ static void * __init memblock_virt_alloc_internal(
> * allocate only from memory limited by memblock.current_limit value
> * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
> *
> - * Public version of _memblock_virt_alloc_try_nid_nopanic() which provides
> - * additional debug information (including caller info), if enabled.
> + * Public function, provides additional debug information (including caller
> + * info), if enabled. This function zeroes the allocated memory.
> *
> * RETURNS:
> * Virtual address of allocated memory block on success, NULL on failure.
> @@ -1362,11 +1393,17 @@ void * __init memblock_virt_alloc_try_nid_nopanic(
> phys_addr_t min_addr, phys_addr_t max_addr,
> int nid)
> {
> + void *ptr;
> +
> memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx %pF\n",
> __func__, (u64)size, (u64)align, nid, (u64)min_addr,
> (u64)max_addr, (void *)_RET_IP_);
> - return memblock_virt_alloc_internal(size, align, min_addr,
> - max_addr, nid);
> +
> + ptr = memblock_virt_alloc_internal(size, align,
> + min_addr, max_addr, nid);
> + if (ptr)
> + memset(ptr, 0, size);
> + return ptr;
> }
>
> /**
> @@ -1380,7 +1417,7 @@ void * __init memblock_virt_alloc_try_nid_nopanic(
> * allocate only from memory limited by memblock.current_limit value
> * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
> *
> - * Public panicking version of _memblock_virt_alloc_try_nid_nopanic()
> + * Public panicking version of memblock_virt_alloc_try_nid_nopanic()
> * which provides debug information (including caller info), if enabled,
> * and panics if the request can not be satisfied.
> *
> @@ -1399,8 +1436,10 @@ void * __init memblock_virt_alloc_try_nid(
> (u64)max_addr, (void *)_RET_IP_);
> ptr = memblock_virt_alloc_internal(size, align,
> min_addr, max_addr, nid);
> - if (ptr)
> + if (ptr) {
> + memset(ptr, 0, size);
> return ptr;
> + }
>
> panic("%s: Failed to allocate %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx\n",
> __func__, (u64)size, (u64)align, nid, (u64)min_addr,
> --
> 2.14.0
--
Michal Hocko
SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-08-11 18:10 +0200 |
| Subject | Re: [v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw |
| Message-ID | <udkFB-5H8-51@gated-at.bofh.it> |
| In reply to | #1709566 |
On Fri 11-08-17 11:58:46, Pasha Tatashin wrote: > On 08/11/2017 08:39 AM, Michal Hocko wrote: > >On Mon 07-08-17 16:38:41, Pavel Tatashin wrote: > >>A new variant of memblock_virt_alloc_* allocations: > >>memblock_virt_alloc_try_nid_raw() > >> - Does not zero the allocated memory > >> - Does not panic if request cannot be satisfied > > > >OK, this looks good but I would not introduce memblock_virt_alloc_raw > >here because we do not have any users. Please move that to "mm: optimize > >early system hash allocations" which actually uses the API. It would be > >easier to review it that way. > > > >>Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com> > >>Reviewed-by: Steven Sistare <steven.sistare@oracle.com> > >>Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com> > >>Reviewed-by: Bob Picco <bob.picco@oracle.com> > > > >other than that > >Acked-by: Michal Hocko <mhocko@suse.com> > > Sure, I could do this, but as I understood from earlier Dave Miller's > comments, we should do one logical change at a time. Hence, introduce API in > one patch use it in another. So, this is how I tried to organize this patch > set. Is this assumption incorrect? Well, it really depends. If the patch is really small then adding a new API along with users is easier to review and backport because you have a clear view of the usage. I believe this is the case here. But if others feel otherwise I will not object. -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-11 18:30 +0200 |
| Subject | Re: [v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw |
| Message-ID | <udkYV-5NJ-1@gated-at.bofh.it> |
| In reply to | #1709796 |
>> Sure, I could do this, but as I understood from earlier Dave Miller's >> comments, we should do one logical change at a time. Hence, introduce API in >> one patch use it in another. So, this is how I tried to organize this patch >> set. Is this assumption incorrect? > > Well, it really depends. If the patch is really small then adding a new > API along with users is easier to review and backport because you have a > clear view of the usage. I believe this is the case here. But if others > feel otherwise I will not object. I will merge them. Thank you, Pasha
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-11 18:10 +0200 |
| Subject | Re: [v6 07/15] mm: defining memblock_virt_alloc_try_nid_raw |
| Message-ID | <udkFB-5H8-47@gated-at.bofh.it> |
| In reply to | #1709566 |
On 08/11/2017 08:39 AM, Michal Hocko wrote: > On Mon 07-08-17 16:38:41, Pavel Tatashin wrote: >> A new variant of memblock_virt_alloc_* allocations: >> memblock_virt_alloc_try_nid_raw() >> - Does not zero the allocated memory >> - Does not panic if request cannot be satisfied > > OK, this looks good but I would not introduce memblock_virt_alloc_raw > here because we do not have any users. Please move that to "mm: optimize > early system hash allocations" which actually uses the API. It would be > easier to review it that way. > >> Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com> >> Reviewed-by: Steven Sistare <steven.sistare@oracle.com> >> Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com> >> Reviewed-by: Bob Picco <bob.picco@oracle.com> > > other than that > Acked-by: Michal Hocko <mhocko@suse.com> Sure, I could do this, but as I understood from earlier Dave Miller's comments, we should do one logical change at a time. Hence, introduce API in one patch use it in another. So, this is how I tried to organize this patch set. Is this assumption incorrect?
[toc] | [prev] | [next] | [standalone]
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-07 22:50 +0200 |
| Subject | [v6 10/15] x86/kasan: explicitly zero kasan shadow memory |
| Message-ID | <ubX8n-5vB-43@gated-at.bofh.it> |
| In reply to | #1705849 |
To optimize the performance of struct page initialization,
vmemmap_populate() will no longer zero memory.
We must explicitly zero the memory that is allocated by vmemmap_populate()
for kasan, as this memory does not go through struct page initialization
path.
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Reviewed-by: Bob Picco <bob.picco@oracle.com>
---
arch/x86/mm/kasan_init_64.c | 67 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c
index 02c9d7553409..ec6b2272fd80 100644
--- a/arch/x86/mm/kasan_init_64.c
+++ b/arch/x86/mm/kasan_init_64.c
@@ -84,6 +84,66 @@ static struct notifier_block kasan_die_notifier = {
};
#endif
+/*
+ * x86 variant of vmemmap_populate() uses either PMD_SIZE pages or base pages
+ * to map allocated memory. This routine determines the page size for the given
+ * address from vmemmap.
+ */
+static u64 get_vmemmap_pgsz(u64 addr)
+{
+ pgd_t *pgd;
+ p4d_t *p4d;
+ pud_t *pud;
+ pmd_t *pmd;
+
+ pgd = pgd_offset_k(addr);
+ BUG_ON(pgd_none(*pgd) || pgd_large(*pgd));
+
+ p4d = p4d_offset(pgd, addr);
+ BUG_ON(p4d_none(*p4d) || p4d_large(*p4d));
+
+ pud = pud_offset(p4d, addr);
+ BUG_ON(pud_none(*pud) || pud_large(*pud));
+
+ pmd = pmd_offset(pud, addr);
+ BUG_ON(pmd_none(*pmd));
+
+ if (pmd_large(*pmd))
+ return PMD_SIZE;
+ return PAGE_SIZE;
+}
+
+/*
+ * Memory that was allocated by vmemmap_populate is not zeroed, so we must
+ * zero it here explicitly.
+ */
+static void
+zero_vmemmap_populated_memory(void)
+{
+ u64 i, start, end;
+
+ for (i = 0; i < E820_MAX_ENTRIES && pfn_mapped[i].end; i++) {
+ void *kaddr_start = pfn_to_kaddr(pfn_mapped[i].start);
+ void *kaddr_end = pfn_to_kaddr(pfn_mapped[i].end);
+
+ start = (u64)kasan_mem_to_shadow(kaddr_start);
+ end = (u64)kasan_mem_to_shadow(kaddr_end);
+
+ /* Round to the start end of the mapped pages */
+ start = rounddown(start, get_vmemmap_pgsz(start));
+ end = roundup(end, get_vmemmap_pgsz(start));
+ memset((void *)start, 0, end - start);
+ }
+
+ start = (u64)kasan_mem_to_shadow(_stext);
+ end = (u64)kasan_mem_to_shadow(_end);
+
+ /* Round to the start end of the mapped pages */
+ start = rounddown(start, get_vmemmap_pgsz(start));
+ end = roundup(end, get_vmemmap_pgsz(start));
+ memset((void *)start, 0, end - start);
+}
+
void __init kasan_early_init(void)
{
int i;
@@ -156,6 +216,13 @@ void __init kasan_init(void)
pte_t pte = __pte(__pa(kasan_zero_page) | __PAGE_KERNEL_RO);
set_pte(&kasan_zero_pte[i], pte);
}
+
+ /*
+ * vmemmap_populate does not zero the memory, so we need to zero it
+ * explicitly
+ */
+ zero_vmemmap_populated_memory();
+
/* Flush TLBs again to be sure that write protection applied. */
__flush_tlb_all();
--
2.14.0
[toc] | [prev] | [next] | [standalone]
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-07 22:50 +0200 |
| Subject | [v6 05/15] mm: don't accessed uninitialized struct pages |
| Message-ID | <ubX8n-5vB-45@gated-at.bofh.it> |
| In reply to | #1705849 |
In deferred_init_memmap() where all deferred struct pages are initialized
we have a check like this:
if (page->flags) {
VM_BUG_ON(page_zone(page) != zone);
goto free_range;
}
This way we are checking if the current deferred page has already been
initialized. It works, because memory for struct pages has been zeroed, and
the only way flags are not zero if it went through __init_single_page()
before. But, once we change the current behavior and won't zero the memory
in memblock allocator, we cannot trust anything inside "struct page"es
until they are initialized. This patch fixes this.
This patch defines a new accessor memblock_get_reserved_pfn_range()
which returns successive ranges of reserved PFNs. deferred_init_memmap()
calls it to determine if a PFN and its struct page has already been
initialized.
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Reviewed-by: Bob Picco <bob.picco@oracle.com>
---
include/linux/memblock.h | 3 +++
mm/memblock.c | 54 ++++++++++++++++++++++++++++++++++++++++++------
mm/page_alloc.c | 11 +++++++++-
3 files changed, 61 insertions(+), 7 deletions(-)
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index bae11c7e7bf3..b6a2a610f5e1 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -320,6 +320,9 @@ int memblock_is_map_memory(phys_addr_t addr);
int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
bool memblock_is_reserved(phys_addr_t addr);
bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
+void memblock_get_reserved_pfn_range(unsigned long pfn,
+ unsigned long *pfn_start,
+ unsigned long *pfn_end);
extern void __memblock_dump_all(void);
diff --git a/mm/memblock.c b/mm/memblock.c
index bf14aea6ab70..08f449acfdd1 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1580,7 +1580,13 @@ void __init memblock_mem_limit_remove_map(phys_addr_t limit)
memblock_cap_memory_range(0, max_addr);
}
-static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
+/**
+ * Return index in regions array if addr is within the region. Otherwise
+ * return -1. If -1 is returned and *next_idx is not %NULL, sets it to the
+ * next region index or -1 if there is none.
+ */
+static int __init_memblock memblock_search(struct memblock_type *type,
+ phys_addr_t addr, int *next_idx)
{
unsigned int left = 0, right = type->cnt;
@@ -1595,22 +1601,26 @@ static int __init_memblock memblock_search(struct memblock_type *type, phys_addr
else
return mid;
} while (left < right);
+
+ if (next_idx)
+ *next_idx = (right == type->cnt) ? -1 : right;
+
return -1;
}
bool __init memblock_is_reserved(phys_addr_t addr)
{
- return memblock_search(&memblock.reserved, addr) != -1;
+ return memblock_search(&memblock.reserved, addr, NULL) != -1;
}
bool __init_memblock memblock_is_memory(phys_addr_t addr)
{
- return memblock_search(&memblock.memory, addr) != -1;
+ return memblock_search(&memblock.memory, addr, NULL) != -1;
}
int __init_memblock memblock_is_map_memory(phys_addr_t addr)
{
- int i = memblock_search(&memblock.memory, addr);
+ int i = memblock_search(&memblock.memory, addr, NULL);
if (i == -1)
return false;
@@ -1622,7 +1632,7 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
unsigned long *start_pfn, unsigned long *end_pfn)
{
struct memblock_type *type = &memblock.memory;
- int mid = memblock_search(type, PFN_PHYS(pfn));
+ int mid = memblock_search(type, PFN_PHYS(pfn), NULL);
if (mid == -1)
return -1;
@@ -1646,7 +1656,7 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
*/
int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)
{
- int idx = memblock_search(&memblock.memory, base);
+ int idx = memblock_search(&memblock.memory, base, NULL);
phys_addr_t end = base + memblock_cap_size(base, &size);
if (idx == -1)
@@ -1655,6 +1665,38 @@ int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size
memblock.memory.regions[idx].size) >= end;
}
+/**
+ * memblock_get_reserved_pfn_range - search for the next reserved region
+ *
+ * @pfn: start searching from this pfn.
+ *
+ * RETURNS:
+ * [start_pfn, end_pfn), where start_pfn >= pfn. If none is found
+ * start_pfn, and end_pfn are both set to ULONG_MAX.
+ */
+void __init_memblock memblock_get_reserved_pfn_range(unsigned long pfn,
+ unsigned long *start_pfn,
+ unsigned long *end_pfn)
+{
+ struct memblock_type *type = &memblock.reserved;
+ int next_idx, idx;
+
+ idx = memblock_search(type, PFN_PHYS(pfn), &next_idx);
+ if (idx == -1 && next_idx == -1) {
+ *start_pfn = ULONG_MAX;
+ *end_pfn = ULONG_MAX;
+ return;
+ }
+
+ if (idx == -1) {
+ idx = next_idx;
+ *start_pfn = PFN_DOWN(type->regions[idx].base);
+ } else {
+ *start_pfn = pfn;
+ }
+ *end_pfn = PFN_DOWN(type->regions[idx].base + type->regions[idx].size);
+}
+
/**
* memblock_is_region_reserved - check if a region intersects reserved memory
* @base: base of region to check
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 63d16c185736..983de0a8047b 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1447,6 +1447,7 @@ static int __init deferred_init_memmap(void *data)
pg_data_t *pgdat = data;
int nid = pgdat->node_id;
struct mminit_pfnnid_cache nid_init_state = { };
+ unsigned long resv_start_pfn = 0, resv_end_pfn = 0;
unsigned long start = jiffies;
unsigned long nr_pages = 0;
unsigned long walk_start, walk_end;
@@ -1491,6 +1492,10 @@ static int __init deferred_init_memmap(void *data)
pfn = zone->zone_start_pfn;
for (; pfn < end_pfn; pfn++) {
+ if (pfn >= resv_end_pfn)
+ memblock_get_reserved_pfn_range(pfn,
+ &resv_start_pfn,
+ &resv_end_pfn);
if (!pfn_valid_within(pfn))
goto free_range;
@@ -1524,7 +1529,11 @@ static int __init deferred_init_memmap(void *data)
cond_resched();
}
- if (page->flags) {
+ /*
+ * Check if this page has already been initialized due
+ * to being reserved during boot in memblock.
+ */
+ if (pfn >= resv_start_pfn) {
VM_BUG_ON(page_zone(page) != zone);
goto free_range;
}
--
2.14.0
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-08-11 11:40 +0200 |
| Subject | Re: [v6 05/15] mm: don't accessed uninitialized struct pages |
| Message-ID | <udeAa-1Md-23@gated-at.bofh.it> |
| In reply to | #1705855 |
On Mon 07-08-17 16:38:39, Pavel Tatashin wrote:
> In deferred_init_memmap() where all deferred struct pages are initialized
> we have a check like this:
>
> if (page->flags) {
> VM_BUG_ON(page_zone(page) != zone);
> goto free_range;
> }
>
> This way we are checking if the current deferred page has already been
> initialized. It works, because memory for struct pages has been zeroed, and
> the only way flags are not zero if it went through __init_single_page()
> before. But, once we change the current behavior and won't zero the memory
> in memblock allocator, we cannot trust anything inside "struct page"es
> until they are initialized. This patch fixes this.
>
> This patch defines a new accessor memblock_get_reserved_pfn_range()
> which returns successive ranges of reserved PFNs. deferred_init_memmap()
> calls it to determine if a PFN and its struct page has already been
> initialized.
Why don't we simply check the pfn against pgdat->first_deferred_pfn?
> Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
> Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
> Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
> Reviewed-by: Bob Picco <bob.picco@oracle.com>
> ---
> include/linux/memblock.h | 3 +++
> mm/memblock.c | 54 ++++++++++++++++++++++++++++++++++++++++++------
> mm/page_alloc.c | 11 +++++++++-
> 3 files changed, 61 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/memblock.h b/include/linux/memblock.h
> index bae11c7e7bf3..b6a2a610f5e1 100644
> --- a/include/linux/memblock.h
> +++ b/include/linux/memblock.h
> @@ -320,6 +320,9 @@ int memblock_is_map_memory(phys_addr_t addr);
> int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
> bool memblock_is_reserved(phys_addr_t addr);
> bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
> +void memblock_get_reserved_pfn_range(unsigned long pfn,
> + unsigned long *pfn_start,
> + unsigned long *pfn_end);
>
> extern void __memblock_dump_all(void);
>
> diff --git a/mm/memblock.c b/mm/memblock.c
> index bf14aea6ab70..08f449acfdd1 100644
> --- a/mm/memblock.c
> +++ b/mm/memblock.c
> @@ -1580,7 +1580,13 @@ void __init memblock_mem_limit_remove_map(phys_addr_t limit)
> memblock_cap_memory_range(0, max_addr);
> }
>
> -static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
> +/**
> + * Return index in regions array if addr is within the region. Otherwise
> + * return -1. If -1 is returned and *next_idx is not %NULL, sets it to the
> + * next region index or -1 if there is none.
> + */
> +static int __init_memblock memblock_search(struct memblock_type *type,
> + phys_addr_t addr, int *next_idx)
> {
> unsigned int left = 0, right = type->cnt;
>
> @@ -1595,22 +1601,26 @@ static int __init_memblock memblock_search(struct memblock_type *type, phys_addr
> else
> return mid;
> } while (left < right);
> +
> + if (next_idx)
> + *next_idx = (right == type->cnt) ? -1 : right;
> +
> return -1;
> }
>
> bool __init memblock_is_reserved(phys_addr_t addr)
> {
> - return memblock_search(&memblock.reserved, addr) != -1;
> + return memblock_search(&memblock.reserved, addr, NULL) != -1;
> }
>
> bool __init_memblock memblock_is_memory(phys_addr_t addr)
> {
> - return memblock_search(&memblock.memory, addr) != -1;
> + return memblock_search(&memblock.memory, addr, NULL) != -1;
> }
>
> int __init_memblock memblock_is_map_memory(phys_addr_t addr)
> {
> - int i = memblock_search(&memblock.memory, addr);
> + int i = memblock_search(&memblock.memory, addr, NULL);
>
> if (i == -1)
> return false;
> @@ -1622,7 +1632,7 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
> unsigned long *start_pfn, unsigned long *end_pfn)
> {
> struct memblock_type *type = &memblock.memory;
> - int mid = memblock_search(type, PFN_PHYS(pfn));
> + int mid = memblock_search(type, PFN_PHYS(pfn), NULL);
>
> if (mid == -1)
> return -1;
> @@ -1646,7 +1656,7 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
> */
> int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)
> {
> - int idx = memblock_search(&memblock.memory, base);
> + int idx = memblock_search(&memblock.memory, base, NULL);
> phys_addr_t end = base + memblock_cap_size(base, &size);
>
> if (idx == -1)
> @@ -1655,6 +1665,38 @@ int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size
> memblock.memory.regions[idx].size) >= end;
> }
>
> +/**
> + * memblock_get_reserved_pfn_range - search for the next reserved region
> + *
> + * @pfn: start searching from this pfn.
> + *
> + * RETURNS:
> + * [start_pfn, end_pfn), where start_pfn >= pfn. If none is found
> + * start_pfn, and end_pfn are both set to ULONG_MAX.
> + */
> +void __init_memblock memblock_get_reserved_pfn_range(unsigned long pfn,
> + unsigned long *start_pfn,
> + unsigned long *end_pfn)
> +{
> + struct memblock_type *type = &memblock.reserved;
> + int next_idx, idx;
> +
> + idx = memblock_search(type, PFN_PHYS(pfn), &next_idx);
> + if (idx == -1 && next_idx == -1) {
> + *start_pfn = ULONG_MAX;
> + *end_pfn = ULONG_MAX;
> + return;
> + }
> +
> + if (idx == -1) {
> + idx = next_idx;
> + *start_pfn = PFN_DOWN(type->regions[idx].base);
> + } else {
> + *start_pfn = pfn;
> + }
> + *end_pfn = PFN_DOWN(type->regions[idx].base + type->regions[idx].size);
> +}
> +
> /**
> * memblock_is_region_reserved - check if a region intersects reserved memory
> * @base: base of region to check
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 63d16c185736..983de0a8047b 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -1447,6 +1447,7 @@ static int __init deferred_init_memmap(void *data)
> pg_data_t *pgdat = data;
> int nid = pgdat->node_id;
> struct mminit_pfnnid_cache nid_init_state = { };
> + unsigned long resv_start_pfn = 0, resv_end_pfn = 0;
> unsigned long start = jiffies;
> unsigned long nr_pages = 0;
> unsigned long walk_start, walk_end;
> @@ -1491,6 +1492,10 @@ static int __init deferred_init_memmap(void *data)
> pfn = zone->zone_start_pfn;
>
> for (; pfn < end_pfn; pfn++) {
> + if (pfn >= resv_end_pfn)
> + memblock_get_reserved_pfn_range(pfn,
> + &resv_start_pfn,
> + &resv_end_pfn);
> if (!pfn_valid_within(pfn))
> goto free_range;
>
> @@ -1524,7 +1529,11 @@ static int __init deferred_init_memmap(void *data)
> cond_resched();
> }
>
> - if (page->flags) {
> + /*
> + * Check if this page has already been initialized due
> + * to being reserved during boot in memblock.
> + */
> + if (pfn >= resv_start_pfn) {
> VM_BUG_ON(page_zone(page) != zone);
> goto free_range;
> }
> --
> 2.14.0
--
Michal Hocko
SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-11 18:00 +0200 |
| Subject | Re: [v6 05/15] mm: don't accessed uninitialized struct pages |
| Message-ID | <udkvU-5mU-23@gated-at.bofh.it> |
| In reply to | #1709412 |
On 08/11/2017 05:37 AM, Michal Hocko wrote:
> On Mon 07-08-17 16:38:39, Pavel Tatashin wrote:
>> In deferred_init_memmap() where all deferred struct pages are initialized
>> we have a check like this:
>>
>> if (page->flags) {
>> VM_BUG_ON(page_zone(page) != zone);
>> goto free_range;
>> }
>>
>> This way we are checking if the current deferred page has already been
>> initialized. It works, because memory for struct pages has been zeroed, and
>> the only way flags are not zero if it went through __init_single_page()
>> before. But, once we change the current behavior and won't zero the memory
>> in memblock allocator, we cannot trust anything inside "struct page"es
>> until they are initialized. This patch fixes this.
>>
>> This patch defines a new accessor memblock_get_reserved_pfn_range()
>> which returns successive ranges of reserved PFNs. deferred_init_memmap()
>> calls it to determine if a PFN and its struct page has already been
>> initialized.
>
> Why don't we simply check the pfn against pgdat->first_deferred_pfn?
Because we are initializing deferred pages, and all of them have pfn
greater than pgdat->first_deferred_pfn. However, some of deferred pages
were already initialized if they were reserved, in this path:
mem_init()
free_all_bootmem()
free_low_memory_core_early()
for_each_reserved_mem_region()
reserve_bootmem_region()
init_reserved_page() <- if this is deferred reserved page
__init_single_pfn()
__init_single_page()
So, currently, we are using the value of page->flags to figure out if
this page has been initialized while being part of deferred page, but
this is not going to work for this project, as we do not zero the memory
that is backing the struct pages, and size the value of page->flags can
be anything.
[toc] | [prev] | [next] | [standalone]
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-07 22:50 +0200 |
| Subject | [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory |
| Message-ID | <ubX8n-5vB-47@gated-at.bofh.it> |
| In reply to | #1705849 |
To optimize the performance of struct page initialization,
vmemmap_populate() will no longer zero memory.
We must explicitly zero the memory that is allocated by vmemmap_populate()
for kasan, as this memory does not go through struct page initialization
path.
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Reviewed-by: Bob Picco <bob.picco@oracle.com>
---
arch/arm64/mm/kasan_init.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index 81f03959a4ab..e78a9ecbb687 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -135,6 +135,41 @@ static void __init clear_pgds(unsigned long start,
set_pgd(pgd_offset_k(start), __pgd(0));
}
+/*
+ * Memory that was allocated by vmemmap_populate is not zeroed, so we must
+ * zero it here explicitly.
+ */
+static void
+zero_vmemmap_populated_memory(void)
+{
+ struct memblock_region *reg;
+ u64 start, end;
+
+ for_each_memblock(memory, reg) {
+ start = __phys_to_virt(reg->base);
+ end = __phys_to_virt(reg->base + reg->size);
+
+ if (start >= end)
+ break;
+
+ start = (u64)kasan_mem_to_shadow((void *)start);
+ end = (u64)kasan_mem_to_shadow((void *)end);
+
+ /* Round to the start end of the mapped pages */
+ start = round_down(start, SWAPPER_BLOCK_SIZE);
+ end = round_up(end, SWAPPER_BLOCK_SIZE);
+ memset((void *)start, 0, end - start);
+ }
+
+ start = (u64)kasan_mem_to_shadow(_text);
+ end = (u64)kasan_mem_to_shadow(_end);
+
+ /* Round to the start end of the mapped pages */
+ start = round_down(start, SWAPPER_BLOCK_SIZE);
+ end = round_up(end, SWAPPER_BLOCK_SIZE);
+ memset((void *)start, 0, end - start);
+}
+
void __init kasan_init(void)
{
u64 kimg_shadow_start, kimg_shadow_end;
@@ -205,8 +240,15 @@ void __init kasan_init(void)
pfn_pte(sym_to_pfn(kasan_zero_page), PAGE_KERNEL_RO));
memset(kasan_zero_page, 0, PAGE_SIZE);
+
cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
+ /*
+ * vmemmap_populate does not zero the memory, so we need to zero it
+ * explicitly
+ */
+ zero_vmemmap_populated_memory();
+
/* At this point kasan is fully initialized. Enable error messages */
init_task.kasan_depth = 0;
pr_info("KernelAddressSanitizer initialized\n");
--
2.14.0
[toc] | [prev] | [next] | [standalone]
| From | Will Deacon <will.deacon@arm.com> |
|---|---|
| Date | 2017-08-08 11:10 +0200 |
| Subject | Re: [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory |
| Message-ID | <uc8Gt-5Tu-1@gated-at.bofh.it> |
| In reply to | #1705856 |
On Mon, Aug 07, 2017 at 04:38:45PM -0400, Pavel Tatashin wrote:
> To optimize the performance of struct page initialization,
> vmemmap_populate() will no longer zero memory.
>
> We must explicitly zero the memory that is allocated by vmemmap_populate()
> for kasan, as this memory does not go through struct page initialization
> path.
>
> Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
> Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
> Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
> Reviewed-by: Bob Picco <bob.picco@oracle.com>
> ---
> arch/arm64/mm/kasan_init.c | 42 ++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 42 insertions(+)
>
> diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
> index 81f03959a4ab..e78a9ecbb687 100644
> --- a/arch/arm64/mm/kasan_init.c
> +++ b/arch/arm64/mm/kasan_init.c
> @@ -135,6 +135,41 @@ static void __init clear_pgds(unsigned long start,
> set_pgd(pgd_offset_k(start), __pgd(0));
> }
>
> +/*
> + * Memory that was allocated by vmemmap_populate is not zeroed, so we must
> + * zero it here explicitly.
> + */
> +static void
> +zero_vmemmap_populated_memory(void)
> +{
> + struct memblock_region *reg;
> + u64 start, end;
> +
> + for_each_memblock(memory, reg) {
> + start = __phys_to_virt(reg->base);
> + end = __phys_to_virt(reg->base + reg->size);
> +
> + if (start >= end)
> + break;
> +
> + start = (u64)kasan_mem_to_shadow((void *)start);
> + end = (u64)kasan_mem_to_shadow((void *)end);
> +
> + /* Round to the start end of the mapped pages */
> + start = round_down(start, SWAPPER_BLOCK_SIZE);
> + end = round_up(end, SWAPPER_BLOCK_SIZE);
> + memset((void *)start, 0, end - start);
> + }
> +
> + start = (u64)kasan_mem_to_shadow(_text);
> + end = (u64)kasan_mem_to_shadow(_end);
> +
> + /* Round to the start end of the mapped pages */
> + start = round_down(start, SWAPPER_BLOCK_SIZE);
> + end = round_up(end, SWAPPER_BLOCK_SIZE);
> + memset((void *)start, 0, end - start);
> +}
I can't help but think this would be an awful lot nicer if you made
vmemmap_alloc_block take extra GFP flags as a parameter. That way, we could
implement a version of vmemmap_populate that does the zeroing when we need
it, without having to duplicate a bunch of the code like this. I think it
would also be less error-prone, because you wouldn't have to do the
allocation and the zeroing in two separate steps.
Will
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-08-08 14:00 +0200 |
| Subject | Re: [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory |
| Message-ID | <ucbl0-7TS-33@gated-at.bofh.it> |
| In reply to | #1706222 |
Hi Will,
Thank you for looking at this change. What you described was in my
previous iterations of this project.
See for example here: https://lkml.org/lkml/2017/5/5/369
I was asked to remove that flag, and only zero memory in place when
needed. Overall the current approach is better everywhere else in the
kernel, but it adds a little extra code to kasan initialization.
Pasha
On 08/08/2017 05:07 AM, Will Deacon wrote:
> On Mon, Aug 07, 2017 at 04:38:45PM -0400, Pavel Tatashin wrote:
>> To optimize the performance of struct page initialization,
>> vmemmap_populate() will no longer zero memory.
>>
>> We must explicitly zero the memory that is allocated by vmemmap_populate()
>> for kasan, as this memory does not go through struct page initialization
>> path.
>>
>> Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
>> Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
>> Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
>> Reviewed-by: Bob Picco <bob.picco@oracle.com>
>> ---
>> arch/arm64/mm/kasan_init.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 42 insertions(+)
>>
>> diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
>> index 81f03959a4ab..e78a9ecbb687 100644
>> --- a/arch/arm64/mm/kasan_init.c
>> +++ b/arch/arm64/mm/kasan_init.c
>> @@ -135,6 +135,41 @@ static void __init clear_pgds(unsigned long start,
>> set_pgd(pgd_offset_k(start), __pgd(0));
>> }
>>
>> +/*
>> + * Memory that was allocated by vmemmap_populate is not zeroed, so we must
>> + * zero it here explicitly.
>> + */
>> +static void
>> +zero_vmemmap_populated_memory(void)
>> +{
>> + struct memblock_region *reg;
>> + u64 start, end;
>> +
>> + for_each_memblock(memory, reg) {
>> + start = __phys_to_virt(reg->base);
>> + end = __phys_to_virt(reg->base + reg->size);
>> +
>> + if (start >= end)
>> + break;
>> +
>> + start = (u64)kasan_mem_to_shadow((void *)start);
>> + end = (u64)kasan_mem_to_shadow((void *)end);
>> +
>> + /* Round to the start end of the mapped pages */
>> + start = round_down(start, SWAPPER_BLOCK_SIZE);
>> + end = round_up(end, SWAPPER_BLOCK_SIZE);
>> + memset((void *)start, 0, end - start);
>> + }
>> +
>> + start = (u64)kasan_mem_to_shadow(_text);
>> + end = (u64)kasan_mem_to_shadow(_end);
>> +
>> + /* Round to the start end of the mapped pages */
>> + start = round_down(start, SWAPPER_BLOCK_SIZE);
>> + end = round_up(end, SWAPPER_BLOCK_SIZE);
>> + memset((void *)start, 0, end - start);
>> +}
>
> I can't help but think this would be an awful lot nicer if you made
> vmemmap_alloc_block take extra GFP flags as a parameter. That way, we could
> implement a version of vmemmap_populate that does the zeroing when we need
> it, without having to duplicate a bunch of the code like this. I think it
> would also be less error-prone, because you wouldn't have to do the
> allocation and the zeroing in two separate steps.
>
> Will
>
[toc] | [prev] | [next] | [standalone]
| From | Will Deacon <will.deacon@arm.com> |
|---|---|
| Date | 2017-08-08 14:40 +0200 |
| Subject | Re: [v6 11/15] arm64/kasan: explicitly zero kasan shadow memory |
| Message-ID | <ucbXJ-8or-27@gated-at.bofh.it> |
| In reply to | #1706426 |
On Tue, Aug 08, 2017 at 07:49:22AM -0400, Pasha Tatashin wrote: > Hi Will, > > Thank you for looking at this change. What you described was in my previous > iterations of this project. > > See for example here: https://lkml.org/lkml/2017/5/5/369 > > I was asked to remove that flag, and only zero memory in place when needed. > Overall the current approach is better everywhere else in the kernel, but it > adds a little extra code to kasan initialization. Damn, I actually prefer the flag :) But actually, if you look at our implementation of vmemmap_populate, then we have our own version of vmemmap_populate_basepages that terminates at the pmd level anyway if ARM64_SWAPPER_USES_SECTION_MAPS. If there's resistance to do this in the core code, then I'd be inclined to replace our vmemmap_populate implementation in the arm64 code with a single version that can terminate at either the PMD or the PTE level, and do zeroing if required. We're already special-casing it, so we don't really lose anything imo. Will
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web