1 From 261520dcfcba93ca5dfe671b88ffab038cd940c8 Mon Sep 17 00:00:00 2001
2 From: David Hildenbrand <dahi@linux.vnet.ibm.com>
3 Date: Wed, 4 Feb 2015 15:53:42 +0100
4 Subject: KVM: s390: fix handling of write errors in the tpi handler
6 From: David Hildenbrand <dahi@linux.vnet.ibm.com>
8 commit 261520dcfcba93ca5dfe671b88ffab038cd940c8 upstream.
10 If the I/O interrupt could not be written to the guest provided
11 area (e.g. access exception), a program exception was injected into the
12 guest but "inti" wasn't freed, therefore resulting in a memory leak.
14 In addition, the I/O interrupt wasn't reinjected. Therefore the dequeued
17 This patch fixes the problem while cleaning up the function and making the
18 cc and rc logic easier to handle.
20 Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
21 Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
22 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
25 arch/s390/kvm/priv.c | 40 +++++++++++++++++++++++-----------------
26 1 file changed, 23 insertions(+), 17 deletions(-)
28 --- a/arch/s390/kvm/priv.c
29 +++ b/arch/s390/kvm/priv.c
30 @@ -229,18 +229,19 @@ static int handle_tpi(struct kvm_vcpu *v
31 struct kvm_s390_interrupt_info *inti;
39 addr = kvm_s390_get_base_disp_s(vcpu);
41 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
44 inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->arch.sie_block->gcr[6], 0);
49 + kvm_s390_set_psw_cc(vcpu, 0);
53 tpi_data[0] = inti->io.subchannel_id << 16 | inti->io.subchannel_nr;
54 tpi_data[1] = inti->io.io_int_parm;
55 tpi_data[2] = inti->io.io_int_word;
56 @@ -251,30 +252,35 @@ static int handle_tpi(struct kvm_vcpu *v
58 len = sizeof(tpi_data) - 4;
59 rc = write_guest(vcpu, addr, &tpi_data, len);
61 - return kvm_s390_inject_prog_cond(vcpu, rc);
63 + rc = kvm_s390_inject_prog_cond(vcpu, rc);
64 + goto reinject_interrupt;
68 * Store the three-word I/O interruption code into
69 * the appropriate lowcore area.
71 len = sizeof(tpi_data);
72 - if (write_guest_lc(vcpu, __LC_SUBCHANNEL_ID, &tpi_data, len))
73 + if (write_guest_lc(vcpu, __LC_SUBCHANNEL_ID, &tpi_data, len)) {
74 + /* failed writes to the low core are not recoverable */
76 + goto reinject_interrupt;
80 + /* irq was successfully handed to the guest */
82 + kvm_s390_set_psw_cc(vcpu, 1);
86 * If we encounter a problem storing the interruption code, the
87 * instruction is suppressed from the guest's view: reinject the
93 - kvm_s390_reinject_io_int(vcpu->kvm, inti);
95 - /* Set condition code and we're done. */
97 - kvm_s390_set_psw_cc(vcpu, cc);
98 + kvm_s390_reinject_io_int(vcpu->kvm, inti);
99 + /* don't set the cc, a pgm irq was injected or we drop to user space */
100 return rc ? -EFAULT : 0;