aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-05-21 16:54:03 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-12 09:22:17 -0400
commitb40977d95fb3a1898ace6a7d97e4ed1a33a440a4 (patch)
treedfbe7909a066c974f16403e25f687496dde7fb0a
parent5af3e91d232b7e022f258202f72ebb79b8b0c706 (diff)
[SCSI] iser: fix handling of scsi cmnds during recovery.
After the stop_conn callback has returned the LLD should not touch the scsi cmds. iscsi_tcp and libiscsi use the conn->recv_lock and suspend_rx field to halt recv path processing, but iser does not have any protection. This patch modifies iser so that userspace can just call the ep_disconnect callback, which will halt all recv IO, before calling the stop_conn callback so we do not have to worry about the conn->recv_lock and suspend rx field. iser just needs to stop the send side from accessing the ib conn. Fixup to handle when the ep poll fails and ep disconnect is called from Erez. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c42
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h5
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c14
-rw-r--r--drivers/scsi/libiscsi.c3
4 files changed, 59 insertions, 5 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 9b34946eb00d..8a1bfb7277c8 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -305,10 +305,18 @@ iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
305{ 305{
306 struct iscsi_conn *conn = cls_conn->dd_data; 306 struct iscsi_conn *conn = cls_conn->dd_data;
307 struct iscsi_iser_conn *iser_conn = conn->dd_data; 307 struct iscsi_iser_conn *iser_conn = conn->dd_data;
308 struct iser_conn *ib_conn = iser_conn->ib_conn;
308 309
309 if (iser_conn->ib_conn)
310 iser_conn->ib_conn->iser_conn = NULL;
311 iscsi_conn_teardown(cls_conn); 310 iscsi_conn_teardown(cls_conn);
311 /*
312 * Userspace will normally call the stop callback and
313 * already have freed the ib_conn, but if it goofed up then
314 * we free it here.
315 */
316 if (ib_conn) {
317 ib_conn->iser_conn = NULL;
318 iser_conn_put(ib_conn);
319 }
312} 320}
313 321
314static int 322static int
@@ -340,12 +348,29 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
340 iser_conn = conn->dd_data; 348 iser_conn = conn->dd_data;
341 ib_conn->iser_conn = iser_conn; 349 ib_conn->iser_conn = iser_conn;
342 iser_conn->ib_conn = ib_conn; 350 iser_conn->ib_conn = ib_conn;
351 iser_conn_get(ib_conn);
343 352
344 conn->recv_lock = &iser_conn->lock; 353 conn->recv_lock = &iser_conn->lock;
345 354
346 return 0; 355 return 0;
347} 356}
348 357
358static void
359iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
360{
361 struct iscsi_conn *conn = cls_conn->dd_data;
362 struct iscsi_iser_conn *iser_conn = conn->dd_data;
363 struct iser_conn *ib_conn = iser_conn->ib_conn;
364
365 iscsi_conn_stop(cls_conn, flag);
366 /*
367 * There is no unbind event so the stop callback
368 * must release the ref from the bind.
369 */
370 iser_conn_put(ib_conn);
371 iser_conn->ib_conn = NULL;
372}
373
349static int 374static int
350iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) 375iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
351{ 376{
@@ -564,6 +589,17 @@ iscsi_iser_ep_disconnect(__u64 ep_handle)
564 if (!ib_conn) 589 if (!ib_conn)
565 return; 590 return;
566 591
592 if (ib_conn->iser_conn)
593 /*
594 * Must suspend xmit path if the ep is bound to the
595 * iscsi_conn, so we know we are not accessing the ib_conn
596 * when we free it.
597 *
598 * This may not be bound if the ep poll failed.
599 */
600 iscsi_suspend_tx(ib_conn->iser_conn->iscsi_conn);
601
602
567 iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state); 603 iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
568 iser_conn_terminate(ib_conn); 604 iser_conn_terminate(ib_conn);
569} 605}
@@ -622,7 +658,7 @@ static struct iscsi_transport iscsi_iser_transport = {
622 .get_conn_param = iscsi_conn_get_param, 658 .get_conn_param = iscsi_conn_get_param,
623 .get_session_param = iscsi_session_get_param, 659 .get_session_param = iscsi_session_get_param,
624 .start_conn = iscsi_iser_conn_start, 660 .start_conn = iscsi_iser_conn_start,
625 .stop_conn = iscsi_conn_stop, 661 .stop_conn = iscsi_iser_conn_stop,
626 /* iscsi host params */ 662 /* iscsi host params */
627 .get_host_param = iscsi_host_get_param, 663 .get_host_param = iscsi_host_get_param,
628 .set_host_param = iscsi_host_set_param, 664 .set_host_param = iscsi_host_set_param,
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 66a2f30ada01..bd5c1a554ea6 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -242,6 +242,7 @@ struct iser_device {
242struct iser_conn { 242struct iser_conn {
243 struct iscsi_iser_conn *iser_conn; /* iser conn for upcalls */ 243 struct iscsi_iser_conn *iser_conn; /* iser conn for upcalls */
244 enum iser_ib_conn_state state; /* rdma connection state */ 244 enum iser_ib_conn_state state; /* rdma connection state */
245 atomic_t refcount;
245 spinlock_t lock; /* used for state changes */ 246 spinlock_t lock; /* used for state changes */
246 struct iser_device *device; /* device context */ 247 struct iser_device *device; /* device context */
247 struct rdma_cm_id *cma_id; /* CMA ID */ 248 struct rdma_cm_id *cma_id; /* CMA ID */
@@ -314,6 +315,10 @@ void iscsi_iser_recv(struct iscsi_conn *conn,
314 315
315int iser_conn_init(struct iser_conn **ib_conn); 316int iser_conn_init(struct iser_conn **ib_conn);
316 317
318void iser_conn_get(struct iser_conn *ib_conn);
319
320void iser_conn_put(struct iser_conn *ib_conn);
321
317void iser_conn_terminate(struct iser_conn *ib_conn); 322void iser_conn_terminate(struct iser_conn *ib_conn);
318 323
319void iser_rcv_completion(struct iser_desc *desc, 324void iser_rcv_completion(struct iser_desc *desc,
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index d19cfe605ebb..5daed2bd710e 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -328,6 +328,17 @@ static void iser_conn_release(struct iser_conn *ib_conn)
328 kfree(ib_conn); 328 kfree(ib_conn);
329} 329}
330 330
331void iser_conn_get(struct iser_conn *ib_conn)
332{
333 atomic_inc(&ib_conn->refcount);
334}
335
336void iser_conn_put(struct iser_conn *ib_conn)
337{
338 if (atomic_dec_and_test(&ib_conn->refcount))
339 iser_conn_release(ib_conn);
340}
341
331/** 342/**
332 * triggers start of the disconnect procedures and wait for them to be done 343 * triggers start of the disconnect procedures and wait for them to be done
333 */ 344 */
@@ -349,7 +360,7 @@ void iser_conn_terminate(struct iser_conn *ib_conn)
349 wait_event_interruptible(ib_conn->wait, 360 wait_event_interruptible(ib_conn->wait,
350 ib_conn->state == ISER_CONN_DOWN); 361 ib_conn->state == ISER_CONN_DOWN);
351 362
352 iser_conn_release(ib_conn); 363 iser_conn_put(ib_conn);
353} 364}
354 365
355static void iser_connect_error(struct rdma_cm_id *cma_id) 366static void iser_connect_error(struct rdma_cm_id *cma_id)
@@ -496,6 +507,7 @@ int iser_conn_init(struct iser_conn **ibconn)
496 init_waitqueue_head(&ib_conn->wait); 507 init_waitqueue_head(&ib_conn->wait);
497 atomic_set(&ib_conn->post_recv_buf_count, 0); 508 atomic_set(&ib_conn->post_recv_buf_count, 0);
498 atomic_set(&ib_conn->post_send_buf_count, 0); 509 atomic_set(&ib_conn->post_send_buf_count, 0);
510 atomic_set(&ib_conn->refcount, 1);
499 INIT_LIST_HEAD(&ib_conn->conn_list); 511 INIT_LIST_HEAD(&ib_conn->conn_list);
500 spin_lock_init(&ib_conn->lock); 512 spin_lock_init(&ib_conn->lock);
501 513
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 784a935fad4a..79bc49fd7f12 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1383,11 +1383,12 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
1383 } 1383 }
1384} 1384}
1385 1385
1386static void iscsi_suspend_tx(struct iscsi_conn *conn) 1386void iscsi_suspend_tx(struct iscsi_conn *conn)
1387{ 1387{
1388 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 1388 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1389 scsi_flush_work(conn->session->host); 1389 scsi_flush_work(conn->session->host);
1390} 1390}
1391EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
1391 1392
1392static void iscsi_start_tx(struct iscsi_conn *conn) 1393static void iscsi_start_tx(struct iscsi_conn *conn)
1393{ 1394{