Hi All, -- Note: This applies cleanly on the thread branch on top of the patches I sent yesterday. -- With the thread-per-connection patches that I sent yesterday, there are three levels of threading that can be achieved 1. No threads at all 2. One thread per target 3. One thread per connection to a target. These are stacked up, i.e when 3 is set 2 is assumed. This patch allows user to select one of the thread type from above. Thread type can be specified at the time of creation of a target. Ex: # Do not use threads at all # tgtadm --lld iscsi --op new --mode target --tid 1 -T mytarget.1:01 -x none # Use Thread per target. This is default too. IOW, both the commands below # achieve the same result. # tgtadm --lld iscsi --op new --mode target --tid 1 -T mytarget.1:01 -x thread # tgtadm --lld iscsi --op new --mode target --tid 1 -T mytarget.1:01 # Use one thread per connection (on top of one thread per target) # tgtadm --lld iscsi --op new --mode target --tid 1 -T mytarget.1:01 -x conn Signed-off-by: Chandra Seetharaman <sekharan@xxxxxxxxxx> --- doc/tgtadm.8.xml | 6 +++++- usr/iscsi/iscsi_tcp.c | 48 ++++++++++++++++++++++++------------------------ usr/iscsi/iscsid.c | 8 ++++++-- usr/iscsi/iscsid.h | 2 +- usr/iscsi/target.c | 2 +- usr/target.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++-- usr/target.h | 2 ++ usr/tgtadm.c | 17 ++++++++++++----- usr/tgtd.h | 6 ++++++ 9 files changed, 106 insertions(+), 36 deletions(-) Index: tgt-thread/usr/tgtd.h =================================================================== --- tgt-thread.orig/usr/tgtd.h +++ tgt-thread/usr/tgtd.h @@ -32,6 +32,12 @@ enum tgt_system_state { TGT_SYSTEM_READY, }; +enum tgt_thread_type { + NO_PTHREAD = 0, + PTHREAD_PER_TARGET, + PTHREAD_PER_CONN, +}; + enum scsi_target_state { SCSI_TARGET_OFFLINE = 1, SCSI_TARGET_READY, Index: tgt-thread/usr/target.h =================================================================== --- tgt-thread.orig/usr/target.h +++ tgt-thread/usr/target.h @@ -43,6 +43,8 @@ struct target { struct tgt_account account; struct bs_finish *bsf; + + enum tgt_thread_type thr_type; }; struct it_nexus { Index: tgt-thread/usr/iscsi/iscsid.h =================================================================== --- tgt-thread.orig/usr/iscsi/iscsid.h +++ tgt-thread/usr/iscsi/iscsid.h @@ -331,7 +331,7 @@ int iscsi_target_update(int mode, int op int target_redirected(struct iscsi_target *target, struct iscsi_connection *conn, char *buf, int *reason); -int iscsi_pthread_per_target(void); +enum tgt_thread_type iscsi_pthread_per_target(struct target *target); /* param.c */ int param_index_by_name(char *name, struct iscsi_key *keys); Index: tgt-thread/usr/target.c =================================================================== --- tgt-thread.orig/usr/target.c +++ tgt-thread/usr/target.c @@ -1639,6 +1639,47 @@ static char *target_state_name(enum scsi return name; } +static struct { + enum tgt_thread_type value; + char *name; +} thread_type[] = { + {NO_PTHREAD, "none"}, + {PTHREAD_PER_TARGET, "target"}, + {PTHREAD_PER_CONN, "conn"}, +}; + +static enum tgt_thread_type target_thread_type(char *name) +{ + int i; + enum tgt_thread_type type = -1; + + for (i = 0; i < ARRAY_SIZE(thread_type); i++) { + if (!strcmp(thread_type[i].name, name)) { + type = thread_type[i].value; + break; + } + } + if (type == -1) { + eprintf("Unknown thread type <%s>, setting to default\n", name); + type = PTHREAD_PER_TARGET; + } + return type; +} + +static char *target_thr_type_name(enum tgt_thread_type type) +{ + int i; + char *name = NULL; + + for (i = 0; i < ARRAY_SIZE(thread_type); i++) { + if (thread_type[i].value == type) { + name = thread_type[i].name; + break; + } + } + return name; +} + int tgt_set_target_state(int tid, char *str) { int i, err = TGTADM_INVALID_REQUEST; @@ -1720,11 +1761,13 @@ int tgt_target_show_all(char *buf, int r "Target %d: %s\n" _TAB1 "System information:\n" _TAB2 "Driver: %s\n" - _TAB2 "State: %s\n", + _TAB2 "State: %s\n" + _TAB2 "Thread type: %s\n", target->tid, target->name, tgt_drivers[target->lid]->name, - target_state_name(target->target_state)); + target_state_name(target->target_state), + target_thr_type_name(target->thr_type)); shprintf(total, buf, rest, _TAB1 "I_T nexus information:\n"); @@ -1816,6 +1859,7 @@ int tgt_target_create(int lld, int tid, struct target *target, *pos; char *p, *q, *targetname = NULL; struct backingstore_template *bst; + int type = PTHREAD_PER_TARGET; p = args; while ((q = strsep(&p, ","))) { @@ -1827,6 +1871,8 @@ int tgt_target_create(int lld, int tid, if (!strcmp("targetname", q)) targetname = str; + else if (!strcmp("thread", q)) + type = target_thread_type(str); else eprintf("Unknow option %s\n", q); } @@ -1869,6 +1915,7 @@ int tgt_target_create(int lld, int tid, target->account.max_inaccount = DEFAULT_NR_ACCOUNT; target->tid = tid; + target->thr_type = type; INIT_LIST_HEAD(&target->device_list); Index: tgt-thread/usr/tgtadm.c =================================================================== --- tgt-thread.orig/usr/tgtadm.c +++ tgt-thread/usr/tgtadm.c @@ -103,6 +103,7 @@ struct option const long_options[] = { {"bstype", required_argument, NULL, 'E'}, {"bsoflags", required_argument, NULL, 'f'}, {"targetname", required_argument, NULL, 'T'}, + {"thread", required_argument, NULL, 'x'}, {"initiator-address", required_argument, NULL, 'I'}, {"user", required_argument, NULL, 'u'}, {"password", required_argument, NULL, 'p'}, @@ -116,7 +117,7 @@ struct option const long_options[] = { {NULL, 0, NULL, 0}, }; -static char *short_options = "dhL:o:m:t:s:c:l:n:v:b:E:f:T:I:u:p:H:P:B:Y:O:C:"; +static char *short_options = "dhL:o:m:t:s:c:l:n:v:b:x:E:f:T:I:u:p:H:P:B:Y:O:C:"; static void usage(int status) { @@ -127,7 +128,7 @@ static void usage(int status) printf("\ Linux SCSI Target Framework Administration Utility, version %s\n\ \n\ - --lld <driver> --mode target --op new --tid <id> --targetname <name>\n\ + --lld <driver> --mode target --op new --tid <id> --targetname <name> [ --thread <type> ]\n\ add a new target with <id> and <name>. <id> must not be zero.\n\ --lld <driver> --mode target --op delete --tid <id>\n\ delete the specific target with <id>. The target must\n\ @@ -423,7 +424,7 @@ int main(int argc, char **argv) uint32_t cid, hostno; uint64_t sid, lun; char *name, *value, *path, *targetname, *params, *address, *targetOps; - char *bstype; + char *bstype, *thread_type; char *bsoflags; char *user, *password; char *buf; @@ -439,7 +440,7 @@ int main(int argc, char **argv) ac_dir = ACCOUNT_TYPE_INCOMING; rest = BUFSIZE; name = value = path = targetname = address = targetOps = bstype = NULL; - bsoflags = user = password = NULL; + bsoflags = user = password = thread_type = NULL; buf = valloc(bufsz); if (!buf) { @@ -531,6 +532,9 @@ int main(int argc, char **argv) case 'h': usage(0); break; + case 'x': + thread_type = optarg; + break; default: usage(1); } @@ -583,7 +587,7 @@ int main(int argc, char **argv) } switch (op) { case OP_NEW: - rc = verify_mode_params(argc, argv, "LmotTC"); + rc = verify_mode_params(argc, argv, "LmotTCx"); if (rc) { eprintf("target mode: option '-%c' is not " "allowed/supported\n", rc); @@ -780,6 +784,9 @@ int main(int argc, char **argv) if (targetname) shprintf(total, params, rest, "%stargetname=%s", rest == BUFSIZE ? "" : ",", targetname); + if (thread_type) + shprintf(total, params, rest, "%sthread=%s", + rest == BUFSIZE ? "" : ",", thread_type); if (address) shprintf(total, params, rest, "%sinitiator-address=%s", rest == BUFSIZE ? "" : ",", address); Index: tgt-thread/usr/iscsi/iscsi_tcp.c =================================================================== --- tgt-thread.orig/usr/iscsi/iscsi_tcp.c +++ tgt-thread/usr/iscsi/iscsi_tcp.c @@ -35,6 +35,7 @@ #include "iscsid.h" #include "tgtd.h" +#include "target.h" #include "util.h" static void iscsi_tcp_event_handler(int fd, int events, void *data); @@ -42,10 +43,6 @@ 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; @@ -293,32 +290,35 @@ static void iscsi_tcp_conn_nexus_init(st { struct iscsi_tcp_connection *tcp_conn = TCP_CONN(conn); struct thread_info *ti; - int ret; + struct target *t = target_lookup(conn->tid); + int ret, type; - if (iscsi_pthread_per_target()) { + if ((type = iscsi_pthread_per_target(t)) != NO_PTHREAD) { /* remove the conn from the main thread. */ tgt_event_del(tcp_conn->fd); - ti = &conn->session->target->ti; - tcp_conn->pthread = PTHREAD_PER_TARGET; + ti = &conn->session->target->ti; - 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; + if (type == PTHREAD_PER_CONN) { + 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, Index: tgt-thread/usr/iscsi/iscsid.c =================================================================== --- tgt-thread.orig/usr/iscsi/iscsid.c +++ tgt-thread/usr/iscsi/iscsid.c @@ -39,6 +39,7 @@ #include "driver.h" #include "scsi.h" #include "tgtadm.h" +#include "target.h" #include "crc32c.h" #define MAX_QUEUE_CMD 128 @@ -76,9 +77,12 @@ enum { int iscsi_rdma_enabled; -int iscsi_pthread_per_target(void) +enum tgt_thread_type iscsi_pthread_per_target(struct target *t) { - return sig_fd >= 0 && !iscsi_rdma_enabled; + if (sig_fd >= 0 && !iscsi_rdma_enabled) + return t->thr_type; + else + return NO_PTHREAD; } void conn_read_pdu(struct iscsi_connection *conn) Index: tgt-thread/usr/iscsi/target.c =================================================================== --- tgt-thread.orig/usr/iscsi/target.c +++ tgt-thread/usr/iscsi/target.c @@ -443,7 +443,7 @@ int iscsi_target_create(struct target *t isns_target_register(tgt_targetname(tid)); - if (iscsi_pthread_per_target()) { + if (iscsi_pthread_per_target(t) != NO_PTHREAD) { int ret; INIT_LIST_HEAD(&target->ti.t_list); Index: tgt-thread/doc/tgtadm.8.xml =================================================================== --- tgt-thread.orig/doc/tgtadm.8.xml +++ tgt-thread/doc/tgtadm.8.xml @@ -21,6 +21,7 @@ <arg choice="opt">-m --mode <mode></arg> <arg choice="opt">-t --tid <id></arg> <arg choice="opt">-T --targetname <targetname></arg> + <arg choice="opt">-x --thread <thread></arg> <arg choice="opt">-Y --device-type <type></arg> <arg choice="opt">-l --lun <lun></arg> <arg choice="opt">-b --backing-store <path></arg> @@ -72,7 +73,7 @@ Possible device-types are: changer : emulate a media changer device </screen> - <varlistentry><term><option>--lld <driver> --op new --mode target --tid <id> --targetname <name></option></term> + <varlistentry><term><option>--lld <driver> --op new --mode target --tid <id> --targetname <name> --thread <thread_type></option> </term> <listitem> <para> Add a new target with <id> and <name>. @@ -390,6 +391,9 @@ two empty DVD-R disks. # Create a target tgtadm --lld iscsi --mode target --op new --tid 1 --targetname iqn.2007-03:virtual-dvd:`hostname` +# Create a target with thread type as connection. Other options are "none" and "thread"(default) +tgtadm --lld iscsi --mode target --op new --tid 1 --targetname iqn.2007-03:virtual-dvd:`hostname` --thread conn + # Create a DVD drive and give it a nice name # The dvd starts out without a backing store file, i.e. no disk loaded tgtadm --op new --mode logicalunit --tid 1 --lun 1 --device-type cd -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html