svn commit: r265101 - in head: sys/amd64/include sys/amd64/vmm usr.sbin/bhyve

Neel Natu neel at FreeBSD.org
Tue Apr 29 18:42:57 UTC 2014


Author: neel
Date: Tue Apr 29 18:42:56 2014
New Revision: 265101
URL: http://svnweb.freebsd.org/changeset/base/265101

Log:
  Some Linux guests will implement a 'halt' by disabling the APIC and executing
  the 'HLT' instruction. This condition was detected by 'vm_handle_hlt()' and
  converted into the SPINDOWN_CPU exitcode . The bhyve(8) process would exit
  the vcpu thread in response to a SPINDOWN_CPU and when the last vcpu was
  spun down it would reset the virtual machine via vm_suspend(VM_SUSPEND_RESET).
  
  This functionality was broken in r263780 in a way that made it impossible
  to kill the bhyve(8) process because it would loop forever in
  vm_handle_suspend().
  
  Unbreak this by removing the code to spindown vcpus. Thus a 'halt' from
  a Linux guest will appear to be hung but this is consistent with the
  behavior on bare metal. The guest can be rebooted by using the bhyvectl
  options '--force-reset' or '--force-poweroff'.
  
  Reviewed by:	grehan@

Modified:
  head/sys/amd64/include/vmm.h
  head/sys/amd64/vmm/vmm.c
  head/usr.sbin/bhyve/bhyverun.c

Modified: head/sys/amd64/include/vmm.h
==============================================================================
--- head/sys/amd64/include/vmm.h	Tue Apr 29 18:42:37 2014	(r265100)
+++ head/sys/amd64/include/vmm.h	Tue Apr 29 18:42:56 2014	(r265101)
@@ -325,7 +325,7 @@ enum vm_exitcode {
 	VM_EXITCODE_PAGING,
 	VM_EXITCODE_INST_EMUL,
 	VM_EXITCODE_SPINUP_AP,
-	VM_EXITCODE_SPINDOWN_CPU,
+	VM_EXITCODE_DEPRECATED1,	/* used to be SPINDOWN_CPU */
 	VM_EXITCODE_RENDEZVOUS,
 	VM_EXITCODE_IOAPIC_EOI,
 	VM_EXITCODE_SUSPENDED,

Modified: head/sys/amd64/vmm/vmm.c
==============================================================================
--- head/sys/amd64/vmm/vmm.c	Tue Apr 29 18:42:37 2014	(r265100)
+++ head/sys/amd64/vmm/vmm.c	Tue Apr 29 18:42:56 2014	(r265101)
@@ -191,8 +191,6 @@ static int vmm_ipinum;
 SYSCTL_INT(_hw_vmm, OID_AUTO, ipinum, CTLFLAG_RD, &vmm_ipinum, 0,
     "IPI vector used for vcpu notifications");
 
-static void vm_deactivate_cpu(struct vm *vm, int vcpuid);
-
 static void
 vcpu_cleanup(struct vm *vm, int i)
 {
@@ -1006,60 +1004,47 @@ vm_handle_rendezvous(struct vm *vm, int 
 static int
 vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu)
 {
-	struct vm_exit *vmexit;
 	struct vcpu *vcpu;
-	int t, timo, spindown;
+	const char *wmesg;
+	int t;
 
 	vcpu = &vm->vcpu[vcpuid];
-	spindown = 0;
 
 	vcpu_lock(vcpu);
+	while (1) {
+		/*
+		 * Do a final check for pending NMI or interrupts before
+		 * really putting this thread to sleep. Also check for
+		 * software events that would cause this vcpu to wakeup.
+		 *
+		 * These interrupts/events could have happened after the
+		 * vcpu returned from VMRUN() and before it acquired the
+		 * vcpu lock above.
+		 */
+		if (vm->rendezvous_func != NULL || vm->suspend)
+			break;
+		if (vm_nmi_pending(vm, vcpuid))
+			break;
+		if (!intr_disabled) {
+			if (vm_extint_pending(vm, vcpuid) ||
+			    vlapic_pending_intr(vcpu->vlapic, NULL)) {
+				break;
+			}
+		}
+
+		if (vlapic_enabled(vcpu->vlapic))
+			wmesg = "vmidle";
+		else
+			wmesg = "vmhalt";
 
-	/*
-	 * Do a final check for pending NMI or interrupts before
-	 * really putting this thread to sleep.
-	 *
-	 * These interrupts could have happened any time after we
-	 * returned from VMRUN() and before we grabbed the vcpu lock.
-	 */
-	if (vm->rendezvous_func == NULL &&
-	    !vm_nmi_pending(vm, vcpuid) &&
-	    (intr_disabled || !vlapic_pending_intr(vcpu->vlapic, NULL))) {
 		t = ticks;
 		vcpu_require_state_locked(vcpu, VCPU_SLEEPING);
-		if (vlapic_enabled(vcpu->vlapic)) {
-			/*
-			 * XXX msleep_spin() is not interruptible so use the
-			 * 'timo' to put an upper bound on the sleep time.
-			 */
-			timo = hz;
-			msleep_spin(vcpu, &vcpu->mtx, "vmidle", timo);
-		} else {
-			/*
-			 * Spindown the vcpu if the APIC is disabled and it
-			 * had entered the halted state, but never spin
-			 * down the BSP.
-			 */
-			if (vcpuid != 0)
-				spindown = 1;
-		}
+		msleep_spin(vcpu, &vcpu->mtx, wmesg, 0);
 		vcpu_require_state_locked(vcpu, VCPU_FROZEN);
 		vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t);
 	}
 	vcpu_unlock(vcpu);
 
-	/*
-	 * Since 'vm_deactivate_cpu()' grabs a sleep mutex we must call it
-	 * outside the confines of the vcpu spinlock.
-	 */
-	if (spindown) {
-		*retu = true;
-		vmexit = vm_exitinfo(vm, vcpuid);
-		vmexit->exitcode = VM_EXITCODE_SPINDOWN_CPU;
-		vm_deactivate_cpu(vm, vcpuid);
-		VCPU_CTR0(vm, vcpuid, "spinning down cpu");
-	}
-
 	return (0);
 }
 
@@ -1673,30 +1658,6 @@ vm_activate_cpu(struct vm *vm, int vcpui
 	CPU_SET_ATOMIC(vcpuid, &vm->active_cpus);
 }
 
-static void
-vm_deactivate_cpu(struct vm *vm, int vcpuid)
-{
-
-	KASSERT(vcpuid >= 0 && vcpuid < VM_MAXCPU,
-	    ("vm_deactivate_cpu: invalid vcpuid %d", vcpuid));
-	KASSERT(CPU_ISSET(vcpuid, &vm->active_cpus),
-	    ("vm_deactivate_cpu: vcpuid %d is not active", vcpuid));
-
-	VCPU_CTR0(vm, vcpuid, "deactivated");
-	CPU_CLR_ATOMIC(vcpuid, &vm->active_cpus);
-
-	/*
-	 * If a vcpu rendezvous is in progress then it could be blocked
-	 * on 'vcpuid' - unblock it before disappearing forever.
-	 */
-	mtx_lock(&vm->rendezvous_mtx);
-	if (vm->rendezvous_func != NULL) {
-		VCPU_CTR0(vm, vcpuid, "unblock rendezvous after deactivation");
-		wakeup(&vm->rendezvous_func);
-	}
-	mtx_unlock(&vm->rendezvous_mtx);
-}
-
 cpuset_t
 vm_active_cpus(struct vm *vm)
 {

Modified: head/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- head/usr.sbin/bhyve/bhyverun.c	Tue Apr 29 18:42:37 2014	(r265100)
+++ head/usr.sbin/bhyve/bhyverun.c	Tue Apr 29 18:42:56 2014	(r265101)
@@ -114,6 +114,7 @@ struct bhyvestats {
         uint64_t        cpu_switch_rotate;
         uint64_t        cpu_switch_direct;
         int             io_reset;
+	int		io_poweroff;
 } stats;
 
 struct mt_vmm_info {
@@ -237,13 +238,6 @@ fbsdrun_deletecpu(struct vmctx *ctx, int
 }
 
 static int
-vmexit_catch_reset(void)
-{
-        stats.io_reset++;
-        return (VMEXIT_RESET);
-}
-
-static int
 vmexit_catch_inout(void)
 {
 	return (VMEXIT_ABORT);
@@ -293,8 +287,10 @@ vmexit_inout(struct vmctx *ctx, struct v
 	case INOUT_OK:
 		return (VMEXIT_CONTINUE);
 	case INOUT_RESET:
+		stats.io_reset++;
 		return (VMEXIT_RESET);
 	case INOUT_POWEROFF:
+		stats.io_poweroff++;
 		return (VMEXIT_POWEROFF);
 	default:
 		fprintf(stderr, "Unhandled %s%c 0x%04x\n",
@@ -365,17 +361,6 @@ vmexit_spinup_ap(struct vmctx *ctx, stru
 }
 
 static int
-vmexit_spindown_cpu(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
-{
-	int lastcpu;
-
-	lastcpu = fbsdrun_deletecpu(ctx, *pvcpu);
-	if (!lastcpu)
-		pthread_exit(NULL);
-	return (vmexit_catch_reset());
-}
-
-static int
 vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
 {
 
@@ -501,7 +486,6 @@ static vmexit_handler_t handler[VM_EXITC
 	[VM_EXITCODE_MTRAP]  = vmexit_mtrap,
 	[VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,
 	[VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap,
-	[VM_EXITCODE_SPINDOWN_CPU] = vmexit_spindown_cpu,
 	[VM_EXITCODE_SUSPENDED] = vmexit_suspend
 };
 


More information about the svn-src-all mailing list