[stgt] [PATCH 2/2] Changes to support thread per connection
Chandra Seetharaman
sekharan at us.ibm.com
Fri Oct 15 07:01:50 CEST 2010
Add thread per connection support. A new thread is created for
each connection to handle the tcp portion. cmd_done is handled
at the thread level.
Signed-off-by: Chandra Seetharaman <sekharan at us.ibm.com>
---
usr/iscsi/conn.c | 4 +++
usr/iscsi/iscsi_tcp.c | 78 +++++++++++++++++++++++++++++++++++++++++---------
usr/iscsi/iscsid.c | 27 +++++++++++++++--
usr/iscsi/iscsid.h | 4 +++
usr/target.c | 4 +-
5 files changed, 98 insertions(+), 19 deletions(-)
Index: tgt-thread/usr/iscsi/iscsid.h
===================================================================
--- tgt-thread.orig/usr/iscsi/iscsid.h
+++ tgt-thread/usr/iscsi/iscsid.h
@@ -181,6 +181,7 @@ struct iscsi_connection {
struct iscsi_task *rx_task;
struct iscsi_task *tx_task;
+ pthread_mutex_t tx_lock;
struct list_head tx_clist;
struct list_head task_list;
@@ -199,6 +200,9 @@ struct iscsi_connection {
} auth;
struct iscsi_transport *tp;
+
+ struct thread_info conn_ti;
+ pthread_t thread;
};
#define STATE_FREE 0
Index: tgt-thread/usr/iscsi/iscsi_tcp.c
===================================================================
--- tgt-thread.orig/usr/iscsi/iscsi_tcp.c
+++ tgt-thread/usr/iscsi/iscsi_tcp.c
@@ -42,6 +42,10 @@ static void iscsi_tcp_event_handler(int
static int listen_fds[8];
static struct iscsi_transport iscsi_tcp;
+#define NO_PTHREAD 0
+#define PTHREAD_PER_TARGET 1
+#define PTHREAD_PER_CONN 2
+
struct iscsi_tcp_connection {
int fd;
int pthread;
@@ -168,15 +172,24 @@ static void iscsi_tcp_event_handler(int
if (conn->state == STATE_CLOSE) {
dprintf("connection closed %p\n", conn);
- if (tcp_conn->pthread) {
- struct iscsi_target *target = conn->session->target;
+ if (tcp_conn->pthread != NO_PTHREAD) {
+ struct thread_info *ti;
- do_tgt_event_del(&target->ti, tcp_conn->fd);
+ if (tcp_conn->pthread == PTHREAD_PER_TARGET) {
+ ti = &conn->session->target->ti;
+ do_tgt_event_del(ti, tcp_conn->fd);
+ } else {
+ ti = &conn->conn_ti;
+ do_tgt_event_del(ti, tcp_conn->fd);
+ conn->conn_ti.stop_pthread = 1;
+ }
/* let the main thread handle this */
- tcp_conn->pthread = 0;
+ tcp_conn->pthread = NO_PTHREAD;
tgt_event_add(tcp_conn->fd, EPOLLIN,
iscsi_tcp_event_handler, conn);
} else {
+ if (conn->thread)
+ pthread_join(conn->thread, NULL);
conn_close(conn);
}
}
@@ -279,16 +292,39 @@ static int iscsi_tcp_conn_login_complete
static void iscsi_tcp_conn_nexus_init(struct iscsi_connection *conn)
{
struct iscsi_tcp_connection *tcp_conn = TCP_CONN(conn);
- struct iscsi_target *target = conn->session->target;
+ struct thread_info *ti;
+ int ret;
if (iscsi_pthread_per_target()) {
/* remove the conn from the main thread. */
tgt_event_del(tcp_conn->fd);
- tcp_conn->pthread = 1;
+ ti = &conn->session->target->ti;
- do_tgt_event_add(&target->ti, tcp_conn->fd, EPOLLIN,
- iscsi_tcp_event_handler, conn);
+ tcp_conn->pthread = PTHREAD_PER_TARGET;
+
+ conn->conn_ti.bsf = NULL;
+ conn->conn_ti.stop_pthread = 0;
+ conn->conn_ti.start_pthread = 0;
+ INIT_LIST_HEAD(&conn->conn_ti.t_list);
+ pthread_rwlock_init(&conn->conn_ti.rwlock, NULL);
+
+ conn->conn_ti.efd = epoll_create(128);
+ if (conn->conn_ti.efd < 0)
+ goto thread_per_target;
+
+ ret = pthread_create(&conn->thread, NULL, thread_fn, &conn->conn_ti);
+ if (!ret) {
+ eprintf("created thread %u for connection %p\n",
+ (unsigned) conn->thread, conn);
+ ti = &conn->conn_ti;
+ tcp_conn->pthread = PTHREAD_PER_CONN;
+ }
+thread_per_target:
+ do_tgt_event_add(ti, tcp_conn->fd, EPOLLIN,
+ iscsi_tcp_event_handler, conn);
+ if (tcp_conn->pthread == PTHREAD_PER_CONN)
+ conn->conn_ti.start_pthread = 1;
} else
conn->tp->ep_event_modify(conn, EPOLLIN);
}
@@ -364,16 +400,30 @@ static int iscsi_tcp_show(struct iscsi_c
static void iscsi_event_modify(struct iscsi_connection *conn, int events)
{
struct iscsi_tcp_connection *tcp_conn = TCP_CONN(conn);
+ struct thread_info *ti;
int ret;
- if (tcp_conn->pthread) {
- do_tgt_event_modify(&conn->session->target->ti,
- tcp_conn->fd, events);
- } else {
+ switch (tcp_conn->pthread) {
+ default:
+ eprintf(" Unknown connection pthread state %d\n",
+ tcp_conn->pthread);
+ return;
+ case NO_PTHREAD:
ret = tgt_event_modify(tcp_conn->fd, events);
- if (ret)
- eprintf("tgt_event_modify failed\n");
+ goto done;
+ break;
+ case PTHREAD_PER_TARGET:
+ ti = &conn->session->target->ti;
+ break;
+ case PTHREAD_PER_CONN:
+ ti = &conn->conn_ti;
+ break;
}
+
+ ret = do_tgt_event_modify(ti, tcp_conn->fd, events);
+done:
+ if (ret)
+ eprintf("event_modify failed\n");
}
static struct iscsi_task *iscsi_tcp_alloc_task(struct iscsi_connection *conn,
Index: tgt-thread/usr/target.c
===================================================================
--- tgt-thread.orig/usr/target.c
+++ tgt-thread/usr/target.c
@@ -856,7 +856,7 @@ static int cmd_enabled(struct tgt_cmd_qu
static void cmd_post_perform(struct tgt_cmd_queue *q, struct scsi_cmd *cmd)
{
- q->active_cmd++;
+ __sync_fetch_and_add(&q->active_cmd, 1);
switch (cmd->attribute) {
case MSG_ORDERED_TAG:
case MSG_HEAD_TAG:
@@ -1029,7 +1029,7 @@ static void __cmd_done(struct target *ta
scsi_get_in_length(cmd), err);
q = &cmd->dev->cmd_queue;
- q->active_cmd--;
+ __sync_fetch_and_sub(&q->active_cmd, 1);
switch (cmd->attribute) {
case MSG_ORDERED_TAG:
case MSG_HEAD_TAG:
Index: tgt-thread/usr/iscsi/conn.c
===================================================================
--- tgt-thread.orig/usr/iscsi/conn.c
+++ tgt-thread/usr/iscsi/conn.c
@@ -63,6 +63,7 @@ int conn_init(struct iscsi_connection *c
INIT_LIST_HEAD(&conn->clist);
INIT_LIST_HEAD(&conn->tx_clist);
+ pthread_mutex_init(&conn->tx_lock, NULL);
INIT_LIST_HEAD(&conn->task_list);
return 0;
@@ -121,6 +122,7 @@ void conn_close(struct iscsi_connection
iscsi_free_task(task);
}
+ pthread_mutex_lock(&conn->tx_lock);
list_for_each_entry_safe(task, tmp, &conn->tx_clist, c_list) {
uint8_t op;
@@ -151,6 +153,8 @@ void conn_close(struct iscsi_connection
break;
}
}
+ pthread_mutex_unlock(&conn->tx_lock);
+ pthread_mutex_destroy(&conn->tx_lock);
if (conn->rx_task) {
eprintf("Forcing release of rx task %p %" PRIx64 "\n",
Index: tgt-thread/usr/iscsi/iscsid.c
===================================================================
--- tgt-thread.orig/usr/iscsi/iscsid.c
+++ tgt-thread/usr/iscsi/iscsid.c
@@ -1210,7 +1210,9 @@ static int iscsi_scsi_cmd_done(uint64_t
task->len = read_len;
}
+ pthread_mutex_lock(&task->conn->tx_lock);
list_add_tail(&task->c_list, &task->conn->tx_clist);
+ pthread_mutex_unlock(&task->conn->tx_lock);
task->conn->tp->ep_event_modify(task->conn, EPOLLIN | EPOLLOUT);
return 0;
@@ -1335,8 +1337,11 @@ int iscsi_scsi_cmd_execute(struct iscsi_
int ret = 0;
if ((req->flags & ISCSI_FLAG_CMD_WRITE) && task->r2t_count) {
- if (!task->unsol_count)
+ if (!task->unsol_count) {
+ pthread_mutex_lock(&task->conn->tx_lock);
list_add_tail(&task->c_list, &task->conn->tx_clist);
+ pthread_mutex_unlock(&task->conn->tx_lock);
+ }
goto no_queuing;
}
@@ -1371,7 +1376,9 @@ static int iscsi_tm_done(struct mgmt_req
task->result = ISCSI_TMF_RSP_REJECTED;
break;
}
+ pthread_mutex_lock(&task->conn->tx_lock);
list_add_tail(&task->c_list, &task->conn->tx_clist);
+ pthread_mutex_unlock(&task->conn->tx_lock);
task->conn->tp->ep_event_modify(task->conn, EPOLLIN | EPOLLOUT);
return 0;
}
@@ -1441,7 +1448,9 @@ static int iscsi_task_execute(struct isc
switch (op) {
case ISCSI_OP_NOOP_OUT:
case ISCSI_OP_LOGOUT:
+ pthread_mutex_lock(&task->conn->tx_lock);
list_add_tail(&task->c_list, &task->conn->tx_clist);
+ pthread_mutex_unlock(&task->conn->tx_lock);
task->conn->tp->ep_event_modify(task->conn, EPOLLIN | EPOLLOUT);
break;
case ISCSI_OP_SCSI_CMD:
@@ -1461,7 +1470,9 @@ static int iscsi_task_execute(struct isc
case ISCSI_OP_SCSI_TMFUNC:
err = iscsi_tm_execute(task);
if (err) {
+ pthread_mutex_lock(&task->conn->tx_lock);
list_add_tail(&task->c_list, &task->conn->tx_clist);
+ pthread_mutex_unlock(&task->conn->tx_lock);
task->conn->tp->ep_event_modify(task->conn,
EPOLLIN | EPOLLOUT);
}
@@ -1548,12 +1559,16 @@ static int iscsi_task_queue(struct iscsi
if (list_empty(&session->pending_cmd_list))
return 0;
+ pthread_mutex_lock(&task->conn->tx_lock);
task = list_first_entry(&session->pending_cmd_list,
struct iscsi_task, c_list);
- if (be32_to_cpu(task->req.statsn) != cmd_sn)
+ if (be32_to_cpu(task->req.statsn) != cmd_sn) {
+ pthread_mutex_unlock(&task->conn->tx_lock);
return 0;
+ }
list_del(&task->c_list);
+ pthread_mutex_unlock(&task->conn->tx_lock);
clear_task_pending(task);
goto retry;
} else {
@@ -1828,7 +1843,9 @@ static int iscsi_scsi_cmd_tx_done(struct
scsi_get_data_dir(&task->scmd) == DATA_BIDIRECTIONAL ||
conn->tp->rdma) {
dprintf("more data or sense or bidir %x\n", hdr->itt);
+ pthread_mutex_lock(&task->conn->tx_lock);
list_add(&task->c_list, &task->conn->tx_clist);
+ pthread_mutex_unlock(&task->conn->tx_lock);
return 0;
}
case ISCSI_OP_SCSI_CMD_RSP:
@@ -1870,8 +1887,11 @@ static int iscsi_task_tx_start(struct is
struct iscsi_task *task;
int is_rsp, err = 0;
- if (list_empty(&conn->tx_clist))
+ pthread_mutex_lock(&conn->tx_lock);
+ if (list_empty(&conn->tx_clist)) {
+ pthread_mutex_unlock(&conn->tx_lock);
goto nodata;
+ }
conn_write_pdu(conn);
@@ -1882,6 +1902,7 @@ static int iscsi_task_tx_start(struct is
task->r2t_count);
list_del(&task->c_list);
+ pthread_mutex_unlock(&conn->tx_lock);
switch (task->req.opcode & ISCSI_OPCODE_MASK) {
case ISCSI_OP_SCSI_CMD:
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the stgt
mailing list