Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Suchanek <msuchanek@suse.de>2018-10-31 12:36:54 +0100
committerMichal Suchanek <msuchanek@suse.de>2018-10-31 23:28:41 +0100
commitb45636488841639276da541ec20421b230e39b13 (patch)
treef8554b775d86cb96e9d58130762a9cfb784899be
parentbaa085fc796e5f84ade8708b91f7107eb03b78b2 (diff)
KVM: PPC: Book3S HV: radix: Do not clear partition PTE when
RC or write bits do not match (bsc#1061840).
-rw-r--r--patches.arch/KVM-PPC-Book3S-HV-radix-Do-not-clear-partition-PTE-w.patch151
-rw-r--r--series.conf1
2 files changed, 152 insertions, 0 deletions
diff --git a/patches.arch/KVM-PPC-Book3S-HV-radix-Do-not-clear-partition-PTE-w.patch b/patches.arch/KVM-PPC-Book3S-HV-radix-Do-not-clear-partition-PTE-w.patch
new file mode 100644
index 0000000000..ced5bf0cb0
--- /dev/null
+++ b/patches.arch/KVM-PPC-Book3S-HV-radix-Do-not-clear-partition-PTE-w.patch
@@ -0,0 +1,151 @@
+From b9719579658ac239b99ae2113e110945d02cfe02 Mon Sep 17 00:00:00 2001
+From: Nicholas Piggin <npiggin@gmail.com>
+Date: Thu, 17 May 2018 17:06:31 +1000
+Subject: [PATCH] KVM: PPC: Book3S HV: radix: Do not clear partition PTE when
+ RC or write bits do not match
+
+References: bsc#1061840
+Patch-mainline: v4.18-rc1
+Git-commit: 878cf2bb2d8d6164df7b63b2239859f99fea212a
+
+Adding the write bit and RC bits to pte permissions does not require a
+pte clear and flush. There should not be other bits changed here,
+because restricting access or changing the PFN must have already
+invalidated any existing ptes (otherwise the race is already lost).
+
+Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
+Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
+Acked-by: Michal Suchanek <msuchanek@suse.de>
+---
+ arch/powerpc/kvm/book3s_64_mmu_radix.c | 68 +++++++++++++++++++++++-----------
+ 1 file changed, 47 insertions(+), 21 deletions(-)
+
+diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c
+index 730127704cdb..8ed0bace7f27 100644
+--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c
++++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c
+@@ -176,7 +176,7 @@ static void kvmppc_radix_flush_pwc(struct kvm *kvm)
+ asm volatile("eieio ; tlbsync ; ptesync": : :"memory");
+ }
+
+-unsigned long kvmppc_radix_update_pte(struct kvm *kvm, pte_t *ptep,
++static unsigned long kvmppc_radix_update_pte(struct kvm *kvm, pte_t *ptep,
+ unsigned long clr, unsigned long set,
+ unsigned long addr, unsigned int shift)
+ {
+@@ -380,6 +380,15 @@ static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud,
+ kvmppc_unmap_free_pmd(kvm, pmd, false);
+ }
+
++/*
++ * There are a number of bits which may differ between different faults to
++ * the same partition scope entry. RC bits, in the course of cleaning and
++ * aging. And the write bit can change, either the access could have been
++ * upgraded, or a read fault could happen concurrently with a write fault
++ * that sets those bits first.
++ */
++#define PTE_BITS_MUST_MATCH (~(_PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED))
++
+ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
+ unsigned int level, unsigned long mmu_seq)
+ {
+@@ -424,19 +433,28 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
+ if (pud_huge(*pud)) {
+ unsigned long hgpa = gpa & PUD_MASK;
+
++ /* Check if we raced and someone else has set the same thing */
++ if (level == 2) {
++ if (pud_raw(*pud) == pte_raw(pte)) {
++ ret = 0;
++ goto out_unlock;
++ }
++ /* Valid 1GB page here already, add our extra bits */
++ WARN_ON_ONCE((pud_val(*pud) ^ pte_val(pte)) &
++ PTE_BITS_MUST_MATCH);
++ kvmppc_radix_update_pte(kvm, (pte_t *)pud,
++ 0, pte_val(pte), hgpa, PUD_SHIFT);
++ ret = 0;
++ goto out_unlock;
++ }
+ /*
+ * If we raced with another CPU which has just put
+ * a 1GB pte in after we saw a pmd page, try again.
+ */
+- if (level <= 1 && !new_pmd) {
++ if (!new_pmd) {
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+- /* Check if we raced and someone else has set the same thing */
+- if (level == 2 && pud_raw(*pud) == pte_raw(pte)) {
+- ret = 0;
+- goto out_unlock;
+- }
+ /* Valid 1GB page here already, remove it */
+ kvmppc_unmap_pte(kvm, (pte_t *)pud, hgpa, PUD_SHIFT);
+ }
+@@ -463,19 +481,29 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
+ if (pmd_is_leaf(*pmd)) {
+ unsigned long lgpa = gpa & PMD_MASK;
+
++ /* Check if we raced and someone else has set the same thing */
++ if (level == 1) {
++ if (pmd_raw(*pmd) == pte_raw(pte)) {
++ ret = 0;
++ goto out_unlock;
++ }
++ /* Valid 2MB page here already, add our extra bits */
++ WARN_ON_ONCE((pmd_val(*pmd) ^ pte_val(pte)) &
++ PTE_BITS_MUST_MATCH);
++ kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd),
++ 0, pte_val(pte), lgpa, PMD_SHIFT);
++ ret = 0;
++ goto out_unlock;
++ }
++
+ /*
+ * If we raced with another CPU which has just put
+ * a 2MB pte in after we saw a pte page, try again.
+ */
+- if (level == 0 && !new_ptep) {
++ if (!new_ptep) {
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+- /* Check if we raced and someone else has set the same thing */
+- if (level == 1 && pmd_raw(*pmd) == pte_raw(pte)) {
+- ret = 0;
+- goto out_unlock;
+- }
+ /* Valid 2MB page here already, remove it */
+ kvmppc_unmap_pte(kvm, pmdp_ptep(pmd), lgpa, PMD_SHIFT);
+ }
+@@ -500,19 +528,17 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
+ }
+ ptep = pte_offset_kernel(pmd, gpa);
+ if (pte_present(*ptep)) {
+- unsigned long old;
+-
+ /* Check if someone else set the same thing */
+ if (pte_raw(*ptep) == pte_raw(pte)) {
+ ret = 0;
+ goto out_unlock;
+ }
+- /* PTE was previously valid, so invalidate it */
+- old = kvmppc_radix_update_pte(kvm, ptep, _PAGE_PRESENT,
+- 0, gpa, 0);
+- kvmppc_radix_tlbie_page(kvm, gpa, 0);
+- if (old & _PAGE_DIRTY)
+- mark_page_dirty(kvm, gpa >> PAGE_SHIFT);
++ /* Valid page here already, add our extra bits */
++ WARN_ON_ONCE((pte_val(*ptep) ^ pte_val(pte)) &
++ PTE_BITS_MUST_MATCH);
++ kvmppc_radix_update_pte(kvm, ptep, 0, pte_val(pte), gpa, 0);
++ ret = 0;
++ goto out_unlock;
+ }
+ kvmppc_radix_set_pte_at(kvm, gpa, ptep, pte);
+ ret = 0;
+--
+2.13.7
+
diff --git a/series.conf b/series.conf
index 727dac88cf..9cfb8d216b 100644
--- a/series.conf
+++ b/series.conf
@@ -16731,6 +16731,7 @@
patches.arch/KVM-PPC-Book3S-HV-Use-a-helper-to-unmap-ptes-in-the-.patch
patches.arch/KVM-PPC-Book3S-HV-Recursively-unmap-all-page-table-e.patch
patches.arch/KVM-PPC-Book3S-HV-radix-Refine-IO-region-partition-s.patch
+ patches.arch/KVM-PPC-Book3S-HV-radix-Do-not-clear-partition-PTE-w.patch
patches.suse/ipv6-allow-PMTU-exceptions-to-local-routes.patch
patches.suse/net-dsa-add-error-handling-for-pskb_trim_rcsum.patch
patches.drivers/ixgbe-Fix-setting-of-TC-configuration-for-macvlan-ca.patch