[RFC PATCH] powerpc/mm: Reduce memory usage for mm_context_t for radix
Christophe Leroy
christophe.leroy at c-s.fr
Wed Apr 3 02:36:17 AEDT 2019
Le 02/04/2019 à 16:34, Aneesh Kumar K.V a écrit :
> Currently, our mm_context_t on book3s64 include all hash specific
> context details like slice mask, subpage protection details. We
> can skip allocating those on radix. This will help us to save
> 8K per mm_context with radix translation.
>
> With the patch applied we have
>
> sizeof(mm_context_t) = 136
> sizeof(struct hash_mm_context) = 8288
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.ibm.com>
> ---
> NOTE:
>
> If we want to do this, I am still trying to figure out how best we can do this
> without all the #ifdef and other overhead for 8xx book3e
Did you have a look at my series
https://patchwork.ozlabs.org/project/linuxppc-dev/list/?series=98170 ?
It tries to reduce as much as feasible the #ifdefs and stuff.
Christophe
>
>
> arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 +-
> arch/powerpc/include/asm/book3s/64/mmu.h | 48 +++++++++++--------
> arch/powerpc/include/asm/book3s/64/slice.h | 6 +--
> arch/powerpc/kernel/paca.c | 9 ++--
> arch/powerpc/kernel/setup-common.c | 7 ++-
> arch/powerpc/mm/hash_utils_64.c | 10 ++--
> arch/powerpc/mm/mmu_context_book3s64.c | 16 ++++++-
> arch/powerpc/mm/slb.c | 2 +-
> arch/powerpc/mm/slice.c | 48 +++++++++----------
> arch/powerpc/mm/subpage-prot.c | 8 ++--
> 10 files changed, 91 insertions(+), 65 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
> index a28a28079edb..d801be977623 100644
> --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
> +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
> @@ -657,7 +657,7 @@ extern void slb_set_size(u16 size);
>
> /* 4 bits per slice and we have one slice per 1TB */
> #define SLICE_ARRAY_SIZE (H_PGTABLE_RANGE >> 41)
> -#define TASK_SLICE_ARRAY_SZ(x) ((x)->context.slb_addr_limit >> 41)
> +#define TASK_SLICE_ARRAY_SZ(x) ((x)->context.hash_context->slb_addr_limit >> 41)
>
> #ifndef __ASSEMBLY__
>
> diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
> index a809bdd77322..07e76e304a3b 100644
> --- a/arch/powerpc/include/asm/book3s/64/mmu.h
> +++ b/arch/powerpc/include/asm/book3s/64/mmu.h
> @@ -114,6 +114,33 @@ struct slice_mask {
> DECLARE_BITMAP(high_slices, SLICE_NUM_HIGH);
> };
>
> +struct hash_mm_context {
> +
> + u16 user_psize; /* page size index */
> +
> +#ifdef CONFIG_PPC_MM_SLICES
> + /* SLB page size encodings*/
> + unsigned char low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE];
> + unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
> + unsigned long slb_addr_limit;
> +#ifdef CONFIG_PPC_64K_PAGES
> + struct slice_mask mask_64k;
> +#endif
> + struct slice_mask mask_4k;
> +#ifdef CONFIG_HUGETLB_PAGE
> + struct slice_mask mask_16m;
> + struct slice_mask mask_16g;
> +#endif
> +#else
> + u16 sllp; /* SLB page size encoding */
> +#endif
> +
> +#ifdef CONFIG_PPC_SUBPAGE_PROT
> + struct subpage_prot_table spt;
> +#endif /* CONFIG_PPC_SUBPAGE_PROT */
> +
> +};
> +
> typedef struct {
> union {
> /*
> @@ -127,7 +154,6 @@ typedef struct {
> mm_context_id_t id;
> mm_context_id_t extended_id[TASK_SIZE_USER64/TASK_CONTEXT_SIZE];
> };
> - u16 user_psize; /* page size index */
>
> /* Number of bits in the mm_cpumask */
> atomic_t active_cpus;
> @@ -137,27 +163,9 @@ typedef struct {
>
> /* NPU NMMU context */
> struct npu_context *npu_context;
> + struct hash_mm_context *hash_context;
>
> -#ifdef CONFIG_PPC_MM_SLICES
> - /* SLB page size encodings*/
> - unsigned char low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE];
> - unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
> - unsigned long slb_addr_limit;
> -# ifdef CONFIG_PPC_64K_PAGES
> - struct slice_mask mask_64k;
> -# endif
> - struct slice_mask mask_4k;
> -# ifdef CONFIG_HUGETLB_PAGE
> - struct slice_mask mask_16m;
> - struct slice_mask mask_16g;
> -# endif
> -#else
> - u16 sllp; /* SLB page size encoding */
> -#endif
> unsigned long vdso_base;
> -#ifdef CONFIG_PPC_SUBPAGE_PROT
> - struct subpage_prot_table spt;
> -#endif /* CONFIG_PPC_SUBPAGE_PROT */
> /*
> * pagetable fragment support
> */
> diff --git a/arch/powerpc/include/asm/book3s/64/slice.h b/arch/powerpc/include/asm/book3s/64/slice.h
> index db0dedab65ee..3ca1bebe258e 100644
> --- a/arch/powerpc/include/asm/book3s/64/slice.h
> +++ b/arch/powerpc/include/asm/book3s/64/slice.h
> @@ -15,11 +15,11 @@
>
> #else /* CONFIG_PPC_MM_SLICES */
>
> -#define get_slice_psize(mm, addr) ((mm)->context.user_psize)
> +#define get_slice_psize(mm, addr) ((mm)->context.hash_context->user_psize)
> #define slice_set_user_psize(mm, psize) \
> do { \
> - (mm)->context.user_psize = (psize); \
> - (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
> + (mm)->context.hash_context->user_psize = (psize); \
> + (mm)->context.hash_context->sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
> } while (0)
>
> #endif /* CONFIG_PPC_MM_SLICES */
> diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
> index e7382abee868..9f1e5d08fa74 100644
> --- a/arch/powerpc/kernel/paca.c
> +++ b/arch/powerpc/kernel/paca.c
> @@ -267,12 +267,13 @@ void copy_mm_to_paca(struct mm_struct *mm)
>
> get_paca()->mm_ctx_id = context->id;
> #ifdef CONFIG_PPC_MM_SLICES
> - VM_BUG_ON(!mm->context.slb_addr_limit);
> - get_paca()->mm_ctx_slb_addr_limit = mm->context.slb_addr_limit;
> + VM_BUG_ON(!mm->context.hash_context->slb_addr_limit);
> + get_paca()->mm_ctx_slb_addr_limit = mm->context.hash_context->slb_addr_limit;
> memcpy(&get_paca()->mm_ctx_low_slices_psize,
> - &context->low_slices_psize, sizeof(context->low_slices_psize));
> + &context->hash_context->low_slices_psize,
> + sizeof(context->hash_context->low_slices_psize));
> memcpy(&get_paca()->mm_ctx_high_slices_psize,
> - &context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm));
> + &context->hash_context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm));
> #else /* CONFIG_PPC_MM_SLICES */
> get_paca()->mm_ctx_user_psize = context->user_psize;
> get_paca()->mm_ctx_sllp = context->sllp;
> diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
> index 2e5dfb6e0823..40290d3d95b0 100644
> --- a/arch/powerpc/kernel/setup-common.c
> +++ b/arch/powerpc/kernel/setup-common.c
> @@ -862,6 +862,7 @@ static void smp_setup_pacas(void)
> }
> #endif
>
> +struct hash_mm_context init_hash_mm_context;
> /*
> * Called into from start_kernel this initializes memblock, which is used
> * to manage page allocation until mem_init is called.
> @@ -949,8 +950,10 @@ void __init setup_arch(char **cmdline_p)
>
> #ifdef CONFIG_PPC_MM_SLICES
> #ifdef CONFIG_PPC64
> - if (!radix_enabled())
> - init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> + if (!radix_enabled()) {
> + init_mm.context.hash_context = &init_hash_mm_context;
> + init_mm.context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> + }
> #elif defined(CONFIG_PPC_8xx)
> init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW;
> #else
> diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
> index 0a4f939a8161..df035c3ebb4b 100644
> --- a/arch/powerpc/mm/hash_utils_64.c
> +++ b/arch/powerpc/mm/hash_utils_64.c
> @@ -1147,7 +1147,7 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
> */
> static int subpage_protection(struct mm_struct *mm, unsigned long ea)
> {
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> u32 spp = 0;
> u32 **sbpm, *sbpp;
>
> @@ -1470,7 +1470,7 @@ static bool should_hash_preload(struct mm_struct *mm, unsigned long ea)
> int psize = get_slice_psize(mm, ea);
>
> /* We only prefault standard pages for now */
> - if (unlikely(psize != mm->context.user_psize))
> + if (unlikely(psize != mm->context.hash_context->user_psize))
> return false;
>
> /*
> @@ -1549,7 +1549,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
>
> /* Hash it in */
> #ifdef CONFIG_PPC_64K_PAGES
> - if (mm->context.user_psize == MMU_PAGE_64K)
> + if (mm->context.hash_context->user_psize == MMU_PAGE_64K)
> rc = __hash_page_64K(ea, access, vsid, ptep, trap,
> update_flags, ssize);
> else
> @@ -1562,8 +1562,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
> */
> if (rc == -1)
> hash_failure_debug(ea, access, vsid, trap, ssize,
> - mm->context.user_psize,
> - mm->context.user_psize,
> + mm->context.hash_context->user_psize,
> + mm->context.hash_context->user_psize,
> pte_val(*ptep));
> out_exit:
> local_irq_restore(flags);
> diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c
> index f720c5cc0b5e..6eef5a36b2e9 100644
> --- a/arch/powerpc/mm/mmu_context_book3s64.c
> +++ b/arch/powerpc/mm/mmu_context_book3s64.c
> @@ -63,6 +63,12 @@ static int hash__init_new_context(struct mm_struct *mm)
> if (index < 0)
> return index;
>
> + mm->context.hash_context = kmalloc(sizeof(struct hash_mm_context), GFP_KERNEL);
> + if (!mm->context.hash_context) {
> + ida_free(&mmu_context_ida, index);
> + return -ENOMEM;
> + }
> +
> /*
> * The old code would re-promote on fork, we don't do that when using
> * slices as it could cause problem promoting slices that have been
> @@ -77,8 +83,14 @@ static int hash__init_new_context(struct mm_struct *mm)
> * We should not be calling init_new_context() on init_mm. Hence a
> * check against 0 is OK.
> */
> - if (mm->context.id == 0)
> + if (mm->context.id == 0) {
> + memset(mm->context.hash_context, 0, sizeof(struct hash_mm_context));
> slice_init_new_context_exec(mm);
> + } else {
> + /* This is fork. Copy hash_context details from current->mm */
> + memcpy(mm->context.hash_context, current->mm->context.hash_context, sizeof(struct hash_mm_context));
> +
> + }
>
> subpage_prot_init_new_context(mm);
>
> @@ -118,6 +130,7 @@ static int radix__init_new_context(struct mm_struct *mm)
> asm volatile("ptesync;isync" : : : "memory");
>
> mm->context.npu_context = NULL;
> + mm->context.hash_context = NULL;
>
> return index;
> }
> @@ -162,6 +175,7 @@ static void destroy_contexts(mm_context_t *ctx)
> if (context_id)
> ida_free(&mmu_context_ida, context_id);
> }
> + kfree(ctx->hash_context);
> }
>
> static void pmd_frag_destroy(void *pmd_frag)
> diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
> index 5986df48359b..2b128939e2e7 100644
> --- a/arch/powerpc/mm/slb.c
> +++ b/arch/powerpc/mm/slb.c
> @@ -739,7 +739,7 @@ static long slb_allocate_user(struct mm_struct *mm, unsigned long ea)
> * consider this as bad access if we take a SLB miss
> * on an address above addr limit.
> */
> - if (ea >= mm->context.slb_addr_limit)
> + if (ea >= mm->context.hash_context->slb_addr_limit)
> return -EFAULT;
>
> context = get_user_context(&mm->context, ea);
> diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
> index aec91dbcdc0b..84b200429464 100644
> --- a/arch/powerpc/mm/slice.c
> +++ b/arch/powerpc/mm/slice.c
> @@ -101,7 +101,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
> {
> struct vm_area_struct *vma;
>
> - if ((mm->context.slb_addr_limit - len) < addr)
> + if ((mm->context.hash_context->slb_addr_limit - len) < addr)
> return 0;
> vma = find_vma(mm, addr);
> return (!vma || (addr + len) <= vm_start_gap(vma));
> @@ -155,15 +155,15 @@ static struct slice_mask *slice_mask_for_size(struct mm_struct *mm, int psize)
> {
> #ifdef CONFIG_PPC_64K_PAGES
> if (psize == MMU_PAGE_64K)
> - return &mm->context.mask_64k;
> + return &mm->context.hash_context->mask_64k;
> #endif
> if (psize == MMU_PAGE_4K)
> - return &mm->context.mask_4k;
> + return &mm->context.hash_context->mask_4k;
> #ifdef CONFIG_HUGETLB_PAGE
> if (psize == MMU_PAGE_16M)
> - return &mm->context.mask_16m;
> + return &mm->context.hash_context->mask_16m;
> if (psize == MMU_PAGE_16G)
> - return &mm->context.mask_16g;
> + return &mm->context.hash_context->mask_16g;
> #endif
> BUG();
> }
> @@ -253,7 +253,7 @@ static void slice_convert(struct mm_struct *mm,
> */
> spin_lock_irqsave(&slice_convert_lock, flags);
>
> - lpsizes = mm->context.low_slices_psize;
> + lpsizes = mm->context.hash_context->low_slices_psize;
> for (i = 0; i < SLICE_NUM_LOW; i++) {
> if (!(mask->low_slices & (1u << i)))
> continue;
> @@ -272,8 +272,8 @@ static void slice_convert(struct mm_struct *mm,
> (((unsigned long)psize) << (mask_index * 4));
> }
>
> - hpsizes = mm->context.high_slices_psize;
> - for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.slb_addr_limit); i++) {
> + hpsizes = mm->context.hash_context->high_slices_psize;
> + for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.hash_context->slb_addr_limit); i++) {
> if (!test_bit(i, mask->high_slices))
> continue;
>
> @@ -292,8 +292,8 @@ static void slice_convert(struct mm_struct *mm,
> }
>
> slice_dbg(" lsps=%lx, hsps=%lx\n",
> - (unsigned long)mm->context.low_slices_psize,
> - (unsigned long)mm->context.high_slices_psize);
> + (unsigned long)mm->context.hash_context->low_slices_psize,
> + (unsigned long)mm->context.hash_context->high_slices_psize);
>
> spin_unlock_irqrestore(&slice_convert_lock, flags);
>
> @@ -393,7 +393,7 @@ static unsigned long slice_find_area_topdown(struct mm_struct *mm,
> * DEFAULT_MAP_WINDOW we should apply this.
> */
> if (high_limit > DEFAULT_MAP_WINDOW)
> - addr += mm->context.slb_addr_limit - DEFAULT_MAP_WINDOW;
> + addr += mm->context.hash_context->slb_addr_limit - DEFAULT_MAP_WINDOW;
>
> while (addr > min_addr) {
> info.high_limit = addr;
> @@ -505,20 +505,20 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
> return -ENOMEM;
> }
>
> - if (high_limit > mm->context.slb_addr_limit) {
> + if (high_limit > mm->context.hash_context->slb_addr_limit) {
> /*
> * Increasing the slb_addr_limit does not require
> * slice mask cache to be recalculated because it should
> * be already initialised beyond the old address limit.
> */
> - mm->context.slb_addr_limit = high_limit;
> + mm->context.hash_context->slb_addr_limit = high_limit;
>
> on_each_cpu(slice_flush_segments, mm, 1);
> }
>
> /* Sanity checks */
> BUG_ON(mm->task_size == 0);
> - BUG_ON(mm->context.slb_addr_limit == 0);
> + BUG_ON(mm->context.hash_context->slb_addr_limit == 0);
> VM_BUG_ON(radix_enabled());
>
> slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize);
> @@ -696,7 +696,7 @@ unsigned long arch_get_unmapped_area(struct file *filp,
> unsigned long flags)
> {
> return slice_get_unmapped_area(addr, len, flags,
> - current->mm->context.user_psize, 0);
> + current->mm->context.hash_context->user_psize, 0);
> }
>
> unsigned long arch_get_unmapped_area_topdown(struct file *filp,
> @@ -706,7 +706,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp,
> const unsigned long flags)
> {
> return slice_get_unmapped_area(addr0, len, flags,
> - current->mm->context.user_psize, 1);
> + current->mm->context.hash_context->user_psize, 1);
> }
>
> unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
> @@ -717,10 +717,10 @@ unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
> VM_BUG_ON(radix_enabled());
>
> if (slice_addr_is_low(addr)) {
> - psizes = mm->context.low_slices_psize;
> + psizes = mm->context.hash_context->low_slices_psize;
> index = GET_LOW_SLICE_INDEX(addr);
> } else {
> - psizes = mm->context.high_slices_psize;
> + psizes = mm->context.hash_context->high_slices_psize;
> index = GET_HIGH_SLICE_INDEX(addr);
> }
> mask_index = index & 0x1;
> @@ -742,20 +742,20 @@ void slice_init_new_context_exec(struct mm_struct *mm)
> * duplicated.
> */
> #ifdef CONFIG_PPC64
> - mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> + mm->context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> #else
> mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
> #endif
>
> - mm->context.user_psize = psize;
> + mm->context.hash_context->user_psize = psize;
>
> /*
> * Set all slice psizes to the default.
> */
> - lpsizes = mm->context.low_slices_psize;
> + lpsizes = mm->context.hash_context->low_slices_psize;
> memset(lpsizes, (psize << 4) | psize, SLICE_NUM_LOW >> 1);
>
> - hpsizes = mm->context.high_slices_psize;
> + hpsizes = mm->context.hash_context->high_slices_psize;
> memset(hpsizes, (psize << 4) | psize, SLICE_NUM_HIGH >> 1);
>
> /*
> @@ -777,7 +777,7 @@ void slice_setup_new_exec(void)
> if (!is_32bit_task())
> return;
>
> - mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
> + mm->context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW;
> }
> #endif
>
> @@ -816,7 +816,7 @@ int slice_is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
> unsigned long len)
> {
> const struct slice_mask *maskp;
> - unsigned int psize = mm->context.user_psize;
> + unsigned int psize = mm->context.hash_context->user_psize;
>
> VM_BUG_ON(radix_enabled());
>
> diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
> index 5e4178790dee..3a13cbcb6f97 100644
> --- a/arch/powerpc/mm/subpage-prot.c
> +++ b/arch/powerpc/mm/subpage-prot.c
> @@ -25,7 +25,7 @@
> */
> void subpage_prot_free(struct mm_struct *mm)
> {
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> unsigned long i, j, addr;
> u32 **p;
>
> @@ -52,7 +52,7 @@ void subpage_prot_free(struct mm_struct *mm)
>
> void subpage_prot_init_new_context(struct mm_struct *mm)
> {
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
>
> memset(spt, 0, sizeof(*spt));
> }
> @@ -93,7 +93,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
> static void subpage_prot_clear(unsigned long addr, unsigned long len)
> {
> struct mm_struct *mm = current->mm;
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> u32 **spm, *spp;
> unsigned long i;
> size_t nw;
> @@ -189,7 +189,7 @@ SYSCALL_DEFINE3(subpage_prot, unsigned long, addr,
> unsigned long, len, u32 __user *, map)
> {
> struct mm_struct *mm = current->mm;
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> u32 **spm, *spp;
> unsigned long i;
> size_t nw;
>
More information about the Linuxppc-dev
mailing list