Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5cf2360b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull KVM fix from Radim Krčmář:
 "Fix PPC HV host crash that can occur as a result of resizing the guest
  hashed page table"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: PPC: Book3S HV: Fix exclusion between HPT resizing and other HPT updates
parents a579e949 d850a255
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -646,6 +646,16 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
		hnow_v = hpte_new_to_old_v(hnow_v, hnow_r);
		hnow_r = hpte_new_to_old_r(hnow_r);
	}

	/*
	 * If the HPT is being resized, don't update the HPTE,
	 * instead let the guest retry after the resize operation is complete.
	 * The synchronization for hpte_setup_done test vs. set is provided
	 * by the HPTE lock.
	 */
	if (!kvm->arch.hpte_setup_done)
		goto out_unlock;

	if ((hnow_v & ~HPTE_V_HVLOCK) != hpte[0] || hnow_r != hpte[1] ||
	    rev->guest_rpte != hpte[2])
		/* HPTE has been changed under us; let the guest retry */
+19 −10
Original line number Diff line number Diff line
@@ -2705,11 +2705,14 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
	 * Hard-disable interrupts, and check resched flag and signals.
	 * If we need to reschedule or deliver a signal, clean up
	 * and return without going into the guest(s).
	 * If the hpte_setup_done flag has been cleared, don't go into the
	 * guest because that means a HPT resize operation is in progress.
	 */
	local_irq_disable();
	hard_irq_disable();
	if (lazy_irq_pending() || need_resched() ||
	    recheck_signals(&core_info)) {
	    recheck_signals(&core_info) ||
	    (!kvm_is_radix(vc->kvm) && !vc->kvm->arch.hpte_setup_done)) {
		local_irq_enable();
		vc->vcore_state = VCORE_INACTIVE;
		/* Unlock all except the primary vcore */
@@ -3078,7 +3081,7 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc)

static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
	int n_ceded, i;
	int n_ceded, i, r;
	struct kvmppc_vcore *vc;
	struct kvm_vcpu *v;

@@ -3132,6 +3135,20 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)

	while (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE &&
	       !signal_pending(current)) {
		/* See if the HPT and VRMA are ready to go */
		if (!kvm_is_radix(vcpu->kvm) &&
		    !vcpu->kvm->arch.hpte_setup_done) {
			spin_unlock(&vc->lock);
			r = kvmppc_hv_setup_htab_rma(vcpu);
			spin_lock(&vc->lock);
			if (r) {
				kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
				kvm_run->fail_entry.hardware_entry_failure_reason = 0;
				vcpu->arch.ret = r;
				break;
			}
		}

		if (vc->vcore_state == VCORE_PREEMPT && vc->runner == NULL)
			kvmppc_vcore_end_preempt(vc);

@@ -3249,13 +3266,6 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
	/* Order vcpus_running vs. hpte_setup_done, see kvmppc_alloc_reset_hpt */
	smp_mb();

	/* On the first time here, set up HTAB and VRMA */
	if (!kvm_is_radix(vcpu->kvm) && !vcpu->kvm->arch.hpte_setup_done) {
		r = kvmppc_hv_setup_htab_rma(vcpu);
		if (r)
			goto out;
	}

	flush_all_to_thread(current);

	/* Save userspace EBB and other register values */
@@ -3303,7 +3313,6 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
	}
	mtspr(SPRN_VRSAVE, user_vrsave);

 out:
	vcpu->arch.state = KVMPPC_VCPU_NOTREADY;
	atomic_dec(&vcpu->kvm->arch.vcpus_running);
	return r;