在 2026/7/10 10:58, Bibo Mao 写道:
> 
> 
> On 2026/7/10 上午8:50, Tao Cui wrote:
>> From: Tao Cui <[email protected]>
>>
>> kvm_set_pv_features() programs the KVM_FEATURE cpucfg attribute, which is a
>> per-vCPU setting. It was called from kvm_arch_put_registers() under a
>> function-local static guard, so it ran only once for the whole VM: only the
>> first vCPU got its pv features pushed to KVM, and on SMP guests the others
>> never saw KVM_FEATURE_IPI / KVM_FEATURE_STEAL_TIME.
>>
>> Drop the static guard and push pv features per vCPU under
>> KVM_PUT_FULL_STATE, the same gate kvm_set_stealtime() already uses. Host
>> feature detection stays in kvm_arch_init_vcpu(); the per-vCPU state write
>> belongs in kvm_arch_put_registers().
>>
>> Signed-off-by: Tao Cui <[email protected]>
>> ---
>>   target/loongarch/kvm/kvm.c | 15 ++++++---------
>>   1 file changed, 6 insertions(+), 9 deletions(-)
>>
>> diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
>> index d6539c12ac..c557ee3c3d 100644
>> --- a/target/loongarch/kvm/kvm.c
>> +++ b/target/loongarch/kvm/kvm.c
>> @@ -816,7 +816,6 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp)
>>   int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
>>   {
>>       int ret;
>> -    static int once;
>>         ret = kvm_loongarch_put_regs_core(cs);
>>       if (ret) {
>> @@ -843,19 +842,17 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState 
>> level, Error **errp)
>>           return ret;
>>       }
>>   -    if (!once) {
>> +    if (level >= KVM_PUT_FULL_STATE) {
>> +        /*
>> +         * pv_features and steal time are per-vCPU state. Push them on
>> +         * full-state sync so every vCPU gets its own settings; the kernel
>> +         * clears the steal-time guest_addr on KVM_PUT_RESET_STATE.
>> +         */
>>           ret = kvm_set_pv_features(cs);
> pv feature is a little different from steal-time. steal-time guest_addr is 
> created from guest OS, pv feature is created from VMM at beginning. 
> steal-time guest_addr can be set for many times, and there is bit 
> KVM_STEAL_PHYS_VALID checking with steal-time guest_addr, however pv feature 
> can be set only once with existing method.
> 

Hi Bibo,

Thanks for catching this — I hadn't fully considered the double-call path.

KVM_PUT_FULL_STATE fires both at realize (cpu_synchronize_post_init) and
on incoming migration load (cpu_synchronize_all_post_init), so
kvm_set_pv_features() runs twice on the destination.

> Although I do not understand flow of VM migration, with KVM_PUT_FULL_STATE 
> state changing, there are at least two places where this state is set, one is 
> from cpu_common_realizefn() which calls cpu_synchronize_post_init(), the 
> other is qemu_loadvm_state()/qemu_loadvm_state_main() which calls 
> cpu_synchronize_all_post_init().
> 
> It seems that VM will fail to migrate since kvm_set_pv_features is called 
> twice at least here. Do you test VM migration with this patch?

I did test migration (virt-11.2 -> virt-11.2, virt-11.1 -> virt-11.1) and
it passed, but that was on a single host — source and destination computed
the same pv_features. The kernel (kvm_loongarch_cpucfg_set_attr) only
rejects a re-set when the value differs:

    if ((kvm->arch.pv_features & LOONGARCH_PV_FEAT_UPDATED) &&
        ((kvm->arch.pv_features & valid) != val))
        return -EINVAL;

So a cross-host migration where the two sides compute different pv_features
would indeed fail on the second set.

I'll add a per-vCPU guard so the push happens exactly once (at the first
FULL_STATE sync); subsequent syncs are skipped and the destination keeps
advertising the features its own host supports. Does that sound like the
right direction?

Thanks,
Tao

> 
> Regards
> Bibo Mao
>>           if (ret) {
>>               return ret;
>>           }
>> -        once = 1;
>> -    }
>>   -    if (level >= KVM_PUT_FULL_STATE) {
>> -        /*
>> -         * only KVM_PUT_FULL_STATE is required, kvm kernel will clear
>> -         * guest_addr for KVM_PUT_RESET_STATE
>> -         */
>>           ret = kvm_set_stealtime(cs);
>>           if (ret) {
>>               return ret;
>>
> 


Reply via email to