From: Janosch Frank <frankja@linux.vnet.ibm.com>
To: kvm@vger.kernel.org
Cc: schwidefsky@de.ibm.com, borntraeger@de.ibm.com, david@redhat.com,
dominik.dingel@gmail.com, linux-s390@vger.kernel.org
Subject: [RFC/PATCH 07/22] RFC: s390/mm: Transfer guest pmd protection to host
Date: Mon, 6 Nov 2017 23:29:45 +0100 [thread overview]
Message-ID: <1510007400-42493-8-git-send-email-frankja@linux.vnet.ibm.com> (raw)
In-Reply-To: <1510007400-42493-1-git-send-email-frankja@linux.vnet.ibm.com>
If we protect the guest pmd, i.e. for dirty tracking, we need to
transfer the protection to the host pmd which we copied when linking
to the guest.
If we don't, we might loose changed that on migration, as changes on
host side don't get tracked.
Signed-off-by: Janosch Frank <frankja@linux.vnet.ibm.com>
---
arch/s390/mm/gmap.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 106 insertions(+), 13 deletions(-)
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index d0d56f6..3054b413 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -14,6 +14,7 @@
#include <linux/swapops.h>
#include <linux/ksm.h>
#include <linux/mman.h>
+#include <linux/hugetlb.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -934,6 +935,88 @@ static inline void gmap_pmd_op_end(struct gmap *gmap, pmd_t *pmdp)
spin_unlock(&gmap->guest_table_lock);
}
+/**
+ * gmap_pmdp_transfer_prot - transfer protection of guest pmd to host pmd
+ * @mm: the memory context
+ * @address: the affected host virtual address
+ * @gpmdp: guest pmd ptr
+ * @hpmdp: host pmd ptr
+ *
+ * Transfers the protection from a guest pmd to the associated guest
+ * pmd. This has to be done with a plain idte to circumvent the gmap
+ * invalidation hooks in the standard invalidation functions provided
+ * by pgtable.c.
+ */
+static void gmap_pmdp_transfer_prot(struct mm_struct *mm, unsigned long addr,
+ pmd_t *gpmdp, pmd_t *hpmdp)
+{
+ int gpmd_i, gpmd_p, hpmd_i, hpmd_p;
+ pmd_t new = *hpmdp;
+
+ hpmd_i = pmd_val(*hpmdp) & _SEGMENT_ENTRY_INVALID;
+ hpmd_p = pmd_val(*hpmdp) & _SEGMENT_ENTRY_PROTECT;
+ gpmd_i = pmd_val(*gpmdp) & _SEGMENT_ENTRY_INVALID;
+ gpmd_p = pmd_val(*gpmdp) & _SEGMENT_ENTRY_PROTECT;
+
+ /* Fastpath, change not needed. */
+ if (hpmd_i || (hpmd_p && gpmd_p) || (!gpmd_i && !gpmd_p))
+ return;
+
+ if (gpmd_p && !hpmd_p)
+ pmd_val(new) |= _SEGMENT_ENTRY_PROTECT;
+ if (!gpmd_i && !hpmd_i)
+ pmd_val(new) &= ~_SEGMENT_ENTRY_INVALID;
+
+ if (MACHINE_HAS_TLB_GUEST)
+ __pmdp_idte(addr, hpmdp,
+ IDTE_GUEST_ASCE,
+ mm->context.asce, IDTE_GLOBAL);
+ else if (MACHINE_HAS_IDTE)
+ __pmdp_idte(addr, hpmdp, 0, 0,
+ IDTE_GLOBAL);
+ else
+ __pmdp_csp(hpmdp);
+ *hpmdp = new;
+}
+
+/**
+ * gmap_pmdp_force_prot - change access rights of a locked pmd
+ * @mm: pointer to the process mm_struct
+ * @addr: virtual address in the guest address space
+ * @pmdp: pointer to the page table entry
+ * @prot: indicates guest access rights: PROT_NONE, PROT_READ or PROT_WRITE
+ * @bits: software bit to set (e.g. for notification)
+ *
+ * Returns 0 if the access rights were changed and -EAGAIN if the current
+ * and requested access rights are incompatible.
+ */
+static int gmap_pmdp_force_prot(struct gmap *gmap, unsigned long addr,
+ pmd_t *pmdp, int prot, unsigned long bits)
+{
+ int pmd_i, pmd_p;
+ pmd_t new = *pmdp;
+
+ pmd_i = pmd_val(*pmdp) & _SEGMENT_ENTRY_INVALID;
+ pmd_p = pmd_val(*pmdp) & _SEGMENT_ENTRY_PROTECT;
+
+ /* Fixup needed */
+ if ((pmd_i && (prot != PROT_NONE)) || (pmd_p && (prot == PROT_WRITE)))
+ return -EAGAIN;
+
+ if (prot == PROT_NONE && !pmd_i) {
+ pmd_val(new) |= _SEGMENT_ENTRY_INVALID;
+ gmap_pmdp_xchg(gmap, pmdp, new, addr);
+ }
+
+ if (prot == PROT_READ && !pmd_p) {
+ pmd_val(new) &= ~_SEGMENT_ENTRY_INVALID;
+ pmd_val(new) |= _SEGMENT_ENTRY_PROTECT;
+ gmap_pmdp_xchg(gmap, pmdp, new, addr);
+ }
+ pmd_val(*pmdp) |= bits;
+ return 0;
+}
+
/*
* gmap_protect_pte - remove access rights to memory and set pgste bits
* @gmap: pointer to guest mapping meta data structure
@@ -990,20 +1073,23 @@ static int gmap_protect_pte(struct gmap *gmap, unsigned long gaddr,
* guest_table_lock held.
*/
static int gmap_protect_large(struct gmap *gmap, unsigned long gaddr,
- pmd_t *pmdp, int prot, unsigned long bits)
+ unsigned long vmaddr, pmd_t *pmdp, pmd_t *hpmdp,
+ int prot, unsigned long bits)
{
- int pmd_i, pmd_p;
+ unsigned long sbits = 0;
+ int ret = 0;
- pmd_i = pmd_val(*pmdp) & _SEGMENT_ENTRY_INVALID;
- pmd_p = pmd_val(*pmdp) & _SEGMENT_ENTRY_PROTECT;
+ sbits |= (bits & GMAP_ENTRY_IN) ? _SEGMENT_ENTRY_GMAP_IN : 0;
+ /* Protect gmap pmd */
+ ret = gmap_pmdp_force_prot(gmap, gaddr, pmdp, prot, sbits);
+ /*
+ * Transfer protection back to the host pmd, so userspace has
+ * never more access rights than the VM.
+ */
+ if (!ret)
+ gmap_pmdp_transfer_prot(gmap->mm, vmaddr, pmdp, hpmdp);
- /* Fixup needed */
- if ((pmd_i && (prot != PROT_NONE)) || (pmd_p && (prot & PROT_WRITE)))
- return -EAGAIN;
-
- if (bits & GMAP_ENTRY_IN)
- pmd_val(*pmdp) |= _SEGMENT_ENTRY_GMAP_IN;
- return 0;
+ return ret;
}
/*
@@ -1024,12 +1110,18 @@ static int gmap_protect_large(struct gmap *gmap, unsigned long gaddr,
static int gmap_protect_range(struct gmap *gmap, unsigned long gaddr,
unsigned long len, int prot, unsigned long bits)
{
+ spinlock_t *ptl;
unsigned long vmaddr;
- pmd_t *pmdp;
+ pmd_t *pmdp, *hpmdp;
int rc;
while (len) {
rc = -EAGAIN;
+ vmaddr = __gmap_translate(gmap, gaddr);
+ hpmdp = (pmd_t *)huge_pte_offset(gmap->mm, vmaddr, HPAGE_SIZE);
+ /* Do we need tests here? */
+ ptl = pmd_lock(gmap->mm, hpmdp);
+
pmdp = gmap_pmd_op_walk(gmap, gaddr);
if (pmdp) {
if (!pmd_large(*pmdp)) {
@@ -1040,7 +1132,7 @@ static int gmap_protect_range(struct gmap *gmap, unsigned long gaddr,
gaddr += PAGE_SIZE;
}
} else {
- rc = gmap_protect_large(gmap, gaddr, pmdp,
+ rc = gmap_protect_large(gmap, gaddr, vmaddr, pmdp, hpmdp,
prot, bits);
if (!rc) {
len = len < HPAGE_SIZE ? 0 : len - HPAGE_SIZE;
@@ -1049,6 +1141,7 @@ static int gmap_protect_range(struct gmap *gmap, unsigned long gaddr,
}
gmap_pmd_op_end(gmap, pmdp);
}
+ spin_unlock(ptl);
if (rc) {
vmaddr = __gmap_translate(gmap, gaddr);
if (IS_ERR_VALUE(vmaddr))
--
2.7.4
next prev parent reply other threads:[~2017-11-06 22:29 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-06 22:29 [RFC/PATCH 00/22] KVM/s390: Hugetlbfs enablement Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 01/22] s390/mm: make gmap_protect_range more modular Janosch Frank
2017-11-08 10:40 ` David Hildenbrand
2017-11-08 12:21 ` Janosch Frank
2017-11-08 12:26 ` David Hildenbrand
2017-11-06 22:29 ` [RFC/PATCH 02/22] s390/mm: Abstract gmap notify bit setting Janosch Frank
2017-11-10 12:57 ` David Hildenbrand
2017-11-13 15:57 ` Janosch Frank
2017-11-15 9:30 ` David Hildenbrand
2017-11-06 22:29 ` [RFC/PATCH 03/22] s390/mm: add gmap PMD invalidation notification Janosch Frank
2017-11-15 9:55 ` David Hildenbrand
2017-11-17 9:02 ` Janosch Frank
2017-11-17 9:19 ` Martin Schwidefsky
2017-11-06 22:29 ` [RFC/PATCH 04/22] s390/mm: Add gmap pmd invalidation and clearing Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 05/22] s390/mm: hugetlb pages within a gmap can not be freed Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 06/22] s390/mm: Introduce gmap_pmdp_xchg Janosch Frank
2017-11-06 22:29 ` Janosch Frank [this message]
2017-11-06 22:29 ` [RFC/PATCH 08/22] s390/mm: Add huge page dirty sync support Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 09/22] s390/mm: clear huge page storage keys on enable_skey Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 10/22] s390/mm: Add huge pmd storage key handling Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 11/22] s390/mm: Remove superfluous parameter Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 12/22] s390/mm: Add gmap_protect_large read protection support Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 13/22] s390/mm: Make gmap_read_table EDAT1 compatible Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 14/22] s390/mm: Make protect_rmap " Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 15/22] s390/mm: GMAP read table extensions Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 16/22] s390/mm: Add shadow segment code Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 17/22] s390/mm: Add VSIE reverse fake case Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 18/22] s390/mm: Remove gmap_pte_op_walk Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 19/22] s390/mm: Split huge pages if granular protection is needed Janosch Frank
2017-12-07 16:32 ` David Hildenbrand
2017-12-08 7:00 ` Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 20/22] s390/mm: Enable gmap huge pmd support Janosch Frank
2017-11-15 10:08 ` David Hildenbrand
2017-11-15 12:24 ` Janosch Frank
2017-11-06 22:29 ` [RFC/PATCH 21/22] KVM: s390: Add KVM HPAGE capability Janosch Frank
2017-11-07 10:07 ` Cornelia Huck
2017-11-07 10:53 ` Janosch Frank
2017-11-15 10:06 ` David Hildenbrand
2017-11-15 12:02 ` Janosch Frank
2017-11-06 22:30 ` [RFC/PATCH 22/22] RFC: s390/mm: Add gmap lock classes Janosch Frank
2017-11-15 10:10 ` David Hildenbrand
2017-11-15 12:16 ` Janosch Frank
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1510007400-42493-8-git-send-email-frankja@linux.vnet.ibm.com \
--to=frankja@linux.vnet.ibm.com \
--cc=borntraeger@de.ibm.com \
--cc=david@redhat.com \
--cc=dominik.dingel@gmail.com \
--cc=kvm@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=schwidefsky@de.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox