s390/mm: disable KSM for storage key enabled pages
authorDominik Dingel <dingel@linux.vnet.ibm.com>
Thu, 23 Oct 2014 10:09:17 +0000 (12:09 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 27 Oct 2014 12:27:26 +0000 (13:27 +0100)
When storage keys are enabled unmerge already merged pages and prevent
new pages from being merged.

Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/pgtable.h
arch/s390/kvm/priv.c
arch/s390/mm/pgtable.c

index df2e7f1..00d4607 100644 (file)
@@ -1751,7 +1751,7 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 extern int vmem_add_mapping(unsigned long start, unsigned long size);
 extern int vmem_remove_mapping(unsigned long start, unsigned long size);
 extern int s390_enable_sie(void);
-extern void s390_enable_skey(void);
+extern int s390_enable_skey(void);
 extern void s390_reset_cmma(struct mm_struct *mm);
 
 /*
index 72bb2dd..f47cb0c 100644 (file)
@@ -156,21 +156,25 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-static void __skey_check_enable(struct kvm_vcpu *vcpu)
+static int __skey_check_enable(struct kvm_vcpu *vcpu)
 {
+       int rc = 0;
        if (!(vcpu->arch.sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE)))
-               return;
+               return rc;
 
-       s390_enable_skey();
+       rc = s390_enable_skey();
        trace_kvm_s390_skey_related_inst(vcpu);
        vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE);
+       return rc;
 }
 
 
 static int handle_skey(struct kvm_vcpu *vcpu)
 {
-       __skey_check_enable(vcpu);
+       int rc = __skey_check_enable(vcpu);
 
+       if (rc)
+               return rc;
        vcpu->stat.instruction_storage_key++;
 
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
@@ -683,7 +687,10 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
                }
 
                if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) {
-                       __skey_check_enable(vcpu);
+                       int rc = __skey_check_enable(vcpu);
+
+                       if (rc)
+                               return rc;
                        if (set_guest_storage_key(current->mm, useraddr,
                                        vcpu->run->s.regs.gprs[reg1] & PFMF_KEY,
                                        vcpu->run->s.regs.gprs[reg1] & PFMF_NQ))
index 0f1e9ff..b1871d3 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/rcupdate.h>
 #include <linux/slab.h>
 #include <linux/swapops.h>
+#include <linux/ksm.h>
+#include <linux/mman.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -1275,22 +1277,34 @@ static int __s390_enable_skey(pte_t *pte, unsigned long addr,
        return 0;
 }
 
-void s390_enable_skey(void)
+int s390_enable_skey(void)
 {
        struct mm_walk walk = { .pte_entry = __s390_enable_skey };
        struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       int rc = 0;
 
        down_write(&mm->mmap_sem);
        if (mm_use_skey(mm))
                goto out_up;
 
        mm->context.use_skey = 1;
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if (ksm_madvise(vma, vma->vm_start, vma->vm_end,
+                               MADV_UNMERGEABLE, &vma->vm_flags)) {
+                       mm->context.use_skey = 0;
+                       rc = -ENOMEM;
+                       goto out_up;
+               }
+       }
+       mm->def_flags &= ~VM_MERGEABLE;
 
        walk.mm = mm;
        walk_page_range(0, TASK_SIZE, &walk);
 
 out_up:
        up_write(&mm->mmap_sem);
+       return rc;
 }
 EXPORT_SYMBOL_GPL(s390_enable_skey);