aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2006-08-31 18:09:25 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-09-02 14:37:07 -0400
commit60ecebf5a10e42f5e2d6e07eb9e24bdee8500b81 (patch)
tree79b27fd89fe175daa4e4cd6feda8a6548c6d9bf1 /drivers
parentffd0436ed2e5a741c8d30062b489b989acf0a526 (diff)
[SCSI] add refcouting around ctask usage in main IO patch
It is possible that a ctask could be completing and getting cleaned up at the same time, we are finishing up the last data transfer. This could then result in the data transfer code using stale or invalid values. This patch adds a refcount to the ctask. When the count goes to zero then we know the transmit thread and recv thread or softirq are not touching it and we can safely release it. The eh should not need to grab a reference because it only cleans up a task if it has both the xmit mutex and recv lock (or recv side suspended). Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/libiscsi.c59
1 files changed, 50 insertions, 9 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index a7c6e70f4ef8..9584cbc082fe 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -179,16 +179,15 @@ EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu);
179 179
180/** 180/**
181 * iscsi_complete_command - return command back to scsi-ml 181 * iscsi_complete_command - return command back to scsi-ml
182 * @session: iscsi session
183 * @ctask: iscsi cmd task 182 * @ctask: iscsi cmd task
184 * 183 *
185 * Must be called with session lock. 184 * Must be called with session lock.
186 * This function returns the scsi command to scsi-ml and returns 185 * This function returns the scsi command to scsi-ml and returns
187 * the cmd task to the pool of available cmd tasks. 186 * the cmd task to the pool of available cmd tasks.
188 */ 187 */
189static void iscsi_complete_command(struct iscsi_session *session, 188static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
190 struct iscsi_cmd_task *ctask)
191{ 189{
190 struct iscsi_session *session = ctask->conn->session;
192 struct scsi_cmnd *sc = ctask->sc; 191 struct scsi_cmnd *sc = ctask->sc;
193 192
194 ctask->state = ISCSI_TASK_COMPLETED; 193 ctask->state = ISCSI_TASK_COMPLETED;
@@ -198,6 +197,35 @@ static void iscsi_complete_command(struct iscsi_session *session,
198 sc->scsi_done(sc); 197 sc->scsi_done(sc);
199} 198}
200 199
200static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask)
201{
202 atomic_inc(&ctask->refcount);
203}
204
205static void iscsi_get_ctask(struct iscsi_cmd_task *ctask)
206{
207 spin_lock_bh(&ctask->conn->session->lock);
208 __iscsi_get_ctask(ctask);
209 spin_unlock_bh(&ctask->conn->session->lock);
210}
211
212static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
213{
214 struct iscsi_conn *conn = ctask->conn;
215
216 if (atomic_dec_and_test(&ctask->refcount)) {
217 conn->session->tt->cleanup_cmd_task(conn, ctask);
218 iscsi_complete_command(ctask);
219 }
220}
221
222static void iscsi_put_ctask(struct iscsi_cmd_task *ctask)
223{
224 spin_lock_bh(&ctask->conn->session->lock);
225 __iscsi_put_ctask(ctask);
226 spin_unlock_bh(&ctask->conn->session->lock);
227}
228
201/** 229/**
202 * iscsi_cmd_rsp - SCSI Command Response processing 230 * iscsi_cmd_rsp - SCSI Command Response processing
203 * @conn: iscsi connection 231 * @conn: iscsi connection
@@ -274,7 +302,7 @@ out:
274 (long)sc, sc->result, ctask->itt); 302 (long)sc, sc->result, ctask->itt);
275 conn->scsirsp_pdus_cnt++; 303 conn->scsirsp_pdus_cnt++;
276 304
277 iscsi_complete_command(conn->session, ctask); 305 __iscsi_put_ctask(ctask);
278 return rc; 306 return rc;
279} 307}
280 308
@@ -338,7 +366,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
338 BUG_ON((void*)ctask != ctask->sc->SCp.ptr); 366 BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
339 if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { 367 if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
340 conn->scsirsp_pdus_cnt++; 368 conn->scsirsp_pdus_cnt++;
341 iscsi_complete_command(session, ctask); 369 __iscsi_put_ctask(ctask);
342 } 370 }
343 break; 371 break;
344 case ISCSI_OP_R2T: 372 case ISCSI_OP_R2T:
@@ -563,7 +591,9 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
563 BUG_ON(conn->ctask && conn->mtask); 591 BUG_ON(conn->ctask && conn->mtask);
564 592
565 if (conn->ctask) { 593 if (conn->ctask) {
594 iscsi_get_ctask(conn->ctask);
566 rc = tt->xmit_cmd_task(conn, conn->ctask); 595 rc = tt->xmit_cmd_task(conn, conn->ctask);
596 iscsi_put_ctask(conn->ctask);
567 if (rc) 597 if (rc)
568 goto again; 598 goto again;
569 /* done with this in-progress ctask */ 599 /* done with this in-progress ctask */
@@ -604,12 +634,19 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
604 struct iscsi_cmd_task, running); 634 struct iscsi_cmd_task, running);
605 conn->ctask->state = ISCSI_TASK_RUNNING; 635 conn->ctask->state = ISCSI_TASK_RUNNING;
606 list_move_tail(conn->xmitqueue.next, &conn->run_list); 636 list_move_tail(conn->xmitqueue.next, &conn->run_list);
637 __iscsi_get_ctask(conn->ctask);
607 spin_unlock_bh(&conn->session->lock); 638 spin_unlock_bh(&conn->session->lock);
608 639
609 rc = tt->xmit_cmd_task(conn, conn->ctask); 640 rc = tt->xmit_cmd_task(conn, conn->ctask);
610 if (rc) 641 if (rc)
611 goto again; 642 goto again;
643
612 spin_lock_bh(&conn->session->lock); 644 spin_lock_bh(&conn->session->lock);
645 __iscsi_put_ctask(conn->ctask);
646 if (rc) {
647 spin_unlock_bh(&conn->session->lock);
648 goto again;
649 }
613 } 650 }
614 spin_unlock_bh(&conn->session->lock); 651 spin_unlock_bh(&conn->session->lock);
615 /* done with this ctask */ 652 /* done with this ctask */
@@ -659,6 +696,7 @@ enum {
659 FAILURE_SESSION_FAILED, 696 FAILURE_SESSION_FAILED,
660 FAILURE_SESSION_FREED, 697 FAILURE_SESSION_FREED,
661 FAILURE_WINDOW_CLOSED, 698 FAILURE_WINDOW_CLOSED,
699 FAILURE_OOM,
662 FAILURE_SESSION_TERMINATE, 700 FAILURE_SESSION_TERMINATE,
663 FAILURE_SESSION_IN_RECOVERY, 701 FAILURE_SESSION_IN_RECOVERY,
664 FAILURE_SESSION_RECOVERY_TIMEOUT, 702 FAILURE_SESSION_RECOVERY_TIMEOUT,
@@ -717,10 +755,15 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
717 755
718 conn = session->leadconn; 756 conn = session->leadconn;
719 757
720 __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); 758 if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
759 sizeof(void*))) {
760 reason = FAILURE_OOM;
761 goto reject;
762 }
721 sc->SCp.phase = session->age; 763 sc->SCp.phase = session->age;
722 sc->SCp.ptr = (char *)ctask; 764 sc->SCp.ptr = (char *)ctask;
723 765
766 atomic_set(&ctask->refcount, 1);
724 ctask->state = ISCSI_TASK_PENDING; 767 ctask->state = ISCSI_TASK_PENDING;
725 ctask->mtask = NULL; 768 ctask->mtask = NULL;
726 ctask->conn = conn; 769 ctask->conn = conn;
@@ -1057,13 +1100,11 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
1057 sc = ctask->sc; 1100 sc = ctask->sc;
1058 if (!sc) 1101 if (!sc)
1059 return; 1102 return;
1060
1061 conn->session->tt->cleanup_cmd_task(conn, ctask);
1062 iscsi_ctask_mtask_cleanup(ctask); 1103 iscsi_ctask_mtask_cleanup(ctask);
1063 1104
1064 sc->result = err; 1105 sc->result = err;
1065 sc->resid = sc->request_bufflen; 1106 sc->resid = sc->request_bufflen;
1066 iscsi_complete_command(conn->session, ctask); 1107 __iscsi_put_ctask(ctask);
1067} 1108}
1068 1109
1069int iscsi_eh_abort(struct scsi_cmnd *sc) 1110int iscsi_eh_abort(struct scsi_cmnd *sc)