Skip to content

Commit e122d7a

Browse files
committed
Merge tag 'kvm-x86-xen-6.7' of https://github.com/kvm-x86/linux into HEAD
KVM x86 Xen changes for 6.7: - Omit "struct kvm_vcpu_xen" entirely when CONFIG_KVM_XEN=n. - Use the fast path directly from the timer callback when delivering Xen timer events. Avoid the problematic races with using the fast path by ensuring the hrtimer isn't running when (re)starting the timer or saving the timer information (for userspace). - Follow the lead of upstream Xen and ignore the VCPU_SSHOTTMR_future flag.
2 parents f0f59d0 + 409f2e9 commit e122d7a

File tree

4 files changed

+58
-6
lines changed

4 files changed

+58
-6
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ struct kvm_hypervisor_cpuid {
687687
u32 limit;
688688
};
689689

690+
#ifdef CONFIG_KVM_XEN
690691
/* Xen HVM per vcpu emulation context */
691692
struct kvm_vcpu_xen {
692693
u64 hypercall_rip;
@@ -709,6 +710,7 @@ struct kvm_vcpu_xen {
709710
struct timer_list poll_timer;
710711
struct kvm_hypervisor_cpuid cpuid;
711712
};
713+
#endif
712714

713715
struct kvm_queued_exception {
714716
bool pending;
@@ -937,8 +939,9 @@ struct kvm_vcpu_arch {
937939

938940
bool hyperv_enabled;
939941
struct kvm_vcpu_hv *hyperv;
942+
#ifdef CONFIG_KVM_XEN
940943
struct kvm_vcpu_xen xen;
941-
944+
#endif
942945
cpumask_var_t wbinvd_dirty_mask;
943946

944947
unsigned long last_retry_eip;

arch/x86/kvm/cpuid.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,9 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
448448
vcpu->arch.cpuid_nent = nent;
449449

450450
vcpu->arch.kvm_cpuid = kvm_get_hypervisor_cpuid(vcpu, KVM_SIGNATURE);
451+
#ifdef CONFIG_KVM_XEN
451452
vcpu->arch.xen.cpuid = kvm_get_hypervisor_cpuid(vcpu, XEN_SIGNATURE);
453+
#endif
452454
kvm_vcpu_after_set_cpuid(vcpu);
453455

454456
return 0;

arch/x86/kvm/x86.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3240,11 +3240,13 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
32403240

32413241
if (vcpu->pv_time.active)
32423242
kvm_setup_guest_pvclock(v, &vcpu->pv_time, 0);
3243+
#ifdef CONFIG_KVM_XEN
32433244
if (vcpu->xen.vcpu_info_cache.active)
32443245
kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_info_cache,
32453246
offsetof(struct compat_vcpu_info, time));
32463247
if (vcpu->xen.vcpu_time_info_cache.active)
32473248
kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_time_info_cache, 0);
3249+
#endif
32483250
kvm_hv_setup_tsc_page(v->kvm, &vcpu->hv_clock);
32493251
return 0;
32503252
}

arch/x86/kvm/xen.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,23 @@ static enum hrtimer_restart xen_timer_callback(struct hrtimer *timer)
134134
{
135135
struct kvm_vcpu *vcpu = container_of(timer, struct kvm_vcpu,
136136
arch.xen.timer);
137+
struct kvm_xen_evtchn e;
138+
int rc;
139+
137140
if (atomic_read(&vcpu->arch.xen.timer_pending))
138141
return HRTIMER_NORESTART;
139142

143+
e.vcpu_id = vcpu->vcpu_id;
144+
e.vcpu_idx = vcpu->vcpu_idx;
145+
e.port = vcpu->arch.xen.timer_virq;
146+
e.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL;
147+
148+
rc = kvm_xen_set_evtchn_fast(&e, vcpu->kvm);
149+
if (rc != -EWOULDBLOCK) {
150+
vcpu->arch.xen.timer_expires = 0;
151+
return HRTIMER_NORESTART;
152+
}
153+
140154
atomic_inc(&vcpu->arch.xen.timer_pending);
141155
kvm_make_request(KVM_REQ_UNBLOCK, vcpu);
142156
kvm_vcpu_kick(vcpu);
@@ -146,6 +160,14 @@ static enum hrtimer_restart xen_timer_callback(struct hrtimer *timer)
146160

147161
static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs, s64 delta_ns)
148162
{
163+
/*
164+
* Avoid races with the old timer firing. Checking timer_expires
165+
* to avoid calling hrtimer_cancel() will only have false positives
166+
* so is fine.
167+
*/
168+
if (vcpu->arch.xen.timer_expires)
169+
hrtimer_cancel(&vcpu->arch.xen.timer);
170+
149171
atomic_set(&vcpu->arch.xen.timer_pending, 0);
150172
vcpu->arch.xen.timer_expires = guest_abs;
151173

@@ -1019,9 +1041,36 @@ int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
10191041
break;
10201042

10211043
case KVM_XEN_VCPU_ATTR_TYPE_TIMER:
1044+
/*
1045+
* Ensure a consistent snapshot of state is captured, with a
1046+
* timer either being pending, or the event channel delivered
1047+
* to the corresponding bit in the shared_info. Not still
1048+
* lurking in the timer_pending flag for deferred delivery.
1049+
* Purely as an optimisation, if the timer_expires field is
1050+
* zero, that means the timer isn't active (or even in the
1051+
* timer_pending flag) and there is no need to cancel it.
1052+
*/
1053+
if (vcpu->arch.xen.timer_expires) {
1054+
hrtimer_cancel(&vcpu->arch.xen.timer);
1055+
kvm_xen_inject_timer_irqs(vcpu);
1056+
}
1057+
10221058
data->u.timer.port = vcpu->arch.xen.timer_virq;
10231059
data->u.timer.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL;
10241060
data->u.timer.expires_ns = vcpu->arch.xen.timer_expires;
1061+
1062+
/*
1063+
* The hrtimer may trigger and raise the IRQ immediately,
1064+
* while the returned state causes it to be set up and
1065+
* raised again on the destination system after migration.
1066+
* That's fine, as the guest won't even have had a chance
1067+
* to run and handle the interrupt. Asserting an already
1068+
* pending event channel is idempotent.
1069+
*/
1070+
if (vcpu->arch.xen.timer_expires)
1071+
hrtimer_start_expires(&vcpu->arch.xen.timer,
1072+
HRTIMER_MODE_ABS_HARD);
1073+
10251074
r = 0;
10261075
break;
10271076

@@ -1374,12 +1423,8 @@ static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd,
13741423
return true;
13751424
}
13761425

1426+
/* A delta <= 0 results in an immediate callback, which is what we want */
13771427
delta = oneshot.timeout_abs_ns - get_kvmclock_ns(vcpu->kvm);
1378-
if ((oneshot.flags & VCPU_SSHOTTMR_future) && delta < 0) {
1379-
*r = -ETIME;
1380-
return true;
1381-
}
1382-
13831428
kvm_xen_start_timer(vcpu, oneshot.timeout_abs_ns, delta);
13841429
*r = 0;
13851430
return true;

0 commit comments

Comments
 (0)