Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arc/mm/highmem: Use generic kmap atomic implementation

Adopt the map ordering to match the other architectures and the generic
code. Also make the maximum entries limited and not dependend on the number
of CPUs. With the original implementation did the following calculation:

nr_slots = mapsize >> PAGE_SHIFT;

The results in either 512 or 1024 total slots depending on
configuration. The total slots have to be divided by the number of CPUs to
get the number of slots per CPU (former KM_TYPE_NR). ARC supports up to 4k
CPUs, so this just falls apart in random ways depending on the number of
CPUs and the actual kmap (atomic) nesting. The comment in highmem.c:

* - fixmap anyhow needs a limited number of mappings. So 2M kvaddr == 256 PTE
* slots across NR_CPUS would be more than sufficient (generic code defines
* KM_TYPE_NR as 20).

is just wrong. KM_TYPE_NR (now KM_MAX_IDX) is the number of slots per CPU
because kmap_local/atomic() needs to support nested mappings (thread,
softirq, interrupt). While KM_MAX_IDX might be overestimated, the above
reasoning is just wrong and clearly the highmem code was never tested with
any system with more than a few CPUs.

Use the default number of slots and fail the build when it does not
fit. Randomly failing at runtime is not a really good option.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Vineet Gupta <vgupta@synopsys.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Link: https://lore.kernel.org/r/20201103095857.472289952@linutronix.de

+27 -70
+1
arch/arc/Kconfig
··· 507 507 config HIGHMEM 508 508 bool "High Memory Support" 509 509 select ARCH_DISCONTIGMEM_ENABLE 510 + select KMAP_LOCAL 510 511 help 511 512 With ARC 2G:2G address split, only upper 2G is directly addressable by 512 513 kernel. Enable this to potentially allow access to rest of 2G and PAE
+20 -6
arch/arc/include/asm/highmem.h
··· 9 9 #ifdef CONFIG_HIGHMEM 10 10 11 11 #include <uapi/asm/page.h> 12 - #include <asm/kmap_types.h> 12 + #include <asm/kmap_size.h> 13 + 14 + #define FIXMAP_SIZE PGDIR_SIZE 15 + #define PKMAP_SIZE PGDIR_SIZE 13 16 14 17 /* start after vmalloc area */ 15 18 #define FIXMAP_BASE (PAGE_OFFSET - FIXMAP_SIZE - PKMAP_SIZE) 16 - #define FIXMAP_SIZE PGDIR_SIZE /* only 1 PGD worth */ 17 - #define KM_TYPE_NR ((FIXMAP_SIZE >> PAGE_SHIFT)/NR_CPUS) 18 - #define FIXMAP_ADDR(nr) (FIXMAP_BASE + ((nr) << PAGE_SHIFT)) 19 + 20 + #define FIX_KMAP_SLOTS (KM_MAX_IDX * NR_CPUS) 21 + #define FIX_KMAP_BEGIN (0UL) 22 + #define FIX_KMAP_END ((FIX_KMAP_BEGIN + FIX_KMAP_SLOTS) - 1) 23 + 24 + #define FIXADDR_TOP (FIXMAP_BASE + (FIX_KMAP_END << PAGE_SHIFT)) 25 + 26 + /* 27 + * This should be converted to the asm-generic version, but of course this 28 + * is needlessly different from all other architectures. Sigh - tglx 29 + */ 30 + #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) 31 + #define __virt_to_fix(x) (((FIXADDR_TOP - ((x) & PAGE_MASK))) >> PAGE_SHIFT) 19 32 20 33 /* start after fixmap area */ 21 34 #define PKMAP_BASE (FIXMAP_BASE + FIXMAP_SIZE) 22 - #define PKMAP_SIZE PGDIR_SIZE 23 35 #define LAST_PKMAP (PKMAP_SIZE >> PAGE_SHIFT) 24 36 #define LAST_PKMAP_MASK (LAST_PKMAP - 1) 25 37 #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) ··· 41 29 42 30 extern void kmap_init(void); 43 31 32 + #define arch_kmap_local_post_unmap(vaddr) \ 33 + local_flush_tlb_kernel_range(vaddr, vaddr + PAGE_SIZE) 34 + 44 35 static inline void flush_cache_kmaps(void) 45 36 { 46 37 flush_cache_all(); 47 38 } 48 - 49 39 #endif 50 40 51 41 #endif
-14
arch/arc/include/asm/kmap_types.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-only */ 2 - /* 3 - * Copyright (C) 2015 Synopsys, Inc. (www.synopsys.com) 4 - */ 5 - 6 - #ifndef _ASM_KMAP_TYPES_H 7 - #define _ASM_KMAP_TYPES_H 8 - 9 - /* 10 - * We primarily need to define KM_TYPE_NR here but that in turn 11 - * is a function of PGDIR_SIZE etc. 12 - * To avoid circular deps issue, put everything in asm/highmem.h 13 - */ 14 - #endif
+6 -50
arch/arc/mm/highmem.c
··· 36 36 * This means each only has 1 PGDIR_SIZE worth of kvaddr mappings, which means 37 37 * 2M of kvaddr space for typical config (8K page and 11:8:13 traversal split) 38 38 * 39 - * - fixmap anyhow needs a limited number of mappings. So 2M kvaddr == 256 PTE 40 - * slots across NR_CPUS would be more than sufficient (generic code defines 41 - * KM_TYPE_NR as 20). 39 + * - The fixed KMAP slots for kmap_local/atomic() require KM_MAX_IDX slots per 40 + * CPU. So the number of CPUs sharing a single PTE page is limited. 42 41 * 43 42 * - pkmap being preemptible, in theory could do with more than 256 concurrent 44 43 * mappings. However, generic pkmap code: map_new_virtual(), doesn't traverse ··· 46 47 */ 47 48 48 49 extern pte_t * pkmap_page_table; 49 - static pte_t * fixmap_page_table; 50 - 51 - void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) 52 - { 53 - int idx, cpu_idx; 54 - unsigned long vaddr; 55 - 56 - cpu_idx = kmap_atomic_idx_push(); 57 - idx = cpu_idx + KM_TYPE_NR * smp_processor_id(); 58 - vaddr = FIXMAP_ADDR(idx); 59 - 60 - set_pte_at(&init_mm, vaddr, fixmap_page_table + idx, 61 - mk_pte(page, prot)); 62 - 63 - return (void *)vaddr; 64 - } 65 - EXPORT_SYMBOL(kmap_atomic_high_prot); 66 - 67 - void kunmap_atomic_high(void *kv) 68 - { 69 - unsigned long kvaddr = (unsigned long)kv; 70 - 71 - if (kvaddr >= FIXMAP_BASE && kvaddr < (FIXMAP_BASE + FIXMAP_SIZE)) { 72 - 73 - /* 74 - * Because preemption is disabled, this vaddr can be associated 75 - * with the current allocated index. 76 - * But in case of multiple live kmap_atomic(), it still relies on 77 - * callers to unmap in right order. 78 - */ 79 - int cpu_idx = kmap_atomic_idx(); 80 - int idx = cpu_idx + KM_TYPE_NR * smp_processor_id(); 81 - 82 - WARN_ON(kvaddr != FIXMAP_ADDR(idx)); 83 - 84 - pte_clear(&init_mm, kvaddr, fixmap_page_table + idx); 85 - local_flush_tlb_kernel_range(kvaddr, kvaddr + PAGE_SIZE); 86 - 87 - kmap_atomic_idx_pop(); 88 - } 89 - } 90 - EXPORT_SYMBOL(kunmap_atomic_high); 91 50 92 51 static noinline pte_t * __init alloc_kmap_pgtable(unsigned long kvaddr) 93 52 { ··· 65 108 { 66 109 /* Due to recursive include hell, we can't do this in processor.h */ 67 110 BUILD_BUG_ON(PAGE_OFFSET < (VMALLOC_END + FIXMAP_SIZE + PKMAP_SIZE)); 68 - 69 - BUILD_BUG_ON(KM_TYPE_NR > PTRS_PER_PTE); 70 - pkmap_page_table = alloc_kmap_pgtable(PKMAP_BASE); 71 - 72 111 BUILD_BUG_ON(LAST_PKMAP > PTRS_PER_PTE); 73 - fixmap_page_table = alloc_kmap_pgtable(FIXMAP_BASE); 112 + BUILD_BUG_ON(FIX_KMAP_SLOTS > PTRS_PER_PTE); 113 + 114 + pkmap_page_table = alloc_kmap_pgtable(PKMAP_BASE); 115 + alloc_kmap_pgtable(FIXMAP_BASE); 74 116 }