diff options
| -rw-r--r-- | arch/s390/include/asm/pgtable.h | 45 |
1 files changed, 43 insertions, 2 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 0bdb704ae051..1a928f84afd6 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
| @@ -281,6 +281,9 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
| 281 | #define RCP_GR_BIT 50 | 281 | #define RCP_GR_BIT 50 |
| 282 | #define RCP_GC_BIT 49 | 282 | #define RCP_GC_BIT 49 |
| 283 | 283 | ||
| 284 | /* User dirty bit for KVM's migration feature */ | ||
| 285 | #define KVM_UD_BIT 47 | ||
| 286 | |||
| 284 | #ifndef __s390x__ | 287 | #ifndef __s390x__ |
| 285 | 288 | ||
| 286 | /* Bits in the segment table address-space-control-element */ | 289 | /* Bits in the segment table address-space-control-element */ |
| @@ -575,12 +578,16 @@ static inline void ptep_rcp_copy(pte_t *ptep) | |||
| 575 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 578 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); |
| 576 | 579 | ||
| 577 | skey = page_get_storage_key(page_to_phys(page)); | 580 | skey = page_get_storage_key(page_to_phys(page)); |
| 578 | if (skey & _PAGE_CHANGED) | 581 | if (skey & _PAGE_CHANGED) { |
| 579 | set_bit_simple(RCP_GC_BIT, pgste); | 582 | set_bit_simple(RCP_GC_BIT, pgste); |
| 583 | set_bit_simple(KVM_UD_BIT, pgste); | ||
| 584 | } | ||
| 580 | if (skey & _PAGE_REFERENCED) | 585 | if (skey & _PAGE_REFERENCED) |
| 581 | set_bit_simple(RCP_GR_BIT, pgste); | 586 | set_bit_simple(RCP_GR_BIT, pgste); |
| 582 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) | 587 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { |
| 583 | SetPageDirty(page); | 588 | SetPageDirty(page); |
| 589 | set_bit_simple(KVM_UD_BIT, pgste); | ||
| 590 | } | ||
| 584 | if (test_and_clear_bit_simple(RCP_HR_BIT, pgste)) | 591 | if (test_and_clear_bit_simple(RCP_HR_BIT, pgste)) |
| 585 | SetPageReferenced(page); | 592 | SetPageReferenced(page); |
| 586 | #endif | 593 | #endif |
| @@ -744,6 +751,40 @@ static inline pte_t pte_mkspecial(pte_t pte) | |||
| 744 | return pte; | 751 | return pte; |
| 745 | } | 752 | } |
| 746 | 753 | ||
| 754 | #ifdef CONFIG_PGSTE | ||
| 755 | /* | ||
| 756 | * Get (and clear) the user dirty bit for a PTE. | ||
| 757 | */ | ||
| 758 | static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm, | ||
| 759 | pte_t *ptep) | ||
| 760 | { | ||
| 761 | int dirty; | ||
| 762 | unsigned long *pgste; | ||
| 763 | struct page *page; | ||
| 764 | unsigned int skey; | ||
| 765 | |||
| 766 | if (!mm->context.pgstes) | ||
| 767 | return -EINVAL; | ||
| 768 | rcp_lock(ptep); | ||
| 769 | pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | ||
| 770 | page = virt_to_page(pte_val(*ptep)); | ||
| 771 | skey = page_get_storage_key(page_to_phys(page)); | ||
| 772 | if (skey & _PAGE_CHANGED) { | ||
| 773 | set_bit_simple(RCP_GC_BIT, pgste); | ||
| 774 | set_bit_simple(KVM_UD_BIT, pgste); | ||
| 775 | } | ||
| 776 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { | ||
| 777 | SetPageDirty(page); | ||
| 778 | set_bit_simple(KVM_UD_BIT, pgste); | ||
| 779 | } | ||
| 780 | dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste); | ||
| 781 | if (skey & _PAGE_CHANGED) | ||
| 782 | page_clear_dirty(page); | ||
| 783 | rcp_unlock(ptep); | ||
| 784 | return dirty; | ||
| 785 | } | ||
| 786 | #endif | ||
| 787 | |||
| 747 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | 788 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |
| 748 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, | 789 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, |
| 749 | unsigned long addr, pte_t *ptep) | 790 | unsigned long addr, pte_t *ptep) |
