arm64: Align less than PAGE_SIZE pgds naturally

When the pgd size is smaller than PAGE_SIZE, pgd_alloc() uses kzalloc()
to save space. However, this is not always naturally aligned as required
by the architecture. This patch creates a kmem_cache for pgd allocations
with the correct alignment.

The current kernel configurations with 4K pages + 39-bit VA and 64K
pages + 42-bit VA use a full page for the pgd and are not affected. The
patch is required for 48-bit VA with 64K pages where the pgd is 512
bytes.

Reported-by: Christoffer Dall <christoffer.dall@linaro.org>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

+16 -2
+16 -2
arch/arm64/mm/pgd.c
··· 30 30 31 31 #define PGD_SIZE (PTRS_PER_PGD * sizeof(pgd_t)) 32 32 33 + static struct kmem_cache *pgd_cache; 34 + 33 35 pgd_t *pgd_alloc(struct mm_struct *mm) 34 36 { 35 37 if (PGD_SIZE == PAGE_SIZE) 36 38 return (pgd_t *)get_zeroed_page(GFP_KERNEL); 37 39 else 38 - return kzalloc(PGD_SIZE, GFP_KERNEL); 40 + return kmem_cache_zalloc(pgd_cache, GFP_KERNEL); 39 41 } 40 42 41 43 void pgd_free(struct mm_struct *mm, pgd_t *pgd) ··· 45 43 if (PGD_SIZE == PAGE_SIZE) 46 44 free_page((unsigned long)pgd); 47 45 else 48 - kfree(pgd); 46 + kmem_cache_free(pgd_cache, pgd); 49 47 } 48 + 49 + static int __init pgd_cache_init(void) 50 + { 51 + /* 52 + * Naturally aligned pgds required by the architecture. 53 + */ 54 + if (PGD_SIZE != PAGE_SIZE) 55 + pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE, 56 + SLAB_PANIC, NULL); 57 + return 0; 58 + } 59 + core_initcall(pgd_cache_init);