diff options
| -rw-r--r-- | arch/s390/include/asm/page.h | 22 | ||||
| -rw-r--r-- | arch/s390/include/asm/pgtable.h | 131 | ||||
| -rw-r--r-- | arch/s390/include/asm/sclp.h | 1 | ||||
| -rw-r--r-- | arch/s390/include/asm/setup.h | 16 | ||||
| -rw-r--r-- | arch/s390/kvm/kvm-s390.c | 2 | ||||
| -rw-r--r-- | arch/s390/lib/uaccess_pt.c | 2 | ||||
| -rw-r--r-- | arch/s390/mm/pageattr.c | 2 | ||||
| -rw-r--r-- | arch/s390/mm/vmem.c | 24 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_cmd.c | 10 | ||||
| -rw-r--r-- | include/asm-generic/pgtable.h | 10 | ||||
| -rw-r--r-- | include/linux/page-flags.h | 8 | ||||
| -rw-r--r-- | mm/rmap.c | 24 |
12 files changed, 112 insertions, 140 deletions
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index a86ad4084073..75ce9b065f9f 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h | |||
| @@ -155,28 +155,6 @@ static inline int page_reset_referenced(unsigned long addr) | |||
| 155 | #define _PAGE_ACC_BITS 0xf0 /* HW access control bits */ | 155 | #define _PAGE_ACC_BITS 0xf0 /* HW access control bits */ |
| 156 | 156 | ||
| 157 | /* | 157 | /* |
| 158 | * Test and clear dirty bit in storage key. | ||
| 159 | * We can't clear the changed bit atomically. This is a potential | ||
| 160 | * race against modification of the referenced bit. This function | ||
| 161 | * should therefore only be called if it is not mapped in any | ||
| 162 | * address space. | ||
| 163 | * | ||
| 164 | * Note that the bit gets set whenever page content is changed. That means | ||
| 165 | * also when the page is modified by DMA or from inside the kernel. | ||
| 166 | */ | ||
| 167 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY | ||
| 168 | static inline int page_test_and_clear_dirty(unsigned long pfn, int mapped) | ||
| 169 | { | ||
| 170 | unsigned char skey; | ||
| 171 | |||
| 172 | skey = page_get_storage_key(pfn << PAGE_SHIFT); | ||
| 173 | if (!(skey & _PAGE_CHANGED)) | ||
| 174 | return 0; | ||
| 175 | page_set_storage_key(pfn << PAGE_SHIFT, skey & ~_PAGE_CHANGED, mapped); | ||
| 176 | return 1; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* | ||
| 180 | * Test and clear referenced bit in storage key. | 158 | * Test and clear referenced bit in storage key. |
| 181 | */ | 159 | */ |
| 182 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | 160 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG |
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index a009d4dd70cb..97de1200c849 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #ifndef __ASSEMBLY__ | 29 | #ifndef __ASSEMBLY__ |
| 30 | #include <linux/sched.h> | 30 | #include <linux/sched.h> |
| 31 | #include <linux/mm_types.h> | 31 | #include <linux/mm_types.h> |
| 32 | #include <linux/page-flags.h> | ||
| 32 | #include <asm/bug.h> | 33 | #include <asm/bug.h> |
| 33 | #include <asm/page.h> | 34 | #include <asm/page.h> |
| 34 | 35 | ||
| @@ -221,13 +222,15 @@ extern unsigned long MODULES_END; | |||
| 221 | /* Software bits in the page table entry */ | 222 | /* Software bits in the page table entry */ |
| 222 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ | 223 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ |
| 223 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ | 224 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ |
| 224 | #define _PAGE_SWC 0x004 /* SW pte changed bit (for KVM) */ | 225 | #define _PAGE_SWC 0x004 /* SW pte changed bit */ |
| 225 | #define _PAGE_SWR 0x008 /* SW pte referenced bit (for KVM) */ | 226 | #define _PAGE_SWR 0x008 /* SW pte referenced bit */ |
| 226 | #define _PAGE_SPECIAL 0x010 /* SW associated with special page */ | 227 | #define _PAGE_SWW 0x010 /* SW pte write bit */ |
| 228 | #define _PAGE_SPECIAL 0x020 /* SW associated with special page */ | ||
| 227 | #define __HAVE_ARCH_PTE_SPECIAL | 229 | #define __HAVE_ARCH_PTE_SPECIAL |
| 228 | 230 | ||
| 229 | /* Set of bits not changed in pte_modify */ | 231 | /* Set of bits not changed in pte_modify */ |
| 230 | #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_SWC | _PAGE_SWR) | 232 | #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_CO | \ |
| 233 | _PAGE_SWC | _PAGE_SWR) | ||
| 231 | 234 | ||
| 232 | /* Six different types of pages. */ | 235 | /* Six different types of pages. */ |
| 233 | #define _PAGE_TYPE_EMPTY 0x400 | 236 | #define _PAGE_TYPE_EMPTY 0x400 |
| @@ -321,6 +324,7 @@ extern unsigned long MODULES_END; | |||
| 321 | 324 | ||
| 322 | /* Bits in the region table entry */ | 325 | /* Bits in the region table entry */ |
| 323 | #define _REGION_ENTRY_ORIGIN ~0xfffUL/* region/segment table origin */ | 326 | #define _REGION_ENTRY_ORIGIN ~0xfffUL/* region/segment table origin */ |
| 327 | #define _REGION_ENTRY_RO 0x200 /* region protection bit */ | ||
| 324 | #define _REGION_ENTRY_INV 0x20 /* invalid region table entry */ | 328 | #define _REGION_ENTRY_INV 0x20 /* invalid region table entry */ |
| 325 | #define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */ | 329 | #define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */ |
| 326 | #define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */ | 330 | #define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */ |
| @@ -382,9 +386,10 @@ extern unsigned long MODULES_END; | |||
| 382 | */ | 386 | */ |
| 383 | #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) | 387 | #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) |
| 384 | #define PAGE_RO __pgprot(_PAGE_TYPE_RO) | 388 | #define PAGE_RO __pgprot(_PAGE_TYPE_RO) |
| 385 | #define PAGE_RW __pgprot(_PAGE_TYPE_RW) | 389 | #define PAGE_RW __pgprot(_PAGE_TYPE_RO | _PAGE_SWW) |
| 390 | #define PAGE_RWC __pgprot(_PAGE_TYPE_RW | _PAGE_SWW | _PAGE_SWC) | ||
| 386 | 391 | ||
| 387 | #define PAGE_KERNEL PAGE_RW | 392 | #define PAGE_KERNEL PAGE_RWC |
| 388 | #define PAGE_SHARED PAGE_KERNEL | 393 | #define PAGE_SHARED PAGE_KERNEL |
| 389 | #define PAGE_COPY PAGE_RO | 394 | #define PAGE_COPY PAGE_RO |
| 390 | 395 | ||
| @@ -632,23 +637,23 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) | |||
| 632 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); | 637 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); |
| 633 | /* Clear page changed & referenced bit in the storage key */ | 638 | /* Clear page changed & referenced bit in the storage key */ |
| 634 | if (bits & _PAGE_CHANGED) | 639 | if (bits & _PAGE_CHANGED) |
| 635 | page_set_storage_key(address, skey ^ bits, 1); | 640 | page_set_storage_key(address, skey ^ bits, 0); |
| 636 | else if (bits) | 641 | else if (bits) |
| 637 | page_reset_referenced(address); | 642 | page_reset_referenced(address); |
| 638 | /* Transfer page changed & referenced bit to guest bits in pgste */ | 643 | /* Transfer page changed & referenced bit to guest bits in pgste */ |
| 639 | pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ | 644 | pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ |
| 640 | /* Get host changed & referenced bits from pgste */ | 645 | /* Get host changed & referenced bits from pgste */ |
| 641 | bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52; | 646 | bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52; |
| 642 | /* Clear host bits in pgste. */ | 647 | /* Transfer page changed & referenced bit to kvm user bits */ |
| 648 | pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */ | ||
| 649 | /* Clear relevant host bits in pgste. */ | ||
| 643 | pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT); | 650 | pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT); |
| 644 | pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT); | 651 | pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT); |
| 645 | /* Copy page access key and fetch protection bit to pgste */ | 652 | /* Copy page access key and fetch protection bit to pgste */ |
| 646 | pgste_val(pgste) |= | 653 | pgste_val(pgste) |= |
| 647 | (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; | 654 | (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; |
| 648 | /* Transfer changed and referenced to kvm user bits */ | 655 | /* Transfer referenced bit to pte */ |
| 649 | pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */ | 656 | pte_val(*ptep) |= (bits & _PAGE_REFERENCED) << 1; |
| 650 | /* Transfer changed & referenced to pte sofware bits */ | ||
| 651 | pte_val(*ptep) |= bits << 1; /* _PAGE_SWR & _PAGE_SWC */ | ||
| 652 | #endif | 657 | #endif |
| 653 | return pgste; | 658 | return pgste; |
| 654 | 659 | ||
| @@ -661,20 +666,25 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste) | |||
| 661 | 666 | ||
| 662 | if (!pte_present(*ptep)) | 667 | if (!pte_present(*ptep)) |
| 663 | return pgste; | 668 | return pgste; |
| 669 | /* Get referenced bit from storage key */ | ||
| 664 | young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); | 670 | young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); |
| 665 | /* Transfer page referenced bit to pte software bit (host view) */ | 671 | if (young) |
| 666 | if (young || (pgste_val(pgste) & RCP_HR_BIT)) | 672 | pgste_val(pgste) |= RCP_GR_BIT; |
| 673 | /* Get host referenced bit from pgste */ | ||
| 674 | if (pgste_val(pgste) & RCP_HR_BIT) { | ||
| 675 | pgste_val(pgste) &= ~RCP_HR_BIT; | ||
| 676 | young = 1; | ||
| 677 | } | ||
| 678 | /* Transfer referenced bit to kvm user bits and pte */ | ||
| 679 | if (young) { | ||
| 680 | pgste_val(pgste) |= KVM_UR_BIT; | ||
| 667 | pte_val(*ptep) |= _PAGE_SWR; | 681 | pte_val(*ptep) |= _PAGE_SWR; |
| 668 | /* Clear host referenced bit in pgste. */ | 682 | } |
| 669 | pgste_val(pgste) &= ~RCP_HR_BIT; | ||
| 670 | /* Transfer page referenced bit to guest bit in pgste */ | ||
| 671 | pgste_val(pgste) |= (unsigned long) young << 50; /* set RCP_GR_BIT */ | ||
| 672 | #endif | 683 | #endif |
| 673 | return pgste; | 684 | return pgste; |
| 674 | |||
| 675 | } | 685 | } |
| 676 | 686 | ||
| 677 | static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry) | 687 | static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry) |
| 678 | { | 688 | { |
| 679 | #ifdef CONFIG_PGSTE | 689 | #ifdef CONFIG_PGSTE |
| 680 | unsigned long address; | 690 | unsigned long address; |
| @@ -688,10 +698,23 @@ static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry) | |||
| 688 | /* Set page access key and fetch protection bit from pgste */ | 698 | /* Set page access key and fetch protection bit from pgste */ |
| 689 | nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; | 699 | nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; |
| 690 | if (okey != nkey) | 700 | if (okey != nkey) |
| 691 | page_set_storage_key(address, nkey, 1); | 701 | page_set_storage_key(address, nkey, 0); |
| 692 | #endif | 702 | #endif |
| 693 | } | 703 | } |
| 694 | 704 | ||
| 705 | static inline void pgste_set_pte(pte_t *ptep, pte_t entry) | ||
| 706 | { | ||
| 707 | if (!MACHINE_HAS_ESOP && (pte_val(entry) & _PAGE_SWW)) { | ||
| 708 | /* | ||
| 709 | * Without enhanced suppression-on-protection force | ||
| 710 | * the dirty bit on for all writable ptes. | ||
| 711 | */ | ||
| 712 | pte_val(entry) |= _PAGE_SWC; | ||
| 713 | pte_val(entry) &= ~_PAGE_RO; | ||
| 714 | } | ||
| 715 | *ptep = entry; | ||
| 716 | } | ||
| 717 | |||
| 695 | /** | 718 | /** |
| 696 | * struct gmap_struct - guest address space | 719 | * struct gmap_struct - guest address space |
| 697 | * @mm: pointer to the parent mm_struct | 720 | * @mm: pointer to the parent mm_struct |
| @@ -750,11 +773,14 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | |||
| 750 | 773 | ||
| 751 | if (mm_has_pgste(mm)) { | 774 | if (mm_has_pgste(mm)) { |
| 752 | pgste = pgste_get_lock(ptep); | 775 | pgste = pgste_get_lock(ptep); |
| 753 | pgste_set_pte(ptep, pgste, entry); | 776 | pgste_set_key(ptep, pgste, entry); |
| 754 | *ptep = entry; | 777 | pgste_set_pte(ptep, entry); |
| 755 | pgste_set_unlock(ptep, pgste); | 778 | pgste_set_unlock(ptep, pgste); |
| 756 | } else | 779 | } else { |
| 780 | if (!(pte_val(entry) & _PAGE_INVALID) && MACHINE_HAS_EDAT1) | ||
| 781 | pte_val(entry) |= _PAGE_CO; | ||
| 757 | *ptep = entry; | 782 | *ptep = entry; |
| 783 | } | ||
| 758 | } | 784 | } |
| 759 | 785 | ||
| 760 | /* | 786 | /* |
| @@ -763,16 +789,12 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | |||
| 763 | */ | 789 | */ |
| 764 | static inline int pte_write(pte_t pte) | 790 | static inline int pte_write(pte_t pte) |
| 765 | { | 791 | { |
| 766 | return (pte_val(pte) & _PAGE_RO) == 0; | 792 | return (pte_val(pte) & _PAGE_SWW) != 0; |
| 767 | } | 793 | } |
| 768 | 794 | ||
| 769 | static inline int pte_dirty(pte_t pte) | 795 | static inline int pte_dirty(pte_t pte) |
| 770 | { | 796 | { |
| 771 | #ifdef CONFIG_PGSTE | 797 | return (pte_val(pte) & _PAGE_SWC) != 0; |
| 772 | if (pte_val(pte) & _PAGE_SWC) | ||
| 773 | return 1; | ||
| 774 | #endif | ||
| 775 | return 0; | ||
| 776 | } | 798 | } |
| 777 | 799 | ||
| 778 | static inline int pte_young(pte_t pte) | 800 | static inline int pte_young(pte_t pte) |
| @@ -822,11 +844,14 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | |||
| 822 | { | 844 | { |
| 823 | pte_val(pte) &= _PAGE_CHG_MASK; | 845 | pte_val(pte) &= _PAGE_CHG_MASK; |
| 824 | pte_val(pte) |= pgprot_val(newprot); | 846 | pte_val(pte) |= pgprot_val(newprot); |
| 847 | if ((pte_val(pte) & _PAGE_SWC) && (pte_val(pte) & _PAGE_SWW)) | ||
| 848 | pte_val(pte) &= ~_PAGE_RO; | ||
| 825 | return pte; | 849 | return pte; |
| 826 | } | 850 | } |
| 827 | 851 | ||
| 828 | static inline pte_t pte_wrprotect(pte_t pte) | 852 | static inline pte_t pte_wrprotect(pte_t pte) |
| 829 | { | 853 | { |
| 854 | pte_val(pte) &= ~_PAGE_SWW; | ||
| 830 | /* Do not clobber _PAGE_TYPE_NONE pages! */ | 855 | /* Do not clobber _PAGE_TYPE_NONE pages! */ |
| 831 | if (!(pte_val(pte) & _PAGE_INVALID)) | 856 | if (!(pte_val(pte) & _PAGE_INVALID)) |
| 832 | pte_val(pte) |= _PAGE_RO; | 857 | pte_val(pte) |= _PAGE_RO; |
| @@ -835,20 +860,26 @@ static inline pte_t pte_wrprotect(pte_t pte) | |||
| 835 | 860 | ||
| 836 | static inline pte_t pte_mkwrite(pte_t pte) | 861 | static inline pte_t pte_mkwrite(pte_t pte) |
| 837 | { | 862 | { |
| 838 | pte_val(pte) &= ~_PAGE_RO; | 863 | pte_val(pte) |= _PAGE_SWW; |
| 864 | if (pte_val(pte) & _PAGE_SWC) | ||
| 865 | pte_val(pte) &= ~_PAGE_RO; | ||
| 839 | return pte; | 866 | return pte; |
| 840 | } | 867 | } |
| 841 | 868 | ||
| 842 | static inline pte_t pte_mkclean(pte_t pte) | 869 | static inline pte_t pte_mkclean(pte_t pte) |
| 843 | { | 870 | { |
| 844 | #ifdef CONFIG_PGSTE | ||
| 845 | pte_val(pte) &= ~_PAGE_SWC; | 871 | pte_val(pte) &= ~_PAGE_SWC; |
| 846 | #endif | 872 | /* Do not clobber _PAGE_TYPE_NONE pages! */ |
| 873 | if (!(pte_val(pte) & _PAGE_INVALID)) | ||
| 874 | pte_val(pte) |= _PAGE_RO; | ||
| 847 | return pte; | 875 | return pte; |
| 848 | } | 876 | } |
| 849 | 877 | ||
| 850 | static inline pte_t pte_mkdirty(pte_t pte) | 878 | static inline pte_t pte_mkdirty(pte_t pte) |
| 851 | { | 879 | { |
| 880 | pte_val(pte) |= _PAGE_SWC; | ||
| 881 | if (pte_val(pte) & _PAGE_SWW) | ||
| 882 | pte_val(pte) &= ~_PAGE_RO; | ||
| 852 | return pte; | 883 | return pte; |
| 853 | } | 884 | } |
| 854 | 885 | ||
| @@ -886,10 +917,10 @@ static inline pte_t pte_mkhuge(pte_t pte) | |||
| 886 | pte_val(pte) |= _SEGMENT_ENTRY_INV; | 917 | pte_val(pte) |= _SEGMENT_ENTRY_INV; |
| 887 | } | 918 | } |
| 888 | /* | 919 | /* |
| 889 | * Clear SW pte bits SWT and SWX, there are no SW bits in a segment | 920 | * Clear SW pte bits, there are no SW bits in a segment table entry. |
| 890 | * table entry. | ||
| 891 | */ | 921 | */ |
| 892 | pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX); | 922 | pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX | _PAGE_SWC | |
| 923 | _PAGE_SWR | _PAGE_SWW); | ||
| 893 | /* | 924 | /* |
| 894 | * Also set the change-override bit because we don't need dirty bit | 925 | * Also set the change-override bit because we don't need dirty bit |
| 895 | * tracking for hugetlbfs pages. | 926 | * tracking for hugetlbfs pages. |
| @@ -1041,9 +1072,11 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm, | |||
| 1041 | unsigned long address, | 1072 | unsigned long address, |
| 1042 | pte_t *ptep, pte_t pte) | 1073 | pte_t *ptep, pte_t pte) |
| 1043 | { | 1074 | { |
| 1044 | *ptep = pte; | 1075 | if (mm_has_pgste(mm)) { |
| 1045 | if (mm_has_pgste(mm)) | 1076 | pgste_set_pte(ptep, pte); |
| 1046 | pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE)); | 1077 | pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE)); |
| 1078 | } else | ||
| 1079 | *ptep = pte; | ||
| 1047 | } | 1080 | } |
| 1048 | 1081 | ||
| 1049 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH | 1082 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH |
| @@ -1111,10 +1144,13 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm, | |||
| 1111 | 1144 | ||
| 1112 | if (!mm_exclusive(mm)) | 1145 | if (!mm_exclusive(mm)) |
| 1113 | __ptep_ipte(address, ptep); | 1146 | __ptep_ipte(address, ptep); |
| 1114 | *ptep = pte_wrprotect(pte); | 1147 | pte = pte_wrprotect(pte); |
| 1115 | 1148 | ||
| 1116 | if (mm_has_pgste(mm)) | 1149 | if (mm_has_pgste(mm)) { |
| 1150 | pgste_set_pte(ptep, pte); | ||
| 1117 | pgste_set_unlock(ptep, pgste); | 1151 | pgste_set_unlock(ptep, pgste); |
| 1152 | } else | ||
| 1153 | *ptep = pte; | ||
| 1118 | } | 1154 | } |
| 1119 | return pte; | 1155 | return pte; |
| 1120 | } | 1156 | } |
| @@ -1132,10 +1168,12 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma, | |||
| 1132 | pgste = pgste_get_lock(ptep); | 1168 | pgste = pgste_get_lock(ptep); |
| 1133 | 1169 | ||
| 1134 | __ptep_ipte(address, ptep); | 1170 | __ptep_ipte(address, ptep); |
| 1135 | *ptep = entry; | ||
| 1136 | 1171 | ||
| 1137 | if (mm_has_pgste(vma->vm_mm)) | 1172 | if (mm_has_pgste(vma->vm_mm)) { |
| 1173 | pgste_set_pte(ptep, entry); | ||
| 1138 | pgste_set_unlock(ptep, pgste); | 1174 | pgste_set_unlock(ptep, pgste); |
| 1175 | } else | ||
| 1176 | *ptep = entry; | ||
| 1139 | return 1; | 1177 | return 1; |
| 1140 | } | 1178 | } |
| 1141 | 1179 | ||
| @@ -1153,8 +1191,13 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) | |||
| 1153 | static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) | 1191 | static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) |
| 1154 | { | 1192 | { |
| 1155 | unsigned long physpage = page_to_phys(page); | 1193 | unsigned long physpage = page_to_phys(page); |
| 1194 | pte_t __pte = mk_pte_phys(physpage, pgprot); | ||
| 1156 | 1195 | ||
| 1157 | return mk_pte_phys(physpage, pgprot); | 1196 | if ((pte_val(__pte) & _PAGE_SWW) && PageDirty(page)) { |
| 1197 | pte_val(__pte) |= _PAGE_SWC; | ||
| 1198 | pte_val(__pte) &= ~_PAGE_RO; | ||
| 1199 | } | ||
| 1200 | return __pte; | ||
| 1158 | } | 1201 | } |
| 1159 | 1202 | ||
| 1160 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) | 1203 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) |
| @@ -1246,6 +1289,8 @@ static inline int pmd_trans_splitting(pmd_t pmd) | |||
| 1246 | static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, | 1289 | static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, |
| 1247 | pmd_t *pmdp, pmd_t entry) | 1290 | pmd_t *pmdp, pmd_t entry) |
| 1248 | { | 1291 | { |
| 1292 | if (!(pmd_val(entry) & _SEGMENT_ENTRY_INV) && MACHINE_HAS_EDAT1) | ||
| 1293 | pmd_val(entry) |= _SEGMENT_ENTRY_CO; | ||
| 1249 | *pmdp = entry; | 1294 | *pmdp = entry; |
| 1250 | } | 1295 | } |
| 1251 | 1296 | ||
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 833788693f09..06a136136047 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h | |||
| @@ -46,7 +46,6 @@ int sclp_cpu_deconfigure(u8 cpu); | |||
| 46 | void sclp_facilities_detect(void); | 46 | void sclp_facilities_detect(void); |
| 47 | unsigned long long sclp_get_rnmax(void); | 47 | unsigned long long sclp_get_rnmax(void); |
| 48 | unsigned long long sclp_get_rzm(void); | 48 | unsigned long long sclp_get_rzm(void); |
| 49 | u8 sclp_get_fac85(void); | ||
| 50 | int sclp_sdias_blk_count(void); | 49 | int sclp_sdias_blk_count(void); |
| 51 | int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); | 50 | int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); |
| 52 | int sclp_chp_configure(struct chp_id chpid); | 51 | int sclp_chp_configure(struct chp_id chpid); |
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index f69f76b3447a..f6857516e523 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h | |||
| @@ -64,13 +64,14 @@ extern unsigned int s390_user_mode; | |||
| 64 | 64 | ||
| 65 | #define MACHINE_FLAG_VM (1UL << 0) | 65 | #define MACHINE_FLAG_VM (1UL << 0) |
| 66 | #define MACHINE_FLAG_IEEE (1UL << 1) | 66 | #define MACHINE_FLAG_IEEE (1UL << 1) |
| 67 | #define MACHINE_FLAG_CSP (1UL << 3) | 67 | #define MACHINE_FLAG_CSP (1UL << 2) |
| 68 | #define MACHINE_FLAG_MVPG (1UL << 4) | 68 | #define MACHINE_FLAG_MVPG (1UL << 3) |
| 69 | #define MACHINE_FLAG_DIAG44 (1UL << 5) | 69 | #define MACHINE_FLAG_DIAG44 (1UL << 4) |
| 70 | #define MACHINE_FLAG_IDTE (1UL << 6) | 70 | #define MACHINE_FLAG_IDTE (1UL << 5) |
| 71 | #define MACHINE_FLAG_DIAG9C (1UL << 7) | 71 | #define MACHINE_FLAG_DIAG9C (1UL << 6) |
| 72 | #define MACHINE_FLAG_MVCOS (1UL << 8) | 72 | #define MACHINE_FLAG_MVCOS (1UL << 7) |
| 73 | #define MACHINE_FLAG_KVM (1UL << 9) | 73 | #define MACHINE_FLAG_KVM (1UL << 8) |
| 74 | #define MACHINE_FLAG_ESOP (1UL << 9) | ||
| 74 | #define MACHINE_FLAG_EDAT1 (1UL << 10) | 75 | #define MACHINE_FLAG_EDAT1 (1UL << 10) |
| 75 | #define MACHINE_FLAG_EDAT2 (1UL << 11) | 76 | #define MACHINE_FLAG_EDAT2 (1UL << 11) |
| 76 | #define MACHINE_FLAG_LPAR (1UL << 12) | 77 | #define MACHINE_FLAG_LPAR (1UL << 12) |
| @@ -84,6 +85,7 @@ extern unsigned int s390_user_mode; | |||
| 84 | #define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR) | 85 | #define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR) |
| 85 | 86 | ||
| 86 | #define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C) | 87 | #define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C) |
| 88 | #define MACHINE_HAS_ESOP (S390_lowcore.machine_flags & MACHINE_FLAG_ESOP) | ||
| 87 | #define MACHINE_HAS_PFMF MACHINE_HAS_EDAT1 | 89 | #define MACHINE_HAS_PFMF MACHINE_HAS_EDAT1 |
| 88 | #define MACHINE_HAS_HPAGE MACHINE_HAS_EDAT1 | 90 | #define MACHINE_HAS_HPAGE MACHINE_HAS_EDAT1 |
| 89 | 91 | ||
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index f090e819bf71..2923781590a6 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
| @@ -147,7 +147,7 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
| 147 | r = KVM_MAX_VCPUS; | 147 | r = KVM_MAX_VCPUS; |
| 148 | break; | 148 | break; |
| 149 | case KVM_CAP_S390_COW: | 149 | case KVM_CAP_S390_COW: |
| 150 | r = sclp_get_fac85() & 0x2; | 150 | r = MACHINE_HAS_ESOP; |
| 151 | break; | 151 | break; |
| 152 | default: | 152 | default: |
| 153 | r = 0; | 153 | r = 0; |
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 9017a63dda3d..a70ee84c0241 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c | |||
| @@ -50,7 +50,7 @@ static __always_inline unsigned long follow_table(struct mm_struct *mm, | |||
| 50 | ptep = pte_offset_map(pmd, addr); | 50 | ptep = pte_offset_map(pmd, addr); |
| 51 | if (!pte_present(*ptep)) | 51 | if (!pte_present(*ptep)) |
| 52 | return -0x11UL; | 52 | return -0x11UL; |
| 53 | if (write && !pte_write(*ptep)) | 53 | if (write && (!pte_write(*ptep) || !pte_dirty(*ptep))) |
| 54 | return -0x04UL; | 54 | return -0x04UL; |
| 55 | 55 | ||
| 56 | return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK); | 56 | return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK); |
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 29ccee3651f4..d21040ed5e59 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c | |||
| @@ -127,7 +127,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
| 127 | pte_val(*pte) = _PAGE_TYPE_EMPTY; | 127 | pte_val(*pte) = _PAGE_TYPE_EMPTY; |
| 128 | continue; | 128 | continue; |
| 129 | } | 129 | } |
| 130 | *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW)); | 130 | pte_val(*pte) = __pa(address); |
| 131 | } | 131 | } |
| 132 | } | 132 | } |
| 133 | 133 | ||
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 6ed1426d27c5..79699f46a443 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c | |||
| @@ -85,11 +85,9 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 85 | pud_t *pu_dir; | 85 | pud_t *pu_dir; |
| 86 | pmd_t *pm_dir; | 86 | pmd_t *pm_dir; |
| 87 | pte_t *pt_dir; | 87 | pte_t *pt_dir; |
| 88 | pte_t pte; | ||
| 89 | int ret = -ENOMEM; | 88 | int ret = -ENOMEM; |
| 90 | 89 | ||
| 91 | while (address < end) { | 90 | while (address < end) { |
| 92 | pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); | ||
| 93 | pg_dir = pgd_offset_k(address); | 91 | pg_dir = pgd_offset_k(address); |
| 94 | if (pgd_none(*pg_dir)) { | 92 | if (pgd_none(*pg_dir)) { |
| 95 | pu_dir = vmem_pud_alloc(); | 93 | pu_dir = vmem_pud_alloc(); |
| @@ -101,9 +99,9 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 101 | #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) | 99 | #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) |
| 102 | if (MACHINE_HAS_EDAT2 && pud_none(*pu_dir) && address && | 100 | if (MACHINE_HAS_EDAT2 && pud_none(*pu_dir) && address && |
| 103 | !(address & ~PUD_MASK) && (address + PUD_SIZE <= end)) { | 101 | !(address & ~PUD_MASK) && (address + PUD_SIZE <= end)) { |
| 104 | pte_val(pte) |= _REGION3_ENTRY_LARGE; | 102 | pud_val(*pu_dir) = __pa(address) | |
| 105 | pte_val(pte) |= _REGION_ENTRY_TYPE_R3; | 103 | _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE | |
| 106 | pud_val(*pu_dir) = pte_val(pte); | 104 | (ro ? _REGION_ENTRY_RO : 0); |
| 107 | address += PUD_SIZE; | 105 | address += PUD_SIZE; |
| 108 | continue; | 106 | continue; |
| 109 | } | 107 | } |
| @@ -118,8 +116,9 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 118 | #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) | 116 | #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) |
| 119 | if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address && | 117 | if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address && |
| 120 | !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) { | 118 | !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) { |
| 121 | pte_val(pte) |= _SEGMENT_ENTRY_LARGE; | 119 | pmd_val(*pm_dir) = __pa(address) | |
| 122 | pmd_val(*pm_dir) = pte_val(pte); | 120 | _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE | |
| 121 | (ro ? _SEGMENT_ENTRY_RO : 0); | ||
| 123 | address += PMD_SIZE; | 122 | address += PMD_SIZE; |
| 124 | continue; | 123 | continue; |
| 125 | } | 124 | } |
| @@ -132,7 +131,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 132 | } | 131 | } |
| 133 | 132 | ||
| 134 | pt_dir = pte_offset_kernel(pm_dir, address); | 133 | pt_dir = pte_offset_kernel(pm_dir, address); |
| 135 | *pt_dir = pte; | 134 | pte_val(*pt_dir) = __pa(address) | (ro ? _PAGE_RO : 0); |
| 136 | address += PAGE_SIZE; | 135 | address += PAGE_SIZE; |
| 137 | } | 136 | } |
| 138 | ret = 0; | 137 | ret = 0; |
| @@ -199,7 +198,6 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | |||
| 199 | pud_t *pu_dir; | 198 | pud_t *pu_dir; |
| 200 | pmd_t *pm_dir; | 199 | pmd_t *pm_dir; |
| 201 | pte_t *pt_dir; | 200 | pte_t *pt_dir; |
| 202 | pte_t pte; | ||
| 203 | int ret = -ENOMEM; | 201 | int ret = -ENOMEM; |
| 204 | 202 | ||
| 205 | start_addr = (unsigned long) start; | 203 | start_addr = (unsigned long) start; |
| @@ -237,9 +235,8 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | |||
| 237 | new_page = vmemmap_alloc_block(PMD_SIZE, node); | 235 | new_page = vmemmap_alloc_block(PMD_SIZE, node); |
| 238 | if (!new_page) | 236 | if (!new_page) |
| 239 | goto out; | 237 | goto out; |
| 240 | pte = mk_pte_phys(__pa(new_page), PAGE_RW); | 238 | pmd_val(*pm_dir) = __pa(new_page) | |
| 241 | pte_val(pte) |= _SEGMENT_ENTRY_LARGE; | 239 | _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE; |
| 242 | pmd_val(*pm_dir) = pte_val(pte); | ||
| 243 | address = (address + PMD_SIZE) & PMD_MASK; | 240 | address = (address + PMD_SIZE) & PMD_MASK; |
| 244 | continue; | 241 | continue; |
| 245 | } | 242 | } |
| @@ -260,8 +257,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | |||
| 260 | new_page =__pa(vmem_alloc_pages(0)); | 257 | new_page =__pa(vmem_alloc_pages(0)); |
| 261 | if (!new_page) | 258 | if (!new_page) |
| 262 | goto out; | 259 | goto out; |
| 263 | pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL); | 260 | pte_val(*pt_dir) = __pa(new_page); |
| 264 | *pt_dir = pte; | ||
| 265 | } | 261 | } |
| 266 | address += PAGE_SIZE; | 262 | address += PAGE_SIZE; |
| 267 | } | 263 | } |
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index c44d13f607bc..30a2255389e5 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c | |||
| @@ -56,7 +56,6 @@ static int __initdata early_read_info_sccb_valid; | |||
| 56 | 56 | ||
| 57 | u64 sclp_facilities; | 57 | u64 sclp_facilities; |
| 58 | static u8 sclp_fac84; | 58 | static u8 sclp_fac84; |
| 59 | static u8 sclp_fac85; | ||
| 60 | static unsigned long long rzm; | 59 | static unsigned long long rzm; |
| 61 | static unsigned long long rnmax; | 60 | static unsigned long long rnmax; |
| 62 | 61 | ||
| @@ -131,7 +130,8 @@ void __init sclp_facilities_detect(void) | |||
| 131 | sccb = &early_read_info_sccb; | 130 | sccb = &early_read_info_sccb; |
| 132 | sclp_facilities = sccb->facilities; | 131 | sclp_facilities = sccb->facilities; |
| 133 | sclp_fac84 = sccb->fac84; | 132 | sclp_fac84 = sccb->fac84; |
| 134 | sclp_fac85 = sccb->fac85; | 133 | if (sccb->fac85 & 0x02) |
| 134 | S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; | ||
| 135 | rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; | 135 | rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; |
| 136 | rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; | 136 | rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; |
| 137 | rzm <<= 20; | 137 | rzm <<= 20; |
| @@ -171,12 +171,6 @@ unsigned long long sclp_get_rzm(void) | |||
| 171 | return rzm; | 171 | return rzm; |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | u8 sclp_get_fac85(void) | ||
| 175 | { | ||
| 176 | return sclp_fac85; | ||
| 177 | } | ||
| 178 | EXPORT_SYMBOL_GPL(sclp_get_fac85); | ||
| 179 | |||
| 180 | /* | 174 | /* |
| 181 | * This function will be called after sclp_facilities_detect(), which gets | 175 | * This function will be called after sclp_facilities_detect(), which gets |
| 182 | * called from early.c code. Therefore the sccb should have valid contents. | 176 | * called from early.c code. Therefore the sccb should have valid contents. |
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 5cf680a98f9b..bfd87685fc1f 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h | |||
| @@ -197,16 +197,6 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b) | |||
| 197 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | 197 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ |
| 198 | #endif | 198 | #endif |
| 199 | 199 | ||
| 200 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY | ||
| 201 | #define page_test_and_clear_dirty(pfn, mapped) (0) | ||
| 202 | #endif | ||
| 203 | |||
| 204 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY | ||
| 205 | #define pte_maybe_dirty(pte) pte_dirty(pte) | ||
| 206 | #else | ||
| 207 | #define pte_maybe_dirty(pte) (1) | ||
| 208 | #endif | ||
| 209 | |||
| 210 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | 200 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG |
| 211 | #define page_test_and_clear_young(pfn) (0) | 201 | #define page_test_and_clear_young(pfn) (0) |
| 212 | #endif | 202 | #endif |
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 70473da47b3f..6d53675c2b54 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h | |||
| @@ -303,21 +303,13 @@ static inline void __SetPageUptodate(struct page *page) | |||
| 303 | 303 | ||
| 304 | static inline void SetPageUptodate(struct page *page) | 304 | static inline void SetPageUptodate(struct page *page) |
| 305 | { | 305 | { |
| 306 | #ifdef CONFIG_S390 | ||
| 307 | if (!test_and_set_bit(PG_uptodate, &page->flags)) | ||
| 308 | page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, 0); | ||
| 309 | #else | ||
| 310 | /* | 306 | /* |
| 311 | * Memory barrier must be issued before setting the PG_uptodate bit, | 307 | * Memory barrier must be issued before setting the PG_uptodate bit, |
| 312 | * so that all previous stores issued in order to bring the page | 308 | * so that all previous stores issued in order to bring the page |
| 313 | * uptodate are actually visible before PageUptodate becomes true. | 309 | * uptodate are actually visible before PageUptodate becomes true. |
| 314 | * | ||
| 315 | * s390 doesn't need an explicit smp_wmb here because the test and | ||
| 316 | * set bit already provides full barriers. | ||
| 317 | */ | 310 | */ |
| 318 | smp_wmb(); | 311 | smp_wmb(); |
| 319 | set_bit(PG_uptodate, &(page)->flags); | 312 | set_bit(PG_uptodate, &(page)->flags); |
| 320 | #endif | ||
| 321 | } | 313 | } |
| 322 | 314 | ||
| 323 | CLEARPAGEFLAG(Uptodate, uptodate) | 315 | CLEARPAGEFLAG(Uptodate, uptodate) |
| @@ -1126,7 +1126,6 @@ void page_add_file_rmap(struct page *page) | |||
| 1126 | */ | 1126 | */ |
| 1127 | void page_remove_rmap(struct page *page) | 1127 | void page_remove_rmap(struct page *page) |
| 1128 | { | 1128 | { |
| 1129 | struct address_space *mapping = page_mapping(page); | ||
| 1130 | bool anon = PageAnon(page); | 1129 | bool anon = PageAnon(page); |
| 1131 | bool locked; | 1130 | bool locked; |
| 1132 | unsigned long flags; | 1131 | unsigned long flags; |
| @@ -1144,29 +1143,6 @@ void page_remove_rmap(struct page *page) | |||
| 1144 | goto out; | 1143 | goto out; |
| 1145 | 1144 | ||
| 1146 | /* | 1145 | /* |
| 1147 | * Now that the last pte has gone, s390 must transfer dirty | ||
| 1148 | * flag from storage key to struct page. We can usually skip | ||
| 1149 | * this if the page is anon, so about to be freed; but perhaps | ||
| 1150 | * not if it's in swapcache - there might be another pte slot | ||
| 1151 | * containing the swap entry, but page not yet written to swap. | ||
| 1152 | * | ||
| 1153 | * And we can skip it on file pages, so long as the filesystem | ||
| 1154 | * participates in dirty tracking (note that this is not only an | ||
| 1155 | * optimization but also solves problems caused by dirty flag in | ||
| 1156 | * storage key getting set by a write from inside kernel); but need to | ||
| 1157 | * catch shm and tmpfs and ramfs pages which have been modified since | ||
| 1158 | * creation by read fault. | ||
| 1159 | * | ||
| 1160 | * Note that mapping must be decided above, before decrementing | ||
| 1161 | * mapcount (which luckily provides a barrier): once page is unmapped, | ||
| 1162 | * it could be truncated and page->mapping reset to NULL at any moment. | ||
| 1163 | * Note also that we are relying on page_mapping(page) to set mapping | ||
| 1164 | * to &swapper_space when PageSwapCache(page). | ||
| 1165 | */ | ||
| 1166 | if (mapping && !mapping_cap_account_dirty(mapping) && | ||
| 1167 | page_test_and_clear_dirty(page_to_pfn(page), 1)) | ||
| 1168 | set_page_dirty(page); | ||
| 1169 | /* | ||
| 1170 | * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED | 1146 | * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED |
| 1171 | * and not charged by memcg for now. | 1147 | * and not charged by memcg for now. |
| 1172 | */ | 1148 | */ |
