Leonard Norrgard wrote:
> I've been looking at the guest reboot problem, which currently reboots
> the host on svm when a Linux guest issues "# shutdown -r now".
>
Obviously a major issue, which we've neglected. Thanks for addressing it.
> The patch below stops the rebooting of the host and handles the request
> to reboot the guest in an orderly fashion, so it's a big step forward,
> but it doesn't yet succeed in rebooting of the guest, instead the VM exits.
>
> The basic approach is to intercept the shutdown. The patch includes some
> possible alternatives to reboot, while searching for the best approach:
>
> 1) Call kvm_qemu_destroy(); and immediately after kvm_qemu_create_context();
>
I don't like this approach. It means memory needs to be deallocated and
reallocated. There's some likelyhood of the reallocation failing, so a
reboot can turn into a dead VM. Memory contents is not preserved, while
a real reset does preserve memory.
More fundamentally, a real cpu can undergo a reset, and so should a
virtual cpu.
> 2) New ioctl to reset a vcpu
>
Definitely the way to go. It'll possibly be needed for guest smp too.
> 3) I also tried calling init_vmcb from shutdown_intercept, but that had
> no noticable effect
>
I think "shutdown" in this context is processor shutdown, not a vcpu
reset. IIRC a processor shutdown can be caused by invalid state or
hardware errors.
We should intercept it, but it's not that important IMO. (We should
also find out what it means exactly)
> Method 1 seems promising, but currently results in kvm exiting due to
> "do_interrupt: unexpect" errors.
>
> Method 2 currently results in vmrun returning KVM_EXIT_TYPE_FAIL_ENTRY.
>
>
Looks like not everything was initialized correctly...
> - Both of methods 1 and 2 need an API version bump
> - This code is safe to run without having to fear a host reboot
> - SVM only, at the moment
> - svm_reset_vcpu() was initially just the one-line call to init_vmcb(),
> there's some leftover cruft now...
> - A printf has been added to cpu_reset(), if this prints, qemu has
> called all registered reset handlers.
>
> Please comment. The Patch is relative to kvm-11.
>
>
>
> ------------------------------------------------------------------------
>
> Index: kernel/kvm_main.c
> ===================================================================
> --- kernel/kvm_main.c (revision 2211)
> +++ kernel/kvm_main.c (working copy)
> @@ -1764,6 +1764,23 @@
> return r;
> }
>
> +static int kvm_dev_ioctl_reset_vcpu(struct kvm *kvm, struct kvm_reset_vcpu
> *slot)
> +{
> + struct kvm_vcpu *vcpu;
> +
> + if (!valid_vcpu(slot->vcpu))
> + return -EINVAL;
> + vcpu = vcpu_load(kvm, slot->vcpu);
> + if (!vcpu)
> + return -ENOENT;
> +
> + kvm_arch_ops->reset_vcpu(vcpu);
> +
> + vcpu_put(vcpu);
> +
> + return 0;
> +}
> +
> static long kvm_dev_ioctl(struct file *filp,
> unsigned int ioctl, unsigned long arg)
> {
> @@ -1780,6 +1797,13 @@
> goto out;
> break;
> }
> + case KVM_RESET_VCPU: {
> + struct kvm_reset_vcpu kvm_reset_vcpu;
>
Empty line here.
> + if (copy_from_user(&kvm_reset_vcpu, (void *)arg, sizeof
> kvm_reset_vcpu))
> + goto out;
> + r = kvm_dev_ioctl_reset_vcpu(kvm, &kvm_reset_vcpu);
> + break;
> + }
> case KVM_RUN: {
> struct kvm_run kvm_run;
>
> Index: kernel/include/linux/kvm.h
> ===================================================================
> --- kernel/include/linux/kvm.h (revision 2211)
> +++ kernel/include/linux/kvm.h (working copy)
> @@ -11,7 +11,7 @@
> #include <asm/types.h>
> #include <linux/ioctl.h>
>
> -#define KVM_API_VERSION 2
> +#define KVM_API_VERSION 3
>
> /*
> * Architectural interrupt line count, and the size of the bitmap needed
> @@ -46,6 +46,7 @@
> KVM_EXIT_HLT = 5,
> KVM_EXIT_MMIO = 6,
> KVM_EXIT_IRQ_WINDOW_OPEN = 7,
> + KVM_EXIT_SHUTDOWN = 8,
> };
>
> /* for KVM_RUN */
> @@ -218,6 +219,12 @@
> };
> };
>
> +/* for KVM_RESET_VCPU */
> +struct kvm_reset_vcpu {
> + /* in */
> + __u32 vcpu;
> +};
> +
>
Why define the structure? Since ioctl() passes one argument, it can be
the vcpu number.
> #define KVMIO 0xAE
>
> #define KVM_GET_API_VERSION _IO(KVMIO, 1)
> @@ -235,5 +242,6 @@
> #define KVM_GET_MSRS _IOWR(KVMIO, 13, struct kvm_msrs)
> #define KVM_SET_MSRS _IOWR(KVMIO, 14, struct kvm_msrs)
> #define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 15, struct kvm_msr_list)
> +#define KVM_RESET_VCPU _IO(KVMIO, 16)
>
If you're passing a structure, this needs to be _IOR(KVMIO, 16, struct
kvm_reset_vcpu).
> @@ -582,6 +583,21 @@
> return r;
> }
>
> +static void svm_reset_vcpu(struct kvm_vcpu *vcpu)
> +{
> + printk("....svm_reset_vcpu\n");
> + memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
> + //vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
> + vcpu->svm->cr0 = 0x00000010;
> + vcpu->svm->asid_generation = 0;
> + memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
> + init_vmcb(vcpu->svm->vmcb);
> +
> + fx_init(vcpu);
> +
> + init_vmcb(vcpu->svm->vmcb);
> +}
>
You will need to reset the mmu context as well, as we're transitioning
from protected mode to real mode. Look at the set_sregs ioctl for an
example. This should be done from common code.
Perhaps init_vmcb relies on the save area being cleared. Try zeroing
vmcb->save in init_vmcb().
>
> @@ -1690,6 +1715,8 @@
> .run = svm_vcpu_run,
> .skip_emulated_instruction = skip_emulated_instruction,
> .vcpu_setup = svm_vcpu_setup,
> +
> + .reset_vcpu = svm_reset_vcpu,
> };
>
It would be nice to call reset_vcpu() as part of the normal vcpu
creating sequence, to avoid having a rarely-used code path.
--
error compiling committee.c: too many arguments to function
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
kvm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel