Skip to content

Commit 310bc39

Browse files
dwmw2bonzini
authored andcommitted
KVM: x86/xen: Avoid deadlock by adding kvm->arch.xen.xen_lock leaf node lock
In commit 14243b3 ("KVM: x86/xen: Add KVM_IRQ_ROUTING_XEN_EVTCHN and event channel delivery") the clever version of me left some helpful notes for those who would come after him: /* * For the irqfd workqueue, using the main kvm->lock mutex is * fine since this function is invoked from kvm_set_irq() with * no other lock held, no srcu. In future if it will be called * directly from a vCPU thread (e.g. on hypercall for an IPI) * then it may need to switch to using a leaf-node mutex for * serializing the shared_info mapping. */ mutex_lock(&kvm->lock); In commit 2fd6df2 ("KVM: x86/xen: intercept EVTCHNOP_send from guests") the other version of me ran straight past that comment without reading it, and introduced a potential deadlock by taking vcpu->mutex and kvm->lock in the wrong order. Solve this as originally suggested, by adding a leaf-node lock in the Xen state rather than using kvm->lock for it. Fixes: 2fd6df2 ("KVM: x86/xen: intercept EVTCHNOP_send from guests") Signed-off-by: David Woodhouse <[email protected]> Message-Id: <[email protected]> [Rebase, add docs. - Paolo] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 42a9000 commit 310bc39

File tree

3 files changed

+32
-38
lines changed

3 files changed

+32
-38
lines changed

Documentation/virt/kvm/locking.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ For SRCU:
3939

4040
On x86:
4141

42-
- vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock
42+
- vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock and kvm->arch.xen.xen_lock
4343

4444
- kvm->arch.mmu_lock is an rwlock. kvm->arch.tdp_mmu_pages_lock and
4545
kvm->arch.mmu_unsync_pages_lock are taken inside kvm->arch.mmu_lock, and

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,7 @@ struct msr_bitmap_range {
11111111

11121112
/* Xen emulation context */
11131113
struct kvm_xen {
1114+
struct mutex xen_lock;
11141115
u32 xen_version;
11151116
bool long_mode;
11161117
bool runstate_update_flag;

arch/x86/kvm/xen.c

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -607,26 +607,26 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
607607
if (!IS_ENABLED(CONFIG_64BIT) && data->u.long_mode) {
608608
r = -EINVAL;
609609
} else {
610-
mutex_lock(&kvm->lock);
610+
mutex_lock(&kvm->arch.xen.xen_lock);
611611
kvm->arch.xen.long_mode = !!data->u.long_mode;
612-
mutex_unlock(&kvm->lock);
612+
mutex_unlock(&kvm->arch.xen.xen_lock);
613613
r = 0;
614614
}
615615
break;
616616

617617
case KVM_XEN_ATTR_TYPE_SHARED_INFO:
618-
mutex_lock(&kvm->lock);
618+
mutex_lock(&kvm->arch.xen.xen_lock);
619619
r = kvm_xen_shared_info_init(kvm, data->u.shared_info.gfn);
620-
mutex_unlock(&kvm->lock);
620+
mutex_unlock(&kvm->arch.xen.xen_lock);
621621
break;
622622

623623
case KVM_XEN_ATTR_TYPE_UPCALL_VECTOR:
624624
if (data->u.vector && data->u.vector < 0x10)
625625
r = -EINVAL;
626626
else {
627-
mutex_lock(&kvm->lock);
627+
mutex_lock(&kvm->arch.xen.xen_lock);
628628
kvm->arch.xen.upcall_vector = data->u.vector;
629-
mutex_unlock(&kvm->lock);
629+
mutex_unlock(&kvm->arch.xen.xen_lock);
630630
r = 0;
631631
}
632632
break;
@@ -636,9 +636,9 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
636636
break;
637637

638638
case KVM_XEN_ATTR_TYPE_XEN_VERSION:
639-
mutex_lock(&kvm->lock);
639+
mutex_lock(&kvm->arch.xen.xen_lock);
640640
kvm->arch.xen.xen_version = data->u.xen_version;
641-
mutex_unlock(&kvm->lock);
641+
mutex_unlock(&kvm->arch.xen.xen_lock);
642642
r = 0;
643643
break;
644644

@@ -647,9 +647,9 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
647647
r = -EOPNOTSUPP;
648648
break;
649649
}
650-
mutex_lock(&kvm->lock);
650+
mutex_lock(&kvm->arch.xen.xen_lock);
651651
kvm->arch.xen.runstate_update_flag = !!data->u.runstate_update_flag;
652-
mutex_unlock(&kvm->lock);
652+
mutex_unlock(&kvm->arch.xen.xen_lock);
653653
r = 0;
654654
break;
655655

@@ -664,7 +664,7 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
664664
{
665665
int r = -ENOENT;
666666

667-
mutex_lock(&kvm->lock);
667+
mutex_lock(&kvm->arch.xen.xen_lock);
668668

669669
switch (data->type) {
670670
case KVM_XEN_ATTR_TYPE_LONG_MODE:
@@ -703,15 +703,15 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
703703
break;
704704
}
705705

706-
mutex_unlock(&kvm->lock);
706+
mutex_unlock(&kvm->arch.xen.xen_lock);
707707
return r;
708708
}
709709

710710
int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
711711
{
712712
int idx, r = -ENOENT;
713713

714-
mutex_lock(&vcpu->kvm->lock);
714+
mutex_lock(&vcpu->kvm->arch.xen.xen_lock);
715715
idx = srcu_read_lock(&vcpu->kvm->srcu);
716716

717717
switch (data->type) {
@@ -939,15 +939,15 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
939939
}
940940

941941
srcu_read_unlock(&vcpu->kvm->srcu, idx);
942-
mutex_unlock(&vcpu->kvm->lock);
942+
mutex_unlock(&vcpu->kvm->arch.xen.xen_lock);
943943
return r;
944944
}
945945

946946
int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
947947
{
948948
int r = -ENOENT;
949949

950-
mutex_lock(&vcpu->kvm->lock);
950+
mutex_lock(&vcpu->kvm->arch.xen.xen_lock);
951951

952952
switch (data->type) {
953953
case KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO:
@@ -1030,7 +1030,7 @@ int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
10301030
break;
10311031
}
10321032

1033-
mutex_unlock(&vcpu->kvm->lock);
1033+
mutex_unlock(&vcpu->kvm->arch.xen.xen_lock);
10341034
return r;
10351035
}
10361036

@@ -1123,7 +1123,7 @@ int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc)
11231123
xhc->blob_size_32 || xhc->blob_size_64))
11241124
return -EINVAL;
11251125

1126-
mutex_lock(&kvm->lock);
1126+
mutex_lock(&kvm->arch.xen.xen_lock);
11271127

11281128
if (xhc->msr && !kvm->arch.xen_hvm_config.msr)
11291129
static_branch_inc(&kvm_xen_enabled.key);
@@ -1132,7 +1132,7 @@ int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc)
11321132

11331133
memcpy(&kvm->arch.xen_hvm_config, xhc, sizeof(*xhc));
11341134

1135-
mutex_unlock(&kvm->lock);
1135+
mutex_unlock(&kvm->arch.xen.xen_lock);
11361136
return 0;
11371137
}
11381138

@@ -1675,15 +1675,7 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *xe, struct kvm *kvm)
16751675
mm_borrowed = true;
16761676
}
16771677

1678-
/*
1679-
* For the irqfd workqueue, using the main kvm->lock mutex is
1680-
* fine since this function is invoked from kvm_set_irq() with
1681-
* no other lock held, no srcu. In future if it will be called
1682-
* directly from a vCPU thread (e.g. on hypercall for an IPI)
1683-
* then it may need to switch to using a leaf-node mutex for
1684-
* serializing the shared_info mapping.
1685-
*/
1686-
mutex_lock(&kvm->lock);
1678+
mutex_lock(&kvm->arch.xen.xen_lock);
16871679

16881680
/*
16891681
* It is theoretically possible for the page to be unmapped
@@ -1712,7 +1704,7 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *xe, struct kvm *kvm)
17121704
srcu_read_unlock(&kvm->srcu, idx);
17131705
} while(!rc);
17141706

1715-
mutex_unlock(&kvm->lock);
1707+
mutex_unlock(&kvm->arch.xen.xen_lock);
17161708

17171709
if (mm_borrowed)
17181710
kthread_unuse_mm(kvm->mm);
@@ -1828,7 +1820,7 @@ static int kvm_xen_eventfd_update(struct kvm *kvm,
18281820
int ret;
18291821

18301822
/* Protect writes to evtchnfd as well as the idr lookup. */
1831-
mutex_lock(&kvm->lock);
1823+
mutex_lock(&kvm->arch.xen.xen_lock);
18321824
evtchnfd = idr_find(&kvm->arch.xen.evtchn_ports, port);
18331825

18341826
ret = -ENOENT;
@@ -1859,7 +1851,7 @@ static int kvm_xen_eventfd_update(struct kvm *kvm,
18591851
}
18601852
ret = 0;
18611853
out_unlock:
1862-
mutex_unlock(&kvm->lock);
1854+
mutex_unlock(&kvm->arch.xen.xen_lock);
18631855
return ret;
18641856
}
18651857

@@ -1922,10 +1914,10 @@ static int kvm_xen_eventfd_assign(struct kvm *kvm,
19221914
evtchnfd->deliver.port.priority = data->u.evtchn.deliver.port.priority;
19231915
}
19241916

1925-
mutex_lock(&kvm->lock);
1917+
mutex_lock(&kvm->arch.xen.xen_lock);
19261918
ret = idr_alloc(&kvm->arch.xen.evtchn_ports, evtchnfd, port, port + 1,
19271919
GFP_KERNEL);
1928-
mutex_unlock(&kvm->lock);
1920+
mutex_unlock(&kvm->arch.xen.xen_lock);
19291921
if (ret >= 0)
19301922
return 0;
19311923

@@ -1943,9 +1935,9 @@ static int kvm_xen_eventfd_deassign(struct kvm *kvm, u32 port)
19431935
{
19441936
struct evtchnfd *evtchnfd;
19451937

1946-
mutex_lock(&kvm->lock);
1938+
mutex_lock(&kvm->arch.xen.xen_lock);
19471939
evtchnfd = idr_remove(&kvm->arch.xen.evtchn_ports, port);
1948-
mutex_unlock(&kvm->lock);
1940+
mutex_unlock(&kvm->arch.xen.xen_lock);
19491941

19501942
if (!evtchnfd)
19511943
return -ENOENT;
@@ -1963,7 +1955,7 @@ static int kvm_xen_eventfd_reset(struct kvm *kvm)
19631955
int i;
19641956
int n = 0;
19651957

1966-
mutex_lock(&kvm->lock);
1958+
mutex_lock(&kvm->arch.xen.xen_lock);
19671959

19681960
/*
19691961
* Because synchronize_srcu() cannot be called inside the
@@ -1975,7 +1967,7 @@ static int kvm_xen_eventfd_reset(struct kvm *kvm)
19751967

19761968
all_evtchnfds = kmalloc_array(n, sizeof(struct evtchnfd *), GFP_KERNEL);
19771969
if (!all_evtchnfds) {
1978-
mutex_unlock(&kvm->lock);
1970+
mutex_unlock(&kvm->arch.xen.xen_lock);
19791971
return -ENOMEM;
19801972
}
19811973

@@ -1984,7 +1976,7 @@ static int kvm_xen_eventfd_reset(struct kvm *kvm)
19841976
all_evtchnfds[n++] = evtchnfd;
19851977
idr_remove(&kvm->arch.xen.evtchn_ports, evtchnfd->send_port);
19861978
}
1987-
mutex_unlock(&kvm->lock);
1979+
mutex_unlock(&kvm->arch.xen.xen_lock);
19881980

19891981
synchronize_srcu(&kvm->srcu);
19901982

@@ -2086,6 +2078,7 @@ void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu)
20862078

20872079
void kvm_xen_init_vm(struct kvm *kvm)
20882080
{
2081+
mutex_init(&kvm->arch.xen.xen_lock);
20892082
idr_init(&kvm->arch.xen.evtchn_ports);
20902083
kvm_gpc_init(&kvm->arch.xen.shinfo_cache, kvm, NULL, KVM_HOST_USES_PFN);
20912084
}

0 commit comments

Comments
 (0)