From: Shlomo Pongratz <[email protected]>

libiscsi_tcp uses two kernel fifos the r2t pool and the r2t queue.

The insertion and deletion from these queues doesn't corespond to the
new forward/backwards session locking paradigm.

That is, in iscsi_tcp_clenup_task which belongs to the RX (backwards)
path, r2t is taken out from r2t queue and inserted to the r2t pool.
In iscsi_tcp_get_curr_r2t which belong to the TX (forward) path, r2t
is also inserted to the r2t pool and another r2t is pulled from r2t queue.

Only in iscsi_tcp_r2t_rsp which is called in the RX path but can requeue
to the TX path, r2t is taken from the r2t pool and inserted to the r2t queue.

In order to cope with this situation, two spin locks were added,
pool2queue and queue2pool. The former protects extracting from the
r2t pool and inserting to the r2t queue, and the later protects the
extracing from the r2t queue and inserting to the r2t pool.

Signed-off-by: Shlomo Pongratz <[email protected]>
---
 drivers/scsi/libiscsi_tcp.c |   18 ++++++++++++------
 include/scsi/libiscsi_tcp.h |    2 ++
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index bf7ead6..91106a7 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -457,6 +457,7 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
        if (!task->sc)
                return;
 
+       spin_lock_bh(&tcp_task->queue2pool);
        /* flush task's r2t queues */
        while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
                kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
@@ -470,6 +471,7 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
                            sizeof(void*));
                tcp_task->r2t = NULL;
        }
+       spin_unlock_bh(&tcp_task->queue2pool);
 }
 EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task);
 
@@ -577,11 +579,13 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, 
struct iscsi_task *task)
                return ISCSI_ERR_DATALEN;
        }
 
+       spin_lock(&tcp_task->pool2queue);
        rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
        if (!rc) {
                iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
                                  "Target has sent more R2Ts than it "
                                  "negotiated for or driver has leaked.\n");
+               spin_unlock(&tcp_task->pool2queue);
                return ISCSI_ERR_PROTO;
        }
 
@@ -596,6 +600,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, 
struct iscsi_task *task)
        tcp_task->exp_datasn = r2tsn + 1;
        kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
        conn->r2t_pdus_cnt++;
+       spin_unlock(&tcp_task->pool2queue);
 
        iscsi_requeue_task(task);
        return 0;
@@ -724,16 +729,18 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct 
iscsi_hdr *hdr)
        case ISCSI_OP_R2T:
                spin_lock(&conn->session->back_lock);
                task = iscsi_itt_to_ctask(conn, hdr->itt);
+               spin_unlock(&conn->session->back_lock);
                if (!task)
                        rc = ISCSI_ERR_BAD_ITT;
                else if (ahslen)
                        rc = ISCSI_ERR_AHSLEN;
                else if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
                        task->last_xfer = jiffies;
+                       spin_lock(&conn->session->frwd_lock);
                        rc = iscsi_tcp_r2t_rsp(conn, task);
+                       spin_unlock(&conn->session->frwd_lock);
                } else
                        rc = ISCSI_ERR_PROTO;
-               spin_unlock(&conn->session->back_lock);
                break;
        case ISCSI_OP_LOGIN_RSP:
        case ISCSI_OP_TEXT_RSP:
@@ -981,38 +988,35 @@ EXPORT_SYMBOL_GPL(iscsi_tcp_task_init);
 
 static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
 {
-       struct iscsi_session *session = task->conn->session;
        struct iscsi_tcp_task *tcp_task = task->dd_data;
        struct iscsi_r2t_info *r2t = NULL;
 
        if (iscsi_task_has_unsol_data(task))
                r2t = &task->unsol_r2t;
        else {
+               spin_lock_bh(&tcp_task->queue2pool);
                if (tcp_task->r2t) {
                        r2t = tcp_task->r2t;
                        /* Continue with this R2T? */
                        if (r2t->data_length <= r2t->sent) {
                                ISCSI_DBG_TCP(task->conn,
                                              "  done with r2t %p\n", r2t);
-                               spin_lock_bh(&session->back_lock);
                                kfifo_in(&tcp_task->r2tpool.queue,
                                            (void *)&tcp_task->r2t,
                                            sizeof(void *));
-                               spin_unlock_bh(&session->back_lock);
                                tcp_task->r2t = r2t = NULL;
                        }
                }
 
                if (r2t == NULL) {
-                       spin_lock_bh(&session->frwd_lock);
                        if (kfifo_out(&tcp_task->r2tqueue,
                            (void *)&tcp_task->r2t, sizeof(void *)) !=
                            sizeof(void *))
                                r2t = NULL;
                        else
                                r2t = tcp_task->r2t;
-                       spin_unlock_bh(&session->frwd_lock);
                }
+               spin_unlock_bh(&tcp_task->queue2pool);
        }
 
        return r2t;
@@ -1142,6 +1146,8 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
                        iscsi_pool_free(&tcp_task->r2tpool);
                        goto r2t_alloc_fail;
                }
+               spin_lock_init(&tcp_task->pool2queue);
+               spin_lock_init(&tcp_task->queue2pool);
        }
 
        return 0;
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h
index 215469a..2a7aa75 100644
--- a/include/scsi/libiscsi_tcp.h
+++ b/include/scsi/libiscsi_tcp.h
@@ -83,6 +83,8 @@ struct iscsi_tcp_task {
        struct iscsi_pool       r2tpool;
        struct kfifo            r2tqueue;
        void                    *dd_data;
+       spinlock_t              pool2queue;
+       spinlock_t              queue2pool;
 };
 
 enum {
-- 
1.7.1

-- 
You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/open-iscsi.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to