KVM: s390: consider epoch index on TOD clock syncs
For now, we don't take care of over/underflows. Especially underflows
are critical:
Assume the epoch is currently 0 and we get a sync request for delta=1,
meaning the TOD is moved forward by 1 and we have to fix it up by
subtracting 1 from the epoch. Right now, this will leave the epoch
index untouched, resulting in epoch=-1, epoch_idx=0, which is wrong.
We have to take care of over and underflows, also for the VSIE case. So
let's factor out calculation into a separate function.
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20180207114647.6220-5-david@redhat.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Fixes: 8fa1696ea7
("KVM: s390: Multiple Epoch Facility support")
Cc: stable@vger.kernel.org
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
[use u8 for idx]
This commit is contained in:
parent
d16b52cb9c
commit
1575767ef3
@ -179,6 +179,28 @@ int kvm_arch_hardware_enable(void)
|
||||
static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start,
|
||||
unsigned long end);
|
||||
|
||||
static void kvm_clock_sync_scb(struct kvm_s390_sie_block *scb, u64 delta)
|
||||
{
|
||||
u8 delta_idx = 0;
|
||||
|
||||
/*
|
||||
* The TOD jumps by delta, we have to compensate this by adding
|
||||
* -delta to the epoch.
|
||||
*/
|
||||
delta = -delta;
|
||||
|
||||
/* sign-extension - we're adding to signed values below */
|
||||
if ((s64)delta < 0)
|
||||
delta_idx = -1;
|
||||
|
||||
scb->epoch += delta;
|
||||
if (scb->ecd & ECD_MEF) {
|
||||
scb->epdx += delta_idx;
|
||||
if (scb->epoch < delta)
|
||||
scb->epdx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback is executed during stop_machine(). All CPUs are therefore
|
||||
* temporarily stopped. In order not to change guest behavior, we have to
|
||||
@ -194,13 +216,17 @@ static int kvm_clock_sync(struct notifier_block *notifier, unsigned long val,
|
||||
unsigned long long *delta = v;
|
||||
|
||||
list_for_each_entry(kvm, &vm_list, vm_list) {
|
||||
kvm->arch.epoch -= *delta;
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
vcpu->arch.sie_block->epoch -= *delta;
|
||||
kvm_clock_sync_scb(vcpu->arch.sie_block, *delta);
|
||||
if (i == 0) {
|
||||
kvm->arch.epoch = vcpu->arch.sie_block->epoch;
|
||||
kvm->arch.epdx = vcpu->arch.sie_block->epdx;
|
||||
}
|
||||
if (vcpu->arch.cputm_enabled)
|
||||
vcpu->arch.cputm_start += *delta;
|
||||
if (vcpu->arch.vsie_block)
|
||||
vcpu->arch.vsie_block->epoch -= *delta;
|
||||
kvm_clock_sync_scb(vcpu->arch.vsie_block,
|
||||
*delta);
|
||||
}
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
|
Loading…
Reference in New Issue
Block a user