aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSagi Grimberg <sagig@mellanox.com>2014-12-07 09:09:59 -0500
committerRoland Dreier <roland@purestorage.com>2014-12-15 21:11:44 -0500
commit7414dde0a6c3a958e26141991bf5c75dc58d28b2 (patch)
tree13cf3044f5372fdc7be1b1ee7c63e57b79dd320f
parent3f562a0b8f0b47c4315e08bccd6a0b2d7f5aae1b (diff)
IB/iser: Fix race between iser connection teardown and scsi TMFs
In certain scenarios (target kill with live IO) scsi TMFs may race with iser RDMA teardown, which might cause NULL dereference on iser IB device handle (which might have been freed). In this case we take a conditional lock for TMFs and check the connection state (avoid introducing lock contention in the IO path). This is indeed best effort approach, but sufficient to survive multi targets sudden death while heavy IO is inflight. While we are on it, add a nice kernel-doc style documentation. Reported-by: Ariel Nahum <arieln@mellanox.com> Signed-off-by: Sagi Grimberg <sagig@mellanox.com> Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c49
1 files changed, 41 insertions, 8 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index cc7b84a235c8..bca97dcf0b4e 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -164,18 +164,42 @@ iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode)
164 return 0; 164 return 0;
165} 165}
166 166
167int iser_initialize_task_headers(struct iscsi_task *task, 167/**
168 struct iser_tx_desc *tx_desc) 168 * iser_initialize_task_headers() - Initialize task headers
169 * @task: iscsi task
170 * @tx_desc: iser tx descriptor
171 *
172 * Notes:
173 * This routine may race with iser teardown flow for scsi
174 * error handling TMFs. So for TMF we should acquire the
175 * state mutex to avoid dereferencing the IB device which
176 * may have already been terminated.
177 */
178int
179iser_initialize_task_headers(struct iscsi_task *task,
180 struct iser_tx_desc *tx_desc)
169{ 181{
170 struct iser_conn *iser_conn = task->conn->dd_data; 182 struct iser_conn *iser_conn = task->conn->dd_data;
171 struct iser_device *device = iser_conn->ib_conn.device; 183 struct iser_device *device = iser_conn->ib_conn.device;
172 struct iscsi_iser_task *iser_task = task->dd_data; 184 struct iscsi_iser_task *iser_task = task->dd_data;
173 u64 dma_addr; 185 u64 dma_addr;
186 const bool mgmt_task = !task->sc && !in_interrupt();
187 int ret = 0;
188
189 if (unlikely(mgmt_task))
190 mutex_lock(&iser_conn->state_mutex);
191
192 if (unlikely(iser_conn->state != ISER_CONN_UP)) {
193 ret = -ENODEV;
194 goto out;
195 }
174 196
175 dma_addr = ib_dma_map_single(device->ib_device, (void *)tx_desc, 197 dma_addr = ib_dma_map_single(device->ib_device, (void *)tx_desc,
176 ISER_HEADERS_LEN, DMA_TO_DEVICE); 198 ISER_HEADERS_LEN, DMA_TO_DEVICE);
177 if (ib_dma_mapping_error(device->ib_device, dma_addr)) 199 if (ib_dma_mapping_error(device->ib_device, dma_addr)) {
178 return -ENOMEM; 200 ret = -ENOMEM;
201 goto out;
202 }
179 203
180 tx_desc->dma_addr = dma_addr; 204 tx_desc->dma_addr = dma_addr;
181 tx_desc->tx_sg[0].addr = tx_desc->dma_addr; 205 tx_desc->tx_sg[0].addr = tx_desc->dma_addr;
@@ -183,7 +207,11 @@ int iser_initialize_task_headers(struct iscsi_task *task,
183 tx_desc->tx_sg[0].lkey = device->mr->lkey; 207 tx_desc->tx_sg[0].lkey = device->mr->lkey;
184 208
185 iser_task->iser_conn = iser_conn; 209 iser_task->iser_conn = iser_conn;
186 return 0; 210out:
211 if (unlikely(mgmt_task))
212 mutex_unlock(&iser_conn->state_mutex);
213
214 return ret;
187} 215}
188 216
189/** 217/**
@@ -199,9 +227,14 @@ static int
199iscsi_iser_task_init(struct iscsi_task *task) 227iscsi_iser_task_init(struct iscsi_task *task)
200{ 228{
201 struct iscsi_iser_task *iser_task = task->dd_data; 229 struct iscsi_iser_task *iser_task = task->dd_data;
230 int ret;
202 231
203 if (iser_initialize_task_headers(task, &iser_task->desc)) 232 ret = iser_initialize_task_headers(task, &iser_task->desc);
204 return -ENOMEM; 233 if (ret) {
234 iser_err("Failed to init task %p, err = %d\n",
235 iser_task, ret);
236 return ret;
237 }
205 238
206 /* mgmt task */ 239 /* mgmt task */
207 if (!task->sc) 240 if (!task->sc)