Skip to content

KVM paravirtualized spinlocks

Kör busy-wait spinlock'ları HLT-and-kick ile değiştiren bir KVM guest/host contract'ı: çok uzun süre spin'leyen bir vCPU halt eder (pCPU'yu host'a geri verir), lock'u bırakan taraf da onu KVM_HC_KICK_CPU hypercall'u ile uyandırır — virtualized spinlock'ların "lock-holder/waiter preemption" patolojisinden böylece kaçınılır.

Mechanism

Note

Native bir spinlock, lock holder'ın çalışmaya devam ettiğini varsayar, yani busy-waiting ucuzdur. Virtualization altında bu varsayım çöker: hypervisor, lock'u tutan vCPU'yu preempt edebilirken, diğer vCPU'lar tüm time slice'larını, holder yeniden schedule edilmeden bırakılamayacak bir lock üzerinde spin'leyerek yakar (lock-holder preemption / lock-waiter preemption). Bu, pCPU cycle'larını israf eder ve throughput'u çökertebilir.

Paravirtualized spinlock'lar bunu bir host/guest anlaşmasıyla çözer. Guest, PV-spinlock desteğini (KVM CPUID features üzerinden) tespit eder ve qspinlock slow-path'ini iki PV hook'una çevirir: kvm_wait() ve kvm_kick_cpu(). Bekleyen bir vCPU bir threshold'u aştığında HLT çalıştırır; bu VM-exit yapar ve host'un vCPU'yu spin'lemek yerine descheduler etmesine izin verir. Lock devredildiğinde, bırakan taraf kvm_kick_cpu() çağırır ve hedef vCPU'nun APIC ID'siyle birlikte KVM_HC_KICK_CPU hypercall'unu (numara 5) issue eder; host da onu uyandırır. Bu state'i migratable yapmak için bir PV_UNHALT MSR eklenir. Invariant şu: spin süresi bounded ve yield edilir, böylece preempt edilmiş bir holder artık waiter'ları aç bırakmaz.

Walkthrough

Public reference'lar: kernel.org KVM hypercalls dokümanı ve LWN PV-spinlock serisi. Kavramsal akış (guest tarafı):

  1. Guest boot eder ve PV-spinlock/PV_UNHALT desteği için KVM PV features'ı kontrol eder; mevcutsa pv_lock_ops'u kvm_wait / kvm_kick_cpu'ya bağlar.
  2. Bir vCPU bir qspinlock üzerinde contend eder. Bounded spinning'den sonra kvm_wait() çağırır; bu HLT çalıştırır ve oluşan VM-exit, host'un o pCPU'da başka bir şey çalıştırmasına izin verir.
  3. Lock owner unlock eder ve halt etmiş bir waiter görünce kvm_kick_cpu(apicid) çağırır, bu da şunu gerçekleştirir:

KVM_HC_KICK_CPU (hypercall #5), arg = APIC ID of the halted vCPU
4. Host hedef vCPU'yu uyandırır, o da lock'u tekrar dener.

Beklenen gözlem: oversubscribe edilmiş vCPU'larla yoğun lock contention altında, PV spinlock'lar native (PV-disabled) baseline'a göre çok daha az israf edilmiş spin-cycle ve daha istikrarlı throughput gösterir.

Warning

Bu bir performance/correctness enlightenment'ıdır, bir security boundary değil. Ama attack surface'tir: KVM_HC_KICK_CPU hypercall'u ve PV-spinlock MSR state'i guest'in erişebildiği host entry point'leridir ve verilen APIC ID ile state'i validate etmek zorundadır, yani hypervisor'ın threat model'ine dahildir.

Detection

  • Varlık: guest'e advertise edilen KVM PV-spinlock CPUID feature bit'i ve KVM_HC_KICK_CPU exit'lerinin kullanımı host üzerinde doğrudan gözlemlenebilir.
  • Geçersiz/out-of-range APIC ID'lerle KVM_HC_KICK_CPU çağrısı yapan bir guest anormaldir ve flag'lenmeye değer.

Mitigation

  • Hypervisor, hypercall argümanlarını (APIC ID) bounds-check etmeli ve özellikle live migration boyunca PV-spinlock MSR state'ini validate etmelidir.
  • Operatörler, workload'un ihtiyacı olmadığı yerde PV spinlock'ları devre dışı bırakarak guest'in erişebildiği surface'i küçültebilir.

References

  • "Linux KVM Hypercall" (KVM_HC_KICK_CPU). https://docs.kernel.org/virt/kvm/x86/hypercalls.html
  • LWN — "kvm: Paravirt-spinlock support for KVM guests." https://lwn.net/Articles/488286/