Re: VM live migration failed from Linux v5.9 to Linux v5.10-rc1

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 11/2/2020 11:12 AM, Peng Liang wrote:
> Hi Marc,
> Sorry for my late reply.
> 
> On 10/31/2020 9:25 PM, Marc Zyngier wrote:
>> Hi Peng,
>>
>> [+Will, as we hacked the new ECE (Ectoplasmic Control Enclosure) together]
>>
>> On Sat, 31 Oct 2020 07:03:02 +0000,
>> Peng Liang <liangpeng10@xxxxxxxxxx> wrote:
>>>
>>> [...]
>>>
>>> I found that the different register and the different field between
>>> source and destination is ID_AA64PFR0_EL1.CSV2. I searched in git log
>>> and found that the commit e1026237f9067 ("KVM: arm64: Set CSV2 for
>>> guests on hardware unaffected by Spectre-v2") may be the cause of the
>>> failure?
>>
>> Thanks for the thorough analysis. Yes, this could well be the issue if
>> CSV2 isn't explicitly set at the source, and is now set on the target.
>> For confirmation, what is the value of ID_AA64PFR0_EL1.CSV2 on the
>> host?  What does /sys/devices/system/cpu/vulnerabilities/spectre_v2
>> contain?
> 
> On host:
>   ID_AA64PFR0_EL1.CSV2: 0
>   /sys/devices/system/cpu/vulnerabilities/spectre_v2: Not affected
> 
>>
>>> So do we need to make it possible to migrate VMs between Linux v5.9 and
>>> Linux v5.10-rc1 with QEMU?
>>
>> We should fix the migration from 5.9 to 5.10. I don't plan to support
>> migrating in the other direction, which is consistent with new sysregs
>> and features appearing in the sysreg space over time (although I would
>> expect 5.9 -> 5.10 -> 5.9 to work once we fix this issue).
> 
> BTW, there always be new sysregs/features introduced to kernel over
> time.  If that happened, do we need to make migration successful from a
> older version without the new sysregs/features?  I think there is no
> reason to not allow migration from old version to new version if the
> source end and the destination end have the same hardware just because
> old version doesn't expose some sysregs/features to guest but new
> version does.
> 
>>
>> Could you please give the patch below a go? I have boot-tested it, but
>> I'm not really equipped to test live migration.
> 
> Great!  I'll test live migration as soon as possible.

I applied the patch on v5.10-rc2, then the migration v5.9 -> v5.10 ->
v5.9 is successful.

Thanks,
Peng

> 
> Thanks,
> Peng
> 
>>
>> Thanks,
>>
>> 	M.
>>
>> >From 2b9202538365bacc0abd01142800234ea1bc5bde Mon Sep 17 00:00:00 2001
>> From: Marc Zyngier <maz@xxxxxxxxxx>
>> Date: Sat, 31 Oct 2020 12:28:50 +0000
>> Subject: [PATCH] KVM: arm64: Allow setting of ID_AA64PFR0_EL1.CSV2 from
>>  userspace
>>
>> We now expose ID_AA64PFR0_EL1.CSV2=1 to guests running on hosts
>> that are immune to Spectre-v2, but that don't have this field set,
>> most likely because they predate the specification.
>>
>> However, this prevents the migration of guests that have started on
>> a host the doesn't fake this CSV2 setting to one that does, as KVM
>> rejects the write to ID_AA64PFR0_EL2 on the grounds that it isn't
>> what is already there.
>>
>> In order to fix this, allow userspace to set this field as long as
>> this doesn't result in a promising more than what is already there
>> (setting CSV2 to 0 is acceptable, but setting it to 1 when it is
>> already set to 0 isn't).
>>
>> Fixes: e1026237f9067 ("KVM: arm64: Set CSV2 for guests on hardware unaffected by Spectre-v2")
>> Reported-by: Peng Liang <liangpeng10@xxxxxxxxxx>
>> Signed-off-by: Marc Zyngier <maz@xxxxxxxxxx>
>> ---
>>  arch/arm64/include/asm/kvm_host.h |  2 ++
>>  arch/arm64/kvm/arm.c              | 21 +++++++++++++++++
>>  arch/arm64/kvm/sys_regs.c         | 38 +++++++++++++++++++++++++++----
>>  3 files changed, 57 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> index 0aecbab6a7fb..160d783eaf89 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -118,6 +118,8 @@ struct kvm_arch {
>>  	 */
>>  	unsigned long *pmu_filter;
>>  	unsigned int pmuver;
>> +
>> +	u8 pfr0_csv2;
>>  };
>>  
>>  struct kvm_vcpu_fault_info {
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index f56122eedffc..1a944c9b48b4 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -102,6 +102,25 @@ static int kvm_arm_default_max_vcpus(void)
>>  	return vgic_present ? kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS;
>>  }
>>  
>> +static void set_default_csv2(struct kvm *kvm)
>> +{
>> +	u64 val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
>> +
>> +	/*
>> +	 * The default is to expose CSV2 == 1 if the HW isn't affected
>> +	 * but doesn't have CSV2 baked in the PFR0 register. Although
>> +	 * this is a per-CPU feature, we make it global because
>> +	 * asymmetric systems are just a nuisance.
>> +	 *
>> +	 * Userspace can override this as long as it doesn't promise
>> +	 * the impossible.
>> +	 */
>> +	kvm->arch.pfr0_csv2 = FIELD_GET(0xfUL << ID_AA64PFR0_CSV2_SHIFT, val);
>> +	if (!kvm->arch.pfr0_csv2 &&
>> +	    arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED)
>> +		kvm->arch.pfr0_csv2 = 1;
>> +}
>> +
>>  /**
>>   * kvm_arch_init_vm - initializes a VM data structure
>>   * @kvm:	pointer to the KVM struct
>> @@ -127,6 +146,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>>  	/* The maximum number of VCPUs is limited by the host's GIC model */
>>  	kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>>  
>> +	set_default_csv2(kvm);
>> +
>>  	return ret;
>>  out_free_stage2_pgd:
>>  	kvm_free_stage2_pgd(&kvm->arch.mmu);
>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index d9117bc56237..4f5716abbb19 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -1128,9 +1128,8 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
>>  		if (!vcpu_has_sve(vcpu))
>>  			val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
>>  		val &= ~(0xfUL << ID_AA64PFR0_AMU_SHIFT);
>> -		if (!(val & (0xfUL << ID_AA64PFR0_CSV2_SHIFT)) &&
>> -		    arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED)
>> -			val |= (1UL << ID_AA64PFR0_CSV2_SHIFT);
>> +		val &= ~(0xfUL << ID_AA64PFR0_CSV2_SHIFT);
>> +		val |= ((u64)vcpu->kvm->arch.pfr0_csv2 << ID_AA64PFR0_CSV2_SHIFT);
>>  	} else if (id == SYS_ID_AA64PFR1_EL1) {
>>  		val &= ~(0xfUL << ID_AA64PFR1_MTE_SHIFT);
>>  	} else if (id == SYS_ID_AA64ISAR1_EL1 && !vcpu_has_ptrauth(vcpu)) {
>> @@ -1260,6 +1259,36 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
>> +			       const struct sys_reg_desc *rd,
>> +			       const struct kvm_one_reg *reg, void __user *uaddr)
>> +{
>> +	const u64 id = sys_reg_to_index(rd);
>> +	int err;
>> +	u64 val;
>> +	u8 csv2;
>> +
>> +	err = reg_from_user(&val, uaddr, id);
>> +	if (err)
>> +		return err;
>> +
>> +	/*
>> +	 * Allow AA64PFR0_EL1.CSV2 to be set from userspace as long as
>> +	 * it doesn't promise more than what is actually provided (the
>> +	 * guest could otherwise be covered in ectoplasmic residue).
>> +	 */
>> +	csv2 = FIELD_GET(0xfUL << ID_AA64PFR0_CSV2_SHIFT, val);
>> +	if (csv2 > vcpu->kvm->arch.pfr0_csv2)
>> +		return -EINVAL;
>> +	vcpu->kvm->arch.pfr0_csv2 = csv2;
>> +
>> +	/* This is what we mean by invariant: you can't change it. */
>> +	if (val != read_id_reg(vcpu, rd, false))
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /*
>>   * cpufeature ID register user accessors
>>   *
>> @@ -1514,7 +1543,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>>  
>>  	/* AArch64 ID registers */
>>  	/* CRm=4 */
>> -	ID_SANITISED(ID_AA64PFR0_EL1),
>> +	{ SYS_DESC(SYS_ID_AA64PFR0_EL1), .access = access_id_reg,
>> +	  .get_user = get_id_reg, .set_user = set_id_aa64pfr0_el1, },
>>  	ID_SANITISED(ID_AA64PFR1_EL1),
>>  	ID_UNALLOCATED(4,2),
>>  	ID_UNALLOCATED(4,3),
>>
> 
_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm



[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux