diff options
58 files changed, 895 insertions, 1284 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 4a7f14079e03..ff2d2371b2e9 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
| @@ -230,17 +230,6 @@ config SYSVIPC_COMPAT | |||
| 230 | config AUDIT_ARCH | 230 | config AUDIT_ARCH |
| 231 | def_bool y | 231 | def_bool y |
| 232 | 232 | ||
| 233 | config S390_EXEC_PROTECT | ||
| 234 | def_bool y | ||
| 235 | prompt "Data execute protection" | ||
| 236 | help | ||
| 237 | This option allows to enable a buffer overflow protection for user | ||
| 238 | space programs and it also selects the addressing mode option above. | ||
| 239 | The kernel parameter noexec=on will enable this feature and also | ||
| 240 | switch the addressing modes, default is disabled. Enabling this (via | ||
| 241 | kernel parameter) on machines earlier than IBM System z9 this will | ||
| 242 | reduce system performance. | ||
| 243 | |||
| 244 | comment "Code generation options" | 233 | comment "Code generation options" |
| 245 | 234 | ||
| 246 | choice | 235 | choice |
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 5c91995b74e4..24bff4f1cc52 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c | |||
| @@ -130,9 +130,7 @@ static void appldata_work_fn(struct work_struct *work) | |||
| 130 | { | 130 | { |
| 131 | struct list_head *lh; | 131 | struct list_head *lh; |
| 132 | struct appldata_ops *ops; | 132 | struct appldata_ops *ops; |
| 133 | int i; | ||
| 134 | 133 | ||
| 135 | i = 0; | ||
| 136 | get_online_cpus(); | 134 | get_online_cpus(); |
| 137 | mutex_lock(&appldata_ops_mutex); | 135 | mutex_lock(&appldata_ops_mutex); |
| 138 | list_for_each(lh, &appldata_ops_list) { | 136 | list_for_each(lh, &appldata_ops_list) { |
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index 7488e52efa97..81d7908416cf 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h | |||
| @@ -167,7 +167,6 @@ static inline unsigned long __cmpxchg(void *ptr, unsigned long old, | |||
| 167 | #ifdef CONFIG_64BIT | 167 | #ifdef CONFIG_64BIT |
| 168 | #define cmpxchg64(ptr, o, n) \ | 168 | #define cmpxchg64(ptr, o, n) \ |
| 169 | ({ \ | 169 | ({ \ |
| 170 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | ||
| 171 | cmpxchg((ptr), (o), (n)); \ | 170 | cmpxchg((ptr), (o), (n)); \ |
| 172 | }) | 171 | }) |
| 173 | #else /* CONFIG_64BIT */ | 172 | #else /* CONFIG_64BIT */ |
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 10c029cfcc7d..64b61bf72e93 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h | |||
| @@ -196,18 +196,6 @@ do { \ | |||
| 196 | } while (0) | 196 | } while (0) |
| 197 | #endif /* __s390x__ */ | 197 | #endif /* __s390x__ */ |
| 198 | 198 | ||
| 199 | /* | ||
| 200 | * An executable for which elf_read_implies_exec() returns TRUE will | ||
| 201 | * have the READ_IMPLIES_EXEC personality flag set automatically. | ||
| 202 | */ | ||
| 203 | #define elf_read_implies_exec(ex, executable_stack) \ | ||
| 204 | ({ \ | ||
| 205 | if (current->mm->context.noexec && \ | ||
| 206 | executable_stack != EXSTACK_DISABLE_X) \ | ||
| 207 | disable_noexec(current->mm, current); \ | ||
| 208 | current->mm->context.noexec == 0; \ | ||
| 209 | }) | ||
| 210 | |||
| 211 | #define STACK_RND_MASK 0x7ffUL | 199 | #define STACK_RND_MASK 0x7ffUL |
| 212 | 200 | ||
| 213 | #define ARCH_DLINFO \ | 201 | #define ARCH_DLINFO \ |
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h index b56403c2df28..799ed0f1643d 100644 --- a/arch/s390/include/asm/hugetlb.h +++ b/arch/s390/include/asm/hugetlb.h | |||
| @@ -111,21 +111,10 @@ static inline void huge_ptep_invalidate(struct mm_struct *mm, | |||
| 111 | { | 111 | { |
| 112 | pmd_t *pmdp = (pmd_t *) ptep; | 112 | pmd_t *pmdp = (pmd_t *) ptep; |
| 113 | 113 | ||
| 114 | if (!MACHINE_HAS_IDTE) { | 114 | if (MACHINE_HAS_IDTE) |
| 115 | __pmd_csp(pmdp); | ||
| 116 | if (mm->context.noexec) { | ||
| 117 | pmdp = get_shadow_table(pmdp); | ||
| 118 | __pmd_csp(pmdp); | ||
| 119 | } | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | |||
| 123 | __pmd_idte(address, pmdp); | ||
| 124 | if (mm->context.noexec) { | ||
| 125 | pmdp = get_shadow_table(pmdp); | ||
| 126 | __pmd_idte(address, pmdp); | 115 | __pmd_idte(address, pmdp); |
| 127 | } | 116 | else |
| 128 | return; | 117 | __pmd_csp(pmdp); |
| 129 | } | 118 | } |
| 130 | 119 | ||
| 131 | #define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ | 120 | #define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ |
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index db14a311f1d2..1544b90bd6d6 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h | |||
| @@ -15,6 +15,7 @@ enum interruption_class { | |||
| 15 | EXTINT_VRT, | 15 | EXTINT_VRT, |
| 16 | EXTINT_SCP, | 16 | EXTINT_SCP, |
| 17 | EXTINT_IUC, | 17 | EXTINT_IUC, |
| 18 | EXTINT_CPM, | ||
| 18 | IOINT_QAI, | 19 | IOINT_QAI, |
| 19 | IOINT_QDI, | 20 | IOINT_QDI, |
| 20 | IOINT_DAS, | 21 | IOINT_DAS, |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 65e172f8209d..228cf0b295db 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
| @@ -124,7 +124,7 @@ struct _lowcore { | |||
| 124 | /* Address space pointer. */ | 124 | /* Address space pointer. */ |
| 125 | __u32 kernel_asce; /* 0x02ac */ | 125 | __u32 kernel_asce; /* 0x02ac */ |
| 126 | __u32 user_asce; /* 0x02b0 */ | 126 | __u32 user_asce; /* 0x02b0 */ |
| 127 | __u32 user_exec_asce; /* 0x02b4 */ | 127 | __u32 current_pid; /* 0x02b4 */ |
| 128 | 128 | ||
| 129 | /* SMP info area */ | 129 | /* SMP info area */ |
| 130 | __u32 cpu_nr; /* 0x02b8 */ | 130 | __u32 cpu_nr; /* 0x02b8 */ |
| @@ -255,7 +255,7 @@ struct _lowcore { | |||
| 255 | /* Address space pointer. */ | 255 | /* Address space pointer. */ |
| 256 | __u64 kernel_asce; /* 0x0310 */ | 256 | __u64 kernel_asce; /* 0x0310 */ |
| 257 | __u64 user_asce; /* 0x0318 */ | 257 | __u64 user_asce; /* 0x0318 */ |
| 258 | __u64 user_exec_asce; /* 0x0320 */ | 258 | __u64 current_pid; /* 0x0320 */ |
| 259 | 259 | ||
| 260 | /* SMP info area */ | 260 | /* SMP info area */ |
| 261 | __u32 cpu_nr; /* 0x0328 */ | 261 | __u32 cpu_nr; /* 0x0328 */ |
diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index 78522cdefdd4..82d0847896a0 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h | |||
| @@ -5,19 +5,18 @@ typedef struct { | |||
| 5 | atomic_t attach_count; | 5 | atomic_t attach_count; |
| 6 | unsigned int flush_mm; | 6 | unsigned int flush_mm; |
| 7 | spinlock_t list_lock; | 7 | spinlock_t list_lock; |
| 8 | struct list_head crst_list; | ||
| 9 | struct list_head pgtable_list; | 8 | struct list_head pgtable_list; |
| 10 | unsigned long asce_bits; | 9 | unsigned long asce_bits; |
| 11 | unsigned long asce_limit; | 10 | unsigned long asce_limit; |
| 12 | unsigned long vdso_base; | 11 | unsigned long vdso_base; |
| 13 | int noexec; | 12 | /* Cloned contexts will be created with extended page tables. */ |
| 14 | int has_pgste; /* The mmu context has extended page tables */ | 13 | unsigned int alloc_pgste:1; |
| 15 | int alloc_pgste; /* cloned contexts will have extended page tables */ | 14 | /* The mmu context has extended page tables. */ |
| 15 | unsigned int has_pgste:1; | ||
| 16 | } mm_context_t; | 16 | } mm_context_t; |
| 17 | 17 | ||
| 18 | #define INIT_MM_CONTEXT(name) \ | 18 | #define INIT_MM_CONTEXT(name) \ |
| 19 | .context.list_lock = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \ | 19 | .context.list_lock = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \ |
| 20 | .context.crst_list = LIST_HEAD_INIT(name.context.crst_list), \ | ||
| 21 | .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), | 20 | .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), |
| 22 | 21 | ||
| 23 | #endif | 22 | #endif |
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 8c277caa8d3a..5682f160ff82 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h | |||
| @@ -35,11 +35,9 @@ static inline int init_new_context(struct task_struct *tsk, | |||
| 35 | * and if has_pgste is set, it will create extended page | 35 | * and if has_pgste is set, it will create extended page |
| 36 | * tables. | 36 | * tables. |
| 37 | */ | 37 | */ |
| 38 | mm->context.noexec = 0; | ||
| 39 | mm->context.has_pgste = 1; | 38 | mm->context.has_pgste = 1; |
| 40 | mm->context.alloc_pgste = 1; | 39 | mm->context.alloc_pgste = 1; |
| 41 | } else { | 40 | } else { |
| 42 | mm->context.noexec = (user_mode == SECONDARY_SPACE_MODE); | ||
| 43 | mm->context.has_pgste = 0; | 41 | mm->context.has_pgste = 0; |
| 44 | mm->context.alloc_pgste = 0; | 42 | mm->context.alloc_pgste = 0; |
| 45 | } | 43 | } |
| @@ -63,10 +61,8 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk) | |||
| 63 | S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); | 61 | S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); |
| 64 | if (user_mode != HOME_SPACE_MODE) { | 62 | if (user_mode != HOME_SPACE_MODE) { |
| 65 | /* Load primary space page table origin. */ | 63 | /* Load primary space page table origin. */ |
| 66 | pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd; | ||
| 67 | S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd); | ||
| 68 | asm volatile(LCTL_OPCODE" 1,1,%0\n" | 64 | asm volatile(LCTL_OPCODE" 1,1,%0\n" |
| 69 | : : "m" (S390_lowcore.user_exec_asce) ); | 65 | : : "m" (S390_lowcore.user_asce) ); |
| 70 | } else | 66 | } else |
| 71 | /* Load home space page table origin. */ | 67 | /* Load home space page table origin. */ |
| 72 | asm volatile(LCTL_OPCODE" 13,13,%0" | 68 | asm volatile(LCTL_OPCODE" 13,13,%0" |
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 3c987e9ec8d6..accb372ddc7e 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h | |||
| @@ -90,6 +90,7 @@ static inline void copy_page(void *to, void *from) | |||
| 90 | */ | 90 | */ |
| 91 | 91 | ||
| 92 | typedef struct { unsigned long pgprot; } pgprot_t; | 92 | typedef struct { unsigned long pgprot; } pgprot_t; |
| 93 | typedef struct { unsigned long pgste; } pgste_t; | ||
| 93 | typedef struct { unsigned long pte; } pte_t; | 94 | typedef struct { unsigned long pte; } pte_t; |
| 94 | typedef struct { unsigned long pmd; } pmd_t; | 95 | typedef struct { unsigned long pmd; } pmd_t; |
| 95 | typedef struct { unsigned long pud; } pud_t; | 96 | typedef struct { unsigned long pud; } pud_t; |
| @@ -97,18 +98,21 @@ typedef struct { unsigned long pgd; } pgd_t; | |||
| 97 | typedef pte_t *pgtable_t; | 98 | typedef pte_t *pgtable_t; |
| 98 | 99 | ||
| 99 | #define pgprot_val(x) ((x).pgprot) | 100 | #define pgprot_val(x) ((x).pgprot) |
| 101 | #define pgste_val(x) ((x).pgste) | ||
| 100 | #define pte_val(x) ((x).pte) | 102 | #define pte_val(x) ((x).pte) |
| 101 | #define pmd_val(x) ((x).pmd) | 103 | #define pmd_val(x) ((x).pmd) |
| 102 | #define pud_val(x) ((x).pud) | 104 | #define pud_val(x) ((x).pud) |
| 103 | #define pgd_val(x) ((x).pgd) | 105 | #define pgd_val(x) ((x).pgd) |
| 104 | 106 | ||
| 107 | #define __pgste(x) ((pgste_t) { (x) } ) | ||
| 105 | #define __pte(x) ((pte_t) { (x) } ) | 108 | #define __pte(x) ((pte_t) { (x) } ) |
| 106 | #define __pmd(x) ((pmd_t) { (x) } ) | 109 | #define __pmd(x) ((pmd_t) { (x) } ) |
| 110 | #define __pud(x) ((pud_t) { (x) } ) | ||
| 107 | #define __pgd(x) ((pgd_t) { (x) } ) | 111 | #define __pgd(x) ((pgd_t) { (x) } ) |
| 108 | #define __pgprot(x) ((pgprot_t) { (x) } ) | 112 | #define __pgprot(x) ((pgprot_t) { (x) } ) |
| 109 | 113 | ||
| 110 | static inline void | 114 | static inline void page_set_storage_key(unsigned long addr, |
| 111 | page_set_storage_key(unsigned long addr, unsigned int skey, int mapped) | 115 | unsigned char skey, int mapped) |
| 112 | { | 116 | { |
| 113 | if (!mapped) | 117 | if (!mapped) |
| 114 | asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0" | 118 | asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0" |
| @@ -117,15 +121,59 @@ page_set_storage_key(unsigned long addr, unsigned int skey, int mapped) | |||
| 117 | asm volatile("sske %0,%1" : : "d" (skey), "a" (addr)); | 121 | asm volatile("sske %0,%1" : : "d" (skey), "a" (addr)); |
| 118 | } | 122 | } |
| 119 | 123 | ||
| 120 | static inline unsigned int | 124 | static inline unsigned char page_get_storage_key(unsigned long addr) |
| 121 | page_get_storage_key(unsigned long addr) | ||
| 122 | { | 125 | { |
| 123 | unsigned int skey; | 126 | unsigned char skey; |
| 124 | 127 | ||
| 125 | asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0)); | 128 | asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr)); |
| 126 | return skey; | 129 | return skey; |
| 127 | } | 130 | } |
| 128 | 131 | ||
| 132 | static inline int page_reset_referenced(unsigned long addr) | ||
| 133 | { | ||
| 134 | unsigned int ipm; | ||
| 135 | |||
| 136 | asm volatile( | ||
| 137 | " rrbe 0,%1\n" | ||
| 138 | " ipm %0\n" | ||
| 139 | : "=d" (ipm) : "a" (addr) : "cc"); | ||
| 140 | return !!(ipm & 0x20000000); | ||
| 141 | } | ||
| 142 | |||
| 143 | /* Bits int the storage key */ | ||
| 144 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ | ||
| 145 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ | ||
| 146 | #define _PAGE_FP_BIT 0x08 /* HW fetch protection bit */ | ||
| 147 | #define _PAGE_ACC_BITS 0xf0 /* HW access control bits */ | ||
| 148 | |||
| 149 | /* | ||
| 150 | * Test and clear dirty bit in storage key. | ||
| 151 | * We can't clear the changed bit atomically. This is a potential | ||
| 152 | * race against modification of the referenced bit. This function | ||
| 153 | * should therefore only be called if it is not mapped in any | ||
| 154 | * address space. | ||
| 155 | */ | ||
| 156 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY | ||
| 157 | static inline int page_test_and_clear_dirty(unsigned long pfn, int mapped) | ||
| 158 | { | ||
| 159 | unsigned char skey; | ||
| 160 | |||
| 161 | skey = page_get_storage_key(pfn << PAGE_SHIFT); | ||
| 162 | if (!(skey & _PAGE_CHANGED)) | ||
| 163 | return 0; | ||
| 164 | page_set_storage_key(pfn << PAGE_SHIFT, skey & ~_PAGE_CHANGED, mapped); | ||
| 165 | return 1; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* | ||
| 169 | * Test and clear referenced bit in storage key. | ||
| 170 | */ | ||
| 171 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | ||
| 172 | static inline int page_test_and_clear_young(unsigned long pfn) | ||
| 173 | { | ||
| 174 | return page_reset_referenced(pfn << PAGE_SHIFT); | ||
| 175 | } | ||
| 176 | |||
| 129 | struct page; | 177 | struct page; |
| 130 | void arch_free_page(struct page *page, int order); | 178 | void arch_free_page(struct page *page, int order); |
| 131 | void arch_alloc_page(struct page *page, int order); | 179 | void arch_alloc_page(struct page *page, int order); |
diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h index f7ad8719d02d..5325c89a5843 100644 --- a/arch/s390/include/asm/percpu.h +++ b/arch/s390/include/asm/percpu.h | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | #ifndef __ARCH_S390_PERCPU__ | 1 | #ifndef __ARCH_S390_PERCPU__ |
| 2 | #define __ARCH_S390_PERCPU__ | 2 | #define __ARCH_S390_PERCPU__ |
| 3 | 3 | ||
| 4 | #include <linux/preempt.h> | ||
| 5 | #include <asm/cmpxchg.h> | ||
| 6 | |||
| 4 | /* | 7 | /* |
| 5 | * s390 uses its own implementation for per cpu data, the offset of | 8 | * s390 uses its own implementation for per cpu data, the offset of |
| 6 | * the cpu local data area is cached in the cpu's lowcore memory. | 9 | * the cpu local data area is cached in the cpu's lowcore memory. |
| @@ -16,6 +19,71 @@ | |||
| 16 | #define ARCH_NEEDS_WEAK_PER_CPU | 19 | #define ARCH_NEEDS_WEAK_PER_CPU |
| 17 | #endif | 20 | #endif |
| 18 | 21 | ||
| 22 | #define arch_irqsafe_cpu_to_op(pcp, val, op) \ | ||
| 23 | do { \ | ||
| 24 | typedef typeof(pcp) pcp_op_T__; \ | ||
| 25 | pcp_op_T__ old__, new__, prev__; \ | ||
| 26 | pcp_op_T__ *ptr__; \ | ||
| 27 | preempt_disable(); \ | ||
| 28 | ptr__ = __this_cpu_ptr(&(pcp)); \ | ||
| 29 | prev__ = *ptr__; \ | ||
| 30 | do { \ | ||
| 31 | old__ = prev__; \ | ||
| 32 | new__ = old__ op (val); \ | ||
| 33 | switch (sizeof(*ptr__)) { \ | ||
| 34 | case 8: \ | ||
| 35 | prev__ = cmpxchg64(ptr__, old__, new__); \ | ||
| 36 | break; \ | ||
| 37 | default: \ | ||
| 38 | prev__ = cmpxchg(ptr__, old__, new__); \ | ||
| 39 | } \ | ||
| 40 | } while (prev__ != old__); \ | ||
| 41 | preempt_enable(); \ | ||
| 42 | } while (0) | ||
| 43 | |||
| 44 | #define irqsafe_cpu_add_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +) | ||
| 45 | #define irqsafe_cpu_add_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +) | ||
| 46 | #define irqsafe_cpu_add_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +) | ||
| 47 | #define irqsafe_cpu_add_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +) | ||
| 48 | |||
| 49 | #define irqsafe_cpu_and_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &) | ||
| 50 | #define irqsafe_cpu_and_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &) | ||
| 51 | #define irqsafe_cpu_and_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &) | ||
| 52 | #define irqsafe_cpu_and_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &) | ||
| 53 | |||
| 54 | #define irqsafe_cpu_or_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |) | ||
| 55 | #define irqsafe_cpu_or_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |) | ||
| 56 | #define irqsafe_cpu_or_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |) | ||
| 57 | #define irqsafe_cpu_or_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |) | ||
| 58 | |||
| 59 | #define irqsafe_cpu_xor_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^) | ||
| 60 | #define irqsafe_cpu_xor_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^) | ||
| 61 | #define irqsafe_cpu_xor_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^) | ||
| 62 | #define irqsafe_cpu_xor_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^) | ||
| 63 | |||
| 64 | #define arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) \ | ||
| 65 | ({ \ | ||
| 66 | typedef typeof(pcp) pcp_op_T__; \ | ||
| 67 | pcp_op_T__ ret__; \ | ||
| 68 | pcp_op_T__ *ptr__; \ | ||
| 69 | preempt_disable(); \ | ||
| 70 | ptr__ = __this_cpu_ptr(&(pcp)); \ | ||
| 71 | switch (sizeof(*ptr__)) { \ | ||
| 72 | case 8: \ | ||
| 73 | ret__ = cmpxchg64(ptr__, oval, nval); \ | ||
| 74 | break; \ | ||
| 75 | default: \ | ||
| 76 | ret__ = cmpxchg(ptr__, oval, nval); \ | ||
| 77 | } \ | ||
| 78 | preempt_enable(); \ | ||
| 79 | ret__; \ | ||
| 80 | }) | ||
| 81 | |||
| 82 | #define irqsafe_cpu_cmpxchg_1(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) | ||
| 83 | #define irqsafe_cpu_cmpxchg_2(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) | ||
| 84 | #define irqsafe_cpu_cmpxchg_4(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) | ||
| 85 | #define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) | ||
| 86 | |||
| 19 | #include <asm-generic/percpu.h> | 87 | #include <asm-generic/percpu.h> |
| 20 | 88 | ||
| 21 | #endif /* __ARCH_S390_PERCPU__ */ | 89 | #endif /* __ARCH_S390_PERCPU__ */ |
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index 082eb4e50e8b..f6314af3b354 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h | |||
| @@ -19,14 +19,13 @@ | |||
| 19 | 19 | ||
| 20 | #define check_pgt_cache() do {} while (0) | 20 | #define check_pgt_cache() do {} while (0) |
| 21 | 21 | ||
| 22 | unsigned long *crst_table_alloc(struct mm_struct *, int); | 22 | unsigned long *crst_table_alloc(struct mm_struct *); |
| 23 | void crst_table_free(struct mm_struct *, unsigned long *); | 23 | void crst_table_free(struct mm_struct *, unsigned long *); |
| 24 | void crst_table_free_rcu(struct mm_struct *, unsigned long *); | 24 | void crst_table_free_rcu(struct mm_struct *, unsigned long *); |
| 25 | 25 | ||
| 26 | unsigned long *page_table_alloc(struct mm_struct *); | 26 | unsigned long *page_table_alloc(struct mm_struct *); |
| 27 | void page_table_free(struct mm_struct *, unsigned long *); | 27 | void page_table_free(struct mm_struct *, unsigned long *); |
| 28 | void page_table_free_rcu(struct mm_struct *, unsigned long *); | 28 | void page_table_free_rcu(struct mm_struct *, unsigned long *); |
| 29 | void disable_noexec(struct mm_struct *, struct task_struct *); | ||
| 30 | 29 | ||
| 31 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) | 30 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) |
| 32 | { | 31 | { |
| @@ -50,9 +49,6 @@ static inline void clear_table(unsigned long *s, unsigned long val, size_t n) | |||
| 50 | static inline void crst_table_init(unsigned long *crst, unsigned long entry) | 49 | static inline void crst_table_init(unsigned long *crst, unsigned long entry) |
| 51 | { | 50 | { |
| 52 | clear_table(crst, entry, sizeof(unsigned long)*2048); | 51 | clear_table(crst, entry, sizeof(unsigned long)*2048); |
| 53 | crst = get_shadow_table(crst); | ||
| 54 | if (crst) | ||
| 55 | clear_table(crst, entry, sizeof(unsigned long)*2048); | ||
| 56 | } | 52 | } |
| 57 | 53 | ||
| 58 | #ifndef __s390x__ | 54 | #ifndef __s390x__ |
| @@ -69,10 +65,7 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm) | |||
| 69 | #define pmd_free(mm, x) do { } while (0) | 65 | #define pmd_free(mm, x) do { } while (0) |
| 70 | 66 | ||
| 71 | #define pgd_populate(mm, pgd, pud) BUG() | 67 | #define pgd_populate(mm, pgd, pud) BUG() |
| 72 | #define pgd_populate_kernel(mm, pgd, pud) BUG() | ||
| 73 | |||
| 74 | #define pud_populate(mm, pud, pmd) BUG() | 68 | #define pud_populate(mm, pud, pmd) BUG() |
| 75 | #define pud_populate_kernel(mm, pud, pmd) BUG() | ||
| 76 | 69 | ||
| 77 | #else /* __s390x__ */ | 70 | #else /* __s390x__ */ |
| 78 | 71 | ||
| @@ -90,7 +83,7 @@ void crst_table_downgrade(struct mm_struct *, unsigned long limit); | |||
| 90 | 83 | ||
| 91 | static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) | 84 | static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) |
| 92 | { | 85 | { |
| 93 | unsigned long *table = crst_table_alloc(mm, mm->context.noexec); | 86 | unsigned long *table = crst_table_alloc(mm); |
| 94 | if (table) | 87 | if (table) |
| 95 | crst_table_init(table, _REGION3_ENTRY_EMPTY); | 88 | crst_table_init(table, _REGION3_ENTRY_EMPTY); |
| 96 | return (pud_t *) table; | 89 | return (pud_t *) table; |
| @@ -99,43 +92,21 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) | |||
| 99 | 92 | ||
| 100 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) | 93 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) |
| 101 | { | 94 | { |
| 102 | unsigned long *table = crst_table_alloc(mm, mm->context.noexec); | 95 | unsigned long *table = crst_table_alloc(mm); |
| 103 | if (table) | 96 | if (table) |
| 104 | crst_table_init(table, _SEGMENT_ENTRY_EMPTY); | 97 | crst_table_init(table, _SEGMENT_ENTRY_EMPTY); |
| 105 | return (pmd_t *) table; | 98 | return (pmd_t *) table; |
| 106 | } | 99 | } |
| 107 | #define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd) | 100 | #define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd) |
| 108 | 101 | ||
| 109 | static inline void pgd_populate_kernel(struct mm_struct *mm, | ||
| 110 | pgd_t *pgd, pud_t *pud) | ||
| 111 | { | ||
| 112 | pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud); | ||
| 113 | } | ||
| 114 | |||
| 115 | static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) | 102 | static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) |
| 116 | { | 103 | { |
| 117 | pgd_populate_kernel(mm, pgd, pud); | 104 | pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud); |
| 118 | if (mm->context.noexec) { | ||
| 119 | pgd = get_shadow_table(pgd); | ||
| 120 | pud = get_shadow_table(pud); | ||
| 121 | pgd_populate_kernel(mm, pgd, pud); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | static inline void pud_populate_kernel(struct mm_struct *mm, | ||
| 126 | pud_t *pud, pmd_t *pmd) | ||
| 127 | { | ||
| 128 | pud_val(*pud) = _REGION3_ENTRY | __pa(pmd); | ||
| 129 | } | 105 | } |
| 130 | 106 | ||
| 131 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | 107 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) |
| 132 | { | 108 | { |
| 133 | pud_populate_kernel(mm, pud, pmd); | 109 | pud_val(*pud) = _REGION3_ENTRY | __pa(pmd); |
| 134 | if (mm->context.noexec) { | ||
| 135 | pud = get_shadow_table(pud); | ||
| 136 | pmd = get_shadow_table(pmd); | ||
| 137 | pud_populate_kernel(mm, pud, pmd); | ||
| 138 | } | ||
| 139 | } | 110 | } |
| 140 | 111 | ||
| 141 | #endif /* __s390x__ */ | 112 | #endif /* __s390x__ */ |
| @@ -143,29 +114,19 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | |||
| 143 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | 114 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) |
| 144 | { | 115 | { |
| 145 | spin_lock_init(&mm->context.list_lock); | 116 | spin_lock_init(&mm->context.list_lock); |
| 146 | INIT_LIST_HEAD(&mm->context.crst_list); | ||
| 147 | INIT_LIST_HEAD(&mm->context.pgtable_list); | 117 | INIT_LIST_HEAD(&mm->context.pgtable_list); |
| 148 | return (pgd_t *) | 118 | return (pgd_t *) crst_table_alloc(mm); |
| 149 | crst_table_alloc(mm, user_mode == SECONDARY_SPACE_MODE); | ||
| 150 | } | 119 | } |
| 151 | #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd) | 120 | #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd) |
| 152 | 121 | ||
| 153 | static inline void pmd_populate_kernel(struct mm_struct *mm, | ||
| 154 | pmd_t *pmd, pte_t *pte) | ||
| 155 | { | ||
| 156 | pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte); | ||
| 157 | } | ||
| 158 | |||
| 159 | static inline void pmd_populate(struct mm_struct *mm, | 122 | static inline void pmd_populate(struct mm_struct *mm, |
| 160 | pmd_t *pmd, pgtable_t pte) | 123 | pmd_t *pmd, pgtable_t pte) |
| 161 | { | 124 | { |
| 162 | pmd_populate_kernel(mm, pmd, pte); | 125 | pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte); |
| 163 | if (mm->context.noexec) { | ||
| 164 | pmd = get_shadow_table(pmd); | ||
| 165 | pmd_populate_kernel(mm, pmd, pte + PTRS_PER_PTE); | ||
| 166 | } | ||
| 167 | } | 126 | } |
| 168 | 127 | ||
| 128 | #define pmd_populate_kernel(mm, pmd, pte) pmd_populate(mm, pmd, pte) | ||
| 129 | |||
| 169 | #define pmd_pgtable(pmd) \ | 130 | #define pmd_pgtable(pmd) \ |
| 170 | (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE) | 131 | (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE) |
| 171 | 132 | ||
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 02ace3491c51..c4773a2ef3d3 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
| @@ -31,9 +31,8 @@ | |||
| 31 | #ifndef __ASSEMBLY__ | 31 | #ifndef __ASSEMBLY__ |
| 32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
| 33 | #include <linux/mm_types.h> | 33 | #include <linux/mm_types.h> |
| 34 | #include <asm/bitops.h> | ||
| 35 | #include <asm/bug.h> | 34 | #include <asm/bug.h> |
| 36 | #include <asm/processor.h> | 35 | #include <asm/page.h> |
| 37 | 36 | ||
| 38 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); | 37 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); |
| 39 | extern void paging_init(void); | 38 | extern void paging_init(void); |
| @@ -243,11 +242,13 @@ extern unsigned long VMALLOC_START; | |||
| 243 | /* Software bits in the page table entry */ | 242 | /* Software bits in the page table entry */ |
| 244 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ | 243 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ |
| 245 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ | 244 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ |
| 246 | #define _PAGE_SPECIAL 0x004 /* SW associated with special page */ | 245 | #define _PAGE_SWC 0x004 /* SW pte changed bit (for KVM) */ |
| 246 | #define _PAGE_SWR 0x008 /* SW pte referenced bit (for KVM) */ | ||
| 247 | #define _PAGE_SPECIAL 0x010 /* SW associated with special page */ | ||
| 247 | #define __HAVE_ARCH_PTE_SPECIAL | 248 | #define __HAVE_ARCH_PTE_SPECIAL |
| 248 | 249 | ||
| 249 | /* Set of bits not changed in pte_modify */ | 250 | /* Set of bits not changed in pte_modify */ |
| 250 | #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL) | 251 | #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_SWC | _PAGE_SWR) |
| 251 | 252 | ||
| 252 | /* Six different types of pages. */ | 253 | /* Six different types of pages. */ |
| 253 | #define _PAGE_TYPE_EMPTY 0x400 | 254 | #define _PAGE_TYPE_EMPTY 0x400 |
| @@ -256,8 +257,6 @@ extern unsigned long VMALLOC_START; | |||
| 256 | #define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */ | 257 | #define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */ |
| 257 | #define _PAGE_TYPE_RO 0x200 | 258 | #define _PAGE_TYPE_RO 0x200 |
| 258 | #define _PAGE_TYPE_RW 0x000 | 259 | #define _PAGE_TYPE_RW 0x000 |
| 259 | #define _PAGE_TYPE_EX_RO 0x202 | ||
| 260 | #define _PAGE_TYPE_EX_RW 0x002 | ||
| 261 | 260 | ||
| 262 | /* | 261 | /* |
| 263 | * Only four types for huge pages, using the invalid bit and protection bit | 262 | * Only four types for huge pages, using the invalid bit and protection bit |
| @@ -287,8 +286,6 @@ extern unsigned long VMALLOC_START; | |||
| 287 | * _PAGE_TYPE_FILE 11?1 -> 11?1 | 286 | * _PAGE_TYPE_FILE 11?1 -> 11?1 |
| 288 | * _PAGE_TYPE_RO 0100 -> 1100 | 287 | * _PAGE_TYPE_RO 0100 -> 1100 |
| 289 | * _PAGE_TYPE_RW 0000 -> 1000 | 288 | * _PAGE_TYPE_RW 0000 -> 1000 |
| 290 | * _PAGE_TYPE_EX_RO 0110 -> 1110 | ||
| 291 | * _PAGE_TYPE_EX_RW 0010 -> 1010 | ||
| 292 | * | 289 | * |
| 293 | * pte_none is true for bits combinations 1000, 1010, 1100, 1110 | 290 | * pte_none is true for bits combinations 1000, 1010, 1100, 1110 |
| 294 | * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001 | 291 | * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001 |
| @@ -297,14 +294,17 @@ extern unsigned long VMALLOC_START; | |||
| 297 | */ | 294 | */ |
| 298 | 295 | ||
| 299 | /* Page status table bits for virtualization */ | 296 | /* Page status table bits for virtualization */ |
| 300 | #define RCP_PCL_BIT 55 | 297 | #define RCP_ACC_BITS 0xf000000000000000UL |
| 301 | #define RCP_HR_BIT 54 | 298 | #define RCP_FP_BIT 0x0800000000000000UL |
| 302 | #define RCP_HC_BIT 53 | 299 | #define RCP_PCL_BIT 0x0080000000000000UL |
| 303 | #define RCP_GR_BIT 50 | 300 | #define RCP_HR_BIT 0x0040000000000000UL |
| 304 | #define RCP_GC_BIT 49 | 301 | #define RCP_HC_BIT 0x0020000000000000UL |
| 305 | 302 | #define RCP_GR_BIT 0x0004000000000000UL | |
| 306 | /* User dirty bit for KVM's migration feature */ | 303 | #define RCP_GC_BIT 0x0002000000000000UL |
| 307 | #define KVM_UD_BIT 47 | 304 | |
| 305 | /* User dirty / referenced bit for KVM's migration feature */ | ||
| 306 | #define KVM_UR_BIT 0x0000800000000000UL | ||
| 307 | #define KVM_UC_BIT 0x0000400000000000UL | ||
| 308 | 308 | ||
| 309 | #ifndef __s390x__ | 309 | #ifndef __s390x__ |
| 310 | 310 | ||
| @@ -377,85 +377,54 @@ extern unsigned long VMALLOC_START; | |||
| 377 | #define _ASCE_USER_BITS (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \ | 377 | #define _ASCE_USER_BITS (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \ |
| 378 | _ASCE_ALT_EVENT) | 378 | _ASCE_ALT_EVENT) |
| 379 | 379 | ||
| 380 | /* Bits int the storage key */ | ||
| 381 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ | ||
| 382 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ | ||
| 383 | |||
| 384 | /* | 380 | /* |
| 385 | * Page protection definitions. | 381 | * Page protection definitions. |
| 386 | */ | 382 | */ |
| 387 | #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) | 383 | #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) |
| 388 | #define PAGE_RO __pgprot(_PAGE_TYPE_RO) | 384 | #define PAGE_RO __pgprot(_PAGE_TYPE_RO) |
| 389 | #define PAGE_RW __pgprot(_PAGE_TYPE_RW) | 385 | #define PAGE_RW __pgprot(_PAGE_TYPE_RW) |
| 390 | #define PAGE_EX_RO __pgprot(_PAGE_TYPE_EX_RO) | ||
| 391 | #define PAGE_EX_RW __pgprot(_PAGE_TYPE_EX_RW) | ||
| 392 | 386 | ||
| 393 | #define PAGE_KERNEL PAGE_RW | 387 | #define PAGE_KERNEL PAGE_RW |
| 394 | #define PAGE_COPY PAGE_RO | 388 | #define PAGE_COPY PAGE_RO |
| 395 | 389 | ||
| 396 | /* | 390 | /* |
| 397 | * Dependent on the EXEC_PROTECT option s390 can do execute protection. | 391 | * On s390 the page table entry has an invalid bit and a read-only bit. |
| 398 | * Write permission always implies read permission. In theory with a | 392 | * Read permission implies execute permission and write permission |
| 399 | * primary/secondary page table execute only can be implemented but | 393 | * implies read permission. |
| 400 | * it would cost an additional bit in the pte to distinguish all the | ||
| 401 | * different pte types. To avoid that execute permission currently | ||
| 402 | * implies read permission as well. | ||
| 403 | */ | 394 | */ |
| 404 | /*xwr*/ | 395 | /*xwr*/ |
| 405 | #define __P000 PAGE_NONE | 396 | #define __P000 PAGE_NONE |
| 406 | #define __P001 PAGE_RO | 397 | #define __P001 PAGE_RO |
| 407 | #define __P010 PAGE_RO | 398 | #define __P010 PAGE_RO |
| 408 | #define __P011 PAGE_RO | 399 | #define __P011 PAGE_RO |
| 409 | #define __P100 PAGE_EX_RO | 400 | #define __P100 PAGE_RO |
| 410 | #define __P101 PAGE_EX_RO | 401 | #define __P101 PAGE_RO |
| 411 | #define __P110 PAGE_EX_RO | 402 | #define __P110 PAGE_RO |
| 412 | #define __P111 PAGE_EX_RO | 403 | #define __P111 PAGE_RO |
| 413 | 404 | ||
| 414 | #define __S000 PAGE_NONE | 405 | #define __S000 PAGE_NONE |
| 415 | #define __S001 PAGE_RO | 406 | #define __S001 PAGE_RO |
| 416 | #define __S010 PAGE_RW | 407 | #define __S010 PAGE_RW |
| 417 | #define __S011 PAGE_RW | 408 | #define __S011 PAGE_RW |
| 418 | #define __S100 PAGE_EX_RO | 409 | #define __S100 PAGE_RO |
| 419 | #define __S101 PAGE_EX_RO | 410 | #define __S101 PAGE_RO |
| 420 | #define __S110 PAGE_EX_RW | 411 | #define __S110 PAGE_RW |
| 421 | #define __S111 PAGE_EX_RW | 412 | #define __S111 PAGE_RW |
| 422 | |||
| 423 | #ifndef __s390x__ | ||
| 424 | # define PxD_SHADOW_SHIFT 1 | ||
| 425 | #else /* __s390x__ */ | ||
| 426 | # define PxD_SHADOW_SHIFT 2 | ||
| 427 | #endif /* __s390x__ */ | ||
| 428 | 413 | ||
| 429 | static inline void *get_shadow_table(void *table) | 414 | static inline int mm_exclusive(struct mm_struct *mm) |
| 430 | { | 415 | { |
| 431 | unsigned long addr, offset; | 416 | return likely(mm == current->active_mm && |
| 432 | struct page *page; | 417 | atomic_read(&mm->context.attach_count) <= 1); |
| 433 | |||
| 434 | addr = (unsigned long) table; | ||
| 435 | offset = addr & ((PAGE_SIZE << PxD_SHADOW_SHIFT) - 1); | ||
| 436 | page = virt_to_page((void *)(addr ^ offset)); | ||
| 437 | return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL); | ||
| 438 | } | 418 | } |
| 439 | 419 | ||
| 440 | /* | 420 | static inline int mm_has_pgste(struct mm_struct *mm) |
| 441 | * Certain architectures need to do special things when PTEs | ||
| 442 | * within a page table are directly modified. Thus, the following | ||
| 443 | * hook is made available. | ||
| 444 | */ | ||
| 445 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
| 446 | pte_t *ptep, pte_t entry) | ||
| 447 | { | 421 | { |
| 448 | *ptep = entry; | 422 | #ifdef CONFIG_PGSTE |
| 449 | if (mm->context.noexec) { | 423 | if (unlikely(mm->context.has_pgste)) |
| 450 | if (!(pte_val(entry) & _PAGE_INVALID) && | 424 | return 1; |
| 451 | (pte_val(entry) & _PAGE_SWX)) | 425 | #endif |
| 452 | pte_val(entry) |= _PAGE_RO; | 426 | return 0; |
| 453 | else | ||
| 454 | pte_val(entry) = _PAGE_TYPE_EMPTY; | ||
| 455 | ptep[PTRS_PER_PTE] = entry; | ||
| 456 | } | ||
| 457 | } | 427 | } |
| 458 | |||
| 459 | /* | 428 | /* |
| 460 | * pgd/pmd/pte query functions | 429 | * pgd/pmd/pte query functions |
| 461 | */ | 430 | */ |
| @@ -568,52 +537,127 @@ static inline int pte_special(pte_t pte) | |||
| 568 | } | 537 | } |
| 569 | 538 | ||
| 570 | #define __HAVE_ARCH_PTE_SAME | 539 | #define __HAVE_ARCH_PTE_SAME |
| 571 | #define pte_same(a,b) (pte_val(a) == pte_val(b)) | 540 | static inline int pte_same(pte_t a, pte_t b) |
| 541 | { | ||
| 542 | return pte_val(a) == pte_val(b); | ||
| 543 | } | ||
| 572 | 544 | ||
| 573 | static inline void rcp_lock(pte_t *ptep) | 545 | static inline pgste_t pgste_get_lock(pte_t *ptep) |
| 574 | { | 546 | { |
| 547 | unsigned long new = 0; | ||
| 575 | #ifdef CONFIG_PGSTE | 548 | #ifdef CONFIG_PGSTE |
| 576 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 549 | unsigned long old; |
| 550 | |||
| 577 | preempt_disable(); | 551 | preempt_disable(); |
| 578 | while (test_and_set_bit(RCP_PCL_BIT, pgste)) | 552 | asm( |
| 579 | ; | 553 | " lg %0,%2\n" |
| 554 | "0: lgr %1,%0\n" | ||
| 555 | " nihh %0,0xff7f\n" /* clear RCP_PCL_BIT in old */ | ||
| 556 | " oihh %1,0x0080\n" /* set RCP_PCL_BIT in new */ | ||
| 557 | " csg %0,%1,%2\n" | ||
| 558 | " jl 0b\n" | ||
| 559 | : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE]) | ||
| 560 | : "Q" (ptep[PTRS_PER_PTE]) : "cc"); | ||
| 580 | #endif | 561 | #endif |
| 562 | return __pgste(new); | ||
| 581 | } | 563 | } |
| 582 | 564 | ||
| 583 | static inline void rcp_unlock(pte_t *ptep) | 565 | static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) |
| 584 | { | 566 | { |
| 585 | #ifdef CONFIG_PGSTE | 567 | #ifdef CONFIG_PGSTE |
| 586 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 568 | asm( |
| 587 | clear_bit(RCP_PCL_BIT, pgste); | 569 | " nihh %1,0xff7f\n" /* clear RCP_PCL_BIT */ |
| 570 | " stg %1,%0\n" | ||
| 571 | : "=Q" (ptep[PTRS_PER_PTE]) | ||
| 572 | : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE]) : "cc"); | ||
| 588 | preempt_enable(); | 573 | preempt_enable(); |
| 589 | #endif | 574 | #endif |
| 590 | } | 575 | } |
| 591 | 576 | ||
| 592 | /* forward declaration for SetPageUptodate in page-flags.h*/ | 577 | static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) |
| 593 | static inline void page_clear_dirty(struct page *page, int mapped); | ||
| 594 | #include <linux/page-flags.h> | ||
| 595 | |||
| 596 | static inline void ptep_rcp_copy(pte_t *ptep) | ||
| 597 | { | 578 | { |
| 598 | #ifdef CONFIG_PGSTE | 579 | #ifdef CONFIG_PGSTE |
| 599 | struct page *page = virt_to_page(pte_val(*ptep)); | 580 | unsigned long pfn, bits; |
| 600 | unsigned int skey; | 581 | unsigned char skey; |
| 601 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 582 | |
| 602 | 583 | pfn = pte_val(*ptep) >> PAGE_SHIFT; | |
| 603 | skey = page_get_storage_key(page_to_phys(page)); | 584 | skey = page_get_storage_key(pfn); |
| 604 | if (skey & _PAGE_CHANGED) { | 585 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); |
| 605 | set_bit_simple(RCP_GC_BIT, pgste); | 586 | /* Clear page changed & referenced bit in the storage key */ |
| 606 | set_bit_simple(KVM_UD_BIT, pgste); | 587 | if (bits) { |
| 588 | skey ^= bits; | ||
| 589 | page_set_storage_key(pfn, skey, 1); | ||
| 607 | } | 590 | } |
| 608 | if (skey & _PAGE_REFERENCED) | 591 | /* Transfer page changed & referenced bit to guest bits in pgste */ |
| 609 | set_bit_simple(RCP_GR_BIT, pgste); | 592 | pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ |
| 610 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { | 593 | /* Get host changed & referenced bits from pgste */ |
| 611 | SetPageDirty(page); | 594 | bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52; |
| 612 | set_bit_simple(KVM_UD_BIT, pgste); | 595 | /* Clear host bits in pgste. */ |
| 613 | } | 596 | pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT); |
| 614 | if (test_and_clear_bit_simple(RCP_HR_BIT, pgste)) | 597 | pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT); |
| 615 | SetPageReferenced(page); | 598 | /* Copy page access key and fetch protection bit to pgste */ |
| 599 | pgste_val(pgste) |= | ||
| 600 | (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; | ||
| 601 | /* Transfer changed and referenced to kvm user bits */ | ||
| 602 | pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */ | ||
| 603 | /* Transfer changed & referenced to pte sofware bits */ | ||
| 604 | pte_val(*ptep) |= bits << 1; /* _PAGE_SWR & _PAGE_SWC */ | ||
| 616 | #endif | 605 | #endif |
| 606 | return pgste; | ||
| 607 | |||
| 608 | } | ||
| 609 | |||
| 610 | static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste) | ||
| 611 | { | ||
| 612 | #ifdef CONFIG_PGSTE | ||
| 613 | int young; | ||
| 614 | |||
| 615 | young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); | ||
| 616 | /* Transfer page referenced bit to pte software bit (host view) */ | ||
| 617 | if (young || (pgste_val(pgste) & RCP_HR_BIT)) | ||
| 618 | pte_val(*ptep) |= _PAGE_SWR; | ||
| 619 | /* Clear host referenced bit in pgste. */ | ||
| 620 | pgste_val(pgste) &= ~RCP_HR_BIT; | ||
| 621 | /* Transfer page referenced bit to guest bit in pgste */ | ||
| 622 | pgste_val(pgste) |= (unsigned long) young << 50; /* set RCP_GR_BIT */ | ||
| 623 | #endif | ||
| 624 | return pgste; | ||
| 625 | |||
| 626 | } | ||
| 627 | |||
| 628 | static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) | ||
| 629 | { | ||
| 630 | #ifdef CONFIG_PGSTE | ||
| 631 | unsigned long pfn; | ||
| 632 | unsigned long okey, nkey; | ||
| 633 | |||
| 634 | pfn = pte_val(*ptep) >> PAGE_SHIFT; | ||
| 635 | okey = nkey = page_get_storage_key(pfn); | ||
| 636 | nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT); | ||
| 637 | /* Set page access key and fetch protection bit from pgste */ | ||
| 638 | nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; | ||
| 639 | if (okey != nkey) | ||
| 640 | page_set_storage_key(pfn, nkey, 1); | ||
| 641 | #endif | ||
| 642 | } | ||
| 643 | |||
| 644 | /* | ||
| 645 | * Certain architectures need to do special things when PTEs | ||
| 646 | * within a page table are directly modified. Thus, the following | ||
| 647 | * hook is made available. | ||
| 648 | */ | ||
| 649 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
| 650 | pte_t *ptep, pte_t entry) | ||
| 651 | { | ||
| 652 | pgste_t pgste; | ||
| 653 | |||
| 654 | if (mm_has_pgste(mm)) { | ||
| 655 | pgste = pgste_get_lock(ptep); | ||
| 656 | pgste_set_pte(ptep, pgste); | ||
| 657 | *ptep = entry; | ||
| 658 | pgste_set_unlock(ptep, pgste); | ||
| 659 | } else | ||
| 660 | *ptep = entry; | ||
| 617 | } | 661 | } |
| 618 | 662 | ||
| 619 | /* | 663 | /* |
| @@ -627,19 +671,19 @@ static inline int pte_write(pte_t pte) | |||
| 627 | 671 | ||
| 628 | static inline int pte_dirty(pte_t pte) | 672 | static inline int pte_dirty(pte_t pte) |
| 629 | { | 673 | { |
| 630 | /* A pte is neither clean nor dirty on s/390. The dirty bit | 674 | #ifdef CONFIG_PGSTE |
| 631 | * is in the storage key. See page_test_and_clear_dirty for | 675 | if (pte_val(pte) & _PAGE_SWC) |
| 632 | * details. | 676 | return 1; |
| 633 | */ | 677 | #endif |
| 634 | return 0; | 678 | return 0; |
| 635 | } | 679 | } |
| 636 | 680 | ||
| 637 | static inline int pte_young(pte_t pte) | 681 | static inline int pte_young(pte_t pte) |
| 638 | { | 682 | { |
| 639 | /* A pte is neither young nor old on s/390. The young bit | 683 | #ifdef CONFIG_PGSTE |
| 640 | * is in the storage key. See page_test_and_clear_young for | 684 | if (pte_val(pte) & _PAGE_SWR) |
| 641 | * details. | 685 | return 1; |
| 642 | */ | 686 | #endif |
| 643 | return 0; | 687 | return 0; |
| 644 | } | 688 | } |
| 645 | 689 | ||
| @@ -647,64 +691,30 @@ static inline int pte_young(pte_t pte) | |||
| 647 | * pgd/pmd/pte modification functions | 691 | * pgd/pmd/pte modification functions |
| 648 | */ | 692 | */ |
| 649 | 693 | ||
| 650 | #ifndef __s390x__ | 694 | static inline void pgd_clear(pgd_t *pgd) |
| 651 | |||
| 652 | #define pgd_clear(pgd) do { } while (0) | ||
| 653 | #define pud_clear(pud) do { } while (0) | ||
| 654 | |||
| 655 | #else /* __s390x__ */ | ||
| 656 | |||
| 657 | static inline void pgd_clear_kernel(pgd_t * pgd) | ||
| 658 | { | 695 | { |
| 696 | #ifdef __s390x__ | ||
| 659 | if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2) | 697 | if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2) |
| 660 | pgd_val(*pgd) = _REGION2_ENTRY_EMPTY; | 698 | pgd_val(*pgd) = _REGION2_ENTRY_EMPTY; |
| 699 | #endif | ||
| 661 | } | 700 | } |
| 662 | 701 | ||
| 663 | static inline void pgd_clear(pgd_t * pgd) | 702 | static inline void pud_clear(pud_t *pud) |
| 664 | { | ||
| 665 | pgd_t *shadow = get_shadow_table(pgd); | ||
| 666 | |||
| 667 | pgd_clear_kernel(pgd); | ||
| 668 | if (shadow) | ||
| 669 | pgd_clear_kernel(shadow); | ||
| 670 | } | ||
| 671 | |||
| 672 | static inline void pud_clear_kernel(pud_t *pud) | ||
| 673 | { | 703 | { |
| 704 | #ifdef __s390x__ | ||
| 674 | if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) | 705 | if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) |
| 675 | pud_val(*pud) = _REGION3_ENTRY_EMPTY; | 706 | pud_val(*pud) = _REGION3_ENTRY_EMPTY; |
| 707 | #endif | ||
| 676 | } | 708 | } |
| 677 | 709 | ||
| 678 | static inline void pud_clear(pud_t *pud) | 710 | static inline void pmd_clear(pmd_t *pmdp) |
| 679 | { | ||
| 680 | pud_t *shadow = get_shadow_table(pud); | ||
| 681 | |||
| 682 | pud_clear_kernel(pud); | ||
| 683 | if (shadow) | ||
| 684 | pud_clear_kernel(shadow); | ||
| 685 | } | ||
| 686 | |||
| 687 | #endif /* __s390x__ */ | ||
| 688 | |||
| 689 | static inline void pmd_clear_kernel(pmd_t * pmdp) | ||
| 690 | { | 711 | { |
| 691 | pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; | 712 | pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; |
| 692 | } | 713 | } |
| 693 | 714 | ||
| 694 | static inline void pmd_clear(pmd_t *pmd) | ||
| 695 | { | ||
| 696 | pmd_t *shadow = get_shadow_table(pmd); | ||
| 697 | |||
| 698 | pmd_clear_kernel(pmd); | ||
| 699 | if (shadow) | ||
| 700 | pmd_clear_kernel(shadow); | ||
| 701 | } | ||
| 702 | |||
| 703 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 715 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
| 704 | { | 716 | { |
| 705 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | 717 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; |
| 706 | if (mm->context.noexec) | ||
| 707 | pte_val(ptep[PTRS_PER_PTE]) = _PAGE_TYPE_EMPTY; | ||
| 708 | } | 718 | } |
| 709 | 719 | ||
| 710 | /* | 720 | /* |
| @@ -734,35 +744,27 @@ static inline pte_t pte_mkwrite(pte_t pte) | |||
| 734 | 744 | ||
| 735 | static inline pte_t pte_mkclean(pte_t pte) | 745 | static inline pte_t pte_mkclean(pte_t pte) |
| 736 | { | 746 | { |
| 737 | /* The only user of pte_mkclean is the fork() code. | 747 | #ifdef CONFIG_PGSTE |
| 738 | We must *not* clear the *physical* page dirty bit | 748 | pte_val(pte) &= ~_PAGE_SWC; |
| 739 | just because fork() wants to clear the dirty bit in | 749 | #endif |
| 740 | *one* of the page's mappings. So we just do nothing. */ | ||
| 741 | return pte; | 750 | return pte; |
| 742 | } | 751 | } |
| 743 | 752 | ||
| 744 | static inline pte_t pte_mkdirty(pte_t pte) | 753 | static inline pte_t pte_mkdirty(pte_t pte) |
| 745 | { | 754 | { |
| 746 | /* We do not explicitly set the dirty bit because the | ||
| 747 | * sske instruction is slow. It is faster to let the | ||
| 748 | * next instruction set the dirty bit. | ||
| 749 | */ | ||
| 750 | return pte; | 755 | return pte; |
| 751 | } | 756 | } |
| 752 | 757 | ||
| 753 | static inline pte_t pte_mkold(pte_t pte) | 758 | static inline pte_t pte_mkold(pte_t pte) |
| 754 | { | 759 | { |
| 755 | /* S/390 doesn't keep its dirty/referenced bit in the pte. | 760 | #ifdef CONFIG_PGSTE |
| 756 | * There is no point in clearing the real referenced bit. | 761 | pte_val(pte) &= ~_PAGE_SWR; |
| 757 | */ | 762 | #endif |
| 758 | return pte; | 763 | return pte; |
| 759 | } | 764 | } |
| 760 | 765 | ||
| 761 | static inline pte_t pte_mkyoung(pte_t pte) | 766 | static inline pte_t pte_mkyoung(pte_t pte) |
| 762 | { | 767 | { |
| 763 | /* S/390 doesn't keep its dirty/referenced bit in the pte. | ||
| 764 | * There is no point in setting the real referenced bit. | ||
| 765 | */ | ||
| 766 | return pte; | 768 | return pte; |
| 767 | } | 769 | } |
| 768 | 770 | ||
| @@ -800,62 +802,60 @@ static inline pte_t pte_mkhuge(pte_t pte) | |||
| 800 | } | 802 | } |
| 801 | #endif | 803 | #endif |
| 802 | 804 | ||
| 803 | #ifdef CONFIG_PGSTE | ||
| 804 | /* | 805 | /* |
| 805 | * Get (and clear) the user dirty bit for a PTE. | 806 | * Get (and clear) the user dirty bit for a pte. |
| 806 | */ | 807 | */ |
| 807 | static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm, | 808 | static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm, |
| 808 | pte_t *ptep) | 809 | pte_t *ptep) |
| 809 | { | 810 | { |
| 810 | int dirty; | 811 | pgste_t pgste; |
| 811 | unsigned long *pgste; | 812 | int dirty = 0; |
| 812 | struct page *page; | 813 | |
| 813 | unsigned int skey; | 814 | if (mm_has_pgste(mm)) { |
| 814 | 815 | pgste = pgste_get_lock(ptep); | |
| 815 | if (!mm->context.has_pgste) | 816 | pgste = pgste_update_all(ptep, pgste); |
| 816 | return -EINVAL; | 817 | dirty = !!(pgste_val(pgste) & KVM_UC_BIT); |
| 817 | rcp_lock(ptep); | 818 | pgste_val(pgste) &= ~KVM_UC_BIT; |
| 818 | pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 819 | pgste_set_unlock(ptep, pgste); |
| 819 | page = virt_to_page(pte_val(*ptep)); | 820 | return dirty; |
| 820 | skey = page_get_storage_key(page_to_phys(page)); | ||
| 821 | if (skey & _PAGE_CHANGED) { | ||
| 822 | set_bit_simple(RCP_GC_BIT, pgste); | ||
| 823 | set_bit_simple(KVM_UD_BIT, pgste); | ||
| 824 | } | 821 | } |
| 825 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { | ||
| 826 | SetPageDirty(page); | ||
| 827 | set_bit_simple(KVM_UD_BIT, pgste); | ||
| 828 | } | ||
| 829 | dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste); | ||
| 830 | if (skey & _PAGE_CHANGED) | ||
| 831 | page_clear_dirty(page, 1); | ||
| 832 | rcp_unlock(ptep); | ||
| 833 | return dirty; | 822 | return dirty; |
| 834 | } | 823 | } |
| 835 | #endif | 824 | |
| 825 | /* | ||
| 826 | * Get (and clear) the user referenced bit for a pte. | ||
| 827 | */ | ||
| 828 | static inline int ptep_test_and_clear_user_young(struct mm_struct *mm, | ||
| 829 | pte_t *ptep) | ||
| 830 | { | ||
| 831 | pgste_t pgste; | ||
| 832 | int young = 0; | ||
| 833 | |||
| 834 | if (mm_has_pgste(mm)) { | ||
| 835 | pgste = pgste_get_lock(ptep); | ||
| 836 | pgste = pgste_update_young(ptep, pgste); | ||
| 837 | young = !!(pgste_val(pgste) & KVM_UR_BIT); | ||
| 838 | pgste_val(pgste) &= ~KVM_UR_BIT; | ||
| 839 | pgste_set_unlock(ptep, pgste); | ||
| 840 | } | ||
| 841 | return young; | ||
| 842 | } | ||
| 836 | 843 | ||
| 837 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | 844 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |
| 838 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, | 845 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, |
| 839 | unsigned long addr, pte_t *ptep) | 846 | unsigned long addr, pte_t *ptep) |
| 840 | { | 847 | { |
| 841 | #ifdef CONFIG_PGSTE | 848 | pgste_t pgste; |
| 842 | unsigned long physpage; | 849 | pte_t pte; |
| 843 | int young; | ||
| 844 | unsigned long *pgste; | ||
| 845 | 850 | ||
| 846 | if (!vma->vm_mm->context.has_pgste) | 851 | if (mm_has_pgste(vma->vm_mm)) { |
| 847 | return 0; | 852 | pgste = pgste_get_lock(ptep); |
| 848 | physpage = pte_val(*ptep) & PAGE_MASK; | 853 | pgste = pgste_update_young(ptep, pgste); |
| 849 | pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 854 | pte = *ptep; |
| 850 | 855 | *ptep = pte_mkold(pte); | |
| 851 | young = ((page_get_storage_key(physpage) & _PAGE_REFERENCED) != 0); | 856 | pgste_set_unlock(ptep, pgste); |
| 852 | rcp_lock(ptep); | 857 | return pte_young(pte); |
| 853 | if (young) | 858 | } |
| 854 | set_bit_simple(RCP_GR_BIT, pgste); | ||
| 855 | young |= test_and_clear_bit_simple(RCP_HR_BIT, pgste); | ||
| 856 | rcp_unlock(ptep); | ||
| 857 | return young; | ||
| 858 | #endif | ||
| 859 | return 0; | 859 | return 0; |
| 860 | } | 860 | } |
| 861 | 861 | ||
| @@ -867,10 +867,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma, | |||
| 867 | * On s390 reference bits are in storage key and never in TLB | 867 | * On s390 reference bits are in storage key and never in TLB |
| 868 | * With virtualization we handle the reference bit, without we | 868 | * With virtualization we handle the reference bit, without we |
| 869 | * we can simply return */ | 869 | * we can simply return */ |
| 870 | #ifdef CONFIG_PGSTE | ||
| 871 | return ptep_test_and_clear_young(vma, address, ptep); | 870 | return ptep_test_and_clear_young(vma, address, ptep); |
| 872 | #endif | ||
| 873 | return 0; | ||
| 874 | } | 871 | } |
| 875 | 872 | ||
| 876 | static inline void __ptep_ipte(unsigned long address, pte_t *ptep) | 873 | static inline void __ptep_ipte(unsigned long address, pte_t *ptep) |
| @@ -890,25 +887,6 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep) | |||
| 890 | } | 887 | } |
| 891 | } | 888 | } |
| 892 | 889 | ||
| 893 | static inline void ptep_invalidate(struct mm_struct *mm, | ||
| 894 | unsigned long address, pte_t *ptep) | ||
| 895 | { | ||
| 896 | if (mm->context.has_pgste) { | ||
| 897 | rcp_lock(ptep); | ||
| 898 | __ptep_ipte(address, ptep); | ||
| 899 | ptep_rcp_copy(ptep); | ||
| 900 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
| 901 | rcp_unlock(ptep); | ||
| 902 | return; | ||
| 903 | } | ||
| 904 | __ptep_ipte(address, ptep); | ||
| 905 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
| 906 | if (mm->context.noexec) { | ||
| 907 | __ptep_ipte(address, ptep + PTRS_PER_PTE); | ||
| 908 | pte_val(*(ptep + PTRS_PER_PTE)) = _PAGE_TYPE_EMPTY; | ||
| 909 | } | ||
| 910 | } | ||
| 911 | |||
| 912 | /* | 890 | /* |
| 913 | * This is hard to understand. ptep_get_and_clear and ptep_clear_flush | 891 | * This is hard to understand. ptep_get_and_clear and ptep_clear_flush |
| 914 | * both clear the TLB for the unmapped pte. The reason is that | 892 | * both clear the TLB for the unmapped pte. The reason is that |
| @@ -923,24 +901,72 @@ static inline void ptep_invalidate(struct mm_struct *mm, | |||
| 923 | * is a nop. | 901 | * is a nop. |
| 924 | */ | 902 | */ |
| 925 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | 903 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR |
| 926 | #define ptep_get_and_clear(__mm, __address, __ptep) \ | 904 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, |
| 927 | ({ \ | 905 | unsigned long address, pte_t *ptep) |
| 928 | pte_t __pte = *(__ptep); \ | 906 | { |
| 929 | (__mm)->context.flush_mm = 1; \ | 907 | pgste_t pgste; |
| 930 | if (atomic_read(&(__mm)->context.attach_count) > 1 || \ | 908 | pte_t pte; |
| 931 | (__mm) != current->active_mm) \ | 909 | |
| 932 | ptep_invalidate(__mm, __address, __ptep); \ | 910 | mm->context.flush_mm = 1; |
| 933 | else \ | 911 | if (mm_has_pgste(mm)) |
| 934 | pte_clear((__mm), (__address), (__ptep)); \ | 912 | pgste = pgste_get_lock(ptep); |
| 935 | __pte; \ | 913 | |
| 936 | }) | 914 | pte = *ptep; |
| 915 | if (!mm_exclusive(mm)) | ||
| 916 | __ptep_ipte(address, ptep); | ||
| 917 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
| 918 | |||
| 919 | if (mm_has_pgste(mm)) { | ||
| 920 | pgste = pgste_update_all(&pte, pgste); | ||
| 921 | pgste_set_unlock(ptep, pgste); | ||
| 922 | } | ||
| 923 | return pte; | ||
| 924 | } | ||
| 925 | |||
| 926 | #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION | ||
| 927 | static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, | ||
| 928 | unsigned long address, | ||
| 929 | pte_t *ptep) | ||
| 930 | { | ||
| 931 | pte_t pte; | ||
| 932 | |||
| 933 | mm->context.flush_mm = 1; | ||
| 934 | if (mm_has_pgste(mm)) | ||
| 935 | pgste_get_lock(ptep); | ||
| 936 | |||
| 937 | pte = *ptep; | ||
| 938 | if (!mm_exclusive(mm)) | ||
| 939 | __ptep_ipte(address, ptep); | ||
| 940 | return pte; | ||
| 941 | } | ||
| 942 | |||
| 943 | static inline void ptep_modify_prot_commit(struct mm_struct *mm, | ||
| 944 | unsigned long address, | ||
| 945 | pte_t *ptep, pte_t pte) | ||
| 946 | { | ||
| 947 | *ptep = pte; | ||
| 948 | if (mm_has_pgste(mm)) | ||
| 949 | pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE)); | ||
| 950 | } | ||
| 937 | 951 | ||
| 938 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH | 952 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH |
| 939 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | 953 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, |
| 940 | unsigned long address, pte_t *ptep) | 954 | unsigned long address, pte_t *ptep) |
| 941 | { | 955 | { |
| 942 | pte_t pte = *ptep; | 956 | pgste_t pgste; |
| 943 | ptep_invalidate(vma->vm_mm, address, ptep); | 957 | pte_t pte; |
| 958 | |||
| 959 | if (mm_has_pgste(vma->vm_mm)) | ||
| 960 | pgste = pgste_get_lock(ptep); | ||
| 961 | |||
| 962 | pte = *ptep; | ||
| 963 | __ptep_ipte(address, ptep); | ||
| 964 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
| 965 | |||
| 966 | if (mm_has_pgste(vma->vm_mm)) { | ||
| 967 | pgste = pgste_update_all(&pte, pgste); | ||
| 968 | pgste_set_unlock(ptep, pgste); | ||
| 969 | } | ||
| 944 | return pte; | 970 | return pte; |
| 945 | } | 971 | } |
| 946 | 972 | ||
| @@ -953,76 +979,67 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | |||
| 953 | */ | 979 | */ |
| 954 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL | 980 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL |
| 955 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, | 981 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, |
| 956 | unsigned long addr, | 982 | unsigned long address, |
| 957 | pte_t *ptep, int full) | 983 | pte_t *ptep, int full) |
| 958 | { | 984 | { |
| 959 | pte_t pte = *ptep; | 985 | pgste_t pgste; |
| 986 | pte_t pte; | ||
| 987 | |||
| 988 | if (mm_has_pgste(mm)) | ||
| 989 | pgste = pgste_get_lock(ptep); | ||
| 990 | |||
| 991 | pte = *ptep; | ||
| 992 | if (!full) | ||
| 993 | __ptep_ipte(address, ptep); | ||
| 994 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
| 960 | 995 | ||
| 961 | if (full) | 996 | if (mm_has_pgste(mm)) { |
| 962 | pte_clear(mm, addr, ptep); | 997 | pgste = pgste_update_all(&pte, pgste); |
| 963 | else | 998 | pgste_set_unlock(ptep, pgste); |
| 964 | ptep_invalidate(mm, addr, ptep); | 999 | } |
| 965 | return pte; | 1000 | return pte; |
| 966 | } | 1001 | } |
| 967 | 1002 | ||
| 968 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT | 1003 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT |
| 969 | #define ptep_set_wrprotect(__mm, __addr, __ptep) \ | 1004 | static inline pte_t ptep_set_wrprotect(struct mm_struct *mm, |
| 970 | ({ \ | 1005 | unsigned long address, pte_t *ptep) |
| 971 | pte_t __pte = *(__ptep); \ | 1006 | { |
| 972 | if (pte_write(__pte)) { \ | 1007 | pgste_t pgste; |
| 973 | (__mm)->context.flush_mm = 1; \ | 1008 | pte_t pte = *ptep; |
| 974 | if (atomic_read(&(__mm)->context.attach_count) > 1 || \ | ||
| 975 | (__mm) != current->active_mm) \ | ||
| 976 | ptep_invalidate(__mm, __addr, __ptep); \ | ||
| 977 | set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \ | ||
| 978 | } \ | ||
| 979 | }) | ||
| 980 | 1009 | ||
| 981 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | 1010 | if (pte_write(pte)) { |
| 982 | #define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ | 1011 | mm->context.flush_mm = 1; |
| 983 | ({ \ | 1012 | if (mm_has_pgste(mm)) |
| 984 | int __changed = !pte_same(*(__ptep), __entry); \ | 1013 | pgste = pgste_get_lock(ptep); |
| 985 | if (__changed) { \ | ||
| 986 | ptep_invalidate((__vma)->vm_mm, __addr, __ptep); \ | ||
| 987 | set_pte_at((__vma)->vm_mm, __addr, __ptep, __entry); \ | ||
| 988 | } \ | ||
| 989 | __changed; \ | ||
| 990 | }) | ||
| 991 | 1014 | ||
| 992 | /* | 1015 | if (!mm_exclusive(mm)) |
| 993 | * Test and clear dirty bit in storage key. | 1016 | __ptep_ipte(address, ptep); |
| 994 | * We can't clear the changed bit atomically. This is a potential | 1017 | *ptep = pte_wrprotect(pte); |
| 995 | * race against modification of the referenced bit. This function | ||
| 996 | * should therefore only be called if it is not mapped in any | ||
| 997 | * address space. | ||
| 998 | */ | ||
| 999 | #define __HAVE_ARCH_PAGE_TEST_DIRTY | ||
| 1000 | static inline int page_test_dirty(struct page *page) | ||
| 1001 | { | ||
| 1002 | return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0; | ||
| 1003 | } | ||
| 1004 | 1018 | ||
| 1005 | #define __HAVE_ARCH_PAGE_CLEAR_DIRTY | 1019 | if (mm_has_pgste(mm)) |
| 1006 | static inline void page_clear_dirty(struct page *page, int mapped) | 1020 | pgste_set_unlock(ptep, pgste); |
| 1007 | { | 1021 | } |
| 1008 | page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, mapped); | 1022 | return pte; |
| 1009 | } | 1023 | } |
| 1010 | 1024 | ||
| 1011 | /* | 1025 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS |
| 1012 | * Test and clear referenced bit in storage key. | 1026 | static inline int ptep_set_access_flags(struct vm_area_struct *vma, |
| 1013 | */ | 1027 | unsigned long address, pte_t *ptep, |
| 1014 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | 1028 | pte_t entry, int dirty) |
| 1015 | static inline int page_test_and_clear_young(struct page *page) | ||
| 1016 | { | 1029 | { |
| 1017 | unsigned long physpage = page_to_phys(page); | 1030 | pgste_t pgste; |
| 1018 | int ccode; | 1031 | |
| 1019 | 1032 | if (pte_same(*ptep, entry)) | |
| 1020 | asm volatile( | 1033 | return 0; |
| 1021 | " rrbe 0,%1\n" | 1034 | if (mm_has_pgste(vma->vm_mm)) |
| 1022 | " ipm %0\n" | 1035 | pgste = pgste_get_lock(ptep); |
| 1023 | " srl %0,28\n" | 1036 | |
| 1024 | : "=d" (ccode) : "a" (physpage) : "cc" ); | 1037 | __ptep_ipte(address, ptep); |
| 1025 | return ccode & 2; | 1038 | *ptep = entry; |
| 1039 | |||
| 1040 | if (mm_has_pgste(vma->vm_mm)) | ||
| 1041 | pgste_set_unlock(ptep, pgste); | ||
| 1042 | return 1; | ||
| 1026 | } | 1043 | } |
| 1027 | 1044 | ||
| 1028 | /* | 1045 | /* |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 2c79b6416271..1300c3025334 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
| @@ -84,6 +84,7 @@ struct thread_struct { | |||
| 84 | struct per_event per_event; /* Cause of the last PER trap */ | 84 | struct per_event per_event; /* Cause of the last PER trap */ |
| 85 | /* pfault_wait is used to block the process on a pfault event */ | 85 | /* pfault_wait is used to block the process on a pfault event */ |
| 86 | unsigned long pfault_wait; | 86 | unsigned long pfault_wait; |
| 87 | struct list_head list; | ||
| 87 | }; | 88 | }; |
| 88 | 89 | ||
| 89 | typedef struct thread_struct thread_struct; | 90 | typedef struct thread_struct thread_struct; |
diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h index 29d5d6d4becc..b7a4f2eb0057 100644 --- a/arch/s390/include/asm/tlbflush.h +++ b/arch/s390/include/asm/tlbflush.h | |||
| @@ -50,7 +50,7 @@ static inline void __tlb_flush_full(struct mm_struct *mm) | |||
| 50 | /* | 50 | /* |
| 51 | * If the process only ran on the local cpu, do a local flush. | 51 | * If the process only ran on the local cpu, do a local flush. |
| 52 | */ | 52 | */ |
| 53 | local_cpumask = cpumask_of_cpu(smp_processor_id()); | 53 | cpumask_copy(&local_cpumask, cpumask_of(smp_processor_id())); |
| 54 | if (cpumask_equal(mm_cpumask(mm), &local_cpumask)) | 54 | if (cpumask_equal(mm_cpumask(mm), &local_cpumask)) |
| 55 | __tlb_flush_local(); | 55 | __tlb_flush_local(); |
| 56 | else | 56 | else |
| @@ -80,16 +80,11 @@ static inline void __tlb_flush_mm(struct mm_struct * mm) | |||
| 80 | * on all cpus instead of doing a local flush if the mm | 80 | * on all cpus instead of doing a local flush if the mm |
| 81 | * only ran on the local cpu. | 81 | * only ran on the local cpu. |
| 82 | */ | 82 | */ |
| 83 | if (MACHINE_HAS_IDTE) { | 83 | if (MACHINE_HAS_IDTE) |
| 84 | if (mm->context.noexec) | ||
| 85 | __tlb_flush_idte((unsigned long) | ||
| 86 | get_shadow_table(mm->pgd) | | ||
| 87 | mm->context.asce_bits); | ||
| 88 | __tlb_flush_idte((unsigned long) mm->pgd | | 84 | __tlb_flush_idte((unsigned long) mm->pgd | |
| 89 | mm->context.asce_bits); | 85 | mm->context.asce_bits); |
| 90 | return; | 86 | else |
| 91 | } | 87 | __tlb_flush_full(mm); |
| 92 | __tlb_flush_full(mm); | ||
| 93 | } | 88 | } |
| 94 | 89 | ||
| 95 | static inline void __tlb_flush_mm_cond(struct mm_struct * mm) | 90 | static inline void __tlb_flush_mm_cond(struct mm_struct * mm) |
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index e82152572377..9208e69245a0 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h | |||
| @@ -385,6 +385,7 @@ | |||
| 385 | 385 | ||
| 386 | /* Ignore system calls that are also reachable via sys_socket */ | 386 | /* Ignore system calls that are also reachable via sys_socket */ |
| 387 | #define __IGNORE_recvmmsg | 387 | #define __IGNORE_recvmmsg |
| 388 | #define __IGNORE_sendmmsg | ||
| 388 | 389 | ||
| 389 | #define __ARCH_WANT_IPC_PARSE_VERSION | 390 | #define __ARCH_WANT_IPC_PARSE_VERSION |
| 390 | #define __ARCH_WANT_OLD_READDIR | 391 | #define __ARCH_WANT_OLD_READDIR |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index fe03c140002a..edfbd17d7082 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
| @@ -124,13 +124,11 @@ int main(void) | |||
| 124 | DEFINE(__LC_LAST_UPDATE_TIMER, offsetof(struct _lowcore, last_update_timer)); | 124 | DEFINE(__LC_LAST_UPDATE_TIMER, offsetof(struct _lowcore, last_update_timer)); |
| 125 | DEFINE(__LC_LAST_UPDATE_CLOCK, offsetof(struct _lowcore, last_update_clock)); | 125 | DEFINE(__LC_LAST_UPDATE_CLOCK, offsetof(struct _lowcore, last_update_clock)); |
| 126 | DEFINE(__LC_CURRENT, offsetof(struct _lowcore, current_task)); | 126 | DEFINE(__LC_CURRENT, offsetof(struct _lowcore, current_task)); |
| 127 | DEFINE(__LC_CURRENT_PID, offsetof(struct _lowcore, current_pid)); | ||
| 127 | DEFINE(__LC_THREAD_INFO, offsetof(struct _lowcore, thread_info)); | 128 | DEFINE(__LC_THREAD_INFO, offsetof(struct _lowcore, thread_info)); |
| 128 | DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack)); | 129 | DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack)); |
| 129 | DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack)); | 130 | DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack)); |
| 130 | DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack)); | 131 | DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack)); |
| 131 | DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce)); | ||
| 132 | DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); | ||
| 133 | DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce)); | ||
| 134 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); | 132 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); |
| 135 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); | 133 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); |
| 136 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); | 134 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1b67fc6ebdc2..0476174dfff5 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
| @@ -212,6 +212,7 @@ __switch_to: | |||
| 212 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 | 212 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 |
| 213 | lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 213 | lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
| 214 | st %r3,__LC_CURRENT # store task struct of next | 214 | st %r3,__LC_CURRENT # store task struct of next |
| 215 | mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next | ||
| 215 | st %r5,__LC_THREAD_INFO # store thread info of next | 216 | st %r5,__LC_THREAD_INFO # store thread info of next |
| 216 | ahi %r5,STACK_SIZE # end of kernel stack of next | 217 | ahi %r5,STACK_SIZE # end of kernel stack of next |
| 217 | st %r5,__LC_KERNEL_STACK # store end of kernel stack | 218 | st %r5,__LC_KERNEL_STACK # store end of kernel stack |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 9fd864563499..d61967e2eab0 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
| @@ -220,6 +220,7 @@ __switch_to: | |||
| 220 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 | 220 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 |
| 221 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 221 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
| 222 | stg %r3,__LC_CURRENT # store task struct of next | 222 | stg %r3,__LC_CURRENT # store task struct of next |
| 223 | mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next | ||
| 223 | stg %r5,__LC_THREAD_INFO # store thread info of next | 224 | stg %r5,__LC_THREAD_INFO # store thread info of next |
| 224 | aghi %r5,STACK_SIZE # end of kernel stack of next | 225 | aghi %r5,STACK_SIZE # end of kernel stack of next |
| 225 | stg %r5,__LC_KERNEL_STACK # store end of kernel stack | 226 | stg %r5,__LC_KERNEL_STACK # store end of kernel stack |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index ea5099c9709c..e204f9597aaf 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
| @@ -32,6 +32,7 @@ static const struct irq_class intrclass_names[] = { | |||
| 32 | {.name = "VRT", .desc = "[EXT] Virtio" }, | 32 | {.name = "VRT", .desc = "[EXT] Virtio" }, |
| 33 | {.name = "SCP", .desc = "[EXT] Service Call" }, | 33 | {.name = "SCP", .desc = "[EXT] Service Call" }, |
| 34 | {.name = "IUC", .desc = "[EXT] IUCV" }, | 34 | {.name = "IUC", .desc = "[EXT] IUCV" }, |
| 35 | {.name = "CPM", .desc = "[EXT] CPU Measurement" }, | ||
| 35 | {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, | 36 | {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, |
| 36 | {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, | 37 | {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, |
| 37 | {.name = "DAS", .desc = "[I/O] DASD" }, | 38 | {.name = "DAS", .desc = "[I/O] DASD" }, |
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index a895e69379f7..541a7509faeb 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
| @@ -9,41 +9,26 @@ | |||
| 9 | 9 | ||
| 10 | #include <linux/compiler.h> | 10 | #include <linux/compiler.h> |
| 11 | #include <linux/cpu.h> | 11 | #include <linux/cpu.h> |
| 12 | #include <linux/errno.h> | ||
| 13 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
| 14 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 15 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
| 16 | #include <linux/fs.h> | ||
| 17 | #include <linux/smp.h> | 15 | #include <linux/smp.h> |
| 18 | #include <linux/stddef.h> | ||
| 19 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 20 | #include <linux/unistd.h> | ||
| 21 | #include <linux/ptrace.h> | ||
| 22 | #include <linux/vmalloc.h> | ||
| 23 | #include <linux/user.h> | ||
| 24 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
| 25 | #include <linux/delay.h> | ||
| 26 | #include <linux/reboot.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/notifier.h> | ||
| 30 | #include <linux/tick.h> | 18 | #include <linux/tick.h> |
| 31 | #include <linux/elfcore.h> | ||
| 32 | #include <linux/kernel_stat.h> | ||
| 33 | #include <linux/personality.h> | 19 | #include <linux/personality.h> |
| 34 | #include <linux/syscalls.h> | 20 | #include <linux/syscalls.h> |
| 35 | #include <linux/compat.h> | 21 | #include <linux/compat.h> |
| 36 | #include <linux/kprobes.h> | 22 | #include <linux/kprobes.h> |
| 37 | #include <linux/random.h> | 23 | #include <linux/random.h> |
| 38 | #include <asm/compat.h> | 24 | #include <linux/module.h> |
| 39 | #include <asm/uaccess.h> | ||
| 40 | #include <asm/pgtable.h> | ||
| 41 | #include <asm/system.h> | 25 | #include <asm/system.h> |
| 42 | #include <asm/io.h> | 26 | #include <asm/io.h> |
| 43 | #include <asm/processor.h> | 27 | #include <asm/processor.h> |
| 44 | #include <asm/irq.h> | 28 | #include <asm/irq.h> |
| 45 | #include <asm/timer.h> | 29 | #include <asm/timer.h> |
| 46 | #include <asm/nmi.h> | 30 | #include <asm/nmi.h> |
| 31 | #include <asm/compat.h> | ||
| 47 | #include <asm/smp.h> | 32 | #include <asm/smp.h> |
| 48 | #include "entry.h" | 33 | #include "entry.h" |
| 49 | 34 | ||
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index f5434d1ecb31..0c35dee10b00 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
| @@ -305,8 +305,7 @@ static int set_amode_and_uaccess(unsigned long user_amode, | |||
| 305 | */ | 305 | */ |
| 306 | static int __init early_parse_switch_amode(char *p) | 306 | static int __init early_parse_switch_amode(char *p) |
| 307 | { | 307 | { |
| 308 | if (user_mode != SECONDARY_SPACE_MODE) | 308 | user_mode = PRIMARY_SPACE_MODE; |
| 309 | user_mode = PRIMARY_SPACE_MODE; | ||
| 310 | return 0; | 309 | return 0; |
| 311 | } | 310 | } |
| 312 | early_param("switch_amode", early_parse_switch_amode); | 311 | early_param("switch_amode", early_parse_switch_amode); |
| @@ -315,10 +314,6 @@ static int __init early_parse_user_mode(char *p) | |||
| 315 | { | 314 | { |
| 316 | if (p && strcmp(p, "primary") == 0) | 315 | if (p && strcmp(p, "primary") == 0) |
| 317 | user_mode = PRIMARY_SPACE_MODE; | 316 | user_mode = PRIMARY_SPACE_MODE; |
| 318 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
| 319 | else if (p && strcmp(p, "secondary") == 0) | ||
| 320 | user_mode = SECONDARY_SPACE_MODE; | ||
| 321 | #endif | ||
| 322 | else if (!p || strcmp(p, "home") == 0) | 317 | else if (!p || strcmp(p, "home") == 0) |
| 323 | user_mode = HOME_SPACE_MODE; | 318 | user_mode = HOME_SPACE_MODE; |
| 324 | else | 319 | else |
| @@ -327,31 +322,9 @@ static int __init early_parse_user_mode(char *p) | |||
| 327 | } | 322 | } |
| 328 | early_param("user_mode", early_parse_user_mode); | 323 | early_param("user_mode", early_parse_user_mode); |
| 329 | 324 | ||
| 330 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
| 331 | /* | ||
| 332 | * Enable execute protection? | ||
| 333 | */ | ||
| 334 | static int __init early_parse_noexec(char *p) | ||
| 335 | { | ||
| 336 | if (!strncmp(p, "off", 3)) | ||
| 337 | return 0; | ||
| 338 | user_mode = SECONDARY_SPACE_MODE; | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | early_param("noexec", early_parse_noexec); | ||
| 342 | #endif /* CONFIG_S390_EXEC_PROTECT */ | ||
| 343 | |||
| 344 | static void setup_addressing_mode(void) | 325 | static void setup_addressing_mode(void) |
| 345 | { | 326 | { |
| 346 | if (user_mode == SECONDARY_SPACE_MODE) { | 327 | if (user_mode == PRIMARY_SPACE_MODE) { |
| 347 | if (set_amode_and_uaccess(PSW_ASC_SECONDARY, | ||
| 348 | PSW32_ASC_SECONDARY)) | ||
| 349 | pr_info("Execute protection active, " | ||
| 350 | "mvcos available\n"); | ||
| 351 | else | ||
| 352 | pr_info("Execute protection active, " | ||
| 353 | "mvcos not available\n"); | ||
| 354 | } else if (user_mode == PRIMARY_SPACE_MODE) { | ||
| 355 | if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY)) | 328 | if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY)) |
| 356 | pr_info("Address spaces switched, " | 329 | pr_info("Address spaces switched, " |
| 357 | "mvcos available\n"); | 330 | "mvcos available\n"); |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 63c7d9ff220d..f8e85ecbc459 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
| @@ -335,7 +335,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) | |||
| 335 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | 335 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; |
| 336 | if (!cpu_stopped(logical_cpu)) | 336 | if (!cpu_stopped(logical_cpu)) |
| 337 | continue; | 337 | continue; |
| 338 | cpu_set(logical_cpu, cpu_present_map); | 338 | set_cpu_present(logical_cpu, true); |
| 339 | smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; | 339 | smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; |
| 340 | logical_cpu = cpumask_next(logical_cpu, &avail); | 340 | logical_cpu = cpumask_next(logical_cpu, &avail); |
| 341 | if (logical_cpu >= nr_cpu_ids) | 341 | if (logical_cpu >= nr_cpu_ids) |
| @@ -367,7 +367,7 @@ static int smp_rescan_cpus_sclp(cpumask_t avail) | |||
| 367 | continue; | 367 | continue; |
| 368 | __cpu_logical_map[logical_cpu] = cpu_id; | 368 | __cpu_logical_map[logical_cpu] = cpu_id; |
| 369 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | 369 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; |
| 370 | cpu_set(logical_cpu, cpu_present_map); | 370 | set_cpu_present(logical_cpu, true); |
| 371 | if (cpu >= info->configured) | 371 | if (cpu >= info->configured) |
| 372 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; | 372 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; |
| 373 | else | 373 | else |
| @@ -385,7 +385,7 @@ static int __smp_rescan_cpus(void) | |||
| 385 | { | 385 | { |
| 386 | cpumask_t avail; | 386 | cpumask_t avail; |
| 387 | 387 | ||
| 388 | cpus_xor(avail, cpu_possible_map, cpu_present_map); | 388 | cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask); |
| 389 | if (smp_use_sigp_detection) | 389 | if (smp_use_sigp_detection) |
| 390 | return smp_rescan_cpus_sigp(avail); | 390 | return smp_rescan_cpus_sigp(avail); |
| 391 | else | 391 | else |
| @@ -467,7 +467,7 @@ int __cpuinit start_secondary(void *cpuvoid) | |||
| 467 | notify_cpu_starting(smp_processor_id()); | 467 | notify_cpu_starting(smp_processor_id()); |
| 468 | /* Mark this cpu as online */ | 468 | /* Mark this cpu as online */ |
| 469 | ipi_call_lock(); | 469 | ipi_call_lock(); |
| 470 | cpu_set(smp_processor_id(), cpu_online_map); | 470 | set_cpu_online(smp_processor_id(), true); |
| 471 | ipi_call_unlock(); | 471 | ipi_call_unlock(); |
| 472 | /* Switch on interrupts */ | 472 | /* Switch on interrupts */ |
| 473 | local_irq_enable(); | 473 | local_irq_enable(); |
| @@ -644,7 +644,7 @@ int __cpu_disable(void) | |||
| 644 | struct ec_creg_mask_parms cr_parms; | 644 | struct ec_creg_mask_parms cr_parms; |
| 645 | int cpu = smp_processor_id(); | 645 | int cpu = smp_processor_id(); |
| 646 | 646 | ||
| 647 | cpu_clear(cpu, cpu_online_map); | 647 | set_cpu_online(cpu, false); |
| 648 | 648 | ||
| 649 | /* Disable pfault pseudo page faults on this cpu. */ | 649 | /* Disable pfault pseudo page faults on this cpu. */ |
| 650 | pfault_fini(); | 650 | pfault_fini(); |
| @@ -654,8 +654,8 @@ int __cpu_disable(void) | |||
| 654 | 654 | ||
| 655 | /* disable all external interrupts */ | 655 | /* disable all external interrupts */ |
| 656 | cr_parms.orvals[0] = 0; | 656 | cr_parms.orvals[0] = 0; |
| 657 | cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 | | 657 | cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 11 | |
| 658 | 1 << 11 | 1 << 10 | 1 << 6 | 1 << 4); | 658 | 1 << 10 | 1 << 9 | 1 << 6 | 1 << 4); |
| 659 | /* disable all I/O interrupts */ | 659 | /* disable all I/O interrupts */ |
| 660 | cr_parms.orvals[6] = 0; | 660 | cr_parms.orvals[6] = 0; |
| 661 | cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 | | 661 | cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 | |
| @@ -681,7 +681,7 @@ void __cpu_die(unsigned int cpu) | |||
| 681 | atomic_dec(&init_mm.context.attach_count); | 681 | atomic_dec(&init_mm.context.attach_count); |
| 682 | } | 682 | } |
| 683 | 683 | ||
| 684 | void cpu_die(void) | 684 | void __noreturn cpu_die(void) |
| 685 | { | 685 | { |
| 686 | idle_task_exit(); | 686 | idle_task_exit(); |
| 687 | while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) | 687 | while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) |
| @@ -738,8 +738,8 @@ void __init smp_prepare_boot_cpu(void) | |||
| 738 | BUG_ON(smp_processor_id() != 0); | 738 | BUG_ON(smp_processor_id() != 0); |
| 739 | 739 | ||
| 740 | current_thread_info()->cpu = 0; | 740 | current_thread_info()->cpu = 0; |
| 741 | cpu_set(0, cpu_present_map); | 741 | set_cpu_present(0, true); |
| 742 | cpu_set(0, cpu_online_map); | 742 | set_cpu_online(0, true); |
| 743 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; | 743 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; |
| 744 | current_set[0] = current; | 744 | current_set[0] = current; |
| 745 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; | 745 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; |
| @@ -1016,21 +1016,21 @@ int __ref smp_rescan_cpus(void) | |||
| 1016 | 1016 | ||
| 1017 | get_online_cpus(); | 1017 | get_online_cpus(); |
| 1018 | mutex_lock(&smp_cpu_state_mutex); | 1018 | mutex_lock(&smp_cpu_state_mutex); |
| 1019 | newcpus = cpu_present_map; | 1019 | cpumask_copy(&newcpus, cpu_present_mask); |
| 1020 | rc = __smp_rescan_cpus(); | 1020 | rc = __smp_rescan_cpus(); |
| 1021 | if (rc) | 1021 | if (rc) |
| 1022 | goto out; | 1022 | goto out; |
| 1023 | cpus_andnot(newcpus, cpu_present_map, newcpus); | 1023 | cpumask_andnot(&newcpus, cpu_present_mask, &newcpus); |
| 1024 | for_each_cpu_mask(cpu, newcpus) { | 1024 | for_each_cpu(cpu, &newcpus) { |
| 1025 | rc = smp_add_present_cpu(cpu); | 1025 | rc = smp_add_present_cpu(cpu); |
| 1026 | if (rc) | 1026 | if (rc) |
| 1027 | cpu_clear(cpu, cpu_present_map); | 1027 | set_cpu_present(cpu, false); |
| 1028 | } | 1028 | } |
| 1029 | rc = 0; | 1029 | rc = 0; |
| 1030 | out: | 1030 | out: |
| 1031 | mutex_unlock(&smp_cpu_state_mutex); | 1031 | mutex_unlock(&smp_cpu_state_mutex); |
| 1032 | put_online_cpus(); | 1032 | put_online_cpus(); |
| 1033 | if (!cpus_empty(newcpus)) | 1033 | if (!cpumask_empty(&newcpus)) |
| 1034 | topology_schedule_update(); | 1034 | topology_schedule_update(); |
| 1035 | return rc; | 1035 | return rc; |
| 1036 | } | 1036 | } |
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 87be655557aa..a59557f1fb5f 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
| @@ -810,7 +810,7 @@ static int etr_sync_clock_stop(struct etr_aib *aib, int port) | |||
| 810 | etr_sync.etr_port = port; | 810 | etr_sync.etr_port = port; |
| 811 | get_online_cpus(); | 811 | get_online_cpus(); |
| 812 | atomic_set(&etr_sync.cpus, num_online_cpus() - 1); | 812 | atomic_set(&etr_sync.cpus, num_online_cpus() - 1); |
| 813 | rc = stop_machine(etr_sync_clock, &etr_sync, &cpu_online_map); | 813 | rc = stop_machine(etr_sync_clock, &etr_sync, cpu_online_mask); |
| 814 | put_online_cpus(); | 814 | put_online_cpus(); |
| 815 | return rc; | 815 | return rc; |
| 816 | } | 816 | } |
| @@ -1579,7 +1579,7 @@ static void stp_work_fn(struct work_struct *work) | |||
| 1579 | memset(&stp_sync, 0, sizeof(stp_sync)); | 1579 | memset(&stp_sync, 0, sizeof(stp_sync)); |
| 1580 | get_online_cpus(); | 1580 | get_online_cpus(); |
| 1581 | atomic_set(&stp_sync.cpus, num_online_cpus() - 1); | 1581 | atomic_set(&stp_sync.cpus, num_online_cpus() - 1); |
| 1582 | stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); | 1582 | stop_machine(stp_sync_clock, &stp_sync, cpu_online_mask); |
| 1583 | put_online_cpus(); | 1583 | put_online_cpus(); |
| 1584 | 1584 | ||
| 1585 | if (!check_sync_clock()) | 1585 | if (!check_sync_clock()) |
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 94b06c31fc8a..2eafb8c7a746 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
| @@ -52,20 +52,20 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) | |||
| 52 | { | 52 | { |
| 53 | cpumask_t mask; | 53 | cpumask_t mask; |
| 54 | 54 | ||
| 55 | cpus_clear(mask); | 55 | cpumask_clear(&mask); |
| 56 | if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) { | 56 | if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) { |
| 57 | cpumask_copy(&mask, cpumask_of(cpu)); | 57 | cpumask_copy(&mask, cpumask_of(cpu)); |
| 58 | return mask; | 58 | return mask; |
| 59 | } | 59 | } |
| 60 | while (info) { | 60 | while (info) { |
| 61 | if (cpu_isset(cpu, info->mask)) { | 61 | if (cpumask_test_cpu(cpu, &info->mask)) { |
| 62 | mask = info->mask; | 62 | mask = info->mask; |
| 63 | break; | 63 | break; |
| 64 | } | 64 | } |
| 65 | info = info->next; | 65 | info = info->next; |
| 66 | } | 66 | } |
| 67 | if (cpus_empty(mask)) | 67 | if (cpumask_empty(&mask)) |
| 68 | mask = cpumask_of_cpu(cpu); | 68 | cpumask_copy(&mask, cpumask_of(cpu)); |
| 69 | return mask; | 69 | return mask; |
| 70 | } | 70 | } |
| 71 | 71 | ||
| @@ -85,10 +85,10 @@ static void add_cpus_to_mask(struct topology_cpu *tl_cpu, | |||
| 85 | if (cpu_logical_map(lcpu) != rcpu) | 85 | if (cpu_logical_map(lcpu) != rcpu) |
| 86 | continue; | 86 | continue; |
| 87 | #ifdef CONFIG_SCHED_BOOK | 87 | #ifdef CONFIG_SCHED_BOOK |
| 88 | cpu_set(lcpu, book->mask); | 88 | cpumask_set_cpu(lcpu, &book->mask); |
| 89 | cpu_book_id[lcpu] = book->id; | 89 | cpu_book_id[lcpu] = book->id; |
| 90 | #endif | 90 | #endif |
| 91 | cpu_set(lcpu, core->mask); | 91 | cpumask_set_cpu(lcpu, &core->mask); |
| 92 | cpu_core_id[lcpu] = core->id; | 92 | cpu_core_id[lcpu] = core->id; |
| 93 | smp_cpu_polarization[lcpu] = tl_cpu->pp; | 93 | smp_cpu_polarization[lcpu] = tl_cpu->pp; |
| 94 | } | 94 | } |
| @@ -101,13 +101,13 @@ static void clear_masks(void) | |||
| 101 | 101 | ||
| 102 | info = &core_info; | 102 | info = &core_info; |
| 103 | while (info) { | 103 | while (info) { |
| 104 | cpus_clear(info->mask); | 104 | cpumask_clear(&info->mask); |
| 105 | info = info->next; | 105 | info = info->next; |
| 106 | } | 106 | } |
| 107 | #ifdef CONFIG_SCHED_BOOK | 107 | #ifdef CONFIG_SCHED_BOOK |
| 108 | info = &book_info; | 108 | info = &book_info; |
| 109 | while (info) { | 109 | while (info) { |
| 110 | cpus_clear(info->mask); | 110 | cpumask_clear(&info->mask); |
| 111 | info = info->next; | 111 | info = info->next; |
| 112 | } | 112 | } |
| 113 | #endif | 113 | #endif |
diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile index d13e8755a8cc..8ad2b34ad151 100644 --- a/arch/s390/kernel/vdso32/Makefile +++ b/arch/s390/kernel/vdso32/Makefile | |||
| @@ -22,6 +22,9 @@ obj-y += vdso32_wrapper.o | |||
| 22 | extra-y += vdso32.lds | 22 | extra-y += vdso32.lds |
| 23 | CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) | 23 | CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) |
| 24 | 24 | ||
| 25 | # Disable gcov profiling for VDSO code | ||
| 26 | GCOV_PROFILE := n | ||
| 27 | |||
| 25 | # Force dependency (incbin is bad) | 28 | # Force dependency (incbin is bad) |
| 26 | $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so | 29 | $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so |
| 27 | 30 | ||
diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile index 449352dda9cd..2a8ddfd12a5b 100644 --- a/arch/s390/kernel/vdso64/Makefile +++ b/arch/s390/kernel/vdso64/Makefile | |||
| @@ -22,6 +22,9 @@ obj-y += vdso64_wrapper.o | |||
| 22 | extra-y += vdso64.lds | 22 | extra-y += vdso64.lds |
| 23 | CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) | 23 | CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) |
| 24 | 24 | ||
| 25 | # Disable gcov profiling for VDSO code | ||
| 26 | GCOV_PROFILE := n | ||
| 27 | |||
| 25 | # Force dependency (incbin is bad) | 28 | # Force dependency (incbin is bad) |
| 26 | $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so | 29 | $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so |
| 27 | 30 | ||
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 3cc95dd0a3a6..075ddada4911 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c | |||
| @@ -412,6 +412,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long | |||
| 412 | struct dcss_segment *seg; | 412 | struct dcss_segment *seg; |
| 413 | int rc, diag_cc; | 413 | int rc, diag_cc; |
| 414 | 414 | ||
| 415 | start_addr = end_addr = 0; | ||
| 415 | seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA); | 416 | seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA); |
| 416 | if (seg == NULL) { | 417 | if (seg == NULL) { |
| 417 | rc = -ENOMEM; | 418 | rc = -ENOMEM; |
| @@ -573,6 +574,7 @@ segment_modify_shared (char *name, int do_nonshared) | |||
| 573 | unsigned long start_addr, end_addr, dummy; | 574 | unsigned long start_addr, end_addr, dummy; |
| 574 | int rc, diag_cc; | 575 | int rc, diag_cc; |
| 575 | 576 | ||
| 577 | start_addr = end_addr = 0; | ||
| 576 | mutex_lock(&dcss_lock); | 578 | mutex_lock(&dcss_lock); |
| 577 | seg = segment_by_name (name); | 579 | seg = segment_by_name (name); |
| 578 | if (seg == NULL) { | 580 | if (seg == NULL) { |
| @@ -681,8 +683,6 @@ void | |||
| 681 | segment_save(char *name) | 683 | segment_save(char *name) |
| 682 | { | 684 | { |
| 683 | struct dcss_segment *seg; | 685 | struct dcss_segment *seg; |
| 684 | int startpfn = 0; | ||
| 685 | int endpfn = 0; | ||
| 686 | char cmd1[160]; | 686 | char cmd1[160]; |
| 687 | char cmd2[80]; | 687 | char cmd2[80]; |
| 688 | int i, response; | 688 | int i, response; |
| @@ -698,8 +698,6 @@ segment_save(char *name) | |||
| 698 | goto out; | 698 | goto out; |
| 699 | } | 699 | } |
| 700 | 700 | ||
| 701 | startpfn = seg->start_addr >> PAGE_SHIFT; | ||
| 702 | endpfn = (seg->end) >> PAGE_SHIFT; | ||
| 703 | sprintf(cmd1, "DEFSEG %s", name); | 701 | sprintf(cmd1, "DEFSEG %s", name); |
| 704 | for (i=0; i<seg->segcnt; i++) { | 702 | for (i=0; i<seg->segcnt; i++) { |
| 705 | sprintf(cmd1+strlen(cmd1), " %lX-%lX %s", | 703 | sprintf(cmd1+strlen(cmd1), " %lX-%lX %s", |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index ab988135e5c6..a0f9e730f26a 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
| @@ -225,33 +225,6 @@ static noinline void do_sigbus(struct pt_regs *regs, long int_code, | |||
| 225 | force_sig_info(SIGBUS, &si, tsk); | 225 | force_sig_info(SIGBUS, &si, tsk); |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
| 229 | static noinline int signal_return(struct pt_regs *regs, long int_code, | ||
| 230 | unsigned long trans_exc_code) | ||
| 231 | { | ||
| 232 | u16 instruction; | ||
| 233 | int rc; | ||
| 234 | |||
| 235 | rc = __get_user(instruction, (u16 __user *) regs->psw.addr); | ||
| 236 | |||
| 237 | if (!rc && instruction == 0x0a77) { | ||
| 238 | clear_tsk_thread_flag(current, TIF_PER_TRAP); | ||
| 239 | if (is_compat_task()) | ||
| 240 | sys32_sigreturn(); | ||
| 241 | else | ||
| 242 | sys_sigreturn(); | ||
| 243 | } else if (!rc && instruction == 0x0aad) { | ||
| 244 | clear_tsk_thread_flag(current, TIF_PER_TRAP); | ||
| 245 | if (is_compat_task()) | ||
| 246 | sys32_rt_sigreturn(); | ||
| 247 | else | ||
| 248 | sys_rt_sigreturn(); | ||
| 249 | } else | ||
| 250 | do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code); | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | #endif /* CONFIG_S390_EXEC_PROTECT */ | ||
| 254 | |||
| 255 | static noinline void do_fault_error(struct pt_regs *regs, long int_code, | 228 | static noinline void do_fault_error(struct pt_regs *regs, long int_code, |
| 256 | unsigned long trans_exc_code, int fault) | 229 | unsigned long trans_exc_code, int fault) |
| 257 | { | 230 | { |
| @@ -259,13 +232,6 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code, | |||
| 259 | 232 | ||
| 260 | switch (fault) { | 233 | switch (fault) { |
| 261 | case VM_FAULT_BADACCESS: | 234 | case VM_FAULT_BADACCESS: |
| 262 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
| 263 | if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY && | ||
| 264 | (trans_exc_code & 3) == 0) { | ||
| 265 | signal_return(regs, int_code, trans_exc_code); | ||
| 266 | break; | ||
| 267 | } | ||
| 268 | #endif /* CONFIG_S390_EXEC_PROTECT */ | ||
| 269 | case VM_FAULT_BADMAP: | 235 | case VM_FAULT_BADMAP: |
| 270 | /* Bad memory access. Check if it is kernel or user space. */ | 236 | /* Bad memory access. Check if it is kernel or user space. */ |
| 271 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 237 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
| @@ -414,11 +380,6 @@ void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code, | |||
| 414 | int access, fault; | 380 | int access, fault; |
| 415 | 381 | ||
| 416 | access = VM_READ | VM_EXEC | VM_WRITE; | 382 | access = VM_READ | VM_EXEC | VM_WRITE; |
| 417 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
| 418 | if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY && | ||
| 419 | (trans_exc_code & 3) == 0) | ||
| 420 | access = VM_EXEC; | ||
| 421 | #endif | ||
| 422 | fault = do_exception(regs, access, trans_exc_code); | 383 | fault = do_exception(regs, access, trans_exc_code); |
| 423 | if (unlikely(fault)) | 384 | if (unlikely(fault)) |
| 424 | do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault); | 385 | do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault); |
| @@ -491,22 +452,28 @@ static int __init nopfault(char *str) | |||
| 491 | 452 | ||
| 492 | __setup("nopfault", nopfault); | 453 | __setup("nopfault", nopfault); |
| 493 | 454 | ||
| 494 | typedef struct { | 455 | struct pfault_refbk { |
| 495 | __u16 refdiagc; | 456 | u16 refdiagc; |
| 496 | __u16 reffcode; | 457 | u16 reffcode; |
| 497 | __u16 refdwlen; | 458 | u16 refdwlen; |
| 498 | __u16 refversn; | 459 | u16 refversn; |
| 499 | __u64 refgaddr; | 460 | u64 refgaddr; |
| 500 | __u64 refselmk; | 461 | u64 refselmk; |
| 501 | __u64 refcmpmk; | 462 | u64 refcmpmk; |
| 502 | __u64 reserved; | 463 | u64 reserved; |
| 503 | } __attribute__ ((packed, aligned(8))) pfault_refbk_t; | 464 | } __attribute__ ((packed, aligned(8))); |
| 504 | 465 | ||
| 505 | int pfault_init(void) | 466 | int pfault_init(void) |
| 506 | { | 467 | { |
| 507 | pfault_refbk_t refbk = | 468 | struct pfault_refbk refbk = { |
| 508 | { 0x258, 0, 5, 2, __LC_CURRENT, 1ULL << 48, 1ULL << 48, | 469 | .refdiagc = 0x258, |
| 509 | __PF_RES_FIELD }; | 470 | .reffcode = 0, |
| 471 | .refdwlen = 5, | ||
| 472 | .refversn = 2, | ||
| 473 | .refgaddr = __LC_CURRENT_PID, | ||
| 474 | .refselmk = 1ULL << 48, | ||
| 475 | .refcmpmk = 1ULL << 48, | ||
| 476 | .reserved = __PF_RES_FIELD }; | ||
| 510 | int rc; | 477 | int rc; |
| 511 | 478 | ||
| 512 | if (!MACHINE_IS_VM || pfault_disable) | 479 | if (!MACHINE_IS_VM || pfault_disable) |
| @@ -524,8 +491,12 @@ int pfault_init(void) | |||
| 524 | 491 | ||
| 525 | void pfault_fini(void) | 492 | void pfault_fini(void) |
| 526 | { | 493 | { |
| 527 | pfault_refbk_t refbk = | 494 | struct pfault_refbk refbk = { |
| 528 | { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; | 495 | .refdiagc = 0x258, |
| 496 | .reffcode = 1, | ||
| 497 | .refdwlen = 5, | ||
| 498 | .refversn = 2, | ||
| 499 | }; | ||
| 529 | 500 | ||
| 530 | if (!MACHINE_IS_VM || pfault_disable) | 501 | if (!MACHINE_IS_VM || pfault_disable) |
| 531 | return; | 502 | return; |
| @@ -537,11 +508,15 @@ void pfault_fini(void) | |||
| 537 | : : "a" (&refbk), "m" (refbk) : "cc"); | 508 | : : "a" (&refbk), "m" (refbk) : "cc"); |
| 538 | } | 509 | } |
| 539 | 510 | ||
| 511 | static DEFINE_SPINLOCK(pfault_lock); | ||
| 512 | static LIST_HEAD(pfault_list); | ||
| 513 | |||
| 540 | static void pfault_interrupt(unsigned int ext_int_code, | 514 | static void pfault_interrupt(unsigned int ext_int_code, |
| 541 | unsigned int param32, unsigned long param64) | 515 | unsigned int param32, unsigned long param64) |
| 542 | { | 516 | { |
| 543 | struct task_struct *tsk; | 517 | struct task_struct *tsk; |
| 544 | __u16 subcode; | 518 | __u16 subcode; |
| 519 | pid_t pid; | ||
| 545 | 520 | ||
| 546 | /* | 521 | /* |
| 547 | * Get the external interruption subcode & pfault | 522 | * Get the external interruption subcode & pfault |
| @@ -553,44 +528,79 @@ static void pfault_interrupt(unsigned int ext_int_code, | |||
| 553 | if ((subcode & 0xff00) != __SUBCODE_MASK) | 528 | if ((subcode & 0xff00) != __SUBCODE_MASK) |
| 554 | return; | 529 | return; |
| 555 | kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; | 530 | kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; |
| 556 | 531 | if (subcode & 0x0080) { | |
| 557 | /* | 532 | /* Get the token (= pid of the affected task). */ |
| 558 | * Get the token (= address of the task structure of the affected task). | 533 | pid = sizeof(void *) == 4 ? param32 : param64; |
| 559 | */ | 534 | rcu_read_lock(); |
| 560 | #ifdef CONFIG_64BIT | 535 | tsk = find_task_by_pid_ns(pid, &init_pid_ns); |
| 561 | tsk = (struct task_struct *) param64; | 536 | if (tsk) |
| 562 | #else | 537 | get_task_struct(tsk); |
| 563 | tsk = (struct task_struct *) param32; | 538 | rcu_read_unlock(); |
| 564 | #endif | 539 | if (!tsk) |
| 565 | 540 | return; | |
| 541 | } else { | ||
| 542 | tsk = current; | ||
| 543 | } | ||
| 544 | spin_lock(&pfault_lock); | ||
| 566 | if (subcode & 0x0080) { | 545 | if (subcode & 0x0080) { |
| 567 | /* signal bit is set -> a page has been swapped in by VM */ | 546 | /* signal bit is set -> a page has been swapped in by VM */ |
| 568 | if (xchg(&tsk->thread.pfault_wait, -1) != 0) { | 547 | if (tsk->thread.pfault_wait == 1) { |
| 569 | /* Initial interrupt was faster than the completion | 548 | /* Initial interrupt was faster than the completion |
| 570 | * interrupt. pfault_wait is valid. Set pfault_wait | 549 | * interrupt. pfault_wait is valid. Set pfault_wait |
| 571 | * back to zero and wake up the process. This can | 550 | * back to zero and wake up the process. This can |
| 572 | * safely be done because the task is still sleeping | 551 | * safely be done because the task is still sleeping |
| 573 | * and can't produce new pfaults. */ | 552 | * and can't produce new pfaults. */ |
| 574 | tsk->thread.pfault_wait = 0; | 553 | tsk->thread.pfault_wait = 0; |
| 554 | list_del(&tsk->thread.list); | ||
| 575 | wake_up_process(tsk); | 555 | wake_up_process(tsk); |
| 576 | put_task_struct(tsk); | 556 | } else { |
| 557 | /* Completion interrupt was faster than initial | ||
| 558 | * interrupt. Set pfault_wait to -1 so the initial | ||
| 559 | * interrupt doesn't put the task to sleep. */ | ||
| 560 | tsk->thread.pfault_wait = -1; | ||
| 577 | } | 561 | } |
| 562 | put_task_struct(tsk); | ||
| 578 | } else { | 563 | } else { |
| 579 | /* signal bit not set -> a real page is missing. */ | 564 | /* signal bit not set -> a real page is missing. */ |
| 580 | get_task_struct(tsk); | 565 | if (tsk->thread.pfault_wait == -1) { |
| 581 | set_task_state(tsk, TASK_UNINTERRUPTIBLE); | ||
| 582 | if (xchg(&tsk->thread.pfault_wait, 1) != 0) { | ||
| 583 | /* Completion interrupt was faster than the initial | 566 | /* Completion interrupt was faster than the initial |
| 584 | * interrupt (swapped in a -1 for pfault_wait). Set | 567 | * interrupt (pfault_wait == -1). Set pfault_wait |
| 585 | * pfault_wait back to zero and exit. This can be | 568 | * back to zero and exit. */ |
| 586 | * done safely because tsk is running in kernel | ||
| 587 | * mode and can't produce new pfaults. */ | ||
| 588 | tsk->thread.pfault_wait = 0; | 569 | tsk->thread.pfault_wait = 0; |
| 589 | set_task_state(tsk, TASK_RUNNING); | 570 | } else { |
| 590 | put_task_struct(tsk); | 571 | /* Initial interrupt arrived before completion |
| 591 | } else | 572 | * interrupt. Let the task sleep. */ |
| 573 | tsk->thread.pfault_wait = 1; | ||
| 574 | list_add(&tsk->thread.list, &pfault_list); | ||
| 575 | set_task_state(tsk, TASK_UNINTERRUPTIBLE); | ||
| 592 | set_tsk_need_resched(tsk); | 576 | set_tsk_need_resched(tsk); |
| 577 | } | ||
| 578 | } | ||
| 579 | spin_unlock(&pfault_lock); | ||
| 580 | } | ||
| 581 | |||
| 582 | static int __cpuinit pfault_cpu_notify(struct notifier_block *self, | ||
| 583 | unsigned long action, void *hcpu) | ||
| 584 | { | ||
| 585 | struct thread_struct *thread, *next; | ||
| 586 | struct task_struct *tsk; | ||
| 587 | |||
| 588 | switch (action) { | ||
| 589 | case CPU_DEAD: | ||
| 590 | case CPU_DEAD_FROZEN: | ||
| 591 | spin_lock_irq(&pfault_lock); | ||
| 592 | list_for_each_entry_safe(thread, next, &pfault_list, list) { | ||
| 593 | thread->pfault_wait = 0; | ||
| 594 | list_del(&thread->list); | ||
| 595 | tsk = container_of(thread, struct task_struct, thread); | ||
| 596 | wake_up_process(tsk); | ||
| 597 | } | ||
| 598 | spin_unlock_irq(&pfault_lock); | ||
| 599 | break; | ||
| 600 | default: | ||
| 601 | break; | ||
| 593 | } | 602 | } |
| 603 | return NOTIFY_OK; | ||
| 594 | } | 604 | } |
| 595 | 605 | ||
| 596 | static int __init pfault_irq_init(void) | 606 | static int __init pfault_irq_init(void) |
| @@ -599,22 +609,21 @@ static int __init pfault_irq_init(void) | |||
| 599 | 609 | ||
| 600 | if (!MACHINE_IS_VM) | 610 | if (!MACHINE_IS_VM) |
| 601 | return 0; | 611 | return 0; |
| 602 | /* | ||
| 603 | * Try to get pfault pseudo page faults going. | ||
| 604 | */ | ||
| 605 | rc = register_external_interrupt(0x2603, pfault_interrupt); | 612 | rc = register_external_interrupt(0x2603, pfault_interrupt); |
| 606 | if (rc) { | 613 | if (rc) |
| 607 | pfault_disable = 1; | 614 | goto out_extint; |
| 608 | return rc; | 615 | rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP; |
| 609 | } | 616 | if (rc) |
| 610 | if (pfault_init() == 0) | 617 | goto out_pfault; |
| 611 | return 0; | 618 | hotcpu_notifier(pfault_cpu_notify, 0); |
| 619 | return 0; | ||
| 612 | 620 | ||
| 613 | /* Tough luck, no pfault. */ | 621 | out_pfault: |
| 614 | pfault_disable = 1; | ||
| 615 | unregister_external_interrupt(0x2603, pfault_interrupt); | 622 | unregister_external_interrupt(0x2603, pfault_interrupt); |
| 616 | return 0; | 623 | out_extint: |
| 624 | pfault_disable = 1; | ||
| 625 | return rc; | ||
| 617 | } | 626 | } |
| 618 | early_initcall(pfault_irq_init); | 627 | early_initcall(pfault_irq_init); |
| 619 | 628 | ||
| 620 | #endif | 629 | #endif /* CONFIG_PFAULT */ |
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index 639cd21f2218..a4d856db9154 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c | |||
| @@ -13,7 +13,6 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | |||
| 13 | pte_t *pteptr, pte_t pteval) | 13 | pte_t *pteptr, pte_t pteval) |
| 14 | { | 14 | { |
| 15 | pmd_t *pmdp = (pmd_t *) pteptr; | 15 | pmd_t *pmdp = (pmd_t *) pteptr; |
| 16 | pte_t shadow_pteval = pteval; | ||
| 17 | unsigned long mask; | 16 | unsigned long mask; |
| 18 | 17 | ||
| 19 | if (!MACHINE_HAS_HPAGE) { | 18 | if (!MACHINE_HAS_HPAGE) { |
| @@ -21,18 +20,9 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | |||
| 21 | mask = pte_val(pteval) & | 20 | mask = pte_val(pteval) & |
| 22 | (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO); | 21 | (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO); |
| 23 | pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask; | 22 | pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask; |
| 24 | if (mm->context.noexec) { | ||
| 25 | pteptr += PTRS_PER_PTE; | ||
| 26 | pte_val(shadow_pteval) = | ||
| 27 | (_SEGMENT_ENTRY + __pa(pteptr)) | mask; | ||
| 28 | } | ||
| 29 | } | 23 | } |
| 30 | 24 | ||
| 31 | pmd_val(*pmdp) = pte_val(pteval); | 25 | pmd_val(*pmdp) = pte_val(pteval); |
| 32 | if (mm->context.noexec) { | ||
| 33 | pmdp = get_shadow_table(pmdp); | ||
| 34 | pmd_val(*pmdp) = pte_val(shadow_pteval); | ||
| 35 | } | ||
| 36 | } | 26 | } |
| 37 | 27 | ||
| 38 | int arch_prepare_hugepage(struct page *page) | 28 | int arch_prepare_hugepage(struct page *page) |
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index bb409332a484..dfefc2171691 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c | |||
| @@ -175,7 +175,8 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
| 175 | pmd = pmd_offset(pud, address); | 175 | pmd = pmd_offset(pud, address); |
| 176 | pte = pte_offset_kernel(pmd, address); | 176 | pte = pte_offset_kernel(pmd, address); |
| 177 | if (!enable) { | 177 | if (!enable) { |
| 178 | ptep_invalidate(&init_mm, address, pte); | 178 | __ptep_ipte(address, pte); |
| 179 | pte_val(*pte) = _PAGE_TYPE_EMPTY; | ||
| 179 | continue; | 180 | continue; |
| 180 | } | 181 | } |
| 181 | *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW)); | 182 | *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW)); |
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index f05edcc3beff..d013ed39743b 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c | |||
| @@ -28,7 +28,7 @@ static void change_page_attr(unsigned long addr, int numpages, | |||
| 28 | 28 | ||
| 29 | pte = *ptep; | 29 | pte = *ptep; |
| 30 | pte = set(pte); | 30 | pte = set(pte); |
| 31 | ptep_invalidate(&init_mm, addr, ptep); | 31 | __ptep_ipte(addr, ptep); |
| 32 | *ptep = pte; | 32 | *ptep = pte; |
| 33 | addr += PAGE_SIZE; | 33 | addr += PAGE_SIZE; |
| 34 | } | 34 | } |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index e1850c28cd68..8d4330642512 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
| @@ -40,7 +40,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | |||
| 40 | static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist); | 40 | static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist); |
| 41 | 41 | ||
| 42 | static void __page_table_free(struct mm_struct *mm, unsigned long *table); | 42 | static void __page_table_free(struct mm_struct *mm, unsigned long *table); |
| 43 | static void __crst_table_free(struct mm_struct *mm, unsigned long *table); | ||
| 44 | 43 | ||
| 45 | static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm) | 44 | static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm) |
| 46 | { | 45 | { |
| @@ -67,7 +66,7 @@ static void rcu_table_freelist_callback(struct rcu_head *head) | |||
| 67 | while (batch->pgt_index > 0) | 66 | while (batch->pgt_index > 0) |
| 68 | __page_table_free(batch->mm, batch->table[--batch->pgt_index]); | 67 | __page_table_free(batch->mm, batch->table[--batch->pgt_index]); |
| 69 | while (batch->crst_index < RCU_FREELIST_SIZE) | 68 | while (batch->crst_index < RCU_FREELIST_SIZE) |
| 70 | __crst_table_free(batch->mm, batch->table[batch->crst_index++]); | 69 | crst_table_free(batch->mm, batch->table[batch->crst_index++]); |
| 71 | free_page((unsigned long) batch); | 70 | free_page((unsigned long) batch); |
| 72 | } | 71 | } |
| 73 | 72 | ||
| @@ -125,63 +124,33 @@ static int __init parse_vmalloc(char *arg) | |||
| 125 | } | 124 | } |
| 126 | early_param("vmalloc", parse_vmalloc); | 125 | early_param("vmalloc", parse_vmalloc); |
| 127 | 126 | ||
| 128 | unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec) | 127 | unsigned long *crst_table_alloc(struct mm_struct *mm) |
| 129 | { | 128 | { |
| 130 | struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); | 129 | struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); |
| 131 | 130 | ||
| 132 | if (!page) | 131 | if (!page) |
| 133 | return NULL; | 132 | return NULL; |
| 134 | page->index = 0; | ||
| 135 | if (noexec) { | ||
| 136 | struct page *shadow = alloc_pages(GFP_KERNEL, ALLOC_ORDER); | ||
| 137 | if (!shadow) { | ||
| 138 | __free_pages(page, ALLOC_ORDER); | ||
| 139 | return NULL; | ||
| 140 | } | ||
| 141 | page->index = page_to_phys(shadow); | ||
| 142 | } | ||
| 143 | spin_lock_bh(&mm->context.list_lock); | ||
| 144 | list_add(&page->lru, &mm->context.crst_list); | ||
| 145 | spin_unlock_bh(&mm->context.list_lock); | ||
| 146 | return (unsigned long *) page_to_phys(page); | 133 | return (unsigned long *) page_to_phys(page); |
| 147 | } | 134 | } |
| 148 | 135 | ||
| 149 | static void __crst_table_free(struct mm_struct *mm, unsigned long *table) | ||
| 150 | { | ||
| 151 | unsigned long *shadow = get_shadow_table(table); | ||
| 152 | |||
| 153 | if (shadow) | ||
| 154 | free_pages((unsigned long) shadow, ALLOC_ORDER); | ||
| 155 | free_pages((unsigned long) table, ALLOC_ORDER); | ||
| 156 | } | ||
| 157 | |||
| 158 | void crst_table_free(struct mm_struct *mm, unsigned long *table) | 136 | void crst_table_free(struct mm_struct *mm, unsigned long *table) |
| 159 | { | 137 | { |
| 160 | struct page *page = virt_to_page(table); | 138 | free_pages((unsigned long) table, ALLOC_ORDER); |
| 161 | |||
| 162 | spin_lock_bh(&mm->context.list_lock); | ||
| 163 | list_del(&page->lru); | ||
| 164 | spin_unlock_bh(&mm->context.list_lock); | ||
| 165 | __crst_table_free(mm, table); | ||
| 166 | } | 139 | } |
| 167 | 140 | ||
| 168 | void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table) | 141 | void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table) |
| 169 | { | 142 | { |
| 170 | struct rcu_table_freelist *batch; | 143 | struct rcu_table_freelist *batch; |
| 171 | struct page *page = virt_to_page(table); | ||
| 172 | 144 | ||
| 173 | spin_lock_bh(&mm->context.list_lock); | ||
| 174 | list_del(&page->lru); | ||
| 175 | spin_unlock_bh(&mm->context.list_lock); | ||
| 176 | if (atomic_read(&mm->mm_users) < 2 && | 145 | if (atomic_read(&mm->mm_users) < 2 && |
| 177 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { | 146 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { |
| 178 | __crst_table_free(mm, table); | 147 | crst_table_free(mm, table); |
| 179 | return; | 148 | return; |
| 180 | } | 149 | } |
| 181 | batch = rcu_table_freelist_get(mm); | 150 | batch = rcu_table_freelist_get(mm); |
| 182 | if (!batch) { | 151 | if (!batch) { |
| 183 | smp_call_function(smp_sync, NULL, 1); | 152 | smp_call_function(smp_sync, NULL, 1); |
| 184 | __crst_table_free(mm, table); | 153 | crst_table_free(mm, table); |
| 185 | return; | 154 | return; |
| 186 | } | 155 | } |
| 187 | batch->table[--batch->crst_index] = table; | 156 | batch->table[--batch->crst_index] = table; |
| @@ -197,7 +166,7 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) | |||
| 197 | 166 | ||
| 198 | BUG_ON(limit > (1UL << 53)); | 167 | BUG_ON(limit > (1UL << 53)); |
| 199 | repeat: | 168 | repeat: |
| 200 | table = crst_table_alloc(mm, mm->context.noexec); | 169 | table = crst_table_alloc(mm); |
| 201 | if (!table) | 170 | if (!table) |
| 202 | return -ENOMEM; | 171 | return -ENOMEM; |
| 203 | spin_lock_bh(&mm->page_table_lock); | 172 | spin_lock_bh(&mm->page_table_lock); |
| @@ -273,7 +242,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) | |||
| 273 | unsigned long *table; | 242 | unsigned long *table; |
| 274 | unsigned long bits; | 243 | unsigned long bits; |
| 275 | 244 | ||
| 276 | bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; | 245 | bits = (mm->context.has_pgste) ? 3UL : 1UL; |
| 277 | spin_lock_bh(&mm->context.list_lock); | 246 | spin_lock_bh(&mm->context.list_lock); |
| 278 | page = NULL; | 247 | page = NULL; |
| 279 | if (!list_empty(&mm->context.pgtable_list)) { | 248 | if (!list_empty(&mm->context.pgtable_list)) { |
| @@ -329,7 +298,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table) | |||
| 329 | struct page *page; | 298 | struct page *page; |
| 330 | unsigned long bits; | 299 | unsigned long bits; |
| 331 | 300 | ||
| 332 | bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; | 301 | bits = (mm->context.has_pgste) ? 3UL : 1UL; |
| 333 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); | 302 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); |
| 334 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | 303 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); |
| 335 | spin_lock_bh(&mm->context.list_lock); | 304 | spin_lock_bh(&mm->context.list_lock); |
| @@ -366,7 +335,7 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
| 366 | page_table_free(mm, table); | 335 | page_table_free(mm, table); |
| 367 | return; | 336 | return; |
| 368 | } | 337 | } |
| 369 | bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; | 338 | bits = (mm->context.has_pgste) ? 3UL : 1UL; |
| 370 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); | 339 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); |
| 371 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | 340 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); |
| 372 | spin_lock_bh(&mm->context.list_lock); | 341 | spin_lock_bh(&mm->context.list_lock); |
| @@ -379,25 +348,6 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
| 379 | rcu_table_freelist_finish(); | 348 | rcu_table_freelist_finish(); |
| 380 | } | 349 | } |
| 381 | 350 | ||
| 382 | void disable_noexec(struct mm_struct *mm, struct task_struct *tsk) | ||
| 383 | { | ||
| 384 | struct page *page; | ||
| 385 | |||
| 386 | spin_lock_bh(&mm->context.list_lock); | ||
| 387 | /* Free shadow region and segment tables. */ | ||
| 388 | list_for_each_entry(page, &mm->context.crst_list, lru) | ||
| 389 | if (page->index) { | ||
| 390 | free_pages((unsigned long) page->index, ALLOC_ORDER); | ||
| 391 | page->index = 0; | ||
| 392 | } | ||
| 393 | /* "Free" second halves of page tables. */ | ||
| 394 | list_for_each_entry(page, &mm->context.pgtable_list, lru) | ||
| 395 | page->flags &= ~SECOND_HALVES; | ||
| 396 | spin_unlock_bh(&mm->context.list_lock); | ||
| 397 | mm->context.noexec = 0; | ||
| 398 | update_mm(mm, tsk); | ||
| 399 | } | ||
| 400 | |||
| 401 | /* | 351 | /* |
| 402 | * switch on pgstes for its userspace process (for kvm) | 352 | * switch on pgstes for its userspace process (for kvm) |
| 403 | */ | 353 | */ |
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 34c43f23b28c..8c1970d1dd91 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c | |||
| @@ -95,7 +95,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 95 | pu_dir = vmem_pud_alloc(); | 95 | pu_dir = vmem_pud_alloc(); |
| 96 | if (!pu_dir) | 96 | if (!pu_dir) |
| 97 | goto out; | 97 | goto out; |
| 98 | pgd_populate_kernel(&init_mm, pg_dir, pu_dir); | 98 | pgd_populate(&init_mm, pg_dir, pu_dir); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | pu_dir = pud_offset(pg_dir, address); | 101 | pu_dir = pud_offset(pg_dir, address); |
| @@ -103,7 +103,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 103 | pm_dir = vmem_pmd_alloc(); | 103 | pm_dir = vmem_pmd_alloc(); |
| 104 | if (!pm_dir) | 104 | if (!pm_dir) |
| 105 | goto out; | 105 | goto out; |
| 106 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); | 106 | pud_populate(&init_mm, pu_dir, pm_dir); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); | 109 | pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); |
| @@ -123,7 +123,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 123 | pt_dir = vmem_pte_alloc(); | 123 | pt_dir = vmem_pte_alloc(); |
| 124 | if (!pt_dir) | 124 | if (!pt_dir) |
| 125 | goto out; | 125 | goto out; |
| 126 | pmd_populate_kernel(&init_mm, pm_dir, pt_dir); | 126 | pmd_populate(&init_mm, pm_dir, pt_dir); |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | pt_dir = pte_offset_kernel(pm_dir, address); | 129 | pt_dir = pte_offset_kernel(pm_dir, address); |
| @@ -159,7 +159,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size) | |||
| 159 | continue; | 159 | continue; |
| 160 | 160 | ||
| 161 | if (pmd_huge(*pm_dir)) { | 161 | if (pmd_huge(*pm_dir)) { |
| 162 | pmd_clear_kernel(pm_dir); | 162 | pmd_clear(pm_dir); |
| 163 | address += HPAGE_SIZE - PAGE_SIZE; | 163 | address += HPAGE_SIZE - PAGE_SIZE; |
| 164 | continue; | 164 | continue; |
| 165 | } | 165 | } |
| @@ -192,7 +192,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | |||
| 192 | pu_dir = vmem_pud_alloc(); | 192 | pu_dir = vmem_pud_alloc(); |
| 193 | if (!pu_dir) | 193 | if (!pu_dir) |
| 194 | goto out; | 194 | goto out; |
| 195 | pgd_populate_kernel(&init_mm, pg_dir, pu_dir); | 195 | pgd_populate(&init_mm, pg_dir, pu_dir); |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | pu_dir = pud_offset(pg_dir, address); | 198 | pu_dir = pud_offset(pg_dir, address); |
| @@ -200,7 +200,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | |||
| 200 | pm_dir = vmem_pmd_alloc(); | 200 | pm_dir = vmem_pmd_alloc(); |
| 201 | if (!pm_dir) | 201 | if (!pm_dir) |
| 202 | goto out; | 202 | goto out; |
| 203 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); | 203 | pud_populate(&init_mm, pu_dir, pm_dir); |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | pm_dir = pmd_offset(pu_dir, address); | 206 | pm_dir = pmd_offset(pu_dir, address); |
| @@ -208,7 +208,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | |||
| 208 | pt_dir = vmem_pte_alloc(); | 208 | pt_dir = vmem_pte_alloc(); |
| 209 | if (!pt_dir) | 209 | if (!pt_dir) |
| 210 | goto out; | 210 | goto out; |
| 211 | pmd_populate_kernel(&init_mm, pm_dir, pt_dir); | 211 | pmd_populate(&init_mm, pm_dir, pt_dir); |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | pt_dir = pte_offset_kernel(pm_dir, address); | 214 | pt_dir = pte_offset_kernel(pm_dir, address); |
diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c index 33cbd373cce4..053caa0fd276 100644 --- a/arch/s390/oprofile/hwsampler.c +++ b/arch/s390/oprofile/hwsampler.c | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | * Author: Heinz Graalfs <graalfs@de.ibm.com> | 5 | * Author: Heinz Graalfs <graalfs@de.ibm.com> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/kernel_stat.h> | ||
| 8 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
| 9 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 10 | #include <linux/smp.h> | 11 | #include <linux/smp.h> |
| @@ -674,17 +675,11 @@ int hwsampler_activate(unsigned int cpu) | |||
| 674 | static void hws_ext_handler(unsigned int ext_int_code, | 675 | static void hws_ext_handler(unsigned int ext_int_code, |
| 675 | unsigned int param32, unsigned long param64) | 676 | unsigned int param32, unsigned long param64) |
| 676 | { | 677 | { |
| 677 | int cpu; | ||
| 678 | struct hws_cpu_buffer *cb; | 678 | struct hws_cpu_buffer *cb; |
| 679 | 679 | ||
| 680 | cpu = smp_processor_id(); | 680 | kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++; |
| 681 | cb = &per_cpu(sampler_cpu_buffer, cpu); | 681 | cb = &__get_cpu_var(sampler_cpu_buffer); |
| 682 | 682 | atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32); | |
| 683 | atomic_xchg( | ||
| 684 | &cb->ext_params, | ||
| 685 | atomic_read(&cb->ext_params) | ||
| 686 | | S390_lowcore.ext_params); | ||
| 687 | |||
| 688 | if (hws_wq) | 683 | if (hws_wq) |
| 689 | queue_work(hws_wq, &cb->worker); | 684 | queue_work(hws_wq, &cb->worker); |
| 690 | } | 685 | } |
| @@ -764,7 +759,7 @@ static int worker_check_error(unsigned int cpu, int ext_params) | |||
| 764 | if (!sdbt || !*sdbt) | 759 | if (!sdbt || !*sdbt) |
| 765 | return -EINVAL; | 760 | return -EINVAL; |
| 766 | 761 | ||
| 767 | if (ext_params & EI_IEA) | 762 | if (ext_params & EI_PRA) |
| 768 | cb->req_alert++; | 763 | cb->req_alert++; |
| 769 | 764 | ||
| 770 | if (ext_params & EI_LSDA) | 765 | if (ext_params & EI_LSDA) |
| @@ -1009,7 +1004,7 @@ int hwsampler_deallocate() | |||
| 1009 | if (hws_state != HWS_STOPPED) | 1004 | if (hws_state != HWS_STOPPED) |
| 1010 | goto deallocate_exit; | 1005 | goto deallocate_exit; |
| 1011 | 1006 | ||
| 1012 | smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */ | 1007 | ctl_clear_bit(0, 5); /* set bit 58 CR0 off */ |
| 1013 | deallocate_sdbt(); | 1008 | deallocate_sdbt(); |
| 1014 | 1009 | ||
| 1015 | hws_state = HWS_DEALLOCATED; | 1010 | hws_state = HWS_DEALLOCATED; |
| @@ -1123,7 +1118,7 @@ int hwsampler_shutdown() | |||
| 1123 | mutex_lock(&hws_sem); | 1118 | mutex_lock(&hws_sem); |
| 1124 | 1119 | ||
| 1125 | if (hws_state == HWS_STOPPED) { | 1120 | if (hws_state == HWS_STOPPED) { |
| 1126 | smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */ | 1121 | ctl_clear_bit(0, 5); /* set bit 58 CR0 off */ |
| 1127 | deallocate_sdbt(); | 1122 | deallocate_sdbt(); |
| 1128 | } | 1123 | } |
| 1129 | if (hws_wq) { | 1124 | if (hws_wq) { |
| @@ -1198,7 +1193,7 @@ start_all_exit: | |||
| 1198 | hws_oom = 1; | 1193 | hws_oom = 1; |
| 1199 | hws_flush_all = 0; | 1194 | hws_flush_all = 0; |
| 1200 | /* now let them in, 1407 CPUMF external interrupts */ | 1195 | /* now let them in, 1407 CPUMF external interrupts */ |
| 1201 | smp_ctl_set_bit(0, 5); /* set CR0 bit 58 */ | 1196 | ctl_set_bit(0, 5); /* set CR0 bit 58 */ |
| 1202 | 1197 | ||
| 1203 | return 0; | 1198 | return 0; |
| 1204 | } | 1199 | } |
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index c64c3807f516..e0b25de1e339 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig | |||
| @@ -74,6 +74,8 @@ config ZCRYPT | |||
| 74 | + PCI-X Cryptographic Coprocessor (PCIXCC) | 74 | + PCI-X Cryptographic Coprocessor (PCIXCC) |
| 75 | + Crypto Express2 Coprocessor (CEX2C) | 75 | + Crypto Express2 Coprocessor (CEX2C) |
| 76 | + Crypto Express2 Accelerator (CEX2A) | 76 | + Crypto Express2 Accelerator (CEX2A) |
| 77 | + Crypto Express3 Coprocessor (CEX3C) | ||
| 78 | + Crypto Express3 Accelerator (CEX3A) | ||
| 77 | 79 | ||
| 78 | config ZCRYPT_MONOLITHIC | 80 | config ZCRYPT_MONOLITHIC |
| 79 | bool "Monolithic zcrypt module" | 81 | bool "Monolithic zcrypt module" |
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 2b771f18d1ad..c388eda1e2b1 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
| @@ -253,13 +253,11 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
| 253 | */ | 253 | */ |
| 254 | void dasd_alias_lcu_setup_complete(struct dasd_device *device) | 254 | void dasd_alias_lcu_setup_complete(struct dasd_device *device) |
| 255 | { | 255 | { |
| 256 | struct dasd_eckd_private *private; | ||
| 257 | unsigned long flags; | 256 | unsigned long flags; |
| 258 | struct alias_server *server; | 257 | struct alias_server *server; |
| 259 | struct alias_lcu *lcu; | 258 | struct alias_lcu *lcu; |
| 260 | struct dasd_uid uid; | 259 | struct dasd_uid uid; |
| 261 | 260 | ||
| 262 | private = (struct dasd_eckd_private *) device->private; | ||
| 263 | device->discipline->get_uid(device, &uid); | 261 | device->discipline->get_uid(device, &uid); |
| 264 | lcu = NULL; | 262 | lcu = NULL; |
| 265 | spin_lock_irqsave(&aliastree.lock, flags); | 263 | spin_lock_irqsave(&aliastree.lock, flags); |
| @@ -279,13 +277,11 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device) | |||
| 279 | 277 | ||
| 280 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) | 278 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) |
| 281 | { | 279 | { |
| 282 | struct dasd_eckd_private *private; | ||
| 283 | unsigned long flags; | 280 | unsigned long flags; |
| 284 | struct alias_server *server; | 281 | struct alias_server *server; |
| 285 | struct alias_lcu *lcu; | 282 | struct alias_lcu *lcu; |
| 286 | struct dasd_uid uid; | 283 | struct dasd_uid uid; |
| 287 | 284 | ||
| 288 | private = (struct dasd_eckd_private *) device->private; | ||
| 289 | device->discipline->get_uid(device, &uid); | 285 | device->discipline->get_uid(device, &uid); |
| 290 | lcu = NULL; | 286 | lcu = NULL; |
| 291 | spin_lock_irqsave(&aliastree.lock, flags); | 287 | spin_lock_irqsave(&aliastree.lock, flags); |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 3ebdf5f92f8f..30fb979d684d 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -1611,10 +1611,8 @@ static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, | |||
| 1611 | 1611 | ||
| 1612 | static int dasd_eckd_start_analysis(struct dasd_block *block) | 1612 | static int dasd_eckd_start_analysis(struct dasd_block *block) |
| 1613 | { | 1613 | { |
| 1614 | struct dasd_eckd_private *private; | ||
| 1615 | struct dasd_ccw_req *init_cqr; | 1614 | struct dasd_ccw_req *init_cqr; |
| 1616 | 1615 | ||
| 1617 | private = (struct dasd_eckd_private *) block->base->private; | ||
| 1618 | init_cqr = dasd_eckd_analysis_ccw(block->base); | 1616 | init_cqr = dasd_eckd_analysis_ccw(block->base); |
| 1619 | if (IS_ERR(init_cqr)) | 1617 | if (IS_ERR(init_cqr)) |
| 1620 | return PTR_ERR(init_cqr); | 1618 | return PTR_ERR(init_cqr); |
| @@ -2264,7 +2262,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
| 2264 | unsigned int blk_per_trk, | 2262 | unsigned int blk_per_trk, |
| 2265 | unsigned int blksize) | 2263 | unsigned int blksize) |
| 2266 | { | 2264 | { |
| 2267 | struct dasd_eckd_private *private; | ||
| 2268 | unsigned long *idaws; | 2265 | unsigned long *idaws; |
| 2269 | struct dasd_ccw_req *cqr; | 2266 | struct dasd_ccw_req *cqr; |
| 2270 | struct ccw1 *ccw; | 2267 | struct ccw1 *ccw; |
| @@ -2283,7 +2280,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
| 2283 | unsigned int recoffs; | 2280 | unsigned int recoffs; |
| 2284 | 2281 | ||
| 2285 | basedev = block->base; | 2282 | basedev = block->base; |
| 2286 | private = (struct dasd_eckd_private *) basedev->private; | ||
| 2287 | if (rq_data_dir(req) == READ) | 2283 | if (rq_data_dir(req) == READ) |
| 2288 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; | 2284 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; |
| 2289 | else if (rq_data_dir(req) == WRITE) | 2285 | else if (rq_data_dir(req) == WRITE) |
| @@ -2556,8 +2552,7 @@ static int prepare_itcw(struct itcw *itcw, | |||
| 2556 | 2552 | ||
| 2557 | dcw = itcw_add_dcw(itcw, pfx_cmd, 0, | 2553 | dcw = itcw_add_dcw(itcw, pfx_cmd, 0, |
| 2558 | &pfxdata, sizeof(pfxdata), total_data_size); | 2554 | &pfxdata, sizeof(pfxdata), total_data_size); |
| 2559 | 2555 | return IS_ERR(dcw) ? PTR_ERR(dcw) : 0; | |
| 2560 | return rc; | ||
| 2561 | } | 2556 | } |
| 2562 | 2557 | ||
| 2563 | static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | 2558 | static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( |
| @@ -2573,7 +2568,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
| 2573 | unsigned int blk_per_trk, | 2568 | unsigned int blk_per_trk, |
| 2574 | unsigned int blksize) | 2569 | unsigned int blksize) |
| 2575 | { | 2570 | { |
| 2576 | struct dasd_eckd_private *private; | ||
| 2577 | struct dasd_ccw_req *cqr; | 2571 | struct dasd_ccw_req *cqr; |
| 2578 | struct req_iterator iter; | 2572 | struct req_iterator iter; |
| 2579 | struct bio_vec *bv; | 2573 | struct bio_vec *bv; |
| @@ -2594,7 +2588,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
| 2594 | unsigned int count, count_to_trk_end; | 2588 | unsigned int count, count_to_trk_end; |
| 2595 | 2589 | ||
| 2596 | basedev = block->base; | 2590 | basedev = block->base; |
| 2597 | private = (struct dasd_eckd_private *) basedev->private; | ||
| 2598 | if (rq_data_dir(req) == READ) { | 2591 | if (rq_data_dir(req) == READ) { |
| 2599 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; | 2592 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; |
| 2600 | itcw_op = ITCW_OP_READ; | 2593 | itcw_op = ITCW_OP_READ; |
| @@ -2801,7 +2794,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, | |||
| 2801 | struct dasd_block *block, | 2794 | struct dasd_block *block, |
| 2802 | struct request *req) | 2795 | struct request *req) |
| 2803 | { | 2796 | { |
| 2804 | struct dasd_eckd_private *private; | ||
| 2805 | unsigned long *idaws; | 2797 | unsigned long *idaws; |
| 2806 | struct dasd_device *basedev; | 2798 | struct dasd_device *basedev; |
| 2807 | struct dasd_ccw_req *cqr; | 2799 | struct dasd_ccw_req *cqr; |
| @@ -2836,7 +2828,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, | |||
| 2836 | trkcount = last_trk - first_trk + 1; | 2828 | trkcount = last_trk - first_trk + 1; |
| 2837 | first_offs = 0; | 2829 | first_offs = 0; |
| 2838 | basedev = block->base; | 2830 | basedev = block->base; |
| 2839 | private = (struct dasd_eckd_private *) basedev->private; | ||
| 2840 | 2831 | ||
| 2841 | if (rq_data_dir(req) == READ) | 2832 | if (rq_data_dir(req) == READ) |
| 2842 | cmd = DASD_ECKD_CCW_READ_TRACK; | 2833 | cmd = DASD_ECKD_CCW_READ_TRACK; |
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index dcee3c5c8954..a4f117d9fdc6 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig | |||
| @@ -119,18 +119,6 @@ config S390_TAPE | |||
| 119 | comment "S/390 tape interface support" | 119 | comment "S/390 tape interface support" |
| 120 | depends on S390_TAPE | 120 | depends on S390_TAPE |
| 121 | 121 | ||
| 122 | config S390_TAPE_BLOCK | ||
| 123 | def_bool y | ||
| 124 | prompt "Support for tape block devices" | ||
| 125 | depends on S390_TAPE && BLOCK | ||
| 126 | help | ||
| 127 | Select this option if you want to access your channel-attached tape | ||
| 128 | devices using the block device interface. This interface is similar | ||
| 129 | to CD-ROM devices on other platforms. The tapes can only be | ||
| 130 | accessed read-only when using this interface. Have a look at | ||
| 131 | <file:Documentation/s390/TAPE> for further information about creating | ||
| 132 | volumes for and using this interface. It is safe to say "Y" here. | ||
| 133 | |||
| 134 | comment "S/390 tape hardware support" | 122 | comment "S/390 tape hardware support" |
| 135 | depends on S390_TAPE | 123 | depends on S390_TAPE |
| 136 | 124 | ||
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index efb500ab66c0..f3c325207445 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ | 5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ |
| 6 | sclp_cmd.o sclp_config.o sclp_cpi_sys.o | 6 | sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o |
| 7 | 7 | ||
| 8 | obj-$(CONFIG_TN3270) += raw3270.o | 8 | obj-$(CONFIG_TN3270) += raw3270.o |
| 9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o | 9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o |
| @@ -22,7 +22,6 @@ obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o | |||
| 22 | obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o | 22 | obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o |
| 23 | obj-$(CONFIG_VMCP) += vmcp.o | 23 | obj-$(CONFIG_VMCP) += vmcp.o |
| 24 | 24 | ||
| 25 | tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o | ||
| 26 | tape-$(CONFIG_PROC_FS) += tape_proc.o | 25 | tape-$(CONFIG_PROC_FS) += tape_proc.o |
| 27 | tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y) | 26 | tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y) |
| 28 | obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o | 27 | obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o |
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index e0702d3ea33b..4600aa10a1c6 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c | |||
| @@ -97,7 +97,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv) | |||
| 97 | { | 97 | { |
| 98 | struct monwrite_hdr *monhdr = &monpriv->hdr; | 98 | struct monwrite_hdr *monhdr = &monpriv->hdr; |
| 99 | struct mon_buf *monbuf; | 99 | struct mon_buf *monbuf; |
| 100 | int rc; | 100 | int rc = 0; |
| 101 | 101 | ||
| 102 | if (monhdr->datalen > MONWRITE_MAX_DATALEN || | 102 | if (monhdr->datalen > MONWRITE_MAX_DATALEN || |
| 103 | monhdr->mon_function > MONWRITE_START_CONFIG || | 103 | monhdr->mon_function > MONWRITE_START_CONFIG || |
| @@ -135,7 +135,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv) | |||
| 135 | mon_buf_count++; | 135 | mon_buf_count++; |
| 136 | } | 136 | } |
| 137 | monpriv->current_buf = monbuf; | 137 | monpriv->current_buf = monbuf; |
| 138 | return 0; | 138 | return rc; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | static int monwrite_new_data(struct mon_private *monpriv) | 141 | static int monwrite_new_data(struct mon_private *monpriv) |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index e21a5c39ef20..810ac38631c3 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
| @@ -598,7 +598,6 @@ __raw3270_size_device(struct raw3270 *rp) | |||
| 598 | static const unsigned char wbuf[] = | 598 | static const unsigned char wbuf[] = |
| 599 | { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 }; | 599 | { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 }; |
| 600 | struct raw3270_ua *uap; | 600 | struct raw3270_ua *uap; |
| 601 | unsigned short count; | ||
| 602 | int rc; | 601 | int rc; |
| 603 | 602 | ||
| 604 | /* | 603 | /* |
| @@ -653,7 +652,6 @@ __raw3270_size_device(struct raw3270 *rp) | |||
| 653 | if (rc) | 652 | if (rc) |
| 654 | return rc; | 653 | return rc; |
| 655 | /* Got a Query Reply */ | 654 | /* Got a Query Reply */ |
| 656 | count = sizeof(rp->init_data) - rp->init_request.rescnt; | ||
| 657 | uap = (struct raw3270_ua *) (rp->init_data + 1); | 655 | uap = (struct raw3270_ua *) (rp->init_data + 1); |
| 658 | /* Paranoia check. */ | 656 | /* Paranoia check. */ |
| 659 | if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81) | 657 | if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81) |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 6bb5a6bdfab5..49a1bb52bc87 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #define EVTYP_CONFMGMDATA 0x04 | 28 | #define EVTYP_CONFMGMDATA 0x04 |
| 29 | #define EVTYP_SDIAS 0x1C | 29 | #define EVTYP_SDIAS 0x1C |
| 30 | #define EVTYP_ASYNC 0x0A | 30 | #define EVTYP_ASYNC 0x0A |
| 31 | #define EVTYP_OCF 0x1E | ||
| 31 | 32 | ||
| 32 | #define EVTYP_OPCMD_MASK 0x80000000 | 33 | #define EVTYP_OPCMD_MASK 0x80000000 |
| 33 | #define EVTYP_MSG_MASK 0x40000000 | 34 | #define EVTYP_MSG_MASK 0x40000000 |
| @@ -40,6 +41,7 @@ | |||
| 40 | #define EVTYP_CONFMGMDATA_MASK 0x10000000 | 41 | #define EVTYP_CONFMGMDATA_MASK 0x10000000 |
| 41 | #define EVTYP_SDIAS_MASK 0x00000010 | 42 | #define EVTYP_SDIAS_MASK 0x00000010 |
| 42 | #define EVTYP_ASYNC_MASK 0x00400000 | 43 | #define EVTYP_ASYNC_MASK 0x00400000 |
| 44 | #define EVTYP_OCF_MASK 0x00000004 | ||
| 43 | 45 | ||
| 44 | #define GNRLMSGFLGS_DOM 0x8000 | 46 | #define GNRLMSGFLGS_DOM 0x8000 |
| 45 | #define GNRLMSGFLGS_SNDALRM 0x4000 | 47 | #define GNRLMSGFLGS_SNDALRM 0x4000 |
| @@ -186,4 +188,26 @@ sclp_ascebc_str(unsigned char *str, int nr) | |||
| 186 | (MACHINE_IS_VM) ? ASCEBC(str, nr) : ASCEBC_500(str, nr); | 188 | (MACHINE_IS_VM) ? ASCEBC(str, nr) : ASCEBC_500(str, nr); |
| 187 | } | 189 | } |
| 188 | 190 | ||
| 191 | static inline struct gds_vector * | ||
| 192 | sclp_find_gds_vector(void *start, void *end, u16 id) | ||
| 193 | { | ||
| 194 | struct gds_vector *v; | ||
| 195 | |||
| 196 | for (v = start; (void *) v < end; v = (void *) v + v->length) | ||
| 197 | if (v->gds_id == id) | ||
| 198 | return v; | ||
| 199 | return NULL; | ||
| 200 | } | ||
| 201 | |||
| 202 | static inline struct gds_subvector * | ||
| 203 | sclp_find_gds_subvector(void *start, void *end, u8 key) | ||
| 204 | { | ||
| 205 | struct gds_subvector *sv; | ||
| 206 | |||
| 207 | for (sv = start; (void *) sv < end; sv = (void *) sv + sv->length) | ||
| 208 | if (sv->key == key) | ||
| 209 | return sv; | ||
| 210 | return NULL; | ||
| 211 | } | ||
| 212 | |||
| 189 | #endif /* __SCLP_H__ */ | 213 | #endif /* __SCLP_H__ */ |
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 16e232a99fb7..95b909ac2b73 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c | |||
| @@ -71,21 +71,9 @@ static struct sclp_register sclp_conf_register = | |||
| 71 | 71 | ||
| 72 | static int __init sclp_conf_init(void) | 72 | static int __init sclp_conf_init(void) |
| 73 | { | 73 | { |
| 74 | int rc; | ||
| 75 | |||
| 76 | INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); | 74 | INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); |
| 77 | INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify); | 75 | INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify); |
| 78 | 76 | return sclp_register(&sclp_conf_register); | |
| 79 | rc = sclp_register(&sclp_conf_register); | ||
| 80 | if (rc) | ||
| 81 | return rc; | ||
| 82 | |||
| 83 | if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) { | ||
| 84 | pr_warning("no configuration management.\n"); | ||
| 85 | sclp_unregister(&sclp_conf_register); | ||
| 86 | rc = -ENOSYS; | ||
| 87 | } | ||
| 88 | return rc; | ||
| 89 | } | 77 | } |
| 90 | 78 | ||
| 91 | __initcall(sclp_conf_init); | 79 | __initcall(sclp_conf_init); |
diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c new file mode 100644 index 000000000000..ab294d5a534e --- /dev/null +++ b/drivers/s390/char/sclp_ocf.c | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | /* | ||
| 2 | * drivers/s390/char/sclp_ocf.c | ||
| 3 | * SCLP OCF communication parameters sysfs interface | ||
| 4 | * | ||
| 5 | * Copyright IBM Corp. 2011 | ||
| 6 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #define KMSG_COMPONENT "sclp_ocf" | ||
| 10 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/stat.h> | ||
| 15 | #include <linux/device.h> | ||
| 16 | #include <linux/string.h> | ||
| 17 | #include <linux/ctype.h> | ||
| 18 | #include <linux/kmod.h> | ||
| 19 | #include <linux/timer.h> | ||
| 20 | #include <linux/err.h> | ||
| 21 | #include <asm/ebcdic.h> | ||
| 22 | #include <asm/sclp.h> | ||
| 23 | |||
| 24 | #include "sclp.h" | ||
| 25 | |||
| 26 | #define OCF_LENGTH_HMC_NETWORK 8UL | ||
| 27 | #define OCF_LENGTH_CPC_NAME 8UL | ||
| 28 | |||
| 29 | static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1]; | ||
| 30 | static char cpc_name[OCF_LENGTH_CPC_NAME + 1]; | ||
| 31 | |||
| 32 | static DEFINE_SPINLOCK(sclp_ocf_lock); | ||
| 33 | static struct work_struct sclp_ocf_change_work; | ||
| 34 | |||
| 35 | static struct kset *ocf_kset; | ||
| 36 | |||
| 37 | static void sclp_ocf_change_notify(struct work_struct *work) | ||
| 38 | { | ||
| 39 | kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE); | ||
| 40 | } | ||
| 41 | |||
| 42 | /* Handler for OCF event. Look for the CPC image name. */ | ||
| 43 | static void sclp_ocf_handler(struct evbuf_header *evbuf) | ||
| 44 | { | ||
| 45 | struct gds_vector *v; | ||
| 46 | struct gds_subvector *sv, *netid, *cpc; | ||
| 47 | size_t size; | ||
| 48 | |||
| 49 | /* Find the 0x9f00 block. */ | ||
| 50 | v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length, | ||
| 51 | 0x9f00); | ||
| 52 | if (!v) | ||
| 53 | return; | ||
| 54 | /* Find the 0x9f22 block inside the 0x9f00 block. */ | ||
| 55 | v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22); | ||
| 56 | if (!v) | ||
| 57 | return; | ||
| 58 | /* Find the 0x81 block inside the 0x9f22 block. */ | ||
| 59 | sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81); | ||
| 60 | if (!sv) | ||
| 61 | return; | ||
| 62 | /* Find the 0x01 block inside the 0x81 block. */ | ||
| 63 | netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1); | ||
| 64 | /* Find the 0x02 block inside the 0x81 block. */ | ||
| 65 | cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2); | ||
| 66 | /* Copy network name and cpc name. */ | ||
| 67 | spin_lock(&sclp_ocf_lock); | ||
| 68 | if (netid) { | ||
| 69 | size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length); | ||
| 70 | memcpy(hmc_network, netid + 1, size); | ||
| 71 | EBCASC(hmc_network, size); | ||
| 72 | hmc_network[size] = 0; | ||
| 73 | } | ||
| 74 | if (cpc) { | ||
| 75 | size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length); | ||
| 76 | memcpy(cpc_name, cpc + 1, size); | ||
| 77 | EBCASC(cpc_name, size); | ||
| 78 | cpc_name[size] = 0; | ||
| 79 | } | ||
| 80 | spin_unlock(&sclp_ocf_lock); | ||
| 81 | schedule_work(&sclp_ocf_change_work); | ||
| 82 | } | ||
| 83 | |||
| 84 | static struct sclp_register sclp_ocf_event = { | ||
| 85 | .receive_mask = EVTYP_OCF_MASK, | ||
| 86 | .receiver_fn = sclp_ocf_handler, | ||
| 87 | }; | ||
| 88 | |||
| 89 | static ssize_t cpc_name_show(struct kobject *kobj, | ||
| 90 | struct kobj_attribute *attr, char *page) | ||
| 91 | { | ||
| 92 | int rc; | ||
| 93 | |||
| 94 | spin_lock_irq(&sclp_ocf_lock); | ||
| 95 | rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name); | ||
| 96 | spin_unlock_irq(&sclp_ocf_lock); | ||
| 97 | return rc; | ||
| 98 | } | ||
| 99 | |||
| 100 | static struct kobj_attribute cpc_name_attr = | ||
| 101 | __ATTR(cpc_name, 0444, cpc_name_show, NULL); | ||
| 102 | |||
| 103 | static ssize_t hmc_network_show(struct kobject *kobj, | ||
| 104 | struct kobj_attribute *attr, char *page) | ||
| 105 | { | ||
| 106 | int rc; | ||
| 107 | |||
| 108 | spin_lock_irq(&sclp_ocf_lock); | ||
| 109 | rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network); | ||
| 110 | spin_unlock_irq(&sclp_ocf_lock); | ||
| 111 | return rc; | ||
| 112 | } | ||
| 113 | |||
| 114 | static struct kobj_attribute hmc_network_attr = | ||
| 115 | __ATTR(hmc_network, 0444, hmc_network_show, NULL); | ||
| 116 | |||
| 117 | static struct attribute *ocf_attrs[] = { | ||
| 118 | &cpc_name_attr.attr, | ||
| 119 | &hmc_network_attr.attr, | ||
| 120 | NULL, | ||
| 121 | }; | ||
| 122 | |||
| 123 | static struct attribute_group ocf_attr_group = { | ||
| 124 | .attrs = ocf_attrs, | ||
| 125 | }; | ||
| 126 | |||
| 127 | static int __init ocf_init(void) | ||
| 128 | { | ||
| 129 | int rc; | ||
| 130 | |||
| 131 | INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify); | ||
| 132 | ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj); | ||
| 133 | if (!ocf_kset) | ||
| 134 | return -ENOMEM; | ||
| 135 | |||
| 136 | rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group); | ||
| 137 | if (rc) { | ||
| 138 | kset_unregister(ocf_kset); | ||
| 139 | return rc; | ||
| 140 | } | ||
| 141 | |||
| 142 | return sclp_register(&sclp_ocf_event); | ||
| 143 | } | ||
| 144 | |||
| 145 | device_initcall(ocf_init); | ||
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c index 6a1c58dc61a7..fa733ecd3d70 100644 --- a/drivers/s390/char/sclp_sdias.c +++ b/drivers/s390/char/sclp_sdias.c | |||
| @@ -69,9 +69,6 @@ static DEFINE_MUTEX(sdias_mutex); | |||
| 69 | 69 | ||
| 70 | static void sdias_callback(struct sclp_req *request, void *data) | 70 | static void sdias_callback(struct sclp_req *request, void *data) |
| 71 | { | 71 | { |
| 72 | struct sdias_sccb *cbsccb; | ||
| 73 | |||
| 74 | cbsccb = (struct sdias_sccb *) request->sccb; | ||
| 75 | sclp_req_done = 1; | 72 | sclp_req_done = 1; |
| 76 | wake_up(&sdias_wq); /* Inform caller, that request is complete */ | 73 | wake_up(&sdias_wq); /* Inform caller, that request is complete */ |
| 77 | TRACE("callback done\n"); | 74 | TRACE("callback done\n"); |
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 8258d590505f..a879c139926a 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c | |||
| @@ -408,118 +408,72 @@ static int sclp_switch_cases(unsigned char *buf, int count) | |||
| 408 | return op - buf; | 408 | return op - buf; |
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | static void | 411 | static void sclp_get_input(struct gds_subvector *sv) |
| 412 | sclp_get_input(unsigned char *start, unsigned char *end) | ||
| 413 | { | 412 | { |
| 413 | unsigned char *str; | ||
| 414 | int count; | 414 | int count; |
| 415 | 415 | ||
| 416 | count = end - start; | 416 | str = (unsigned char *) (sv + 1); |
| 417 | count = sv->length - sizeof(*sv); | ||
| 417 | if (sclp_tty_tolower) | 418 | if (sclp_tty_tolower) |
| 418 | EBC_TOLOWER(start, count); | 419 | EBC_TOLOWER(str, count); |
| 419 | count = sclp_switch_cases(start, count); | 420 | count = sclp_switch_cases(str, count); |
| 420 | /* convert EBCDIC to ASCII (modify original input in SCCB) */ | 421 | /* convert EBCDIC to ASCII (modify original input in SCCB) */ |
| 421 | sclp_ebcasc_str(start, count); | 422 | sclp_ebcasc_str(str, count); |
| 422 | 423 | ||
| 423 | /* transfer input to high level driver */ | 424 | /* transfer input to high level driver */ |
| 424 | sclp_tty_input(start, count); | 425 | sclp_tty_input(str, count); |
| 425 | } | ||
| 426 | |||
| 427 | static inline struct gds_vector * | ||
| 428 | find_gds_vector(struct gds_vector *start, struct gds_vector *end, u16 id) | ||
| 429 | { | ||
| 430 | struct gds_vector *vec; | ||
| 431 | |||
| 432 | for (vec = start; vec < end; vec = (void *) vec + vec->length) | ||
| 433 | if (vec->gds_id == id) | ||
| 434 | return vec; | ||
| 435 | return NULL; | ||
| 436 | } | 426 | } |
| 437 | 427 | ||
| 438 | static inline struct gds_subvector * | 428 | static inline void sclp_eval_selfdeftextmsg(struct gds_subvector *sv) |
| 439 | find_gds_subvector(struct gds_subvector *start, | ||
| 440 | struct gds_subvector *end, u8 key) | ||
| 441 | { | 429 | { |
| 442 | struct gds_subvector *subvec; | 430 | void *end; |
| 443 | 431 | ||
| 444 | for (subvec = start; subvec < end; | 432 | end = (void *) sv + sv->length; |
| 445 | subvec = (void *) subvec + subvec->length) | 433 | for (sv = sv + 1; (void *) sv < end; sv = (void *) sv + sv->length) |
| 446 | if (subvec->key == key) | 434 | if (sv->key == 0x30) |
| 447 | return subvec; | 435 | sclp_get_input(sv); |
| 448 | return NULL; | ||
| 449 | } | 436 | } |
| 450 | 437 | ||
| 451 | static inline void | 438 | static inline void sclp_eval_textcmd(struct gds_vector *v) |
| 452 | sclp_eval_selfdeftextmsg(struct gds_subvector *start, | ||
| 453 | struct gds_subvector *end) | ||
| 454 | { | 439 | { |
| 455 | struct gds_subvector *subvec; | 440 | struct gds_subvector *sv; |
| 456 | 441 | void *end; | |
| 457 | subvec = start; | ||
| 458 | while (subvec < end) { | ||
| 459 | subvec = find_gds_subvector(subvec, end, 0x30); | ||
| 460 | if (!subvec) | ||
| 461 | break; | ||
| 462 | sclp_get_input((unsigned char *)(subvec + 1), | ||
| 463 | (unsigned char *) subvec + subvec->length); | ||
| 464 | subvec = (void *) subvec + subvec->length; | ||
| 465 | } | ||
| 466 | } | ||
| 467 | 442 | ||
| 468 | static inline void | 443 | end = (void *) v + v->length; |
| 469 | sclp_eval_textcmd(struct gds_subvector *start, | 444 | for (sv = (struct gds_subvector *) (v + 1); |
| 470 | struct gds_subvector *end) | 445 | (void *) sv < end; sv = (void *) sv + sv->length) |
| 471 | { | 446 | if (sv->key == GDS_KEY_SELFDEFTEXTMSG) |
| 472 | struct gds_subvector *subvec; | 447 | sclp_eval_selfdeftextmsg(sv); |
| 473 | 448 | ||
| 474 | subvec = start; | ||
| 475 | while (subvec < end) { | ||
| 476 | subvec = find_gds_subvector(subvec, end, | ||
| 477 | GDS_KEY_SELFDEFTEXTMSG); | ||
| 478 | if (!subvec) | ||
| 479 | break; | ||
| 480 | sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1), | ||
| 481 | (void *)subvec + subvec->length); | ||
| 482 | subvec = (void *) subvec + subvec->length; | ||
| 483 | } | ||
| 484 | } | 449 | } |
| 485 | 450 | ||
| 486 | static inline void | 451 | static inline void sclp_eval_cpmsu(struct gds_vector *v) |
| 487 | sclp_eval_cpmsu(struct gds_vector *start, struct gds_vector *end) | ||
| 488 | { | 452 | { |
| 489 | struct gds_vector *vec; | 453 | void *end; |
| 490 | 454 | ||
| 491 | vec = start; | 455 | end = (void *) v + v->length; |
| 492 | while (vec < end) { | 456 | for (v = v + 1; (void *) v < end; v = (void *) v + v->length) |
| 493 | vec = find_gds_vector(vec, end, GDS_ID_TEXTCMD); | 457 | if (v->gds_id == GDS_ID_TEXTCMD) |
| 494 | if (!vec) | 458 | sclp_eval_textcmd(v); |
| 495 | break; | ||
| 496 | sclp_eval_textcmd((struct gds_subvector *)(vec + 1), | ||
| 497 | (void *) vec + vec->length); | ||
| 498 | vec = (void *) vec + vec->length; | ||
| 499 | } | ||
| 500 | } | 459 | } |
| 501 | 460 | ||
| 502 | 461 | ||
| 503 | static inline void | 462 | static inline void sclp_eval_mdsmu(struct gds_vector *v) |
| 504 | sclp_eval_mdsmu(struct gds_vector *start, void *end) | ||
| 505 | { | 463 | { |
| 506 | struct gds_vector *vec; | 464 | v = sclp_find_gds_vector(v + 1, (void *) v + v->length, GDS_ID_CPMSU); |
| 507 | 465 | if (v) | |
| 508 | vec = find_gds_vector(start, end, GDS_ID_CPMSU); | 466 | sclp_eval_cpmsu(v); |
| 509 | if (vec) | ||
| 510 | sclp_eval_cpmsu(vec + 1, (void *) vec + vec->length); | ||
| 511 | } | 467 | } |
| 512 | 468 | ||
| 513 | static void | 469 | static void sclp_tty_receiver(struct evbuf_header *evbuf) |
| 514 | sclp_tty_receiver(struct evbuf_header *evbuf) | ||
| 515 | { | 470 | { |
| 516 | struct gds_vector *start, *end, *vec; | 471 | struct gds_vector *v; |
| 517 | 472 | ||
| 518 | start = (struct gds_vector *)(evbuf + 1); | 473 | v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length, |
| 519 | end = (void *) evbuf + evbuf->length; | 474 | GDS_ID_MDSMU); |
| 520 | vec = find_gds_vector(start, end, GDS_ID_MDSMU); | 475 | if (v) |
| 521 | if (vec) | 476 | sclp_eval_mdsmu(v); |
| 522 | sclp_eval_mdsmu(vec + 1, (void *) vec + vec->length); | ||
| 523 | } | 477 | } |
| 524 | 478 | ||
| 525 | static void | 479 | static void |
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index b98dcbd16711..a7d570728882 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
| @@ -796,10 +796,8 @@ static void tape_3590_med_state_set(struct tape_device *device, | |||
| 796 | static int | 796 | static int |
| 797 | tape_3590_done(struct tape_device *device, struct tape_request *request) | 797 | tape_3590_done(struct tape_device *device, struct tape_request *request) |
| 798 | { | 798 | { |
| 799 | struct tape_3590_disc_data *disc_data; | ||
| 800 | 799 | ||
| 801 | DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); | 800 | DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); |
| 802 | disc_data = device->discdata; | ||
| 803 | 801 | ||
| 804 | switch (request->op) { | 802 | switch (request->op) { |
| 805 | case TO_BSB: | 803 | case TO_BSB: |
| @@ -1394,17 +1392,12 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) | |||
| 1394 | static int tape_3590_crypt_error(struct tape_device *device, | 1392 | static int tape_3590_crypt_error(struct tape_device *device, |
| 1395 | struct tape_request *request, struct irb *irb) | 1393 | struct tape_request *request, struct irb *irb) |
| 1396 | { | 1394 | { |
| 1397 | u8 cu_rc, ekm_rc1; | 1395 | u8 cu_rc; |
| 1398 | u16 ekm_rc2; | 1396 | u16 ekm_rc2; |
| 1399 | u32 drv_rc; | ||
| 1400 | const char *bus_id; | ||
| 1401 | char *sense; | 1397 | char *sense; |
| 1402 | 1398 | ||
| 1403 | sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; | 1399 | sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; |
| 1404 | bus_id = dev_name(&device->cdev->dev); | ||
| 1405 | cu_rc = sense[0]; | 1400 | cu_rc = sense[0]; |
| 1406 | drv_rc = *((u32*) &sense[5]) & 0xffffff; | ||
| 1407 | ekm_rc1 = sense[9]; | ||
| 1408 | ekm_rc2 = *((u16*) &sense[10]); | 1401 | ekm_rc2 = *((u16*) &sense[10]); |
| 1409 | if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) | 1402 | if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) |
| 1410 | /* key not defined on EKM */ | 1403 | /* key not defined on EKM */ |
| @@ -1429,7 +1422,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, | |||
| 1429 | struct irb *irb) | 1422 | struct irb *irb) |
| 1430 | { | 1423 | { |
| 1431 | struct tape_3590_sense *sense; | 1424 | struct tape_3590_sense *sense; |
| 1432 | int rc; | ||
| 1433 | 1425 | ||
| 1434 | #ifdef CONFIG_S390_TAPE_BLOCK | 1426 | #ifdef CONFIG_S390_TAPE_BLOCK |
| 1435 | if (request->op == TO_BLOCK) { | 1427 | if (request->op == TO_BLOCK) { |
| @@ -1454,7 +1446,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, | |||
| 1454 | * - "break": basic error recovery is done | 1446 | * - "break": basic error recovery is done |
| 1455 | * - "goto out:": just print error message if available | 1447 | * - "goto out:": just print error message if available |
| 1456 | */ | 1448 | */ |
| 1457 | rc = -EIO; | ||
| 1458 | switch (sense->rc_rqc) { | 1449 | switch (sense->rc_rqc) { |
| 1459 | 1450 | ||
| 1460 | case 0x1110: | 1451 | case 0x1110: |
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c deleted file mode 100644 index 1b3924c2fffd..000000000000 --- a/drivers/s390/char/tape_block.c +++ /dev/null | |||
| @@ -1,444 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * drivers/s390/char/tape_block.c | ||
| 3 | * block device frontend for tape device driver | ||
| 4 | * | ||
| 5 | * S390 and zSeries version | ||
| 6 | * Copyright (C) 2001,2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | ||
| 7 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
| 8 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> | ||
| 9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 10 | * Stefan Bader <shbader@de.ibm.com> | ||
| 11 | */ | ||
| 12 | |||
| 13 | #define KMSG_COMPONENT "tape" | ||
| 14 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 15 | |||
| 16 | #include <linux/fs.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/blkdev.h> | ||
| 19 | #include <linux/mutex.h> | ||
| 20 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/buffer_head.h> | ||
| 22 | #include <linux/kernel.h> | ||
| 23 | |||
| 24 | #include <asm/debug.h> | ||
| 25 | |||
| 26 | #define TAPE_DBF_AREA tape_core_dbf | ||
| 27 | |||
| 28 | #include "tape.h" | ||
| 29 | |||
| 30 | #define TAPEBLOCK_MAX_SEC 100 | ||
| 31 | #define TAPEBLOCK_MIN_REQUEUE 3 | ||
| 32 | |||
| 33 | /* | ||
| 34 | * 2003/11/25 Stefan Bader <shbader@de.ibm.com> | ||
| 35 | * | ||
| 36 | * In 2.5/2.6 the block device request function is very likely to be called | ||
| 37 | * with disabled interrupts (e.g. generic_unplug_device). So the driver can't | ||
| 38 | * just call any function that tries to allocate CCW requests from that con- | ||
| 39 | * text since it might sleep. There are two choices to work around this: | ||
| 40 | * a) do not allocate with kmalloc but use its own memory pool | ||
| 41 | * b) take requests from the queue outside that context, knowing that | ||
| 42 | * allocation might sleep | ||
| 43 | */ | ||
| 44 | |||
| 45 | /* | ||
| 46 | * file operation structure for tape block frontend | ||
| 47 | */ | ||
| 48 | static DEFINE_MUTEX(tape_block_mutex); | ||
| 49 | static int tapeblock_open(struct block_device *, fmode_t); | ||
| 50 | static int tapeblock_release(struct gendisk *, fmode_t); | ||
| 51 | static unsigned int tapeblock_check_events(struct gendisk *, unsigned int); | ||
| 52 | static int tapeblock_revalidate_disk(struct gendisk *); | ||
| 53 | |||
| 54 | static const struct block_device_operations tapeblock_fops = { | ||
| 55 | .owner = THIS_MODULE, | ||
| 56 | .open = tapeblock_open, | ||
| 57 | .release = tapeblock_release, | ||
| 58 | .check_events = tapeblock_check_events, | ||
| 59 | .revalidate_disk = tapeblock_revalidate_disk, | ||
| 60 | }; | ||
| 61 | |||
| 62 | static int tapeblock_major = 0; | ||
| 63 | |||
| 64 | static void | ||
| 65 | tapeblock_trigger_requeue(struct tape_device *device) | ||
| 66 | { | ||
| 67 | /* Protect against rescheduling. */ | ||
| 68 | if (atomic_cmpxchg(&device->blk_data.requeue_scheduled, 0, 1) != 0) | ||
| 69 | return; | ||
| 70 | schedule_work(&device->blk_data.requeue_task); | ||
| 71 | } | ||
| 72 | |||
| 73 | /* | ||
| 74 | * Post finished request. | ||
| 75 | */ | ||
| 76 | static void | ||
| 77 | __tapeblock_end_request(struct tape_request *ccw_req, void *data) | ||
| 78 | { | ||
| 79 | struct tape_device *device; | ||
| 80 | struct request *req; | ||
| 81 | |||
| 82 | DBF_LH(6, "__tapeblock_end_request()\n"); | ||
| 83 | |||
| 84 | device = ccw_req->device; | ||
| 85 | req = (struct request *) data; | ||
| 86 | blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO); | ||
| 87 | if (ccw_req->rc == 0) | ||
| 88 | /* Update position. */ | ||
| 89 | device->blk_data.block_position = | ||
| 90 | (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B; | ||
| 91 | else | ||
| 92 | /* We lost the position information due to an error. */ | ||
| 93 | device->blk_data.block_position = -1; | ||
| 94 | device->discipline->free_bread(ccw_req); | ||
| 95 | if (!list_empty(&device->req_queue) || | ||
| 96 | blk_peek_request(device->blk_data.request_queue)) | ||
| 97 | tapeblock_trigger_requeue(device); | ||
| 98 | } | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Feed the tape device CCW queue with requests supplied in a list. | ||
| 102 | */ | ||
| 103 | static int | ||
| 104 | tapeblock_start_request(struct tape_device *device, struct request *req) | ||
| 105 | { | ||
| 106 | struct tape_request * ccw_req; | ||
| 107 | int rc; | ||
| 108 | |||
| 109 | DBF_LH(6, "tapeblock_start_request(%p, %p)\n", device, req); | ||
| 110 | |||
| 111 | ccw_req = device->discipline->bread(device, req); | ||
| 112 | if (IS_ERR(ccw_req)) { | ||
| 113 | DBF_EVENT(1, "TBLOCK: bread failed\n"); | ||
| 114 | blk_end_request_all(req, -EIO); | ||
| 115 | return PTR_ERR(ccw_req); | ||
| 116 | } | ||
| 117 | ccw_req->callback = __tapeblock_end_request; | ||
| 118 | ccw_req->callback_data = (void *) req; | ||
| 119 | ccw_req->retries = TAPEBLOCK_RETRIES; | ||
| 120 | |||
| 121 | rc = tape_do_io_async(device, ccw_req); | ||
| 122 | if (rc) { | ||
| 123 | /* | ||
| 124 | * Start/enqueueing failed. No retries in | ||
| 125 | * this case. | ||
| 126 | */ | ||
| 127 | blk_end_request_all(req, -EIO); | ||
| 128 | device->discipline->free_bread(ccw_req); | ||
| 129 | } | ||
| 130 | |||
| 131 | return rc; | ||
| 132 | } | ||
| 133 | |||
| 134 | /* | ||
| 135 | * Move requests from the block device request queue to the tape device ccw | ||
| 136 | * queue. | ||
| 137 | */ | ||
| 138 | static void | ||
| 139 | tapeblock_requeue(struct work_struct *work) { | ||
| 140 | struct tape_blk_data * blkdat; | ||
| 141 | struct tape_device * device; | ||
| 142 | struct request_queue * queue; | ||
| 143 | int nr_queued; | ||
| 144 | struct request * req; | ||
| 145 | struct list_head * l; | ||
| 146 | int rc; | ||
| 147 | |||
| 148 | blkdat = container_of(work, struct tape_blk_data, requeue_task); | ||
| 149 | device = blkdat->device; | ||
| 150 | if (!device) | ||
| 151 | return; | ||
| 152 | |||
| 153 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
| 154 | queue = device->blk_data.request_queue; | ||
| 155 | |||
| 156 | /* Count number of requests on ccw queue. */ | ||
| 157 | nr_queued = 0; | ||
| 158 | list_for_each(l, &device->req_queue) | ||
| 159 | nr_queued++; | ||
| 160 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
| 161 | |||
| 162 | spin_lock_irq(&device->blk_data.request_queue_lock); | ||
| 163 | while ( | ||
| 164 | blk_peek_request(queue) && | ||
| 165 | nr_queued < TAPEBLOCK_MIN_REQUEUE | ||
| 166 | ) { | ||
| 167 | req = blk_fetch_request(queue); | ||
| 168 | if (rq_data_dir(req) == WRITE) { | ||
| 169 | DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); | ||
| 170 | spin_unlock_irq(&device->blk_data.request_queue_lock); | ||
| 171 | blk_end_request_all(req, -EIO); | ||
| 172 | spin_lock_irq(&device->blk_data.request_queue_lock); | ||
| 173 | continue; | ||
| 174 | } | ||
| 175 | nr_queued++; | ||
| 176 | spin_unlock_irq(&device->blk_data.request_queue_lock); | ||
| 177 | rc = tapeblock_start_request(device, req); | ||
| 178 | spin_lock_irq(&device->blk_data.request_queue_lock); | ||
| 179 | } | ||
| 180 | spin_unlock_irq(&device->blk_data.request_queue_lock); | ||
| 181 | atomic_set(&device->blk_data.requeue_scheduled, 0); | ||
| 182 | } | ||
| 183 | |||
| 184 | /* | ||
| 185 | * Tape request queue function. Called from ll_rw_blk.c | ||
| 186 | */ | ||
| 187 | static void | ||
| 188 | tapeblock_request_fn(struct request_queue *queue) | ||
| 189 | { | ||
| 190 | struct tape_device *device; | ||
| 191 | |||
| 192 | device = (struct tape_device *) queue->queuedata; | ||
| 193 | DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device); | ||
| 194 | BUG_ON(device == NULL); | ||
| 195 | tapeblock_trigger_requeue(device); | ||
| 196 | } | ||
| 197 | |||
| 198 | /* | ||
| 199 | * This function is called for every new tapedevice | ||
| 200 | */ | ||
| 201 | int | ||
| 202 | tapeblock_setup_device(struct tape_device * device) | ||
| 203 | { | ||
| 204 | struct tape_blk_data * blkdat; | ||
| 205 | struct gendisk * disk; | ||
| 206 | int rc; | ||
| 207 | |||
| 208 | blkdat = &device->blk_data; | ||
| 209 | blkdat->device = device; | ||
| 210 | spin_lock_init(&blkdat->request_queue_lock); | ||
| 211 | atomic_set(&blkdat->requeue_scheduled, 0); | ||
| 212 | |||
| 213 | blkdat->request_queue = blk_init_queue( | ||
| 214 | tapeblock_request_fn, | ||
| 215 | &blkdat->request_queue_lock | ||
| 216 | ); | ||
| 217 | if (!blkdat->request_queue) | ||
| 218 | return -ENOMEM; | ||
| 219 | |||
| 220 | rc = elevator_change(blkdat->request_queue, "noop"); | ||
| 221 | if (rc) | ||
| 222 | goto cleanup_queue; | ||
| 223 | |||
| 224 | blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); | ||
| 225 | blk_queue_max_hw_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC); | ||
| 226 | blk_queue_max_segments(blkdat->request_queue, -1L); | ||
| 227 | blk_queue_max_segment_size(blkdat->request_queue, -1L); | ||
| 228 | blk_queue_segment_boundary(blkdat->request_queue, -1L); | ||
| 229 | |||
| 230 | disk = alloc_disk(1); | ||
| 231 | if (!disk) { | ||
| 232 | rc = -ENOMEM; | ||
| 233 | goto cleanup_queue; | ||
| 234 | } | ||
| 235 | |||
| 236 | disk->major = tapeblock_major; | ||
| 237 | disk->first_minor = device->first_minor; | ||
| 238 | disk->fops = &tapeblock_fops; | ||
| 239 | disk->private_data = tape_get_device(device); | ||
| 240 | disk->queue = blkdat->request_queue; | ||
| 241 | set_capacity(disk, 0); | ||
| 242 | sprintf(disk->disk_name, "btibm%d", | ||
| 243 | device->first_minor / TAPE_MINORS_PER_DEV); | ||
| 244 | |||
| 245 | blkdat->disk = disk; | ||
| 246 | blkdat->medium_changed = 1; | ||
| 247 | blkdat->request_queue->queuedata = tape_get_device(device); | ||
| 248 | |||
| 249 | add_disk(disk); | ||
| 250 | |||
| 251 | tape_get_device(device); | ||
| 252 | INIT_WORK(&blkdat->requeue_task, tapeblock_requeue); | ||
| 253 | |||
| 254 | return 0; | ||
| 255 | |||
| 256 | cleanup_queue: | ||
| 257 | blk_cleanup_queue(blkdat->request_queue); | ||
| 258 | blkdat->request_queue = NULL; | ||
| 259 | |||
| 260 | return rc; | ||
| 261 | } | ||
| 262 | |||
| 263 | void | ||
| 264 | tapeblock_cleanup_device(struct tape_device *device) | ||
| 265 | { | ||
| 266 | flush_work_sync(&device->blk_data.requeue_task); | ||
| 267 | tape_put_device(device); | ||
| 268 | |||
| 269 | if (!device->blk_data.disk) { | ||
| 270 | goto cleanup_queue; | ||
| 271 | } | ||
| 272 | |||
| 273 | del_gendisk(device->blk_data.disk); | ||
| 274 | device->blk_data.disk->private_data = NULL; | ||
| 275 | tape_put_device(device); | ||
| 276 | put_disk(device->blk_data.disk); | ||
| 277 | |||
| 278 | device->blk_data.disk = NULL; | ||
| 279 | cleanup_queue: | ||
| 280 | device->blk_data.request_queue->queuedata = NULL; | ||
| 281 | tape_put_device(device); | ||
| 282 | |||
| 283 | blk_cleanup_queue(device->blk_data.request_queue); | ||
| 284 | device->blk_data.request_queue = NULL; | ||
| 285 | } | ||
| 286 | |||
| 287 | /* | ||
| 288 | * Detect number of blocks of the tape. | ||
| 289 | * FIXME: can we extent this to detect the blocks size as well ? | ||
| 290 | */ | ||
| 291 | static int | ||
| 292 | tapeblock_revalidate_disk(struct gendisk *disk) | ||
| 293 | { | ||
| 294 | struct tape_device * device; | ||
| 295 | unsigned int nr_of_blks; | ||
| 296 | int rc; | ||
| 297 | |||
| 298 | device = (struct tape_device *) disk->private_data; | ||
| 299 | BUG_ON(!device); | ||
| 300 | |||
| 301 | if (!device->blk_data.medium_changed) | ||
| 302 | return 0; | ||
| 303 | |||
| 304 | rc = tape_mtop(device, MTFSFM, 1); | ||
| 305 | if (rc) | ||
| 306 | return rc; | ||
| 307 | |||
| 308 | rc = tape_mtop(device, MTTELL, 1); | ||
| 309 | if (rc < 0) | ||
| 310 | return rc; | ||
| 311 | |||
| 312 | pr_info("%s: Determining the size of the recorded area...\n", | ||
| 313 | dev_name(&device->cdev->dev)); | ||
| 314 | DBF_LH(3, "Image file ends at %d\n", rc); | ||
| 315 | nr_of_blks = rc; | ||
| 316 | |||
| 317 | /* This will fail for the first file. Catch the error by checking the | ||
| 318 | * position. */ | ||
| 319 | tape_mtop(device, MTBSF, 1); | ||
| 320 | |||
| 321 | rc = tape_mtop(device, MTTELL, 1); | ||
| 322 | if (rc < 0) | ||
| 323 | return rc; | ||
| 324 | |||
| 325 | if (rc > nr_of_blks) | ||
| 326 | return -EINVAL; | ||
| 327 | |||
| 328 | DBF_LH(3, "Image file starts at %d\n", rc); | ||
| 329 | device->bof = rc; | ||
| 330 | nr_of_blks -= rc; | ||
| 331 | |||
| 332 | pr_info("%s: The size of the recorded area is %i blocks\n", | ||
| 333 | dev_name(&device->cdev->dev), nr_of_blks); | ||
| 334 | set_capacity(device->blk_data.disk, | ||
| 335 | nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); | ||
| 336 | |||
| 337 | device->blk_data.block_position = 0; | ||
| 338 | device->blk_data.medium_changed = 0; | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | static unsigned int | ||
| 343 | tapeblock_check_events(struct gendisk *disk, unsigned int clearing) | ||
| 344 | { | ||
| 345 | struct tape_device *device; | ||
| 346 | |||
| 347 | device = (struct tape_device *) disk->private_data; | ||
| 348 | DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n", | ||
| 349 | device, device->blk_data.medium_changed); | ||
| 350 | |||
| 351 | return device->blk_data.medium_changed ? DISK_EVENT_MEDIA_CHANGE : 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | /* | ||
| 355 | * Block frontend tape device open function. | ||
| 356 | */ | ||
| 357 | static int | ||
| 358 | tapeblock_open(struct block_device *bdev, fmode_t mode) | ||
| 359 | { | ||
| 360 | struct gendisk * disk = bdev->bd_disk; | ||
| 361 | struct tape_device * device; | ||
| 362 | int rc; | ||
| 363 | |||
| 364 | mutex_lock(&tape_block_mutex); | ||
| 365 | device = tape_get_device(disk->private_data); | ||
| 366 | |||
| 367 | if (device->required_tapemarks) { | ||
| 368 | DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); | ||
| 369 | pr_warning("%s: Opening the tape failed because of missing " | ||
| 370 | "end-of-file marks\n", dev_name(&device->cdev->dev)); | ||
| 371 | rc = -EPERM; | ||
| 372 | goto put_device; | ||
| 373 | } | ||
| 374 | |||
| 375 | rc = tape_open(device); | ||
| 376 | if (rc) | ||
| 377 | goto put_device; | ||
| 378 | |||
| 379 | rc = tapeblock_revalidate_disk(disk); | ||
| 380 | if (rc) | ||
| 381 | goto release; | ||
| 382 | |||
| 383 | /* | ||
| 384 | * Note: The reference to <device> is hold until the release function | ||
| 385 | * is called. | ||
| 386 | */ | ||
| 387 | tape_state_set(device, TS_BLKUSE); | ||
| 388 | mutex_unlock(&tape_block_mutex); | ||
| 389 | return 0; | ||
| 390 | |||
| 391 | release: | ||
| 392 | tape_release(device); | ||
| 393 | put_device: | ||
| 394 | tape_put_device(device); | ||
| 395 | mutex_unlock(&tape_block_mutex); | ||
| 396 | return rc; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* | ||
| 400 | * Block frontend tape device release function. | ||
| 401 | * | ||
| 402 | * Note: One reference to the tape device was made by the open function. So | ||
| 403 | * we just get the pointer here and release the reference. | ||
| 404 | */ | ||
| 405 | static int | ||
| 406 | tapeblock_release(struct gendisk *disk, fmode_t mode) | ||
| 407 | { | ||
| 408 | struct tape_device *device = disk->private_data; | ||
| 409 | |||
| 410 | mutex_lock(&tape_block_mutex); | ||
| 411 | tape_state_set(device, TS_IN_USE); | ||
| 412 | tape_release(device); | ||
| 413 | tape_put_device(device); | ||
| 414 | mutex_unlock(&tape_block_mutex); | ||
| 415 | |||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | |||
| 419 | /* | ||
| 420 | * Initialize block device frontend. | ||
| 421 | */ | ||
| 422 | int | ||
| 423 | tapeblock_init(void) | ||
| 424 | { | ||
| 425 | int rc; | ||
| 426 | |||
| 427 | /* Register the tape major number to the kernel */ | ||
| 428 | rc = register_blkdev(tapeblock_major, "tBLK"); | ||
| 429 | if (rc < 0) | ||
| 430 | return rc; | ||
| 431 | |||
| 432 | if (tapeblock_major == 0) | ||
| 433 | tapeblock_major = rc; | ||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | /* | ||
| 438 | * Deregister major for block device frontend | ||
| 439 | */ | ||
| 440 | void | ||
| 441 | tapeblock_exit(void) | ||
| 442 | { | ||
| 443 | unregister_blkdev(tapeblock_major, "tBLK"); | ||
| 444 | } | ||
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 3c3f342149ec..e7650170274a 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c | |||
| @@ -564,7 +564,6 @@ int | |||
| 564 | tape_std_mtreten(struct tape_device *device, int mt_count) | 564 | tape_std_mtreten(struct tape_device *device, int mt_count) |
| 565 | { | 565 | { |
| 566 | struct tape_request *request; | 566 | struct tape_request *request; |
| 567 | int rc; | ||
| 568 | 567 | ||
| 569 | request = tape_alloc_request(4, 0); | 568 | request = tape_alloc_request(4, 0); |
| 570 | if (IS_ERR(request)) | 569 | if (IS_ERR(request)) |
| @@ -576,7 +575,7 @@ tape_std_mtreten(struct tape_device *device, int mt_count) | |||
| 576 | tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL); | 575 | tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL); |
| 577 | tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr); | 576 | tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr); |
| 578 | /* execute it, MTRETEN rc gets ignored */ | 577 | /* execute it, MTRETEN rc gets ignored */ |
| 579 | rc = tape_do_io_interruptible(device, request); | 578 | tape_do_io_interruptible(device, request); |
| 580 | tape_free_request(request); | 579 | tape_free_request(request); |
| 581 | return tape_mtop(device, MTREW, 1); | 580 | return tape_mtop(device, MTREW, 1); |
| 582 | } | 581 | } |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 0689fcf23a11..75c3f1f8fd43 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
| @@ -326,6 +326,36 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) | |||
| 326 | s390_process_res_acc(&link); | 326 | s390_process_res_acc(&link); |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | static void chsc_process_sei_chp_avail(struct chsc_sei_area *sei_area) | ||
| 330 | { | ||
| 331 | struct channel_path *chp; | ||
| 332 | struct chp_id chpid; | ||
| 333 | u8 *data; | ||
| 334 | int num; | ||
| 335 | |||
| 336 | CIO_CRW_EVENT(4, "chsc: channel path availability information\n"); | ||
| 337 | if (sei_area->rs != 0) | ||
| 338 | return; | ||
| 339 | data = sei_area->ccdf; | ||
| 340 | chp_id_init(&chpid); | ||
| 341 | for (num = 0; num <= __MAX_CHPID; num++) { | ||
| 342 | if (!chp_test_bit(data, num)) | ||
| 343 | continue; | ||
| 344 | chpid.id = num; | ||
| 345 | |||
| 346 | CIO_CRW_EVENT(4, "Update information for channel path " | ||
| 347 | "%x.%02x\n", chpid.cssid, chpid.id); | ||
| 348 | chp = chpid_to_chp(chpid); | ||
| 349 | if (!chp) { | ||
| 350 | chp_new(chpid); | ||
| 351 | continue; | ||
| 352 | } | ||
| 353 | mutex_lock(&chp->lock); | ||
| 354 | chsc_determine_base_channel_path_desc(chpid, &chp->desc); | ||
| 355 | mutex_unlock(&chp->lock); | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 329 | struct chp_config_data { | 359 | struct chp_config_data { |
| 330 | u8 map[32]; | 360 | u8 map[32]; |
| 331 | u8 op; | 361 | u8 op; |
| @@ -376,9 +406,12 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area) | |||
| 376 | case 1: /* link incident*/ | 406 | case 1: /* link incident*/ |
| 377 | chsc_process_sei_link_incident(sei_area); | 407 | chsc_process_sei_link_incident(sei_area); |
| 378 | break; | 408 | break; |
| 379 | case 2: /* i/o resource accessibiliy */ | 409 | case 2: /* i/o resource accessibility */ |
| 380 | chsc_process_sei_res_acc(sei_area); | 410 | chsc_process_sei_res_acc(sei_area); |
| 381 | break; | 411 | break; |
| 412 | case 7: /* channel-path-availability information */ | ||
| 413 | chsc_process_sei_chp_avail(sei_area); | ||
| 414 | break; | ||
| 382 | case 8: /* channel-path-configuration notification */ | 415 | case 8: /* channel-path-configuration notification */ |
| 383 | chsc_process_sei_chp_config(sei_area); | 416 | chsc_process_sei_chp_config(sei_area); |
| 384 | break; | 417 | break; |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 6084103672b5..52c233fa2b12 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
| @@ -408,9 +408,10 @@ ccw_device_done(struct ccw_device *cdev, int state) | |||
| 408 | CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel " | 408 | CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel " |
| 409 | "%04x\n", cdev->private->dev_id.devno, | 409 | "%04x\n", cdev->private->dev_id.devno, |
| 410 | sch->schid.sch_no); | 410 | sch->schid.sch_no); |
| 411 | if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) | 411 | if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) { |
| 412 | cdev->private->state = DEV_STATE_NOT_OPER; | ||
| 412 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); | 413 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); |
| 413 | else | 414 | } else |
| 414 | ccw_device_set_disconnected(cdev); | 415 | ccw_device_set_disconnected(cdev); |
| 415 | cdev->private->flags.donotify = 0; | 416 | cdev->private->flags.donotify = 0; |
| 416 | break; | 417 | break; |
| @@ -840,9 +841,6 @@ call_handler: | |||
| 840 | static void | 841 | static void |
| 841 | ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) | 842 | ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) |
| 842 | { | 843 | { |
| 843 | struct subchannel *sch; | ||
| 844 | |||
| 845 | sch = to_subchannel(cdev->dev.parent); | ||
| 846 | ccw_device_set_timeout(cdev, 0); | 844 | ccw_device_set_timeout(cdev, 0); |
| 847 | /* Start delayed path verification. */ | 845 | /* Start delayed path verification. */ |
| 848 | ccw_device_online_verify(cdev, 0); | 846 | ccw_device_online_verify(cdev, 0); |
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 651976b54af8..f98698d5735e 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c | |||
| @@ -418,12 +418,9 @@ int ccw_device_resume(struct ccw_device *cdev) | |||
| 418 | int | 418 | int |
| 419 | ccw_device_call_handler(struct ccw_device *cdev) | 419 | ccw_device_call_handler(struct ccw_device *cdev) |
| 420 | { | 420 | { |
| 421 | struct subchannel *sch; | ||
| 422 | unsigned int stctl; | 421 | unsigned int stctl; |
| 423 | int ending_status; | 422 | int ending_status; |
| 424 | 423 | ||
| 425 | sch = to_subchannel(cdev->dev.parent); | ||
| 426 | |||
| 427 | /* | 424 | /* |
| 428 | * we allow for the device action handler if . | 425 | * we allow for the device action handler if . |
| 429 | * - we received ending status | 426 | * - we received ending status |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index e8f267eb8887..55e8f721e38a 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
| @@ -1446,7 +1446,7 @@ set: | |||
| 1446 | static int handle_outbound(struct qdio_q *q, unsigned int callflags, | 1446 | static int handle_outbound(struct qdio_q *q, unsigned int callflags, |
| 1447 | int bufnr, int count) | 1447 | int bufnr, int count) |
| 1448 | { | 1448 | { |
| 1449 | unsigned char state; | 1449 | unsigned char state = 0; |
| 1450 | int used, rc = 0; | 1450 | int used, rc = 0; |
| 1451 | 1451 | ||
| 1452 | qperf_inc(q, outbound_call); | 1452 | qperf_inc(q, outbound_call); |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 67302b944ab3..16e4a25596e7 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
| @@ -1183,8 +1183,12 @@ static void ap_scan_bus(struct work_struct *unused) | |||
| 1183 | INIT_LIST_HEAD(&ap_dev->list); | 1183 | INIT_LIST_HEAD(&ap_dev->list); |
| 1184 | setup_timer(&ap_dev->timeout, ap_request_timeout, | 1184 | setup_timer(&ap_dev->timeout, ap_request_timeout, |
| 1185 | (unsigned long) ap_dev); | 1185 | (unsigned long) ap_dev); |
| 1186 | if (device_type == 0) | 1186 | if (device_type == 0) { |
| 1187 | ap_probe_device_type(ap_dev); | 1187 | if (ap_probe_device_type(ap_dev)) { |
| 1188 | kfree(ap_dev); | ||
| 1189 | continue; | ||
| 1190 | } | ||
| 1191 | } | ||
| 1188 | else | 1192 | else |
| 1189 | ap_dev->device_type = device_type; | 1193 | ap_dev->device_type = device_type; |
| 1190 | 1194 | ||
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index b4bfe338ea0e..e9b8e5926bef 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h | |||
| @@ -184,22 +184,18 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b) | |||
| 184 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | 184 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ |
| 185 | #endif | 185 | #endif |
| 186 | 186 | ||
| 187 | #ifndef __HAVE_ARCH_PAGE_TEST_DIRTY | 187 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY |
| 188 | #define page_test_dirty(page) (0) | 188 | #define page_test_and_clear_dirty(pfn, mapped) (0) |
| 189 | #endif | 189 | #endif |
| 190 | 190 | ||
| 191 | #ifndef __HAVE_ARCH_PAGE_CLEAR_DIRTY | 191 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY |
| 192 | #define page_clear_dirty(page, mapped) do { } while (0) | ||
| 193 | #endif | ||
| 194 | |||
| 195 | #ifndef __HAVE_ARCH_PAGE_TEST_DIRTY | ||
| 196 | #define pte_maybe_dirty(pte) pte_dirty(pte) | 192 | #define pte_maybe_dirty(pte) pte_dirty(pte) |
| 197 | #else | 193 | #else |
| 198 | #define pte_maybe_dirty(pte) (1) | 194 | #define pte_maybe_dirty(pte) (1) |
| 199 | #endif | 195 | #endif |
| 200 | 196 | ||
| 201 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | 197 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG |
| 202 | #define page_test_and_clear_young(page) (0) | 198 | #define page_test_and_clear_young(pfn) (0) |
| 203 | #endif | 199 | #endif |
| 204 | 200 | ||
| 205 | #ifndef __HAVE_ARCH_PGD_OFFSET_GATE | 201 | #ifndef __HAVE_ARCH_PGD_OFFSET_GATE |
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 811183de1ef5..79a6700b7162 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h | |||
| @@ -308,7 +308,7 @@ static inline void SetPageUptodate(struct page *page) | |||
| 308 | { | 308 | { |
| 309 | #ifdef CONFIG_S390 | 309 | #ifdef CONFIG_S390 |
| 310 | if (!test_and_set_bit(PG_uptodate, &page->flags)) | 310 | if (!test_and_set_bit(PG_uptodate, &page->flags)) |
| 311 | page_clear_dirty(page, 0); | 311 | page_set_storage_key(page_to_pfn(page), PAGE_DEFAULT_KEY, 0); |
| 312 | #else | 312 | #else |
| 313 | /* | 313 | /* |
| 314 | * Memory barrier must be issued before setting the PG_uptodate bit, | 314 | * Memory barrier must be issued before setting the PG_uptodate bit, |
| @@ -719,7 +719,7 @@ int page_referenced(struct page *page, | |||
| 719 | unlock_page(page); | 719 | unlock_page(page); |
| 720 | } | 720 | } |
| 721 | out: | 721 | out: |
| 722 | if (page_test_and_clear_young(page)) | 722 | if (page_test_and_clear_young(page_to_pfn(page))) |
| 723 | referenced++; | 723 | referenced++; |
| 724 | 724 | ||
| 725 | return referenced; | 725 | return referenced; |
| @@ -785,10 +785,8 @@ int page_mkclean(struct page *page) | |||
| 785 | struct address_space *mapping = page_mapping(page); | 785 | struct address_space *mapping = page_mapping(page); |
| 786 | if (mapping) { | 786 | if (mapping) { |
| 787 | ret = page_mkclean_file(mapping, page); | 787 | ret = page_mkclean_file(mapping, page); |
| 788 | if (page_test_dirty(page)) { | 788 | if (page_test_and_clear_dirty(page_to_pfn(page), 1)) |
| 789 | page_clear_dirty(page, 1); | ||
| 790 | ret = 1; | 789 | ret = 1; |
| 791 | } | ||
| 792 | } | 790 | } |
| 793 | } | 791 | } |
| 794 | 792 | ||
| @@ -981,10 +979,9 @@ void page_remove_rmap(struct page *page) | |||
| 981 | * not if it's in swapcache - there might be another pte slot | 979 | * not if it's in swapcache - there might be another pte slot |
| 982 | * containing the swap entry, but page not yet written to swap. | 980 | * containing the swap entry, but page not yet written to swap. |
| 983 | */ | 981 | */ |
| 984 | if ((!PageAnon(page) || PageSwapCache(page)) && page_test_dirty(page)) { | 982 | if ((!PageAnon(page) || PageSwapCache(page)) && |
| 985 | page_clear_dirty(page, 1); | 983 | page_test_and_clear_dirty(page_to_pfn(page), 1)) |
| 986 | set_page_dirty(page); | 984 | set_page_dirty(page); |
| 987 | } | ||
| 988 | /* | 985 | /* |
| 989 | * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED | 986 | * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED |
| 990 | * and not charged by memcg for now. | 987 | * and not charged by memcg for now. |
