s390/mm: set and get guest storage key mmap locking
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 8 Mar 2016 10:53:35 +0000 (11:53 +0100)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Fri, 10 Jun 2016 10:07:27 +0000 (12:07 +0200)
Move the mmap semaphore locking out of set_guest_storage_key
and get_guest_storage_key. This makes the two functions more
like the other ptep_xxx operations and allows to avoid repeated
semaphore operations if multiple keys are read or written.

Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c
arch/s390/mm/pgtable.c

index 9d0e4d0487f431f9f1deadc4d52b2d9f578db078..d0156d7969e039b0807b53d63f915781255005c8 100644 (file)
@@ -1050,26 +1050,30 @@ static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
        if (!keys)
                return -ENOMEM;
 
+       down_read(&current->mm->mmap_sem);
        for (i = 0; i < args->count; i++) {
                hva = gfn_to_hva(kvm, args->start_gfn + i);
                if (kvm_is_error_hva(hva)) {
                        r = -EFAULT;
-                       goto out;
+                       break;
                }
 
                curkey = get_guest_storage_key(current->mm, hva);
                if (IS_ERR_VALUE(curkey)) {
                        r = curkey;
-                       goto out;
+                       break;
                }
                keys[i] = curkey;
        }
+       up_read(&current->mm->mmap_sem);
+
+       if (!r) {
+               r = copy_to_user((uint8_t __user *)args->skeydata_addr, keys,
+                                sizeof(uint8_t) * args->count);
+               if (r)
+                       r = -EFAULT;
+       }
 
-       r = copy_to_user((uint8_t __user *)args->skeydata_addr, keys,
-                        sizeof(uint8_t) * args->count);
-       if (r)
-               r = -EFAULT;
-out:
        kvfree(keys);
        return r;
 }
@@ -1106,24 +1110,26 @@ static long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
        if (r)
                goto out;
 
+       down_read(&current->mm->mmap_sem);
        for (i = 0; i < args->count; i++) {
                hva = gfn_to_hva(kvm, args->start_gfn + i);
                if (kvm_is_error_hva(hva)) {
                        r = -EFAULT;
-                       goto out;
+                       break;
                }
 
                /* Lowest order bit is reserved */
                if (keys[i] & 0x01) {
                        r = -EINVAL;
-                       goto out;
+                       break;
                }
 
                r = set_guest_storage_key(current->mm, hva,
                                          (unsigned long)keys[i], 0);
                if (r)
-                       goto out;
+                       break;
        }
+       up_read(&current->mm->mmap_sem);
 out:
        kvfree(keys);
        return r;
index 95916fa7c670be54c7e5c63008024a7d6289ea31..c6deed782c615cebb6417f440da3ed4bcbf6d6a6 100644 (file)
@@ -728,9 +728,12 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
 
                        if (rc)
                                return rc;
-                       if (set_guest_storage_key(current->mm, useraddr,
+                       down_read(&current->mm->mmap_sem);
+                       rc = set_guest_storage_key(current->mm, useraddr,
                                        vcpu->run->s.regs.gprs[reg1] & PFMF_KEY,
-                                       vcpu->run->s.regs.gprs[reg1] & PFMF_NQ))
+                                       vcpu->run->s.regs.gprs[reg1] & PFMF_NQ);
+                       up_read(&current->mm->mmap_sem);
+                       if (rc)
                                return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
                }
 
index 2a23ca96f9c29bd9429a722d5fc8f7d69709629a..7612a7c3a3a8bc498509f93fea0d2b067803f836 100644 (file)
@@ -506,12 +506,9 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
        pgste_t old, new;
        pte_t *ptep;
 
-       down_read(&mm->mmap_sem);
        ptep = get_locked_pte(mm, addr, &ptl);
-       if (unlikely(!ptep)) {
-               up_read(&mm->mmap_sem);
+       if (unlikely(!ptep))
                return -EFAULT;
-       }
 
        new = old = pgste_get_lock(ptep);
        pgste_val(new) &= ~(PGSTE_GR_BIT | PGSTE_GC_BIT |
@@ -538,7 +535,6 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
 
        pgste_set_unlock(ptep, new);
        pte_unmap_unlock(ptep, ptl);
-       up_read(&mm->mmap_sem);
        return 0;
 }
 EXPORT_SYMBOL(set_guest_storage_key);
@@ -550,14 +546,11 @@ unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr)
        pgste_t pgste;
        pte_t *ptep;
 
-       down_read(&mm->mmap_sem);
        ptep = get_locked_pte(mm, addr, &ptl);
-       if (unlikely(!ptep)) {
-               up_read(&mm->mmap_sem);
+       if (unlikely(!ptep))
                return -EFAULT;
-       }
-       pgste = pgste_get_lock(ptep);
 
+       pgste = pgste_get_lock(ptep);
        if (pte_val(*ptep) & _PAGE_INVALID) {
                key  = (pgste_val(pgste) & PGSTE_ACC_BITS) >> 56;
                key |= (pgste_val(pgste) & PGSTE_FP_BIT) >> 56;
@@ -572,10 +565,8 @@ unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr)
                if (pgste_val(pgste) & PGSTE_GC_BIT)
                        key |= _PAGE_CHANGED;
        }
-
        pgste_set_unlock(ptep, pgste);
        pte_unmap_unlock(ptep, ptl);
-       up_read(&mm->mmap_sem);
        return key;
 }
 EXPORT_SYMBOL(get_guest_storage_key);