Commit 1de1ea7e authored by Christian Borntraeger's avatar Christian Borntraeger

KVM: s390: add proper locking for CMMA migration bitmap

Some parts of the cmma migration bitmap is already protected
with the kvm->lock (e.g. the migration start). On the other
hand the read of the cmma bits is not protected against a
concurrent free, neither is the emulation of the ESSA instruction.
Let's extend the locking to all related ioctls by using
the slots lock for
- kvm_s390_vm_start_migration
- kvm_s390_vm_stop_migration
- kvm_s390_set_cmma_bits
- kvm_s390_get_cmma_bits

In addition to that, we use synchronize_srcu before freeing
the migration structure as all users hold kvm->srcu for read.
(e.g. the ESSA handler).
Reported-by: default avatarDavid Hildenbrand <david@redhat.com>
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Cc: stable@vger.kernel.org # 4.13+
Fixes: 190df4a2 (KVM: s390: CMMA tracking, ESSA emulation, migration mode)
Reviewed-by: default avatarClaudio Imbrenda <imbrenda@linux.vnet.ibm.com>
Reviewed-by: default avatarDavid Hildenbrand <david@redhat.com>
Reviewed-by: default avatarCornelia Huck <cohuck@redhat.com>
parent c2cf265d
...@@ -766,7 +766,7 @@ static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req) ...@@ -766,7 +766,7 @@ static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)
/* /*
* Must be called with kvm->srcu held to avoid races on memslots, and with * Must be called with kvm->srcu held to avoid races on memslots, and with
* kvm->lock to avoid races with ourselves and kvm_s390_vm_stop_migration. * kvm->slots_lock to avoid races with ourselves and kvm_s390_vm_stop_migration.
*/ */
static int kvm_s390_vm_start_migration(struct kvm *kvm) static int kvm_s390_vm_start_migration(struct kvm *kvm)
{ {
...@@ -822,7 +822,7 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm) ...@@ -822,7 +822,7 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)
} }
/* /*
* Must be called with kvm->lock to avoid races with ourselves and * Must be called with kvm->slots_lock to avoid races with ourselves and
* kvm_s390_vm_start_migration. * kvm_s390_vm_start_migration.
*/ */
static int kvm_s390_vm_stop_migration(struct kvm *kvm) static int kvm_s390_vm_stop_migration(struct kvm *kvm)
...@@ -837,6 +837,8 @@ static int kvm_s390_vm_stop_migration(struct kvm *kvm) ...@@ -837,6 +837,8 @@ static int kvm_s390_vm_stop_migration(struct kvm *kvm)
if (kvm->arch.use_cmma) { if (kvm->arch.use_cmma) {
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION); kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION);
/* We have to wait for the essa emulation to finish */
synchronize_srcu(&kvm->srcu);
vfree(mgs->pgste_bitmap); vfree(mgs->pgste_bitmap);
} }
kfree(mgs); kfree(mgs);
...@@ -846,14 +848,12 @@ static int kvm_s390_vm_stop_migration(struct kvm *kvm) ...@@ -846,14 +848,12 @@ static int kvm_s390_vm_stop_migration(struct kvm *kvm)
static int kvm_s390_vm_set_migration(struct kvm *kvm, static int kvm_s390_vm_set_migration(struct kvm *kvm,
struct kvm_device_attr *attr) struct kvm_device_attr *attr)
{ {
int idx, res = -ENXIO; int res = -ENXIO;
mutex_lock(&kvm->lock); mutex_lock(&kvm->slots_lock);
switch (attr->attr) { switch (attr->attr) {
case KVM_S390_VM_MIGRATION_START: case KVM_S390_VM_MIGRATION_START:
idx = srcu_read_lock(&kvm->srcu);
res = kvm_s390_vm_start_migration(kvm); res = kvm_s390_vm_start_migration(kvm);
srcu_read_unlock(&kvm->srcu, idx);
break; break;
case KVM_S390_VM_MIGRATION_STOP: case KVM_S390_VM_MIGRATION_STOP:
res = kvm_s390_vm_stop_migration(kvm); res = kvm_s390_vm_stop_migration(kvm);
...@@ -861,7 +861,7 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm, ...@@ -861,7 +861,7 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm,
default: default:
break; break;
} }
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->slots_lock);
return res; return res;
} }
...@@ -1751,7 +1751,9 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -1751,7 +1751,9 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = -EFAULT; r = -EFAULT;
if (copy_from_user(&args, argp, sizeof(args))) if (copy_from_user(&args, argp, sizeof(args)))
break; break;
mutex_lock(&kvm->slots_lock);
r = kvm_s390_get_cmma_bits(kvm, &args); r = kvm_s390_get_cmma_bits(kvm, &args);
mutex_unlock(&kvm->slots_lock);
if (!r) { if (!r) {
r = copy_to_user(argp, &args, sizeof(args)); r = copy_to_user(argp, &args, sizeof(args));
if (r) if (r)
...@@ -1765,7 +1767,9 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -1765,7 +1767,9 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = -EFAULT; r = -EFAULT;
if (copy_from_user(&args, argp, sizeof(args))) if (copy_from_user(&args, argp, sizeof(args)))
break; break;
mutex_lock(&kvm->slots_lock);
r = kvm_s390_set_cmma_bits(kvm, &args); r = kvm_s390_set_cmma_bits(kvm, &args);
mutex_unlock(&kvm->slots_lock);
break; break;
} }
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment