diff options
author | Florian Funke <ffunke@de.ibm.com> | 2008-10-10 15:33:26 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-10-10 15:34:00 -0400 |
commit | 15e86b0c752d50e910b2cca6e83ce74c4440d06c (patch) | |
tree | c17e8e71362bb9432e215a01bbd671c76216d262 /arch | |
parent | ab1d848fd6a9151b02c6cbf4bddce6e24707b094 (diff) |
[S390] introduce dirty bit for kvm live migration
This patch defines a dirty bit in the PGSTE that can be used to implement
dirty pages logging for KVM's live migration. The bit is set in the
ptep_rcp_copy function, which is called to save dirty and referenced information
from the storage key in the PGSTE. The bit can be tested and reset by KVM using
the kvm_s390_test_and_clear_page_dirty function that is introduced by this patch.
Acked-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Florian Funke <ffunke@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch')
-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) |