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 kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel