diff options
Diffstat (limited to 'arch/s390/kvm/sigp.c')
| -rw-r--r-- | arch/s390/kvm/sigp.c | 28 | 
1 files changed, 28 insertions, 0 deletions
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index cf4de80bd541..8aaee2892ec3 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -276,6 +276,34 @@ static int handle_sigp_dst(struct kvm_vcpu *vcpu, u8 order_code,  	if (!dst_vcpu)  		return SIGP_CC_NOT_OPERATIONAL; +	/* +	 * SIGP RESTART, SIGP STOP, and SIGP STOP AND STORE STATUS orders +	 * are processed asynchronously. Until the affected VCPU finishes +	 * its work and calls back into KVM to clear the (RESTART or STOP) +	 * interrupt, we need to return any new non-reset orders "busy". +	 * +	 * This is important because a single VCPU could issue: +	 *  1) SIGP STOP $DESTINATION +	 *  2) SIGP SENSE $DESTINATION +	 * +	 * If the SIGP SENSE would not be rejected as "busy", it could +	 * return an incorrect answer as to whether the VCPU is STOPPED +	 * or OPERATING. +	 */ +	if (order_code != SIGP_INITIAL_CPU_RESET && +	    order_code != SIGP_CPU_RESET) { +		/* +		 * Lockless check. Both SIGP STOP and SIGP (RE)START +		 * properly synchronize everything while processing +		 * their orders, while the guest cannot observe a +		 * difference when issuing other orders from two +		 * different VCPUs. +		 */ +		if (kvm_s390_is_stop_irq_pending(dst_vcpu) || +		    kvm_s390_is_restart_irq_pending(dst_vcpu)) +			return SIGP_CC_BUSY; +	} +  	switch (order_code) {  	case SIGP_SENSE:  		vcpu->stat.instruction_sigp_sense++;  |