]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.19.7/kvm-s390-fix-handling-of-write-errors-in-the-tpi-handler.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.19.7 / kvm-s390-fix-handling-of-write-errors-in-the-tpi-handler.patch
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
5
6 From: David Hildenbrand <dahi@linux.vnet.ibm.com>
7
8 commit 261520dcfcba93ca5dfe671b88ffab038cd940c8 upstream.
9
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.
13
14 In addition, the I/O interrupt wasn't reinjected. Therefore the dequeued
15 interrupt is lost.
16
17 This patch fixes the problem while cleaning up the function and making the
18 cc and rc logic easier to handle.
19
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>
23
24 ---
25 arch/s390/kvm/priv.c | 40 +++++++++++++++++++++++-----------------
26 1 file changed, 23 insertions(+), 17 deletions(-)
27
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;
32 unsigned long len;
33 u32 tpi_data[3];
34 - int cc, rc;
35 + int rc;
36 u64 addr;
37
38 - rc = 0;
39 addr = kvm_s390_get_base_disp_s(vcpu);
40 if (addr & 3)
41 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
42 - cc = 0;
43 +
44 inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->arch.sie_block->gcr[6], 0);
45 - if (!inti)
46 - goto no_interrupt;
47 - cc = 1;
48 + if (!inti) {
49 + kvm_s390_set_psw_cc(vcpu, 0);
50 + return 0;
51 + }
52 +
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
57 */
58 len = sizeof(tpi_data) - 4;
59 rc = write_guest(vcpu, addr, &tpi_data, len);
60 - if (rc)
61 - return kvm_s390_inject_prog_cond(vcpu, rc);
62 + if (rc) {
63 + rc = kvm_s390_inject_prog_cond(vcpu, rc);
64 + goto reinject_interrupt;
65 + }
66 } else {
67 /*
68 * Store the three-word I/O interruption code into
69 * the appropriate lowcore area.
70 */
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 */
75 rc = -EFAULT;
76 + goto reinject_interrupt;
77 + }
78 }
79 +
80 + /* irq was successfully handed to the guest */
81 + kfree(inti);
82 + kvm_s390_set_psw_cc(vcpu, 1);
83 + return 0;
84 +reinject_interrupt:
85 /*
86 * If we encounter a problem storing the interruption code, the
87 * instruction is suppressed from the guest's view: reinject the
88 * interrupt.
89 */
90 - if (!rc)
91 - kfree(inti);
92 - else
93 - kvm_s390_reinject_io_int(vcpu->kvm, inti);
94 -no_interrupt:
95 - /* Set condition code and we're done. */
96 - if (!rc)
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;
101 }
102