diff options
Diffstat (limited to 'arch/s390/mm')
-rw-r--r-- | arch/s390/mm/extmem.c | 6 | ||||
-rw-r--r-- | arch/s390/mm/fault.c | 187 | ||||
-rw-r--r-- | arch/s390/mm/hugetlbpage.c | 10 | ||||
-rw-r--r-- | arch/s390/mm/init.c | 3 | ||||
-rw-r--r-- | arch/s390/mm/pageattr.c | 2 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 68 | ||||
-rw-r--r-- | arch/s390/mm/vmem.c | 14 |
7 files changed, 119 insertions, 171 deletions
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); |