| Subject: highmem: Store ptes right away in the task struct |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Tue, 12 Feb 2013 11:32:38 +0100 |
| |
| Get rid of the per cpu variable and store the idx and the pte content |
| right away in the task struct. Shortens the context switch code. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| --- |
| arch/x86/kernel/process_32.c | 63 +++++++++++++++++++------------------------ |
| arch/x86/mm/highmem_32.c | 6 +++- |
| arch/x86/mm/iomap_32.c | 6 +++- |
| include/linux/highmem.h | 25 ++++++++++++++--- |
| mm/highmem.c | 6 ++-- |
| 5 files changed, 64 insertions(+), 42 deletions(-) |
| |
| Index: linux-stable/arch/x86/kernel/process_32.c |
| =================================================================== |
| --- linux-stable.orig/arch/x86/kernel/process_32.c |
| +++ linux-stable/arch/x86/kernel/process_32.c |
| @@ -198,6 +198,34 @@ start_thread(struct pt_regs *regs, unsig |
| } |
| EXPORT_SYMBOL_GPL(start_thread); |
| |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| +static void switch_kmaps(struct task_struct *prev_p, struct task_struct *next_p) |
| +{ |
| + int i; |
| + |
| + /* |
| + * Clear @prev's kmap_atomic mappings |
| + */ |
| + for (i = 0; i < prev_p->kmap_idx; i++) { |
| + int idx = i + KM_TYPE_NR * smp_processor_id(); |
| + pte_t *ptep = kmap_pte - idx; |
| + |
| + kpte_clear_flush(ptep, __fix_to_virt(FIX_KMAP_BEGIN + idx)); |
| + } |
| + /* |
| + * Restore @next_p's kmap_atomic mappings |
| + */ |
| + for (i = 0; i < next_p->kmap_idx; i++) { |
| + int idx = i + KM_TYPE_NR * smp_processor_id(); |
| + |
| + set_pte(kmap_pte - idx, next_p->kmap_pte[i]); |
| + } |
| +} |
| +#else |
| +static inline void |
| +switch_kmaps(struct task_struct *prev_p, struct task_struct *next_p) { } |
| +#endif |
| + |
| |
| /* |
| * switch_to(x,y) should switch tasks from x to y. |
| @@ -277,40 +305,7 @@ __switch_to(struct task_struct *prev_p, |
| task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT)) |
| __switch_to_xtra(prev_p, next_p, tss); |
| |
| -#ifdef CONFIG_PREEMPT_RT_FULL |
| - /* |
| - * Save @prev's kmap_atomic stack |
| - */ |
| - prev_p->kmap_idx = __this_cpu_read(__kmap_atomic_idx); |
| - if (unlikely(prev_p->kmap_idx)) { |
| - int i; |
| - |
| - for (i = 0; i < prev_p->kmap_idx; i++) { |
| - int idx = i + KM_TYPE_NR * smp_processor_id(); |
| - |
| - pte_t *ptep = kmap_pte - idx; |
| - prev_p->kmap_pte[i] = *ptep; |
| - kpte_clear_flush(ptep, __fix_to_virt(FIX_KMAP_BEGIN + idx)); |
| - } |
| - |
| - __this_cpu_write(__kmap_atomic_idx, 0); |
| - } |
| - |
| - /* |
| - * Restore @next_p's kmap_atomic stack |
| - */ |
| - if (unlikely(next_p->kmap_idx)) { |
| - int i; |
| - |
| - __this_cpu_write(__kmap_atomic_idx, next_p->kmap_idx); |
| - |
| - for (i = 0; i < next_p->kmap_idx; i++) { |
| - int idx = i + KM_TYPE_NR * smp_processor_id(); |
| - |
| - set_pte(kmap_pte - idx, next_p->kmap_pte[i]); |
| - } |
| - } |
| -#endif |
| + switch_kmaps(prev_p, next_p); |
| |
| /* |
| * Leave lazy mode, flushing any hypercalls made here. |
| Index: linux-stable/arch/x86/mm/highmem_32.c |
| =================================================================== |
| --- linux-stable.orig/arch/x86/mm/highmem_32.c |
| +++ linux-stable/arch/x86/mm/highmem_32.c |
| @@ -31,6 +31,7 @@ EXPORT_SYMBOL(kunmap); |
| */ |
| void *kmap_atomic_prot(struct page *page, pgprot_t prot) |
| { |
| + pte_t pte = mk_pte(page, prot); |
| unsigned long vaddr; |
| int idx, type; |
| |
| @@ -44,7 +45,10 @@ void *kmap_atomic_prot(struct page *page |
| idx = type + KM_TYPE_NR*smp_processor_id(); |
| vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); |
| WARN_ON(!pte_none(*(kmap_pte-idx))); |
| - set_pte(kmap_pte-idx, mk_pte(page, prot)); |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| + current->kmap_pte[type] = pte; |
| +#endif |
| + set_pte(kmap_pte-idx, pte); |
| arch_flush_lazy_mmu_mode(); |
| |
| return (void *)vaddr; |
| Index: linux-stable/arch/x86/mm/iomap_32.c |
| =================================================================== |
| --- linux-stable.orig/arch/x86/mm/iomap_32.c |
| +++ linux-stable/arch/x86/mm/iomap_32.c |
| @@ -56,6 +56,7 @@ EXPORT_SYMBOL_GPL(iomap_free); |
| |
| void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot) |
| { |
| + pte_t pte = pfn_pte(pfn, prot); |
| unsigned long vaddr; |
| int idx, type; |
| |
| @@ -64,7 +65,10 @@ void *kmap_atomic_prot_pfn(unsigned long |
| type = kmap_atomic_idx_push(); |
| idx = type + KM_TYPE_NR * smp_processor_id(); |
| vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); |
| - set_pte(kmap_pte - idx, pfn_pte(pfn, prot)); |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| + current->kmap_pte[type] = pte; |
| +#endif |
| + set_pte(kmap_pte - idx, pte); |
| arch_flush_lazy_mmu_mode(); |
| |
| return (void *)vaddr; |
| Index: linux-stable/include/linux/highmem.h |
| =================================================================== |
| --- linux-stable.orig/include/linux/highmem.h |
| +++ linux-stable/include/linux/highmem.h |
| @@ -85,32 +85,49 @@ static inline void __kunmap_atomic(void |
| |
| #if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) |
| |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| DECLARE_PER_CPU(int, __kmap_atomic_idx); |
| +#endif |
| |
| static inline int kmap_atomic_idx_push(void) |
| { |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| int idx = __this_cpu_inc_return(__kmap_atomic_idx) - 1; |
| |
| -#ifdef CONFIG_DEBUG_HIGHMEM |
| +# ifdef CONFIG_DEBUG_HIGHMEM |
| WARN_ON_ONCE(in_irq() && !irqs_disabled()); |
| BUG_ON(idx > KM_TYPE_NR); |
| -#endif |
| +# endif |
| return idx; |
| +#else |
| + return current->kmap_idx++; |
| +#endif |
| } |
| |
| static inline int kmap_atomic_idx(void) |
| { |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| return __this_cpu_read(__kmap_atomic_idx) - 1; |
| +#else |
| + return current->kmap_idx - 1; |
| +#endif |
| } |
| |
| static inline void kmap_atomic_idx_pop(void) |
| { |
| -#ifdef CONFIG_DEBUG_HIGHMEM |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| +# ifdef CONFIG_DEBUG_HIGHMEM |
| int idx = __this_cpu_dec_return(__kmap_atomic_idx); |
| |
| BUG_ON(idx < 0); |
| -#else |
| +# else |
| __this_cpu_dec(__kmap_atomic_idx); |
| +# endif |
| +#else |
| + current->kmap_idx--; |
| +# ifdef CONFIG_DEBUG_HIGHMEM |
| + BUG_ON(current->kmap_idx < 0); |
| +# endif |
| #endif |
| } |
| |
| Index: linux-stable/mm/highmem.c |
| =================================================================== |
| --- linux-stable.orig/mm/highmem.c |
| +++ linux-stable/mm/highmem.c |
| @@ -29,10 +29,11 @@ |
| #include <linux/kgdb.h> |
| #include <asm/tlbflush.h> |
| |
| - |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| #if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) |
| DEFINE_PER_CPU(int, __kmap_atomic_idx); |
| #endif |
| +#endif |
| |
| /* |
| * Virtual_count is not a pure "count". |
| @@ -47,8 +48,9 @@ DEFINE_PER_CPU(int, __kmap_atomic_idx); |
| unsigned long totalhigh_pages __read_mostly; |
| EXPORT_SYMBOL(totalhigh_pages); |
| |
| - |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| EXPORT_PER_CPU_SYMBOL(__kmap_atomic_idx); |
| +#endif |
| |
| unsigned int nr_free_highpages (void) |
| { |