diff options
Diffstat (limited to 'arch/s390/mm/pgtable.c')
| -rw-r--r-- | arch/s390/mm/pgtable.c | 68 |
1 files changed, 9 insertions, 59 deletions
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index e1850c28cd6..8d433064251 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 | */ |
