]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Stefan Roscher <stefan.roscher@de.ibm.com> |
2 | Subject: ehca: fix a possible nullpointer access | |
3 | References: bnc#441966 | |
4 | ||
5 | If the initialization of a special QP (e.g. AQP1) fails due to a | |
6 | software timeout, we have to remove the reference to that special | |
7 | QP struct from the port struct preventing the driver to access the | |
8 | QP, since it will be/has been destroyed by the caller, ie in this | |
9 | case ib_mad. | |
10 | ||
11 | Acked-by: John Jolly <jjolly@novell.com> | |
12 | ||
13 | Index: linux-2.6.27/drivers/infiniband/hw/ehca/ehca_irq.c | |
14 | =================================================================== | |
15 | --- linux-2.6.27.orig/drivers/infiniband/hw/ehca/ehca_irq.c | |
16 | +++ linux-2.6.27/drivers/infiniband/hw/ehca/ehca_irq.c | |
17 | @@ -359,36 +359,48 @@ static void notify_port_conf_change(stru | |
18 | *old_attr = new_attr; | |
19 | } | |
20 | ||
21 | +/* replay modify_qp for sqps -- return 0 if all is well, 1 if AQP1 destroyed */ | |
22 | +static int replay_modify_qp(struct ehca_sport *sport) | |
23 | +{ | |
24 | + int aqp1_destroyed; | |
25 | + unsigned long flags; | |
26 | + | |
27 | + spin_lock_irqsave(&sport->mod_sqp_lock, flags); | |
28 | + | |
29 | + aqp1_destroyed = !sport->ibqp_sqp[IB_QPT_GSI]; | |
30 | + | |
31 | + if (sport->ibqp_sqp[IB_QPT_SMI]) | |
32 | + ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]); | |
33 | + if (!aqp1_destroyed) | |
34 | + ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]); | |
35 | + | |
36 | + spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); | |
37 | + | |
38 | + return aqp1_destroyed; | |
39 | +} | |
40 | + | |
41 | static void parse_ec(struct ehca_shca *shca, u64 eqe) | |
42 | { | |
43 | u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe); | |
44 | u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe); | |
45 | u8 spec_event; | |
46 | struct ehca_sport *sport = &shca->sport[port - 1]; | |
47 | - unsigned long flags; | |
48 | ||
49 | switch (ec) { | |
50 | case 0x30: /* port availability change */ | |
51 | if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) { | |
52 | - int suppress_event; | |
53 | - /* replay modify_qp for sqps */ | |
54 | - spin_lock_irqsave(&sport->mod_sqp_lock, flags); | |
55 | - suppress_event = !sport->ibqp_sqp[IB_QPT_GSI]; | |
56 | - if (sport->ibqp_sqp[IB_QPT_SMI]) | |
57 | - ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]); | |
58 | - if (!suppress_event) | |
59 | - ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]); | |
60 | - spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); | |
61 | - | |
62 | - /* AQP1 was destroyed, ignore this event */ | |
63 | - if (suppress_event) | |
64 | - break; | |
65 | + /* only replay modify_qp calls in autodetect mode; | |
66 | + * if AQP1 was destroyed, the port is already down | |
67 | + * again and we can drop the event. | |
68 | + */ | |
69 | + if (ehca_nr_ports < 0) | |
70 | + if (replay_modify_qp(sport)) | |
71 | + break; | |
72 | ||
73 | sport->port_state = IB_PORT_ACTIVE; | |
74 | dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE, | |
75 | "is active"); | |
76 | - ehca_query_sma_attr(shca, port, | |
77 | - &sport->saved_attr); | |
78 | + ehca_query_sma_attr(shca, port, &sport->saved_attr); | |
79 | } else { | |
80 | sport->port_state = IB_PORT_DOWN; | |
81 | dispatch_port_event(shca, port, IB_EVENT_PORT_ERR, | |
82 | Index: linux-2.6.27/drivers/infiniband/hw/ehca/ehca_qp.c | |
83 | =================================================================== | |
84 | --- linux-2.6.27.orig/drivers/infiniband/hw/ehca/ehca_qp.c | |
85 | +++ linux-2.6.27/drivers/infiniband/hw/ehca/ehca_qp.c | |
86 | @@ -854,6 +854,11 @@ static struct ehca_qp *internal_create_q | |
87 | if (qp_type == IB_QPT_GSI) { | |
88 | h_ret = ehca_define_sqp(shca, my_qp, init_attr); | |
89 | if (h_ret != H_SUCCESS) { | |
90 | + kfree(my_qp->mod_qp_parm); | |
91 | + my_qp->mod_qp_parm = NULL; | |
92 | + /* the QP pointer is no longer valid */ | |
93 | + shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] = | |
94 | + NULL; | |
95 | ret = ehca2ib_return_code(h_ret); | |
96 | goto create_qp_exit6; | |
97 | } |