KVM: s390: Allow userspace to limit guest memory size
authorDominik Dingel <dingel@linux.vnet.ibm.com>
Fri, 31 Oct 2014 13:10:41 +0000 (14:10 +0100)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Fri, 23 Jan 2015 12:25:30 +0000 (13:25 +0100)
With commit c6c956b80bdf ("KVM: s390/mm: support gmap page tables with less
than 5 levels") we are able to define a limit for the guest memory size.

As we round up the guest size in respect to the levels of page tables
we get to guest limits of: 2048 MB, 4096 GB, 8192 TB and 16384 PB.
We currently limit the guest size to 16 TB, which means we end up
creating a page table structure supporting guest sizes up to 8192 TB.

This patch introduces an interface that allows userspace to tune
this limit. This may bring performance improvements for small guests.

Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Documentation/virtual/kvm/devices/vm.txt
arch/s390/include/uapi/asm/kvm.h
arch/s390/kvm/kvm-s390.c

index d426fc87fe938c40a5fa87f55bed4c5edde0e26c..c3b17c61b7dd26aab7d3339771f630b4aa674454 100644 (file)
@@ -24,3 +24,17 @@ Returns: 0
 
 Clear the CMMA status for all guest pages, so any pages the guest marked
 as unused are again used any may not be reclaimed by the host.
+
+1.3. ATTRIBUTE KVM_S390_VM_MEM_LIMIT_SIZE
+Parameters: in attr->addr the address for the new limit of guest memory
+Returns: -EFAULT if the given address is not accessible
+         -EINVAL if the virtual machine is of type UCONTROL
+         -E2BIG if the given guest memory is to big for that machine
+         -EBUSY if a vcpu is already defined
+         -ENOMEM if not enough memory is available for a new shadow guest mapping
+          0 otherwise
+
+Allows userspace to query the actual limit and set a new limit for
+the maximum guest memory size. The limit will be rounded up to
+2048 MB, 4096 GB, 8192 TB respectively, as this limit is governed by
+the number of page table levels.
index 48eda3ab494478444876f7c233b318d9f38538fa..9c01159cf6678e23466d9c85383d6d73d2f58137 100644 (file)
@@ -61,6 +61,7 @@ struct kvm_s390_io_adapter_req {
 /* kvm attributes for mem_ctrl */
 #define KVM_S390_VM_MEM_ENABLE_CMMA    0
 #define KVM_S390_VM_MEM_CLR_CMMA       1
+#define KVM_S390_VM_MEM_LIMIT_SIZE     2
 
 /* for KVM_GET_REGS and KVM_SET_REGS */
 struct kvm_regs {
index 529f7905b341afac266f144d55bee39658a4e7b4..14cdf1c3b99527c319fee9567808b3ca2838acbc 100644 (file)
@@ -261,7 +261,24 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
        return r;
 }
 
-static int kvm_s390_mem_control(struct kvm *kvm, struct kvm_device_attr *attr)
+static int kvm_s390_get_mem_control(struct kvm *kvm, struct kvm_device_attr *attr)
+{
+       int ret;
+
+       switch (attr->attr) {
+       case KVM_S390_VM_MEM_LIMIT_SIZE:
+               ret = 0;
+               if (put_user(kvm->arch.gmap->asce_end, (u64 __user *)attr->addr))
+                       ret = -EFAULT;
+               break;
+       default:
+               ret = -ENXIO;
+               break;
+       }
+       return ret;
+}
+
+static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *attr)
 {
        int ret;
        unsigned int idx;
@@ -283,6 +300,36 @@ static int kvm_s390_mem_control(struct kvm *kvm, struct kvm_device_attr *attr)
                mutex_unlock(&kvm->lock);
                ret = 0;
                break;
+       case KVM_S390_VM_MEM_LIMIT_SIZE: {
+               unsigned long new_limit;
+
+               if (kvm_is_ucontrol(kvm))
+                       return -EINVAL;
+
+               if (get_user(new_limit, (u64 __user *)attr->addr))
+                       return -EFAULT;
+
+               if (new_limit > kvm->arch.gmap->asce_end)
+                       return -E2BIG;
+
+               ret = -EBUSY;
+               mutex_lock(&kvm->lock);
+               if (atomic_read(&kvm->online_vcpus) == 0) {
+                       /* gmap_alloc will round the limit up */
+                       struct gmap *new = gmap_alloc(current->mm, new_limit);
+
+                       if (!new) {
+                               ret = -ENOMEM;
+                       } else {
+                               gmap_free(kvm->arch.gmap);
+                               new->private = kvm;
+                               kvm->arch.gmap = new;
+                               ret = 0;
+                       }
+               }
+               mutex_unlock(&kvm->lock);
+               break;
+       }
        default:
                ret = -ENXIO;
                break;
@@ -296,7 +343,7 @@ static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
 
        switch (attr->group) {
        case KVM_S390_VM_MEM_CTRL:
-               ret = kvm_s390_mem_control(kvm, attr);
+               ret = kvm_s390_set_mem_control(kvm, attr);
                break;
        default:
                ret = -ENXIO;
@@ -308,7 +355,18 @@ static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
 
 static int kvm_s390_vm_get_attr(struct kvm *kvm, struct kvm_device_attr *attr)
 {
-       return -ENXIO;
+       int ret;
+
+       switch (attr->group) {
+       case KVM_S390_VM_MEM_CTRL:
+               ret = kvm_s390_get_mem_control(kvm, attr);
+               break;
+       default:
+               ret = -ENXIO;
+               break;
+       }
+
+       return ret;
 }
 
 static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
@@ -320,6 +378,7 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
                switch (attr->attr) {
                case KVM_S390_VM_MEM_ENABLE_CMMA:
                case KVM_S390_VM_MEM_CLR_CMMA:
+               case KVM_S390_VM_MEM_LIMIT_SIZE:
                        ret = 0;
                        break;
                default: