KVM: s390: streamline memslot handling
authorChristian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
Mon, 25 May 2009 11:40:51 +0000 (13:40 +0200)
committerAvi Kivity <avi@redhat.com>
Thu, 10 Sep 2009 05:32:42 +0000 (08:32 +0300)
This patch relocates the variables kvm-s390 uses to track guest mem addr/size.
As discussed dropping the variables at struct kvm_arch level allows to use the
common vcpu->request based mechanism to reload guest memory if e.g. changes
via set_memory_region.

The kick mechanism introduced in this series is used to ensure running vcpus
leave guest state to catch the update.

Signed-off-by: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/s390/include/asm/kvm_host.h
arch/s390/kvm/gaccess.h
arch/s390/kvm/intercept.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/sigp.c

index 0a784f6f9c904a191e61399abda560a5615357b2..75535d4d7a05593145e1b216f748bed8dbb27805 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * asm-s390/kvm_host.h - definition for kernel virtual machines on s390
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License (version 2 only)
@@ -228,8 +228,6 @@ struct kvm_vm_stat {
 };
 
 struct kvm_arch{
-       unsigned long guest_origin;
-       unsigned long guest_memsize;
        struct sca_block *sca;
        debug_info_t *dbf;
        struct kvm_s390_float_interrupt float_int;
index ed60f3a74a85f1ca6a8e994a974fc2bba6dd1652..03c716a0f01f9d6b9c295dd8f31123660565223e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * gaccess.h -  access guest memory
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License (version 2 only)
 #include <linux/compiler.h>
 #include <linux/kvm_host.h>
 #include <asm/uaccess.h>
+#include "kvm-s390.h"
 
 static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
                                               unsigned long guestaddr)
 {
        unsigned long prefix  = vcpu->arch.sie_block->prefix;
-       unsigned long origin  = vcpu->kvm->arch.guest_origin;
-       unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+       unsigned long origin  = vcpu->arch.sie_block->gmsor;
+       unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
 
        if (guestaddr < 2 * PAGE_SIZE)
                guestaddr += prefix;
@@ -158,8 +159,8 @@ static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest,
                                const void *from, unsigned long n)
 {
        unsigned long prefix  = vcpu->arch.sie_block->prefix;
-       unsigned long origin  = vcpu->kvm->arch.guest_origin;
-       unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+       unsigned long origin  = vcpu->arch.sie_block->gmsor;
+       unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
 
        if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE))
                goto slowpath;
@@ -209,8 +210,8 @@ static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to,
                                  unsigned long guestsrc, unsigned long n)
 {
        unsigned long prefix  = vcpu->arch.sie_block->prefix;
-       unsigned long origin  = vcpu->kvm->arch.guest_origin;
-       unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+       unsigned long origin  = vcpu->arch.sie_block->gmsor;
+       unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
 
        if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE))
                goto slowpath;
@@ -244,8 +245,8 @@ static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu,
                                         unsigned long guestdest,
                                         const void *from, unsigned long n)
 {
-       unsigned long origin  = vcpu->kvm->arch.guest_origin;
-       unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+       unsigned long origin  = vcpu->arch.sie_block->gmsor;
+       unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
 
        if (guestdest + n > memsize)
                return -EFAULT;
@@ -262,8 +263,8 @@ static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to,
                                           unsigned long guestsrc,
                                           unsigned long n)
 {
-       unsigned long origin  = vcpu->kvm->arch.guest_origin;
-       unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+       unsigned long origin  = vcpu->arch.sie_block->gmsor;
+       unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
 
        if (guestsrc + n > memsize)
                return -EFAULT;
index 0732ab4305f4adbdf7e59e1c00fda43b8dd6a2df..ba9d8a7bc1ac93d6b41fff692ec4f3e3b2e30e9d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * intercept.c - in-kernel handling for sie intercepts
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License (version 2 only)
@@ -164,9 +164,9 @@ static int handle_validity(struct kvm_vcpu *vcpu)
 
        vcpu->stat.exit_validity++;
        if ((viwhy == 0x37) && (vcpu->arch.sie_block->prefix
-               <= vcpu->kvm->arch.guest_memsize - 2*PAGE_SIZE)){
+               <= kvm_s390_vcpu_get_memsize(vcpu) - 2*PAGE_SIZE)) {
                rc = fault_in_pages_writeable((char __user *)
-                        vcpu->kvm->arch.guest_origin +
+                        vcpu->arch.sie_block->gmsor +
                         vcpu->arch.sie_block->prefix,
                         2*PAGE_SIZE);
                if (rc)
index 5c1c3025900292cbd30bcd83dd260814dc7c1353..098bfa6fbdf6da191997df568a531daa582004ef 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * s390host.c --  hosting zSeries kernel virtual machines
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License (version 2 only)
@@ -10,6 +10,7 @@
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *               Christian Borntraeger <borntraeger@de.ibm.com>
  *               Heiko Carstens <heiko.carstens@de.ibm.com>
+ *               Christian Ehrhardt <ehrhardt@de.ibm.com>
  */
 
 #include <linux/compiler.h>
@@ -278,16 +279,10 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
        vcpu->arch.sie_block->gbea = 1;
 }
 
-/* The current code can have up to 256 pages for virtio */
-#define VIRTIODESCSPACE (256ul * 4096ul)
-
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
        atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH);
-       vcpu->arch.sie_block->gmslm = vcpu->kvm->arch.guest_memsize +
-                                     vcpu->kvm->arch.guest_origin +
-                                     VIRTIODESCSPACE - 1ul;
-       vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin;
+       set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests);
        vcpu->arch.sie_block->ecb   = 2;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
        vcpu->arch.sie_block->fac   = (int) (long) facilities;
@@ -491,9 +486,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        vcpu_load(vcpu);
 
 rerun_vcpu:
+       if (vcpu->requests)
+               if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
+                       kvm_s390_vcpu_set_mem(vcpu);
+
        /* verify, that memory has been registered */
-       if (!vcpu->kvm->arch.guest_memsize) {
+       if (!vcpu->arch.sie_block->gmslm) {
                vcpu_put(vcpu);
+               VCPU_EVENT(vcpu, 3, "%s", "no memory registered to run vcpu");
                return -EINVAL;
        }
 
@@ -691,7 +691,7 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
           vmas. It is okay to mmap() and munmap() stuff in this slot after
           doing this call at any time */
 
-       if (mem->slot || kvm->arch.guest_memsize)
+       if (mem->slot)
                return -EINVAL;
 
        if (mem->guest_phys_addr)
@@ -706,36 +706,18 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
        if (!user_alloc)
                return -EINVAL;
 
-       /* lock all vcpus */
-       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-               if (!kvm->vcpus[i])
-                       continue;
-               if (!mutex_trylock(&kvm->vcpus[i]->mutex))
-                       goto fail_out;
-       }
-
-       kvm->arch.guest_origin = mem->userspace_addr;
-       kvm->arch.guest_memsize = mem->memory_size;
-
-       /* update sie control blocks, and unlock all vcpus */
+       /* request update of sie control block for all available vcpus */
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                if (kvm->vcpus[i]) {
-                       kvm->vcpus[i]->arch.sie_block->gmsor =
-                               kvm->arch.guest_origin;
-                       kvm->vcpus[i]->arch.sie_block->gmslm =
-                               kvm->arch.guest_memsize +
-                               kvm->arch.guest_origin +
-                               VIRTIODESCSPACE - 1ul;
-                       mutex_unlock(&kvm->vcpus[i]->mutex);
+                       if (test_and_set_bit(KVM_REQ_MMU_RELOAD,
+                                               &kvm->vcpus[i]->requests))
+                               continue;
+                       kvm_s390_inject_sigp_stop(kvm->vcpus[i],
+                                                 ACTION_RELOADVCPU_ON_STOP);
                }
        }
 
        return 0;
-
-fail_out:
-       for (; i >= 0; i--)
-               mutex_unlock(&kvm->vcpus[i]->mutex);
-       return -EINVAL;
 }
 
 void kvm_arch_flush_shadow(struct kvm *kvm)
index 2072cd4a013e26aa361788f9963cdc4c82697862..ec5eee7c25d83e4dcc2245f80382b13938c6a263 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * kvm_s390.h -  definition for kvm on s390
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License (version 2 only)
@@ -9,6 +9,7 @@
  *
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *               Christian Borntraeger <borntraeger@de.ibm.com>
+ *               Christian Ehrhardt <ehrhardt@de.ibm.com>
  */
 
 #ifndef ARCH_S390_KVM_S390_H
@@ -18,6 +19,9 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 
+/* The current code can have up to 256 pages for virtio */
+#define VIRTIODESCSPACE (256ul * 4096ul)
+
 typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
 
 /* negativ values are error codes, positive values for internal conditions */
@@ -54,6 +58,29 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
 int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
 int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action);
 
+static inline int kvm_s390_vcpu_get_memsize(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.sie_block->gmslm
+               - vcpu->arch.sie_block->gmsor
+               - VIRTIODESCSPACE + 1ul;
+}
+
+static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu)
+{
+       struct kvm_memory_slot *mem;
+
+       down_read(&vcpu->kvm->slots_lock);
+       mem = &vcpu->kvm->memslots[0];
+
+       vcpu->arch.sie_block->gmsor = mem->userspace_addr;
+       vcpu->arch.sie_block->gmslm =
+               mem->userspace_addr +
+               (mem->npages << PAGE_SHIFT) +
+               VIRTIODESCSPACE - 1ul;
+
+       up_read(&vcpu->kvm->slots_lock);
+}
+
 /* implemented in priv.c */
 int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
 
index 21897b0f8a36dfd4baababe0aecef1dec66f20d1..40c8c6748cfeece75f37ecbec8bcb8fbe95ce172 100644 (file)
@@ -189,9 +189,9 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
        /* make sure that the new value is valid memory */
        address = address & 0x7fffe000u;
        if ((copy_from_guest(vcpu, &tmp,
-               (u64) (address + vcpu->kvm->arch.guest_origin) , 1)) ||
+               (u64) (address + vcpu->arch.sie_block->gmsor) , 1)) ||
           (copy_from_guest(vcpu, &tmp, (u64) (address +
-                       vcpu->kvm->arch.guest_origin + PAGE_SIZE), 1))) {
+                       vcpu->arch.sie_block->gmsor + PAGE_SIZE), 1))) {
                *reg |= SIGP_STAT_INVALID_PARAMETER;
                return 1; /* invalid parameter */
        }