- Fixed a major IET-derived iSCSI RFC violation: sessions and connections were not...
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Tue, 3 Mar 2009 18:13:23 +0000 (18:13 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Tue, 3 Mar 2009 18:13:23 +0000 (18:13 +0000)
 - A lot of cleanups and minor fixes, mostly IET-derived

git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@685 d57e44dd-8a1f-0410-8b47-8ef2f437770f

23 files changed:
iscsi-scst/doc/iscsi-scst-howto.txt
iscsi-scst/include/iscsi_scst.h
iscsi-scst/kernel/config.c
iscsi-scst/kernel/conn.c
iscsi-scst/kernel/event.c
iscsi-scst/kernel/iscsi.c
iscsi-scst/kernel/iscsi.h
iscsi-scst/kernel/nthread.c
iscsi-scst/kernel/param.c
iscsi-scst/kernel/session.c
iscsi-scst/kernel/target.c
iscsi-scst/usr/Makefile
iscsi-scst/usr/conn.c
iscsi-scst/usr/ctldev.c
iscsi-scst/usr/event.c
iscsi-scst/usr/iscsi_scstd.c
iscsi-scst/usr/iscsid.c
iscsi-scst/usr/iscsid.h
iscsi-scst/usr/message.c
iscsi-scst/usr/param.c
iscsi-scst/usr/plain.c
iscsi-scst/usr/session.c
iscsi-scst/usr/target.c

index 886c04d..0243ffb 100644 (file)
@@ -262,21 +262,21 @@ Show the configured parameters for a specific target:
 
 # iscsi-scst-adm --op show --tid=1 --sid=0
 InitialR2T=No
-ImmediateData=
-MaxConnections=0
-MaxRecvDataSegmentLength=4269849632
-MaxXmitDataSegmentLength=10933
-MaxBurstLength=4294967295
-FirstBurstLength=32767
-DefaultTime2Wait=4203042
-DefaultTime2Retain=5
-MaxOutstandingR2T=0
-DataPDUInOrder=No
+ImmediateData=Yes
+MaxConnections=1
+MaxRecvDataSegmentLength=2097152
+MaxXmitDataSegmentLength=131072
+MaxBurstLength=2097152
+FirstBurstLength=262144
+DefaultTime2Wait=2
+DefaultTime2Retain=0
+MaxOutstandingR2T=1
+DataPDUInOrder=Yes
 DataSequenceInOrder=Yes
 ErrorRecoveryLevel=0
-HeaderDigest=
-DataDigest=CRC32C
-OFMarker=
+HeaderDigest=None
+DataDigest=None
+OFMarker=No
 IFMarker=No
 OFMarkInt=Reject
 IFMarkInt=Reject
index 9c7bc3c..086c526 100644 (file)
 #define aligned_u64 uint64_t __attribute__((aligned(8)))
 #endif
 
-struct target_info {
+struct iscsi_kern_target_info {
        u32 tid;
        char name[ISCSI_NAME_LEN];
 };
 
-struct session_info {
+struct iscsi_kern_session_info {
        u32 tid;
 
        aligned_u64 sid;
@@ -52,7 +52,7 @@ struct session_info {
 #define DIGEST_NONE            (1 << 0)
 #define DIGEST_CRC32C           (1 << 1)
 
-struct conn_info {
+struct iscsi_kern_conn_info {
        u32 tid;
        aligned_u64 sid;
 
@@ -97,7 +97,7 @@ enum {
        key_target,
 };
 
-struct iscsi_param_info {
+struct iscsi_kern_param_info {
        u32 tid;
        aligned_u64 sid;
 
@@ -108,18 +108,18 @@ struct iscsi_param_info {
        s32 target_param[target_key_last];
 };
 
-enum iscsi_event_state {
+enum iscsi_kern_event_state {
        E_CONN_CLOSE,
 };
 
-struct iscsi_event {
+struct iscsi_kern_event {
        u32 tid;
        aligned_u64 sid;
        u32 cid;
        u32 state;
 };
 
-struct iscsi_register_info {
+struct iscsi_kern_register_info {
        aligned_u64 version;
 };
 
@@ -130,18 +130,16 @@ struct iscsi_register_info {
 #define NETLINK_ISCSI_SCST     25
 
 /* On success returns MAX_DATA_SEG_LEN */
-#define REGISTER_USERD         _IOW('s', 0, struct iscsi_register_info)
-
-#define ADD_TARGET             _IOW('s', 1, struct target_info)
-#define DEL_TARGET             _IOW('s', 2, struct target_info)
-#define ADD_SESSION            _IOW('s', 3, struct session_info)
-#define DEL_SESSION            _IOW('s', 4, struct session_info)
-#define GET_SESSION_INFO       _IOWR('s', 5, struct session_info)
-#define ADD_CONN               _IOW('s', 6, struct conn_info)
-#define DEL_CONN               _IOW('s', 7, struct conn_info)
-#define GET_CONN_INFO          _IOWR('s', 8, struct conn_info)
-#define ISCSI_PARAM_SET                _IOW('s', 9, struct iscsi_param_info)
-#define ISCSI_PARAM_GET                _IOWR('s', 10, struct iscsi_param_info)
+#define REGISTER_USERD         _IOW('s', 0, struct iscsi_kern_register_info)
+
+#define ADD_TARGET             _IOW('s', 1, struct iscsi_kern_target_info)
+#define DEL_TARGET             _IOW('s', 2, struct iscsi_kern_target_info)
+#define ADD_SESSION            _IOW('s', 3, struct iscsi_kern_session_info)
+#define DEL_SESSION            _IOW('s', 4, struct iscsi_kern_session_info)
+#define ADD_CONN               _IOW('s', 5, struct iscsi_kern_conn_info)
+#define DEL_CONN               _IOW('s', 6, struct iscsi_kern_conn_info)
+#define ISCSI_PARAM_SET                _IOW('s', 7, struct iscsi_kern_param_info)
+#define ISCSI_PARAM_GET                _IOWR('s', 8, struct iscsi_kern_param_info)
 
 static inline int iscsi_is_key_declarative(int key)
 {
index 0831c69..5bdd98f 100644 (file)
@@ -229,39 +229,12 @@ err:
        goto out;
 }
 
-/* target_mutex supposed to be locked */
-static int get_conn_info(struct iscsi_target *target, void __user *ptr)
-{
-       int err;
-       struct iscsi_session *session;
-       struct conn_info info;
-       struct iscsi_conn *conn;
-
-       err = copy_from_user(&info, ptr, sizeof(info));
-       if (err < 0)
-               return err;
-
-       session = session_lookup(target, info.sid);
-       if (!session)
-               return -ENOENT;
-       conn = conn_lookup(session, info.cid);
-
-       info.cid = conn->cid;
-       info.stat_sn = conn->stat_sn;
-       info.exp_stat_sn = conn->exp_stat_sn;
-
-       if (copy_to_user(ptr, &info, sizeof(info)))
-               return -EFAULT;
-
-       return 0;
-}
-
 /* target_mutex supposed to be locked */
 static int add_conn(struct iscsi_target *target, void __user *ptr)
 {
        int err;
        struct iscsi_session *session;
-       struct conn_info info;
+       struct iscsi_kern_conn_info info;
 
        err = copy_from_user(&info, ptr, sizeof(info));
        if (err < 0)
@@ -279,7 +252,7 @@ static int del_conn(struct iscsi_target *target, void __user *ptr)
 {
        int err;
        struct iscsi_session *session;
-       struct conn_info info;
+       struct iscsi_kern_conn_info info;
 
        err = copy_from_user(&info, ptr, sizeof(info));
        if (err < 0)
@@ -292,35 +265,11 @@ static int del_conn(struct iscsi_target *target, void __user *ptr)
        return conn_del(session, &info);
 }
 
-/* target_mutex supposed to be locked */
-static int get_session_info(struct iscsi_target *target, void __user *ptr)
-{
-       int err;
-       struct iscsi_session *session;
-       struct session_info info;
-
-       err = copy_from_user(&info, ptr, sizeof(info));
-       if (err < 0)
-               return err;
-
-       session = session_lookup(target, info.sid);
-
-       if (!session)
-               return -ENOENT;
-
-       info.exp_cmd_sn = session->exp_cmd_sn;
-
-       if (copy_to_user(ptr, &info, sizeof(info)))
-               return -EFAULT;
-
-       return 0;
-}
-
 /* target_mutex supposed to be locked */
 static int add_session(struct iscsi_target *target, void __user *ptr)
 {
        int err;
-       struct session_info info;
+       struct iscsi_kern_session_info info;
 
        err = copy_from_user(&info, ptr, sizeof(info));
        if (err < 0)
@@ -336,7 +285,7 @@ static int add_session(struct iscsi_target *target, void __user *ptr)
 static int del_session(struct iscsi_target *target, void __user *ptr)
 {
        int err;
-       struct session_info info;
+       struct iscsi_kern_session_info info;
 
        err = copy_from_user(&info, ptr, sizeof(info));
        if (err < 0)
@@ -350,7 +299,7 @@ static int iscsi_param_config(struct iscsi_target *target, void __user *ptr,
                              int set)
 {
        int err;
-       struct iscsi_param_info info;
+       struct iscsi_kern_param_info info;
 
        err = copy_from_user(&info, ptr, sizeof(info));
        if (err < 0)
@@ -371,7 +320,7 @@ out:
 static int add_target(void __user *ptr)
 {
        int err;
-       struct target_info info;
+       struct iscsi_kern_target_info info;
 
        err = copy_from_user(&info, ptr, sizeof(info));
        if (err < 0)
@@ -386,7 +335,7 @@ static int add_target(void __user *ptr)
 
 static int iscsi_check_version(void __user *arg)
 {
-       struct iscsi_register_info reg;
+       struct iscsi_kern_register_info reg;
        char ver[sizeof(ISCSI_SCST_INTERFACE_VERSION)+1];
        int res;
 
@@ -428,12 +377,10 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case DEL_TARGET:
        case ADD_SESSION:
        case DEL_SESSION:
-       case GET_SESSION_INFO:
        case ISCSI_PARAM_SET:
        case ISCSI_PARAM_GET:
        case ADD_CONN:
        case DEL_CONN:
-       case GET_CONN_INFO:
                break;
 
        case REGISTER_USERD:
@@ -491,10 +438,6 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                err = del_session(target, (void __user *) arg);
                break;
 
-       case GET_SESSION_INFO:
-               err = get_session_info(target, (void __user *) arg);
-               break;
-
        case ISCSI_PARAM_SET:
                err = iscsi_param_config(target, (void __user *) arg, 1);
                break;
@@ -511,10 +454,6 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                err = del_conn(target, (void __user *) arg);
                break;
 
-       case GET_CONN_INFO:
-               err = get_conn_info(target, (void __user *) arg);
-               break;
-
        default:
                sBUG();
                break;
@@ -555,9 +494,9 @@ static void iscsi_dump_char(int ch)
                        text[i] = ' ';
                        i++;
                        if ((i % 16) == 0)
-                               printk(LOG_FLAG " | %.16s |\n", text);
+                               printk(" | %.16s |\n", text);
                        else if ((i % 4) == 0)
-                               printk(LOG_FLAG " |");
+                               printk(" |");
                }
                i = 0;
                return;
@@ -567,10 +506,10 @@ static void iscsi_dump_char(int ch)
        printk(LOG_FLAG " %02x", ch);
        i++;
        if ((i % 16) == 0) {
-               printk(LOG_FLAG " | %.16s |\n", text);
+               printk(" | %.16s |\n", text);
                i = 0;
        } else if ((i % 4) == 0)
-               printk(LOG_FLAG " |");
+               printk(" |");
 }
 
 void iscsi_dump_pdu(struct iscsi_pdu *pdu)
index 55e45d3..42bd843 100644 (file)
@@ -107,7 +107,12 @@ struct iscsi_conn *conn_lookup(struct iscsi_session *session, u16 cid)
 {
        struct iscsi_conn *conn;
 
-       list_for_each_entry(conn, &session->conn_list, conn_list_entry) {
+       /*
+        * We need to find the latest conn to correctly handle
+        * multi-reinstatements
+        */
+       list_for_each_entry_reverse(conn, &session->conn_list,
+                                       conn_list_entry) {
                if (conn->cid == cid)
                        return conn;
        }
@@ -118,6 +123,8 @@ static void iscsi_make_conn_rd_active(struct iscsi_conn *conn)
 {
        TRACE_ENTRY();
 
+       EXTRACHECKS_BUG_ON(conn->conn_reinstating);
+
        spin_lock_bh(&iscsi_rd_lock);
 
        TRACE_DBG("conn %p, rd_state %x, rd_data_ready %d", conn,
@@ -168,7 +175,8 @@ void __mark_conn_closed(struct iscsi_conn *conn, int flags)
                conn->deleting = 1;
        spin_unlock_bh(&iscsi_rd_lock);
 
-       iscsi_make_conn_rd_active(conn);
+       if (!conn->conn_reinstating)
+               iscsi_make_conn_rd_active(conn);
 }
 
 void mark_conn_closed(struct iscsi_conn *conn)
@@ -184,9 +192,11 @@ static void iscsi_state_change(struct sock *sk)
 
        if (unlikely(sk->sk_state != TCP_ESTABLISHED)) {
                if (!conn->closing) {
-                       PRINT_ERROR("Connection with initiator %s (%p) "
+                       PRINT_ERROR("Connection with initiator %s "
                                "unexpectedly closed!",
-                               conn->session->initiator_name, conn);
+                               conn->session->initiator_name);
+                       TRACE_MGMT_DBG("conn %p, sk state %d", conn,
+                               sk->sk_state);
                        __mark_conn_closed(conn, 0);
                }
        } else
@@ -275,13 +285,41 @@ static void conn_rsp_timer_fn(unsigned long arg)
        return;
 }
 
+void __iscsi_socket_bind(struct iscsi_conn *conn)
+{
+       TRACE_MGMT_DBG("Enabling conn %p", conn);
+
+       /* Catch double bind */
+       sBUG_ON(conn->sock->sk->sk_state_change == iscsi_state_change);
+
+       /* Let's reset this flag in one place */
+       conn->conn_reinstating = 0;
+
+       write_lock_bh(&conn->sock->sk->sk_callback_lock);
+
+       conn->old_state_change = conn->sock->sk->sk_state_change;
+       conn->sock->sk->sk_state_change = iscsi_state_change;
+
+       conn->old_data_ready = conn->sock->sk->sk_data_ready;
+       conn->sock->sk->sk_data_ready = iscsi_data_ready;
+
+       conn->old_write_space = conn->sock->sk->sk_write_space;
+       conn->sock->sk->sk_write_space = iscsi_write_space_ready;
+
+       write_unlock_bh(&conn->sock->sk->sk_callback_lock);
+
+       iscsi_make_conn_rd_active(conn);
+
+       return;
+}
+
 /*
- * Note: the code belows passes a kernel space pointer (&opt) to setsockopt()
+ * Note: the code below passes a kernel space pointer (&opt) to setsockopt()
  * while the declaration of setsockopt specifies that it expects a user space
  * pointer. This seems to work fine, and this approach is also used in some
  * other parts of the Linux kernel (see e.g. fs/ocfs2/cluster/tcp.c).
  */
-static int iscsi_socket_bind(struct iscsi_conn *conn)
+static int iscsi_socket_bind(struct iscsi_conn *conn, bool reinstating)
 {
        int res = 0;
        int opt = 1;
@@ -304,25 +342,23 @@ static int iscsi_socket_bind(struct iscsi_conn *conn)
 #endif
        conn->sock->sk->sk_user_data = conn;
 
-       write_lock_bh(&conn->sock->sk->sk_callback_lock);
-
-       conn->old_state_change = conn->sock->sk->sk_state_change;
-       conn->sock->sk->sk_state_change = iscsi_state_change;
-
-       conn->old_data_ready = conn->sock->sk->sk_data_ready;
-       conn->sock->sk->sk_data_ready = iscsi_data_ready;
-
-       conn->old_write_space = conn->sock->sk->sk_write_space;
-       conn->sock->sk->sk_write_space = iscsi_write_space_ready;
-
-       write_unlock_bh(&conn->sock->sk->sk_callback_lock);
-
        oldfs = get_fs();
        set_fs(get_ds());
        conn->sock->ops->setsockopt(conn->sock, SOL_TCP, TCP_NODELAY,
                (void __force __user *)&opt, sizeof(opt));
        set_fs(oldfs);
 
+       if (!reinstating) {
+               /*
+                * We will delay full conn serving until all commands in
+                * replacing connections are done to prevent them from
+                * spoil our data by writing to them too late.
+                */
+               __iscsi_socket_bind(conn);
+       } else
+               TRACE_MGMT_DBG("conn %p is reinstating, delaying enabling it",
+                       conn);
+
 out:
        return res;
 }
@@ -341,6 +377,19 @@ int conn_free(struct iscsi_conn *conn)
        sBUG_ON(!list_empty(&conn->cmd_list));
        sBUG_ON(!list_empty(&conn->write_list));
        sBUG_ON(!list_empty(&conn->written_list));
+       sBUG_ON(conn->conn_reinst_successor != NULL);
+
+       if (conn->conn_reinstating) {
+               struct iscsi_conn *c;
+               TRACE_MGMT_DBG("Freeing being reinstated conn %p", conn);
+               list_for_each_entry(c, &conn->session->conn_list,
+                                       conn_list_entry) {
+                       if (c->conn_reinst_successor == conn) {
+                               c->conn_reinst_successor = NULL;
+                               break;
+                       }
+               }
+       }
 
        list_del(&conn->conn_list_entry);
 
@@ -357,11 +406,14 @@ int conn_free(struct iscsi_conn *conn)
 
 /* target_mutex supposed to be locked */
 static int iscsi_conn_alloc(struct iscsi_session *session,
-                           struct conn_info *info)
+       struct iscsi_kern_conn_info *info, bool reinstating,
+       struct iscsi_conn **new_conn)
 {
        struct iscsi_conn *conn;
        int res = 0;
 
+       reinstating |= session->sess_reinstating;
+
        conn = kzalloc(sizeof(*conn), GFP_KERNEL);
        if (!conn) {
                res = -ENOMEM;
@@ -380,6 +432,7 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
 
        atomic_set(&conn->conn_ref_cnt, 0);
        conn->session = session;
+       conn->conn_reinstating = reinstating;
        conn->cid = info->cid;
        conn->stat_sn = info->stat_sn;
        conn->exp_stat_sn = info->exp_stat_sn;
@@ -399,14 +452,17 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
        INIT_LIST_HEAD(&conn->write_list);
        INIT_LIST_HEAD(&conn->written_list);
        setup_timer(&conn->rsp_timer, conn_rsp_timer_fn, (unsigned long)conn);
+       init_completion(&conn->ready_to_free);
 
        conn->file = fget(info->fd);
 
-       res = iscsi_socket_bind(conn);
+       res = iscsi_socket_bind(conn, reinstating);
        if (res != 0)
                goto out_err_free2;
 
-       list_add(&conn->conn_list_entry, &session->conn_list);
+       list_add_tail(&conn->conn_list_entry, &session->conn_list);
+
+       *new_conn = conn;
 
 out:
        return res;
@@ -425,20 +481,38 @@ out_err:
 }
 
 /* target_mutex supposed to be locked */
-int conn_add(struct iscsi_session *session, struct conn_info *info)
+int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
 {
-       struct iscsi_conn *conn;
-       int err = -EEXIST;
+       struct iscsi_conn *conn, *new_conn;
+       int err;
+       bool reinstatement = false;
 
        conn = conn_lookup(session, info->cid);
-       if (conn)
-               return err;
+       if (conn != NULL) {
+               /* conn reinstatement */
+               reinstatement = true;
+       } else if (!list_empty(&session->conn_list)) {
+               err = -EEXIST;
+               goto out;
+       }
+
+       err = iscsi_conn_alloc(session, info, reinstatement, &new_conn);
+       if (err != 0)
+               goto out;
 
-       return iscsi_conn_alloc(session, info);
+       if (reinstatement) {
+               TRACE_MGMT_DBG("Reinstating conn %p", conn);
+               conn->conn_reinst_successor = new_conn;
+               new_conn->conn_reinstating = 1;
+               __mark_conn_closed(conn, 0);
+       }
+
+out:
+       return err;
 }
 
 /* target_mutex supposed to be locked */
-int conn_del(struct iscsi_session *session, struct conn_info *info)
+int conn_del(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
 {
        struct iscsi_conn *conn;
        int err = -EEXIST;
index 45675e0..4b33243 100644 (file)
@@ -107,14 +107,14 @@ static int notify(void *data, int len, gfp_t gfp_mask)
 int event_send(u32 tid, u64 sid, u32 cid, u32 state, int atomic)
 {
        int err;
-       struct iscsi_event event;
+       struct iscsi_kern_event event;
 
        event.tid = tid;
        event.sid = sid;
        event.cid = cid;
        event.state = state;
 
-       err = notify(&event, NLMSG_SPACE(sizeof(struct iscsi_event)), 0);
+       err = notify(&event, NLMSG_SPACE(sizeof(struct iscsi_kern_event)), 0);
 
        return err;
 }
index affa359..3e1fffd 100644 (file)
@@ -572,7 +572,7 @@ static void iscsi_cmnd_init_write(struct iscsi_cmnd *rsp, int flags)
                        list_empty(&rsp->rsp_cmd_list), rsp->hashed);
                sBUG();
        }
-       list_add(&rsp->write_list_entry, &head);
+       list_add_tail(&rsp->write_list_entry, &head);
        iscsi_cmnds_init_write(&head, flags);
        return;
 }
@@ -1638,7 +1638,7 @@ static void __cmnd_abort(struct iscsi_cmnd *cmnd)
        return;
 }
 
-/* Must be called from the read thread */
+/* Must be called from the read or conn close thread */
 static int cmnd_abort(struct iscsi_cmnd *req)
 {
        struct iscsi_session *session = req->conn->session;
@@ -1719,7 +1719,7 @@ out_put:
        goto out;
 }
 
-/* Must be called from the read thread */
+/* Must be called from the read or conn close thread */
 static int target_abort(struct iscsi_cmnd *req, int all)
 {
        struct iscsi_target *target = req->conn->session->target;
@@ -1753,7 +1753,7 @@ static int target_abort(struct iscsi_cmnd *req, int all)
        return 0;
 }
 
-/* Must be called from the read thread */
+/* Must be called from the read or conn close thread */
 static void task_set_abort(struct iscsi_cmnd *req)
 {
        struct iscsi_session *session = req->conn->session;
@@ -1785,7 +1785,7 @@ static void task_set_abort(struct iscsi_cmnd *req)
        return;
 }
 
-/* Must be called from the read thread */
+/* Must be called from the read or conn close thread */
 void conn_abort(struct iscsi_conn *conn)
 {
        struct iscsi_cmnd *cmnd;
@@ -2237,7 +2237,7 @@ void cmnd_tx_end(struct iscsi_cmnd *cmnd)
                                "initiator's %s request",
                                cmnd->conn->session->target->tid,
                                conn->session->initiator_name);
-                       target_del_all_sess(cmnd->conn->session->target, false);
+                       target_del_all_sess(cmnd->conn->session->target, 0);
                } else {
                        PRINT_INFO("Closing connection at initiator's %s "
                                "request", conn->session->initiator_name);
@@ -2300,6 +2300,8 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
 
                        iscsi_cmnd_exec(cmnd);
 
+                       spin_lock(&session->sn_lock);
+
                        if (list_empty(&session->pending_list))
                                break;
                        cmnd = list_entry(session->pending_list.next,
@@ -2313,8 +2315,6 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
 
                        TRACE_DBG("Processing pending cmd %p (cmd_sn %u)",
                                cmnd, cmd_sn);
-
-                       spin_lock(&session->sn_lock);
                }
        } else {
                int drop = 0;
@@ -2377,6 +2377,7 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
                                PRINT_ERROR("%s", "Unable to create TM clone");
                }
 
+               spin_lock(&session->sn_lock);
                list_for_each(entry, &session->pending_list) {
                        struct iscsi_cmnd *tmp =
                                list_entry(entry, struct iscsi_cmnd,
@@ -2384,10 +2385,11 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
                        if (before(cmd_sn, tmp->pdu.bhs.sn))
                                break;
                }
-
                list_add_tail(&cmnd->pending_list_entry, entry);
                cmnd->pending = 1;
        }
+
+       spin_unlock(&session->sn_lock);
 out:
        return;
 }
@@ -2888,19 +2890,25 @@ static inline int iscsi_get_mgmt_response(int status)
 
 static void iscsi_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd)
 {
+       int fn = scst_mgmt_cmd_get_fn(scst_mcmd);
        struct iscsi_cmnd *req = (struct iscsi_cmnd *)
                                scst_mgmt_cmd_get_tgt_priv(scst_mcmd);
        int status =
                iscsi_get_mgmt_response(scst_mgmt_cmd_get_status(scst_mcmd));
 
        TRACE_MGMT_DBG("req %p, scst_mcmd %p, fn %d, scst status %d",
-               req, scst_mcmd, scst_mgmt_cmd_get_fn(scst_mcmd),
-               scst_mgmt_cmd_get_status(scst_mcmd));
-
-       iscsi_send_task_mgmt_resp(req, status);
-
-       scst_mgmt_cmd_set_tgt_priv(scst_mcmd, NULL);
+               req, scst_mcmd, fn, scst_mgmt_cmd_get_status(scst_mcmd));
 
+       switch (fn) {
+       case SCST_NEXUS_LOSS_SESS:
+       case SCST_ABORT_ALL_TASKS_SESS:
+               /* They are internal */
+               break;
+       default:
+               iscsi_send_task_mgmt_resp(req, status);
+               scst_mgmt_cmd_set_tgt_priv(scst_mcmd, NULL);
+               break;
+       }
        return;
 }
 
@@ -2930,6 +2938,7 @@ struct scst_tgt_template iscsi_template = {
 #endif
        .preprocessing_done = iscsi_preprocessing_done,
        .pre_exec = iscsi_pre_exec,
+       .task_mgmt_affected_cmds_done = iscsi_task_mgmt_affected_cmds_done,
        .task_mgmt_fn_done = iscsi_task_mgmt_fn_done,
 };
 
@@ -2953,7 +2962,7 @@ static __init int iscsi_run_threads(int count, char *name, int (*fn)(void *))
                        kfree(thr);
                        goto out;
                }
-               list_add(&thr->threads_list_entry, &iscsi_threads_list);
+               list_add_tail(&thr->threads_list_entry, &iscsi_threads_list);
        }
 
 out:
index 30d11a9..6049cf7 100644 (file)
@@ -88,8 +88,9 @@ struct iscsi_session {
        struct iscsi_target *target;
        struct scst_session *scst_sess;
 
-       /* Both unprotected, since accessed only from a single read thread */
-       struct list_head pending_list;
+       struct list_head pending_list; /* protected by sn_lock */
+
+       /* Unprotected, since accessed only from a single read thread */
        u32 next_ttt;
 
        u32 max_queued_cmnds; /* unprotected, since read-only */
@@ -113,11 +114,12 @@ struct iscsi_session {
 
        struct list_head session_list_entry;
 
-       struct completion unreg_compl;
+       /* All don't need any protection */
+       struct iscsi_session *sess_reinst_successor;
+       unsigned int sess_reinstating:1;
 
        /* All don't need any protection */
        char *initiator_name;
-       unsigned int shutting_down:1;
        u64 sid;
 };
 
@@ -216,6 +218,12 @@ struct iscsi_conn {
 
        struct list_head conn_list_entry; /* list entry in session conn_list */
 
+       /* All don't need any protection */
+       struct iscsi_conn *conn_reinst_successor;
+       unsigned int conn_reinstating:1;
+
+       struct completion ready_to_free;
+
        /* Doesn't need any protection */
        u16 cid;
 };
@@ -367,8 +375,9 @@ extern void conn_abort(struct iscsi_conn *conn);
 
 /* conn.c */
 extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
-extern int conn_add(struct iscsi_session *, struct conn_info *);
-extern int conn_del(struct iscsi_session *, struct conn_info *);
+extern void __iscsi_socket_bind(struct iscsi_conn *);
+extern int conn_add(struct iscsi_session *, struct iscsi_kern_conn_info *);
+extern int conn_del(struct iscsi_session *, struct iscsi_kern_conn_info *);
 extern int conn_free(struct iscsi_conn *);
 
 #define ISCSI_CONN_ACTIVE_CLOSE                1
@@ -387,12 +396,15 @@ extern void iscsi_put_page_callback(struct page *page);
 #endif
 extern int istrd(void *arg);
 extern int istwr(void *arg);
+extern void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd);
 
 /* target.c */
 struct iscsi_target *target_lookup_by_id(u32);
-extern int target_add(struct target_info *);
+extern int target_add(struct iscsi_kern_target_info *);
 extern int target_del(u32 id);
-extern void target_del_all_sess(struct iscsi_target *target, bool deleting);
+extern void target_del_session(struct iscsi_target *target,
+       struct iscsi_session *session, int flags);
+extern void target_del_all_sess(struct iscsi_target *target, int flags);
 extern void target_del_all(void);
 
 extern struct seq_operations iscsi_seq_op;
@@ -404,13 +416,14 @@ extern void iscsi_procfs_exit(void);
 /* session.c */
 extern struct file_operations session_seq_fops;
 extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
-extern int session_add(struct iscsi_target *, struct session_info *);
+extern void sess_enable_reinstated_sess(struct iscsi_session *);
+extern int session_add(struct iscsi_target *, struct iscsi_kern_session_info *);
 extern int session_del(struct iscsi_target *, u64);
 extern int session_free(struct iscsi_session *session);
 
 /* params.c */
-extern int iscsi_param_set(struct iscsi_target *, struct iscsi_param_info *,
-                          int);
+extern int iscsi_param_set(struct iscsi_target *,
+       struct iscsi_kern_param_info *, int);
 
 /* event.c */
 extern int event_send(u32, u64, u32, u32, int);
index 398b089..bc717fa 100644 (file)
@@ -167,22 +167,6 @@ out:
 static inline void iscsi_check_closewait(struct iscsi_conn *conn) {};
 #endif
 
-static void iscsi_unreg_cmds_done_fn(struct scst_session *scst_sess)
-{
-       struct iscsi_session *sess =
-               (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
-
-       TRACE_ENTRY();
-
-       TRACE_CONN_CLOSE_DBG("sess %p (scst_sess %p)", sess, scst_sess);
-
-       sess->shutting_down = 1;
-       complete_all(&sess->unreg_compl);
-
-       TRACE_EXIT();
-       return;
-}
-
 static void free_pending_commands(struct iscsi_conn *conn)
 {
        struct iscsi_session *session = conn->session;
@@ -219,6 +203,7 @@ static void free_pending_commands(struct iscsi_conn *conn)
                }
        } while (req_freed);
        spin_unlock(&session->sn_lock);
+
        return;
 }
 
@@ -258,6 +243,7 @@ static void free_orphaned_pending_commands(struct iscsi_conn *conn)
                }
        } while (req_freed);
        spin_unlock(&session->sn_lock);
+
        return;
 }
 
@@ -331,6 +317,42 @@ static void trace_conn_close(struct iscsi_conn *conn)
 static void trace_conn_close(struct iscsi_conn *conn) {}
 #endif /* CONFIG_SCST_DEBUG */
 
+void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd)
+{
+       int fn = scst_mgmt_cmd_get_fn(scst_mcmd);
+       void *priv = scst_mgmt_cmd_get_tgt_priv(scst_mcmd);
+
+       TRACE_MGMT_DBG("scst_mcmd %p, fn %d, priv %p", scst_mcmd, fn, priv);
+
+       switch (fn) {
+       case SCST_NEXUS_LOSS_SESS:
+       case SCST_ABORT_ALL_TASKS_SESS:
+       {
+               struct iscsi_conn *conn = (struct iscsi_conn *)priv;
+               struct iscsi_session *sess = conn->session;
+
+               mutex_lock(&sess->target->target_mutex);
+               if (conn->conn_reinst_successor != NULL) {
+                       sBUG_ON(!conn->conn_reinst_successor->conn_reinstating);
+                       __iscsi_socket_bind(conn->conn_reinst_successor);
+                       /* We will check for conn_reinst_successor later */
+               } else if (sess->sess_reinst_successor != NULL) {
+                       sess_enable_reinstated_sess(sess->sess_reinst_successor);
+                       sess->sess_reinst_successor = NULL;
+               }
+               mutex_unlock(&sess->target->target_mutex);
+
+               complete_all(&conn->ready_to_free);
+               break;
+       }
+       default:
+               /* Nothing to do */
+               break;
+       }
+
+       return;
+}
+
 /* No locks */
 static void close_conn(struct iscsi_conn *conn)
 {
@@ -339,6 +361,7 @@ static void close_conn(struct iscsi_conn *conn)
        typeof(jiffies) start_waiting = jiffies;
        typeof(jiffies) shut_start_waiting = start_waiting;
        bool pending_reported = 0, wait_expired = 0, shut_expired = 0;
+       bool free_sess;
 
 #define CONN_PENDING_TIMEOUT   ((typeof(jiffies))10*HZ)
 #define CONN_WAIT_TIMEOUT      ((typeof(jiffies))10*HZ)
@@ -362,15 +385,26 @@ static void close_conn(struct iscsi_conn *conn)
                        RCV_SHUTDOWN|SEND_SHUTDOWN);
        }
 
-       /*
-        * We need to call scst_unregister_session() ASAP to make SCST start
-        * recovering stuck commands.
-        *
-        * ToDo: this is incompatible with MC/S
-        */
-       scst_unregister_session_ex(session->scst_sess, 0,
-               NULL, iscsi_unreg_cmds_done_fn);
-       session->scst_sess = NULL;
+       if (conn->conn_reinst_successor != NULL) {
+               int rc;
+               int lun = 0;
+
+               /* Abort all outstanding commands */
+               rc = scst_rx_mgmt_fn_lun(session->scst_sess,
+                       SCST_ABORT_ALL_TASKS_SESS, (uint8_t *)&lun, sizeof(lun),
+                       SCST_NON_ATOMIC, conn);
+               if (rc != 0)
+                       PRINT_ERROR("SCST_ABORT_ALL_TASKS_SESS failed %d", rc);
+       } else {
+               int rc;
+               int lun = 0;
+
+               rc = scst_rx_mgmt_fn_lun(session->scst_sess,
+                       SCST_NEXUS_LOSS_SESS, (uint8_t *)&lun, sizeof(lun),
+                       SCST_NON_ATOMIC, conn);
+               if (rc != 0)
+                       PRINT_ERROR("SCST_NEXUS_LOSS_SESS failed %d", rc);
+       }
 
        if (conn->read_state != RX_INIT_BHS) {
                struct iscsi_cmnd *cmnd = conn->read_cmnd;
@@ -401,18 +435,11 @@ static void close_conn(struct iscsi_conn *conn)
                        mutex_unlock(&target->target_mutex);
                }
 
+               /* It's safe to check it without sn_lock */
                if (!list_empty(&session->pending_list)) {
                        TRACE_CONN_CLOSE_DBG("Disposing pending commands on "
-                                            "connection %p (conn_ref_cnt=%d)",
-                                            conn,
-                                            atomic_read(&conn->conn_ref_cnt));
-
-                       /*
-                        * Such complicated approach currently isn't really
-                        * necessary, but it will be necessary for MC/S, if we
-                        * won't want to reestablish the whole session on a
-                        * connection failure.
-                        */
+                               "connection %p (conn_ref_cnt=%d)", conn,
+                               atomic_read(&conn->conn_ref_cnt));
 
                        free_pending_commands(conn);
 
@@ -487,18 +514,27 @@ static void close_conn(struct iscsi_conn *conn)
                msleep(50);
        }
 
+       wait_for_completion(&conn->ready_to_free);
+
        TRACE_CONN_CLOSE("Notifying user space about closing connection %p",
                         conn);
        event_send(target->tid, session->sid, conn->cid, E_CONN_CLOSE, 0);
 
-       wait_for_completion(&session->unreg_compl);
-
-       sBUG_ON(!session->shutting_down);
+       sBUG_ON(conn->conn_reinstating);
+       sBUG_ON(session->sess_reinstating);
 
        mutex_lock(&target->target_mutex);
+
+       free_sess = (conn->conn_reinst_successor == NULL);
+
        conn_free(conn);
-       /* ToDo: this is incompatible with MC/S */
-       session_free(session);
+
+       if (free_sess) {
+               sBUG_ON(session->sess_reinst_successor != NULL);
+               /* ToDo: this is incompatible with MC/S */
+               session_free(session);
+       }
+
        mutex_unlock(&target->target_mutex);
 
        TRACE_EXIT();
@@ -512,6 +548,11 @@ static int close_conn_thr(void *arg)
        TRACE_ENTRY();
 
 #ifdef CONFIG_SCST_EXTRACHECKS
+       /*
+        * To satisfy iscsi_extracheck_is_rd_thread() in functions called
+        * on the connection close. It is safe, because at this point conn
+        * can't be used by any other thread.
+        */
        conn->rd_task = current;
 #endif
        close_conn(conn);
index 588bf1e..f865016 100644 (file)
@@ -92,7 +92,7 @@ static void log_params(struct iscsi_sess_param *param)
 }
 
 /* target_mutex supposed to be locked */
-static void sess_param_check(struct iscsi_param_info *info)
+static void sess_param_check(struct iscsi_kern_param_info *info)
 {
        int32_t *iparam = info->session_param;
 
@@ -114,7 +114,7 @@ static void sess_param_check(struct iscsi_param_info *info)
 
 /* target_mutex supposed to be locked */
 static void sess_param_set(struct iscsi_sess_param *param,
-                          struct iscsi_param_info *info)
+                          struct iscsi_kern_param_info *info)
 {
        int32_t *iparam = info->session_param;
 
@@ -140,7 +140,7 @@ static void sess_param_set(struct iscsi_sess_param *param,
 }
 
 static void sess_param_get(struct iscsi_sess_param *param,
-                          struct iscsi_param_info *info)
+                          struct iscsi_kern_param_info *info)
 {
        int32_t *iparam = info->session_param;
 
@@ -166,7 +166,7 @@ static void sess_param_get(struct iscsi_sess_param *param,
 }
 
 /* target_mutex supposed to be locked */
-static void trgt_param_check(struct iscsi_param_info *info)
+static void trgt_param_check(struct iscsi_kern_param_info *info)
 {
        int32_t *iparam = info->target_param;
 
@@ -176,7 +176,7 @@ static void trgt_param_check(struct iscsi_param_info *info)
 
 /* target_mutex supposed to be locked */
 static void trgt_param_set(struct iscsi_target *target,
-                          struct iscsi_param_info *info)
+                          struct iscsi_kern_param_info *info)
 {
        struct iscsi_trgt_param *param = &target->trgt_param;
        int32_t *iparam = info->target_param;
@@ -186,7 +186,7 @@ static void trgt_param_set(struct iscsi_target *target,
 
 /* target_mutex supposed to be locked */
 static void trgt_param_get(struct iscsi_trgt_param *param,
-                          struct iscsi_param_info *info)
+                          struct iscsi_kern_param_info *info)
 {
        int32_t *iparam = info->target_param;
 
@@ -195,7 +195,7 @@ static void trgt_param_get(struct iscsi_trgt_param *param,
 
 /* target_mutex supposed to be locked */
 static int trgt_param(struct iscsi_target *target,
-                     struct iscsi_param_info *info, int set)
+                     struct iscsi_kern_param_info *info, int set)
 {
        if (set) {
                struct iscsi_trgt_param *prm;
@@ -213,7 +213,7 @@ static int trgt_param(struct iscsi_target *target,
 
 /* target_mutex supposed to be locked */
 static int sess_param(struct iscsi_target *target,
-                     struct iscsi_param_info *info, int set)
+                     struct iscsi_kern_param_info *info, int set)
 {
        struct iscsi_session *session = NULL;
        struct iscsi_sess_param *param;
@@ -247,8 +247,8 @@ out:
 }
 
 /* target_mutex supposed to be locked */
-int iscsi_param_set(struct iscsi_target *target, struct iscsi_param_info *info,
-                   int set)
+int iscsi_param_set(struct iscsi_target *target,
+       struct iscsi_kern_param_info *info, int set)
 {
        int err;
 
index 9db6018..f81688d 100644 (file)
@@ -23,7 +23,7 @@ struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid)
 
        list_for_each_entry(session, &target->session_list,
                        session_list_entry) {
-               if ((session->sid == sid) && !session->shutting_down)
+               if (session->sid == sid)
                        return session;
        }
        return NULL;
@@ -31,7 +31,7 @@ struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid)
 
 /* target_mutex supposed to be locked */
 static int iscsi_session_alloc(struct iscsi_target *target,
-                              struct session_info *info)
+       struct iscsi_kern_session_info *info, struct iscsi_session **result)
 {
        int err;
        unsigned int i;
@@ -93,14 +93,15 @@ static int iscsi_session_alloc(struct iscsi_target *target,
        kfree(name);
 
        scst_sess_set_tgt_priv(session->scst_sess, session);
-       init_completion(&session->unreg_compl);
 
-       list_add(&session->session_list_entry, &target->session_list);
+       list_add_tail(&session->session_list_entry, &target->session_list);
 
        TRACE_MGMT_DBG("Session %p created: target %p, tid %u, sid %#Lx",
                session, target, target->tid, info->sid);
 
+       *result = session;
        return 0;
+
 err:
        if (session) {
                kfree(session->initiator_name);
@@ -111,20 +112,89 @@ err:
 }
 
 /* target_mutex supposed to be locked */
-int session_add(struct iscsi_target *target, struct session_info *info)
+void sess_enable_reinstated_sess(struct iscsi_session *sess)
 {
-       struct iscsi_session *session;
-       int err = -EEXIST;
+       struct iscsi_conn *c;
+
+       TRACE_ENTRY();
+
+       TRACE_MGMT_DBG("Enabling reinstate successor sess %p", sess);
+
+       sBUG_ON(!sess->sess_reinstating);
+
+       list_for_each_entry(c, &sess->conn_list, conn_list_entry) {
+               __iscsi_socket_bind(c);
+       }
+       sess->sess_reinstating = 0;
+
+       TRACE_EXIT();
+       return;
+}
+
+/* target_mutex supposed to be locked */
+static void session_reinstate(struct iscsi_session *old_sess,
+       struct iscsi_session *new_sess)
+{
+       TRACE_ENTRY();
+
+       TRACE_MGMT_DBG("Reinstating sess %p with SID %llx (old %p, SID %llx)",
+               new_sess, new_sess->sid, old_sess, old_sess->sid);
+
+       new_sess->sess_reinstating = 1;
+       old_sess->sess_reinst_successor = new_sess;
+
+       scst_set_initial_UA(new_sess->scst_sess,
+               SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
+
+       target_del_session(old_sess->target, old_sess, 0);
+
+       TRACE_EXIT();
+       return;
+}
+
+/* target_mutex supposed to be locked */
+int session_add(struct iscsi_target *target,
+       struct iscsi_kern_session_info *info)
+{
+       struct iscsi_session *session, *old_sess;
+       int err = 0;
+       union iscsi_sid sid;
+
+       TRACE_MGMT_DBG("Adding session SID %llx", info->sid);
 
        session = session_lookup(target, info->sid);
        if (session) {
                PRINT_ERROR("Attempt to add session with existing SID %llx",
                        info->sid);
-               return err;
+               err = -EEXIST;
+               goto out;
+       }
+
+       sid = (union iscsi_sid)info->sid;
+       sid.id.tsih = 0;
+       old_sess = NULL;
+
+       /*
+        * We need to find the latest session to correctly handle
+        * multi-reinstatements
+        */
+       list_for_each_entry_reverse(session, &target->session_list,
+                       session_list_entry) {
+               union iscsi_sid i = (union iscsi_sid)session->sid;
+               i.id.tsih = 0;
+               if ((sid.id64 == i.id64) &&
+                   (strcmp(info->initiator_name, session->initiator_name) == 0)) {
+                       /* session reinstatement */
+                       old_sess = session;
+                       break;
+               }
        }
 
-       err = iscsi_session_alloc(target, info);
+       err = iscsi_session_alloc(target, info, &session);
+       if ((err == 0) && (old_sess != NULL))
+               session_reinstate(old_sess, session);
 
+out:
        return err;
 }
 
@@ -133,8 +203,8 @@ int session_free(struct iscsi_session *session)
 {
        unsigned int i;
 
-       TRACE_MGMT_DBG("Freeing session %p:%#Lx",
-               session, (long long unsigned int)session->sid);
+       TRACE_MGMT_DBG("Freeing session %p (SID %llx)",
+               session, session->sid);
 
        sBUG_ON(!list_empty(&session->conn_list));
        if (unlikely(atomic_read(&session->active_cmds) != 0)) {
@@ -149,6 +219,21 @@ int session_free(struct iscsi_session *session)
        if (session->scst_sess != NULL)
                scst_unregister_session(session->scst_sess, 1, NULL);
 
+       if (session->sess_reinst_successor != NULL)
+               sess_enable_reinstated_sess(session->sess_reinst_successor);
+
+       if (session->sess_reinstating) {
+               struct iscsi_session *s;
+               TRACE_MGMT_DBG("Freeing being reinstated sess %p", session);
+               list_for_each_entry(s, &session->target->session_list,
+                                               session_list_entry) {
+                       if (s->sess_reinst_successor == session) {
+                               s->sess_reinst_successor = NULL;
+                               break;
+                       }
+               }
+       }
+
        list_del(&session->session_list_entry);
 
        kfree(session->initiator_name);
@@ -183,10 +268,10 @@ static void iscsi_session_info_show(struct seq_file *seq,
 
        list_for_each_entry(session, &target->session_list,
                            session_list_entry) {
-               seq_printf(seq, "\tsid:%llx initiator:%s shutting down %d\n",
+               seq_printf(seq, "\tsid:%llx initiator:%s reinstating %d\n",
                        (long long unsigned int)session->sid,
                        session->initiator_name,
-                       session->shutting_down);
+                       session->sess_reinstating);
                conn_info_show(seq, session);
        }
        return;
index 483ef65..a6d8dd3 100644 (file)
@@ -28,32 +28,6 @@ static LIST_HEAD(target_list);
 static u32 next_target_id;
 static u32 nr_targets;
 
-static struct iscsi_sess_param default_session_param = {
-       .initial_r2t = 1,
-       .immediate_data = 1,
-       .max_connections = 1,
-       .max_recv_data_length = 8192,
-       .max_xmit_data_length = 8192,
-       .max_burst_length = 262144,
-       .first_burst_length = 65536,
-       .default_wait_time = 2,
-       .default_retain_time = 20,
-       .max_outstanding_r2t = 1,
-       .data_pdu_inorder = 1,
-       .data_sequence_inorder = 1,
-       .error_recovery_level = 0,
-       .header_digest = DIGEST_NONE,
-       .data_digest = DIGEST_NONE,
-       .ofmarker = 0,
-       .ifmarker = 0,
-       .ofmarkint = 2048,
-       .ifmarkint = 2048,
-};
-
-static struct iscsi_trgt_param default_target_param = {
-       .queued_cmnds = DEFAULT_NR_QUEUED_CMNDS,
-};
-
 /* target_mgmt_mutex supposed to be locked */
 struct iscsi_target *target_lookup_by_id(u32 id)
 {
@@ -79,7 +53,7 @@ static struct iscsi_target *target_lookup_by_name(char *name)
 }
 
 /* target_mgmt_mutex supposed to be locked */
-static int iscsi_target_create(struct target_info *info, u32 tid)
+static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid)
 {
        int err = -EINVAL, len;
        char *name = info->name;
@@ -106,11 +80,6 @@ static int iscsi_target_create(struct target_info *info, u32 tid)
 
        target->tid = info->tid = tid;
 
-       memcpy(&target->trgt_sess_param, &default_session_param,
-               sizeof(default_session_param));
-       memcpy(&target->trgt_param, &default_target_param,
-               sizeof(default_target_param));
-
        strncpy(target->name, name, sizeof(target->name) - 1);
 
        mutex_init(&target->target_mutex);
@@ -123,7 +92,7 @@ static int iscsi_target_create(struct target_info *info, u32 tid)
                goto out_free;
        }
 
-       list_add(&target->target_list_entry, &target_list);
+       list_add_tail(&target->target_list_entry, &target_list);
 
        return 0;
 
@@ -138,7 +107,7 @@ out:
 }
 
 /* target_mgmt_mutex supposed to be locked */
-int target_add(struct target_info *info)
+int target_add(struct iscsi_kern_target_info *info)
 {
        int err = -EEXIST;
        u32 tid = info->tid;
@@ -215,15 +184,13 @@ out:
        return err;
 }
 
-static void target_del_session(struct iscsi_target *target,
-       struct iscsi_session *session, bool deleting)
+void target_del_session(struct iscsi_target *target,
+       struct iscsi_session *session, int flags)
 {
-       int flags = ISCSI_CONN_ACTIVE_CLOSE;
+       TRACE_ENTRY();
 
-       if (deleting)
-               flags |= ISCSI_CONN_DELETING;
+       TRACE_MGMT_DBG("Deleting session %p", session);
 
-       TRACE_MGMT_DBG("Cleaning up session %p", session);
        if (!list_empty(&session->conn_list)) {
                struct iscsi_conn *conn, *tc;
                list_for_each_entry_safe(conn, tc, &session->conn_list,
@@ -236,10 +203,13 @@ static void target_del_session(struct iscsi_target *target,
                               session);
                session_del(target, session->sid);
        }
+
+       TRACE_EXIT();
+       return;
 }
 
 /* target_mutex supposed to be locked */
-void target_del_all_sess(struct iscsi_target *target, bool deleting)
+void target_del_all_sess(struct iscsi_target *target, int flags)
 {
        struct iscsi_session *session, *ts;
 
@@ -249,7 +219,7 @@ void target_del_all_sess(struct iscsi_target *target, bool deleting)
                TRACE_MGMT_DBG("Deleting all sessions from target %p", target);
                list_for_each_entry_safe(session, ts, &target->session_list,
                                                session_list_entry) {
-                       target_del_session(target, session, deleting);
+                       target_del_session(target, session, flags);
                }
        }
 
@@ -276,7 +246,9 @@ void target_del_all(void)
                                         target_list_entry) {
                        mutex_lock(&target->target_mutex);
                        if (!list_empty(&target->session_list)) {
-                               target_del_all_sess(target, true);
+                               target_del_all_sess(target,
+                                       ISCSI_CONN_ACTIVE_CLOSE |
+                                       ISCSI_CONN_DELETING);
                                mutex_unlock(&target->target_mutex);
                        } else {
                                TRACE_MGMT_DBG("Deleting target %p", target);
index 24605da..9710bb1 100644 (file)
@@ -21,8 +21,11 @@ OBJS_D = $(SRCS_D:.c=.o)
 SRCS_ADM = iscsi_adm.c param.c
 OBJS_ADM = $(SRCS_ADM:.c=.o)
 
-CFLAGS += -O2 -fno-inline -Wall -Wstrict-prototypes -g -I../include
+CFLAGS += -O2 -fno-inline -Wall -Wextra -Wstrict-prototypes -Wno-sign-compare \
+       -Werror=implicit-function-declaration -Wno-unused-parameter \
+       -Wno-missing-field-initializers -g -I../include
 CFLAGS += -D_GNU_SOURCE # required for glibc >= 2.8
+
 PROGRAMS = iscsi-scstd iscsi-scst-adm
 LIBS = -lcrypto
 
index a1a82bd..f5c2296 100644 (file)
@@ -31,101 +31,46 @@ struct connection *conn_alloc(void)
 {
        struct connection *conn;
 
-       if (!(conn = malloc(sizeof(*conn))))
-               return NULL;
+       conn = malloc(sizeof(*conn));
+       if (conn == NULL)
+               goto out;
 
        memset(conn, 0, sizeof(*conn));
        conn->state = STATE_FREE;
        param_set_defaults(conn->session_param, session_keys);
        INIT_LIST_HEAD(&conn->rsp_buf_list);
 
+out:
        return conn;
 }
 
 void conn_free(struct connection *conn)
 {
+       remque(&conn->clist);
        free(conn->initiator);
        free(conn->user);
        free(conn);
+       return;
 }
 
-int conn_test(struct connection *conn)
-{
-       FILE *f;
-       char buf[8192], *p;
-       u32 tid, t_tid, cid, t_cid;
-       u64 sid, t_sid;
-       int err = -ENOENT, find = 0;
-
-       t_tid = conn->tid;
-       t_sid = conn->session->sid.id64;
-       t_cid = conn->cid;
-
-       if ((f = fopen(PROC_SESSION, "r")) == NULL) {
-               fprintf(stderr, "Can't open %s\n", PROC_SESSION);
-               return -errno;
-       }
-
-       while (fgets(buf, sizeof(buf), f)) {
-               p = buf;
-               while (isspace((int) *p))
-                       p++;
-
-               if (!strncmp(p, "tid:", 4)) {
-                       if (sscanf(p, "tid:%u", &tid) != 1) {
-                               err = -EIO;
-                               goto out;
-                       }
-                       if (tid == t_tid)
-                               find = 1;
-                       else
-                               find = 0;
-               } else if (!strncmp(p, "sid:", 4)) {
-                       if (!find)
-                               continue;
-                       if (sscanf(p, "sid:%" SCNu64, &sid) != 1) {
-                               err = -EIO;
-                               goto out;
-                       }
-
-                       if (sid == t_sid)
-                               find = 1;
-                       else
-                               find = 0;
-               } else if (!strncmp(p, "cid:", 4)) {
-                       if (!find)
-                               continue;
-                       if (sscanf(p, "cid:%u", &cid) != 1) {
-                               err = -EIO;
-                               goto out;
-                       }
-
-                       if (cid == t_cid) {
-                               err = 0;
-                               goto out;
-                       }
-               }
-       }
-
-out:
-       fclose(f);
-
-       return err;
-}
-
-void conn_take_fd(struct connection *conn, int fd)
+void conn_pass_to_kern(struct connection *conn, int fd)
 {
        int err;
-       log_debug(1, "conn_take_fd: %d %u %u %u %" PRIx64,
-                 fd, conn->cid, conn->stat_sn, conn->exp_stat_sn, conn->sid.id64);
 
-       conn->session->conn_cnt++;
+       log_debug(1, "fd %d, cid %u, stat_sn %u, exp_stat_sn %u sid%" PRIx64,
+               fd, conn->cid, conn->stat_sn, conn->exp_stat_sn, conn->sid.id64);
 
-       err = ki->conn_create(conn->tid, conn->session->sid.id64, conn->cid,
+       err = kernel_conn_create(conn->tid, conn->sess->sid.id64, conn->cid,
                              conn->stat_sn, conn->exp_stat_sn, fd,
                              conn->session_param[key_header_digest].val,
                              conn->session_param[key_data_digest].val);
 
+       if (err == 0)
+               conn->sess->kern_conn_cnt++;
+       else
+               log_error("kernel_conn_create() failed: %s", strerror(errno));
+
+       /* We don't need to return err, because we are going to close conn anyway */
        return;
 }
 
@@ -134,6 +79,7 @@ void conn_read_pdu(struct connection *conn)
        conn->iostate = IOSTATE_READ_BHS;
        conn->buffer = (void *)&conn->req.bhs;
        conn->rwsize = BHS_SIZE;
+       return;
 }
 
 void conn_write_pdu(struct connection *conn)
@@ -142,6 +88,7 @@ void conn_write_pdu(struct connection *conn)
        memset(&conn->rsp, 0, sizeof(conn->rsp));
        conn->buffer = (void *)&conn->rsp.bhs;
        conn->rwsize = BHS_SIZE;
+       return;
 }
 
 void conn_free_rsp_buf_list(struct connection *conn)
@@ -155,6 +102,7 @@ void conn_free_rsp_buf_list(struct connection *conn)
 
        conn->rsp.datasize = 0;
        conn->rsp.data = NULL;
+       return;
 }
 
 void conn_free_pdu(struct connection *conn)
@@ -169,4 +117,5 @@ void conn_free_pdu(struct connection *conn)
                conn->rsp.ahs = NULL;
        }
        conn_free_rsp_buf_list(conn);
+       return;
 }
index 22c0460..f5d6a83 100644 (file)
@@ -34,7 +34,7 @@ struct session_file_operations {
        int (*connection_op) (int fd, u32 tid, u64 sid, u32 cid, void *arg);
 };
 
-static int ctrdev_open(int *max_data_seg_len)
+int kernel_open(int *max_data_seg_len)
 {
        FILE *f;
        char devname[256];
@@ -42,7 +42,7 @@ static int ctrdev_open(int *max_data_seg_len)
        int devn;
        int ctlfd = -1;
        int err;
-       struct iscsi_register_info reg = { 0 };
+       struct iscsi_kern_register_info reg = { 0 };
 
        if (!(f = fopen("/proc/devices", "r"))) {
                perror("Cannot open control path to the driver");
@@ -104,10 +104,10 @@ out_close:
        goto out;
 }
 
-static int iscsi_target_create(u32 *tid, char *name)
+int kernel_target_create(u32 *tid, char *name)
 {
        int err;
-       struct target_info info;
+       struct iscsi_kern_target_info info;
 
        memset(&info, 0, sizeof(info));
 
@@ -122,9 +122,9 @@ static int iscsi_target_create(u32 *tid, char *name)
        return err;
 }
 
-static int iscsi_target_destroy(u32 tid)
+int kernel_target_destroy(u32 tid)
 {
-       struct target_info info;
+       struct iscsi_kern_target_info info;
        int res;
 
        memset(&info, 0, sizeof(info));
@@ -137,10 +137,10 @@ static int iscsi_target_destroy(u32 tid)
        return res;
 }
 
-static int iscsi_conn_destroy(u32 tid, u64 sid, u32 cid)
+int kernel_conn_destroy(u32 tid, u64 sid, u32 cid)
 {
        int err;
-       struct conn_info info;
+       struct iscsi_kern_conn_info info;
 
        info.tid = tid;
        info.sid = sid;
@@ -152,173 +152,14 @@ static int iscsi_conn_destroy(u32 tid, u64 sid, u32 cid)
        return err;
 }
 
-static int __conn_close(int fd, u32 tid, u64 sid, u32 cid, void *arg)
-{
-       return ki->conn_destroy(tid, sid, cid);
-}
-
-static int __target_del(int fd, u32 tid, void *arg)
-{
-       return ki->target_destroy(tid);
-}
-
-static int proc_session_parse(int fd, struct session_file_operations *ops,
-       int op_tid, void *arg)
-{
-       FILE *f;
-       char buf[8192], *p;
-       u32 tid, cid;
-       u64 sid;
-       int err, skip, done = 0;
-
-       if ((f = fopen(PROC_SESSION, "r")) == NULL) {
-               fprintf(stderr, "Can't open %s\n", PROC_SESSION);
-               return errno;
-       }
-
-       skip = 0;
-       while (fgets(buf, sizeof(buf), f)) {
-               p = buf;
-               while (isspace((int) *p))
-                       p++;
-
-               if (!strncmp(p, "tid:", 4)) {
-                       if (sscanf(p, "tid:%u", &tid) != 1)
-                               break;
-                       if (op_tid != -1) {
-                               if (tid == op_tid)
-                                       skip = 0;
-                               else {
-                                       skip = 1;
-                                       if (done)
-                                               break;
-                                       else
-                                               continue;
-                               }
-                       }
-                       if (ops->target_op)
-                               if ((err = ops->target_op(fd, tid, arg)) < 0)
-                                       goto out;
-                       continue;
-               }
-               if (skip)
-                       continue;
-               if (!strncmp(p, "sid:", 4)) {
-                       if (sscanf(p, "sid:%" SCNu64, &sid) != 1) {
-                               log_error("Unknown %s sid syntax: %s\n", PROC_SESSION, p);
-                               break;
-                       }
-
-                       if (ops->session_op)
-                               if ((err = ops->session_op(fd, tid, sid, arg)) < 0)
-                                       goto out;
-               } else if (!strncmp(p, "cid:", 4)) {
-                       if (sscanf(p, "cid:%u", &cid) != 1) {
-                               log_error("Unknown %s cid syntax: %s\n", PROC_SESSION, p);
-                               break;
-                       }
-                       if (ops->connection_op)
-                               if ((err = ops->connection_op(fd, tid, sid, cid, arg)) < 0)
-                                       goto out;
-               } else
-                       log_error("Unknown %s string: %s\n", PROC_SESSION, p);
-
-               done = 1;
-       }
-
-       err = 0;
-out:
-       fclose(f);
-
-       return err;
-}
-
-static int session_retry (int fd, u32 tid, u64 sid, void *arg)
-{
-       return -EAGAIN;
-}
-
-static int conn_retry (int fd, u32 tid, u64 sid, u32 cid, void *arg)
-{
-       return -EAGAIN;
-}
-
-static int __sess_cleanup(int fd, u32 tid, void *arg)
-{
-       wait_4_iscsi_event(100);
-       return 0;
-}
-
-static struct session_file_operations conn_close_ops = {
-       .connection_op = __conn_close,
-};
-
-static struct session_file_operations conn_sess_cleanup_ops = {
-       .target_op = __sess_cleanup,
-};
-
-static struct session_file_operations shutdown_wait_ops = {
-       .session_op = session_retry,
-       .connection_op = conn_retry,
-};
-
-static struct session_file_operations target_del_ops = {
-       .target_op = __target_del,
-};
-
-int target_destroy(u32 tid)
-{
-       int err;
-
-       conn_blocked = 1;
-
-       proc_session_parse(ctrl_fd, &conn_close_ops, tid, NULL);
-
-       while (proc_session_parse(ctrl_fd, &shutdown_wait_ops, tid, NULL) < 0) {
-               sleep(1);
-       }
-       proc_session_parse(ctrl_fd, &conn_sess_cleanup_ops, tid, NULL);
-
-       err = proc_session_parse(ctrl_fd, &target_del_ops, tid, NULL);
-
-       conn_blocked = 0;
-
-       return err;
-}
-
 struct session_conn_close_arg {
        u64 sid;
 };
 
-static int session_conn_close(int fd, u32 tid, u64 sid, u32 cid, void *opaque)
-{
-       struct session_conn_close_arg *arg = (struct session_conn_close_arg *) opaque;
-       int err;
-
-       if (arg->sid == sid)
-               err = ki->conn_destroy(tid, sid, cid);
-
-       return 0;
-}
-
-struct session_file_operations session_conns_close_ops = {
-       .connection_op = session_conn_close,
-};
-
-int session_conns_close(u32 tid, u64 sid)
-{
-       int err;
-       struct session_conn_close_arg arg = {sid};
-
-       err = proc_session_parse(ctrl_fd, &session_conns_close_ops, tid, &arg);
-
-       return err;
-}
-
-static int iscsi_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param)
+int kernel_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param)
 {
        int err, i;
-       struct iscsi_param_info info;
+       struct iscsi_kern_param_info info;
 
        memset(&info, 0, sizeof(info));
        info.tid = tid;
@@ -341,11 +182,11 @@ static int iscsi_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param
        return err;
 }
 
-static int iscsi_param_set(u32 tid, u64 sid, int type, u32 partial,
+int kernel_param_set(u32 tid, u64 sid, int type, u32 partial,
        struct iscsi_param *param)
 {
        int i, err;
-       struct iscsi_param_info info;
+       struct iscsi_kern_param_info info;
 
        memset(&info, 0, sizeof(info));
        info.tid = tid;
@@ -369,10 +210,10 @@ static int iscsi_param_set(u32 tid, u64 sid, int type, u32 partial,
        return err;
 }
 
-static int iscsi_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
+int kernel_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
        char *name, char *user)
 {
-       struct session_info info;
+       struct iscsi_kern_session_info info;
        int res;
 
        memset(&info, 0, sizeof(info));
@@ -390,9 +231,9 @@ static int iscsi_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
        return res;
 }
 
-static int iscsi_session_destroy(u32 tid, u64 sid)
+int kernel_session_destroy(u32 tid, u64 sid)
 {
-       struct session_info info;
+       struct iscsi_kern_session_info info;
        int res;
 
        memset(&info, 0, sizeof(info));
@@ -410,10 +251,10 @@ static int iscsi_session_destroy(u32 tid, u64 sid)
        return res;
 }
 
-static int iscsi_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_stat_sn,
+int kernel_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_stat_sn,
                             int fd, u32 hdigest, u32 ddigest)
 {
-       struct conn_info info;
+       struct iscsi_kern_conn_info info;
        int res;
 
        memset(&info, 0, sizeof(info));
@@ -433,17 +274,3 @@ static int iscsi_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_sta
 
        return res;
 }
-
-struct iscsi_kernel_interface ioctl_ki = {
-       .ctldev_open = ctrdev_open,
-       .param_get = iscsi_param_get,
-       .param_set = iscsi_param_set,
-       .target_create = iscsi_target_create,
-       .target_destroy = iscsi_target_destroy,
-       .session_create = iscsi_session_create,
-       .session_destroy = iscsi_session_destroy,
-       .conn_create = iscsi_conn_create,
-       .conn_destroy = iscsi_conn_destroy,
-};
-
-struct iscsi_kernel_interface *ki = &ioctl_ki;
index 539f329..ec6bf40 100644 (file)
@@ -80,7 +80,7 @@ static int nl_read(int fd, void *data, int len)
 void handle_iscsi_events(int fd)
 {
        struct session *session;
-       struct iscsi_event event;
+       struct iscsi_kern_event event;
        int res;
 
 retry:
@@ -103,8 +103,9 @@ retry:
                        goto retry;
                }
 
-               if (!--session->conn_cnt)
-                       session_remove(session);
+               session->kern_conn_cnt--;
+               if ((session->kern_conn_cnt == 0) && list_empty(&session->conn_list))
+                       session_free(session);
                break;
        default:
                log_warning("%s(%d) %u\n", __FUNCTION__, __LINE__, event.state);
index b300d05..9720dac 100644 (file)
@@ -208,39 +208,75 @@ static void create_listen_socket(struct pollfd *array)
 
 static void accept_connection(int listen)
 {
-       struct sockaddr_storage from;
+       struct sockaddr_storage from, to;
+       char portal[50]; /* for full IP6 address + port */
        socklen_t namesize;
        struct pollfd *pollfd;
        struct connection *conn;
-       int fd, i;
+       int fd, i, rc;
 
        namesize = sizeof(from);
-       if ((fd = accept(listen, (struct sockaddr *) &from, &namesize)) < 0) {
-               if (errno != EINTR && errno != EAGAIN) {
+       if ((fd = accept(listen, (struct sockaddr *)&from, &namesize)) < 0) {
+               switch (errno) {
+               case EINTR:
+               case EAGAIN:
+               case ENETDOWN:
+               case EPROTO:
+               case ENOPROTOOPT:
+               case EHOSTDOWN:
+               case ENONET:
+               case EHOSTUNREACH:
+               case EOPNOTSUPP:
+               case ENETUNREACH:
+                       break;
+               default:
                        perror("accept(incoming_socket) failed");
                        exit(1);
                }
-               return;
+               goto out;
+       }
+
+       namesize = sizeof(to);
+       rc = getsockname(fd, (struct sockaddr *)&to, &namesize);
+       if (rc == 0) {
+               if (from.ss_family == AF_INET) {
+                       struct sockaddr_in *in = (struct sockaddr_in *)&to;
+                       rc = snprintf(portal, sizeof(portal), "%s:%hu",
+                               inet_ntoa(in->sin_addr), ntohs(in->sin_port));
+               } else if (from.ss_family == AF_INET6) {
+                       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&to;
+                       rc = snprintf(portal, sizeof(portal), "%x:%x:%x:%x:%x:%x:%x:%x.%hu",
+                               in6->sin6_addr.s6_addr16[7], in6->sin6_addr.s6_addr16[6],
+                               in6->sin6_addr.s6_addr16[5], in6->sin6_addr.s6_addr16[4],
+                               in6->sin6_addr.s6_addr16[3], in6->sin6_addr.s6_addr16[2],
+                               in6->sin6_addr.s6_addr16[1], in6->sin6_addr.s6_addr16[0],
+                               ntohs(in6->sin6_port));
+               }
+               if (rc >= sizeof(portal))
+                       log_error("portal too small %zu (needed %d)", sizeof(portal), rc);
+       } else {
+               portal[0] = '\0';
+               perror("getsockname() failed");
+               goto out_close;
        }
 
        if (from.ss_family == AF_INET) {
                struct sockaddr_in *in = (struct sockaddr_in *)&from;
-               log_info("Connect from %s:%hu", inet_ntoa(in->sin_addr),
-                       ntohs(in->sin_port));
+               log_info("Connect from %s:%hu to %s", inet_ntoa(in->sin_addr),
+                       ntohs(in->sin_port), portal);
        } else if (from.ss_family == AF_INET6) {
                struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&from;
-               log_info("Connect from %x:%x:%x:%x:%x:%x:%x:%x.%hu",
+               log_info("Connect from %x:%x:%x:%x:%x:%x:%x:%x.%hu to %s",
                        in6->sin6_addr.s6_addr16[7], in6->sin6_addr.s6_addr16[6],
                        in6->sin6_addr.s6_addr16[5], in6->sin6_addr.s6_addr16[4],
                        in6->sin6_addr.s6_addr16[3], in6->sin6_addr.s6_addr16[2],
                        in6->sin6_addr.s6_addr16[1], in6->sin6_addr.s6_addr16[0],
-                        ntohs(in6->sin6_port));
+                       ntohs(in6->sin6_port), portal);
        }
 
        if (conn_blocked) {
-               log_warning("A connection refused\n");
-               close(fd);
-               return;
+               log_warning("Connection refused due to blocking\n");
+               goto out_close;
        }
 
        for (i = 0; i < INCOMING_MAX; i++) {
@@ -248,14 +284,15 @@ static void accept_connection(int listen)
                        break;
        }
        if (i >= INCOMING_MAX) {
-               log_error("unable to find incoming slot? %d\n", i);
-               exit(1);
+               log_error("Unable to find incoming slot? %d\n", i);
+               goto out_close;
        }
 
        if (!(conn = conn_alloc())) {
-               log_error("fail to allocate %s", "conn\n");
-               exit(1);
+               log_error("Fail to allocate %s", "conn\n");
+               goto out_close;
        }
+
        conn->fd = fd;
        incoming[i] = conn;
        conn_read_pdu(conn);
@@ -269,6 +306,13 @@ static void accept_connection(int listen)
        incoming_cnt++;
        if (incoming_cnt >= INCOMING_MAX)
                poll_array[POLL_LISTEN].events = 0;
+
+out:
+       return;
+
+out_close:
+       close(fd);
+       goto out;
 }
 
 static void __set_fd(int idx, int fd)
@@ -396,7 +440,7 @@ static void event_conn(struct connection *conn, struct pollfd *pollfd)
 
                        switch (conn->state) {
                        case STATE_KERNEL:
-                               conn_take_fd(conn, pollfd->fd);
+                               conn_pass_to_kern(conn, pollfd->fd);
                                conn->state = STATE_CLOSE;
                                break;
                        case STATE_EXIT:
@@ -522,7 +566,7 @@ static void event_loop(int timeout)
                        event_conn(conn, pollfd);
 
                        if (conn->state == STATE_CLOSE) {
-                               log_debug(0, "connection closed");
+                               log_debug(0, "closing conn %p", conn);
                                conn_free_pdu(conn);
                                conn_free(conn);
                                close(pollfd->fd);
@@ -536,33 +580,33 @@ static void event_loop(int timeout)
 
 void init_max_data_seg_len(int max_data_seg_len)
 {
-       if ((session_keys[3].local_def != -1) ||
-           (session_keys[3].max != -1) ||
-           (session_keys[4].local_def != -1) ||
-           (session_keys[4].max != -1) ||
-           (session_keys[5].local_def != -1) ||
-           (session_keys[5].max != -1) ||
-           (session_keys[6].local_def != -1) ||
-           (session_keys[6].max != -1)) {
+       if ((session_keys[key_max_recv_data_length].local_def != -1) ||
+           (session_keys[key_max_recv_data_length].max != -1) ||
+           (session_keys[key_max_xmit_data_length].local_def != -1) ||
+           (session_keys[key_max_xmit_data_length].max != -1) ||
+           (session_keys[key_max_burst_length].local_def != -1) ||
+           (session_keys[key_max_burst_length].max != -1) ||
+           (session_keys[key_first_burst_length].local_def != -1) ||
+           (session_keys[key_first_burst_length].max != -1)) {
                log_error("Wrong session_keys initialization");
                exit(-1);
        }
 
        /* MaxRecvDataSegmentLength */
-       session_keys[3].local_def = max_data_seg_len;
-       session_keys[3].max = max_data_seg_len;
+       session_keys[key_max_recv_data_length].local_def = max_data_seg_len;
+       session_keys[key_max_recv_data_length].max = max_data_seg_len;
 
        /* MaxXmitDataSegmentLength */
-       session_keys[4].local_def = max_data_seg_len;
-       session_keys[4].max = max_data_seg_len;
+       session_keys[key_max_xmit_data_length].local_def = max_data_seg_len;
+       session_keys[key_max_xmit_data_length].max = max_data_seg_len;
 
        /* MaxBurstLength */
-       session_keys[5].local_def = max_data_seg_len;
-       session_keys[5].max = max_data_seg_len;
+       session_keys[key_max_burst_length].local_def = max_data_seg_len;
+       session_keys[key_max_burst_length].max = max_data_seg_len;
 
        /* FirstBurstLength */
-       session_keys[6].local_def = max_data_seg_len;
-       session_keys[6].max = max_data_seg_len;
+       session_keys[key_first_burst_length].local_def = max_data_seg_len;
+       session_keys[key_first_burst_length].max = max_data_seg_len;
 
        return;
 }
@@ -607,6 +651,10 @@ int main(int argc, char **argv)
                        break;
                case 'a':
                        server_address = strdup(optarg);
+                       if (server_address == NULL) {
+                               perror("strdup failed");
+                               exit(-1);
+                       }
                        break;
                case 'p':
                        server_port = (uint16_t)strtoul(optarg, NULL, 0);
@@ -629,7 +677,7 @@ int main(int argc, char **argv)
                exit(-1);
        };
 
-       if ((ctrl_fd = ki->ctldev_open(&max_data_seg_len)) < 0)
+       if ((ctrl_fd = kernel_open(&max_data_seg_len)) < 0)
                exit(-1);
 
        init_max_data_seg_len(max_data_seg_len);
index 6a6b4a8..3304a12 100644 (file)
@@ -241,44 +241,82 @@ static void text_scan_security(struct connection *conn)
                rsp->status_detail = ISCSI_STATUS_AUTH_FAILED;
                conn->state = STATE_EXIT;
        }
+       return;
 }
 
-static void login_security_done(struct connection *conn)
+static int login_check_reinstatement(struct connection *conn)
 {
-       int err;
        struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
        struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
        struct session *session;
+       int res = 0;
 
-       if (!conn->tid)
-               return;
+       /*
+        * We only check here to catch errors earlier. Actual session/connection
+        * reinstatement, if necessary, will be done in the kernel.
+        */
+
+       sBUG_ON(conn->sess != NULL);
 
-       if ((session = session_find_name(conn->tid, conn->initiator, req->sid))) {
-               if (!req->sid.id.tsih) {
-                       /* do session reinstatement */
-                       session_conns_close(conn->tid, session->sid.id64);
-                       session = NULL;
+       session = session_find_name(conn->tid, conn->initiator, req->sid);
+       if (session != NULL) {
+               if (req->sid.id.tsih == 0) {
+                       /* Kernel will do session reinstatement */
+                       log_debug(1, "Session sid %#" PRIx64 " reinstatement "
+                               "detected (tid %d, initiator %s)", req->sid.id64,
+                               conn->tid, conn->initiator);
                } else if (req->sid.id.tsih != session->sid.id.tsih) {
-                       /* fail the login */
+                       log_error("TSIH for existing session sid %#" PRIx64
+                               ") doesn't match (tid %d, initiator %s, sid requested "
+                               "%#" PRIx64, session->sid.id64, conn->tid,
+                               conn->initiator, req->sid.id64);
+                       /* Fail the login */
                        rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
                        rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
                        conn->state = STATE_EXIT;
-                       return;
-               } else if ((err = conn_test(conn)) == -ENOENT) {
-                       /* do connection reinstatement */
+                       res = -1;
+                       goto out;
+               } else {
+                       struct connection *c = conn_find(session, conn->cid);
+                       if (c != NULL) {
+                               /* Kernel will do connection reinstatement */
+                               log_debug(1, "Conn %x reinstatement "
+                                       "detected (tid %d, sid %#" PRIx64
+                                       "initiator %s)", conn->cid, conn->tid,
+                                       req->sid.id64, conn->initiator);
+                               conn->sess = session;
+                               insque(&conn->clist, &session->conn_list);
+                       } else {
+                               log_error("Only a single connection supported "
+                                       "(initiator %s)", conn->initiator);
+                               /* Fail the login */
+                               rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
+                               rsp->status_detail = ISCSI_STATUS_TOO_MANY_CONN;
+                               conn->state = STATE_EXIT;
+                               res = -1;
+                               goto out;
+                       }
                }
-               /* add a new connection to the session */
-               conn->session = session;
        } else {
-               if (req->sid.id.tsih) {
-                       /* fail the login */
+               if (req->sid.id.tsih != 0) {
+                       log_error("Requested TSIH not 0 (TSIH %d, tid %d, "
+                               "initiator %s, sid requisted %#" PRIx64 ")",
+                               req->sid.id.tsih, conn->tid, conn->initiator,
+                               req->sid.id64);
+                       /* Fail the login */
                        rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
                        rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
                        conn->state = STATE_EXIT;
-                       return;
-               }
-               /* instantiate a new session */
+                       res = -1;
+                       goto out;
+               } else
+                       log_debug(1, "New session sid %#" PRIx64 "(tid %d, "
+                               "initiator %s)", req->sid.id64,
+                               conn->tid, conn->initiator);
        }
+
+out:
+       return res;
 }
 
 static void text_scan_login(struct connection *conn)
@@ -429,7 +467,16 @@ static void login_start(struct connection *conn)
                conn->state = STATE_EXIT;
                return;
        }
+
        conn->initiator = strdup(name);
+       if (conn->initiator == NULL) {
+               log_error("Unable to dublicate initiator's name %s", name);
+               rsp->status_class = ISCSI_STATUS_TARGET_ERR;
+               rsp->status_detail = ISCSI_STATUS_NO_RESOURCES;
+               conn->state = STATE_EXIT;
+               return;
+       }
+
        alias = text_key_find(conn, "InitiatorAlias");
        session_type = text_key_find(conn, "SessionType");
        target_name = text_key_find(conn, "TargetName");
@@ -465,34 +512,34 @@ static void login_start(struct connection *conn)
                        return;
                }
 
-               if (ki->param_get(conn->tid, 0, key_session,
-                               conn->session_param))  {
-                       rsp->status_class = ISCSI_STATUS_TARGET_ERROR;
-                       rsp->status_detail = ISCSI_STATUS_SVC_UNAVAILABLE;
-                       conn->state = STATE_EXIT;
-               }
+               if (login_check_reinstatement(conn) != 0)
+                       return;
        }
+
        conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
-       log_debug(1, "exp_cmd_sn: %d,%d", conn->exp_cmd_sn, req->cmd_sn);
+       log_debug(1, "exp_cmd_sn %u, cmd_sn %u", conn->exp_cmd_sn, req->cmd_sn);
        text_key_add(conn, "TargetPortalGroupTag", "1");
+       return;
 }
 
-static void login_finish(struct connection *conn)
+static int login_finish(struct connection *conn)
 {
+       int res = 0;
+
        switch (conn->session_type) {
        case SESSION_NORMAL:
-       {
-               
-               if (!conn->session)
-                       session_create(conn);
-               conn->sid = conn->session->sid;
+               if (!conn->sess)
+                       res = session_create(conn);
+               if (res == 0)
+                       conn->sid = conn->sess->sid;
                break;
-       }
        case SESSION_DISCOVERY:
                /* set a dummy tsih value */
                conn->sid.id.tsih = 1;
                break;
        }
+
+       return res;
 }
 
 static void cmnd_reject(struct connection *conn, u8 reason)
@@ -649,7 +696,6 @@ static void cmnd_exec_login(struct connection *conn)
                        case STATE_SECURITY:
                        case STATE_SECURITY_DONE:
                                conn->state = STATE_SECURITY_LOGIN;
-                               login_security_done(conn);
                                break;
                        default:
                                goto init_err;
@@ -665,7 +711,6 @@ static void cmnd_exec_login(struct connection *conn)
                                        break;
                                }
                                conn->state = STATE_SECURITY_FULL;
-                               login_security_done(conn);
                                break;
                        case STATE_LOGIN:
                                if (stay)
@@ -677,8 +722,14 @@ static void cmnd_exec_login(struct connection *conn)
                                goto init_err;
                        }
                        if (!stay && !nsg_disagree) {
+                               int err;
                                text_check_param(conn);
-                               login_finish(conn);
+                               err = login_finish(conn);
+                               if (err != 0) {
+                                       log_debug(1, "login_finish() failed: %d", err);
+                                       /* Make initiator retry later */
+                                       goto tgt_no_mem;
+                               }
                        }
                        break;
                default:
@@ -724,6 +775,13 @@ target_err:
        rsp->status_detail = ISCSI_STATUS_TARGET_ERROR;
        conn->state = STATE_EXIT;
        return;
+
+tgt_no_mem:
+       rsp->flags = 0;
+       rsp->status_class = ISCSI_STATUS_TARGET_ERR;
+       rsp->status_detail = ISCSI_STATUS_NO_RESOURCES;
+       conn->state = STATE_EXIT;
+       return;
 }
 
 static void text_scan_text(struct connection *conn)
index 52d484f..b96b955 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <search.h>
 #include <sys/types.h>
+#include <assert.h>
 
 #include "types.h"
 #include "iscsi_hdr.h"
@@ -27,7 +28,8 @@
 #include "config.h"
 #include "misc.h"
 
-#define PROC_SESSION   "/proc/scsi_tgt/iscsi/session"
+#define sBUG() assert(0)
+#define sBUG_ON(p) assert(!(p))
 
 struct buf_segment {
        struct __qelem entry;
@@ -56,7 +58,8 @@ struct session {
        struct target *target;
        union iscsi_sid sid;
 
-       int conn_cnt;
+       int kern_conn_cnt;
+       struct __qelem conn_list;
 };
 
 struct connection {
@@ -64,7 +67,7 @@ struct connection {
        int iostate;
        int fd;
 
-       struct session *session;
+       struct session *sess;
 
        u32 tid;
        struct iscsi_param session_param[session_key_last];
@@ -100,6 +103,8 @@ struct connection {
                        unsigned char *challenge;
                } chap;
        } auth;
+
+       struct __qelem clist;
 };
 
 #define IOSTATE_FREE           0
@@ -138,6 +143,11 @@ struct connection {
 
 #define BHS_SIZE               48
 
+/*
+ * Must be 8192, since it used as MaxRecvDataSegmentLength during Login phase,
+ * because iSCSI RFC requires: "The default MaxRecvDataSegmentLength is used
+ * during Login".
+ */
 #define INCOMING_BUFSIZE       8192
 
 struct target {
@@ -149,9 +159,6 @@ struct target {
        char name[ISCSI_NAME_LEN];
        char *alias;
 
-       int max_nr_sessions;
-       int nr_sessions;
-
        struct __qelem isns_head;
 };
 
@@ -165,8 +172,7 @@ extern int cmnd_exec_auth_chap(struct connection *conn);
 /* conn.c */
 extern struct connection *conn_alloc(void);
 extern void conn_free(struct connection *conn);
-extern int conn_test(struct connection *conn);
-extern void conn_take_fd(struct connection *conn, int fd);
+extern void conn_pass_to_kern(struct connection *conn, int fd);
 extern void conn_read_pdu(struct connection *conn);
 extern void conn_write_pdu(struct connection *conn);
 extern void conn_free_pdu(struct connection *conn);
@@ -209,8 +215,9 @@ extern void __log_pdu(const char *func, int line, int level, struct PDU *pdu);
 /* session.c */
 extern struct session *session_find_name(u32 tid, const char *iname, union iscsi_sid sid);
 extern struct session *session_find_id(u32 tid, u64 sid);
-extern void session_create(struct connection *conn);
-extern void session_remove(struct session *session);
+extern int session_create(struct connection *conn);
+extern void session_free(struct session *session);
+extern struct connection *conn_find(struct session *session, u16 cid);
 
 /* target.c */
 extern struct __qelem targets_list;
@@ -225,23 +232,18 @@ extern int iscsi_adm_request_listen(void);
 extern int iscsi_adm_request_handle(int accept_fd);
 
 /* ctldev.c */
-struct iscsi_kernel_interface {
-       int (*ctldev_open) (int *);
-       int (*param_get) (u32, u64, int, struct iscsi_param *);
-       int (*param_set) (u32, u64, int, u32, struct iscsi_param *);
-       int (*target_create) (u32 *, char *);
-       int (*target_destroy) (u32);
-       int (*session_create) (u32, u64, u32, char *, char *);
-       int (*session_destroy) (u32, u64);
-       int (*conn_create) (u32, u64, u32, u32, u32, int, u32, u32);
-       int (*conn_destroy) (u32 tid, u64 sid, u32 cid);
-};
-
-extern struct iscsi_kernel_interface *ki;
-
-/* the following functions should be killed */
-extern int session_conns_close(u32 tid, u64 sid);
-extern int target_destroy(u32 tid);
+extern int kernel_open(int *max_data_seg_len);
+extern int kernel_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param);
+extern int kernel_param_set(u32 tid, u64 sid, int type, u32 partial,
+       struct iscsi_param *param);
+extern int kernel_target_create(u32 *tid, char *name);
+extern int kernel_target_destroy(u32 tid);
+extern int kernel_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
+       char *name, char *user);
+extern int kernel_session_destroy(u32 tid, u64 sid);
+extern int kernel_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_stat_sn,
+       int fd, u32 hdigest, u32 ddigest);
+extern int kernel_conn_destroy(u32 tid, u64 sid, u32 cid);     
 
 /* event.c */
 extern void handle_iscsi_events(int fd);
index 94b5e7d..a26ead2 100644 (file)
@@ -79,7 +79,7 @@ static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_r
                                              req->u.trgt.target_param);
                break;
        case C_TRGT_SHOW:
-               err = ki->param_get(req->tid, req->sid, key_target,
+               err = kernel_param_get(req->tid, req->sid, key_target,
                                    req->u.trgt.target_param);
                break;
 
@@ -88,14 +88,14 @@ static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_r
        case C_SESS_UPDATE:
                break;
        case C_SESS_SHOW:
-               err = ki->param_get(req->tid, req->sid, key_session,
+               err = kernel_param_get(req->tid, req->sid, key_session,
                                    req->u.trgt.session_param);
                break;
 
        case C_CONN_NEW:
        case C_CONN_DEL:
                conn_blocked = 1;
-               err = ki->conn_destroy(req->tid, req->sid, req->cid);
+               err = kernel_conn_destroy(req->tid, req->sid, req->cid);
                conn_blocked = 0;
                break;
        case C_CONN_UPDATE:
index b677ccf..cad5bf8 100644 (file)
@@ -280,11 +280,19 @@ static struct iscsi_key_ops marker_ops = {
 
 #define        SET_KEY_VALUES(x)       DEFAULT_NR_##x,DEFAULT_NR_##x,MIN_NR_##x,MAX_NR_##x
 
+/*
+ * List of local target keys with initial values.
+ * Must match corresponding key_* enum in iscsi_scst.h!!
+ */
 struct iscsi_key target_keys[] = {
        {"QueuedCommands", SET_KEY_VALUES(QUEUED_CMNDS), &minimum_ops},
        {NULL,},
 };
 
+/*
+ * List of iSCSI RFC specified session keys with initial values.
+ * Must match corresponding key_* enum in iscsi_scst.h!!
+ */
 struct iscsi_key session_keys[] = {
        {"InitialR2T", 1, 0, 0, 1, &or_ops},
        {"ImmediateData", 1, 1, 0, 1, &and_ops},
index 977cfef..20efe3f 100644 (file)
@@ -324,7 +324,7 @@ static int netmask_match_v4(struct sockaddr *sa1, struct sockaddr *sa2, uint32_t
 
 static int netmask_match(struct sockaddr *sa1, struct sockaddr *sa2, char *buf)
 {
-       uint32_t mbit;
+       int32_t mbit;
        uint8_t family = sa1->sa_family;
 
        mbit = strtoul(buf, NULL, 0);
@@ -465,7 +465,6 @@ static int plain_initiator_access(u32 tid, int fd)
 static int __plain_target_create(u32 *tid, char *name, int update)
 {
        int err;
-       struct iscsi_param params[session_key_last];
 
        if (target_find_by_name(name)) {
                log_error("duplicated target %s", name);
@@ -474,13 +473,6 @@ static int __plain_target_create(u32 *tid, char *name, int update)
        if ((err = target_add(tid, name)) < 0)
                return err;
 
-       param_set_defaults(params, session_keys);
-       if ((err = ki->param_set(*tid, 0, key_session, 0, params)) < 0)
-               return err;
-
-       if (update)
-               ; /* Update the config file here. */
-
        return err;
 }
 
@@ -505,12 +497,9 @@ static int __plain_param_set(u32 tid, u64 sid, int type,
 {
        int err;
 
-       if ((err = ki->param_set(tid, sid, type, partial, param)) < 0)
+       if ((err = kernel_param_set(tid, sid, type, partial, param)) < 0)
                return err;
 
-       if (update)
-               ;
-
        return err;
 }
 
index 64c0b45..3567eac 100644 (file)
 
 #include "iscsid.h"
 
-static struct session *session_alloc(u32 tid)
+static int session_alloc(u32 tid, struct session **psess)
 {
        struct session *session;
        struct target *target = target_find_by_id(tid);
+       int res = 0;
+
+       if (!target) {
+               log_error("tid %x not found", tid);
+               res = -ENOENT;
+               goto out;
+       }
+
+       if (!(session = malloc(sizeof(*session)))) {
+               res = -ENOMEM;
+               goto out;
+       }
 
-       if (!target)
-               return NULL;
-       if (!(session = malloc(sizeof(*session))))
-               return NULL;
        memset(session, 0, sizeof(*session));
 
        session->target = target;
        INIT_LIST_HEAD(&session->slist);
        insque(&session->slist, &target->sessions_list);
 
-       return session;
+       *psess = session;
+
+out:
+       return res;
 }
 
 struct session *session_find_name(u32 tid, const char *iname, union iscsi_sid sid)
@@ -49,10 +60,13 @@ struct session *session_find_name(u32 tid, const char *iname, union iscsi_sid si
        struct session *session;
        struct target *target;
 
-       if (!(target = target_find_by_id(tid)))
+       if (!(target = target_find_by_id(tid))) {
+               log_error("Target tid %d not found", tid);
                return NULL;
+       }
+
+       log_debug(1, "Finding session %s, sid %#" PRIx64, iname, sid.id64);
 
-       log_debug(1, "session_find_name: %s %#" PRIx64, iname, sid.id64);
        list_for_each_entry(session, &target->sessions_list, slist) {
                if (!memcmp(sid.id.isid, session->sid.id.isid, 6) &&
                    !strcmp(iname, session->initiator))
@@ -70,7 +84,8 @@ struct session *session_find_id(u32 tid, u64 sid)
        if (!(target = target_find_by_id(tid)))
                return NULL;
 
-       log_debug(1, "session_find_id: %#" PRIx64, sid);
+       log_debug(1, "Searching for sid %#" PRIx64, sid);
+
        list_for_each_entry(session, &target->sessions_list, slist) {
                if (session->sid.id64 == sid)
                        return session;
@@ -79,105 +94,101 @@ struct session *session_find_id(u32 tid, u64 sid)
        return NULL;
 }
 
-static int session_test(u32 t_tid, u64 t_sid)
+int session_create(struct connection *conn)
 {
-       FILE *f;
-       char buf[8192], *p;
-       u32 tid;
-       u64 sid;
-       int err = -ENOENT, find = 0;
-
-       if ((f = fopen(PROC_SESSION, "r")) == NULL) {
-               fprintf(stderr, "Can't open %s\n", PROC_SESSION);
-               return -errno;
-       }
-
-       while (fgets(buf, sizeof(buf), f)) {
-               p = buf;
-               while (isspace((int) *p))
-                       p++;
-
-               if (!strncmp(p, "tid:", 4)) {
-                       if (sscanf(p, "tid:%u", &tid) != 1) {
-                               err = -EIO;
-                               goto out;
-                       }
-                       if (tid == t_tid)
-                               find = 1;
-                       else
-                               find = 0;
-               } else if (!strncmp(p, "sid:", 4)) {
-                       if (!find)
-                               continue;
-                       if (sscanf(p, "sid:%" SCNu64, &sid) != 1) {
-                               err = -EIO;
-                               goto out;
-                       }
-
-                       if (sid == t_sid) {
-                               err = 0;
-                               goto out;
-                       }
-               }
-       }
-
-out:
-       fclose(f);
-
-       return err;
-}
-
-void session_create(struct connection *conn)
-{
-       struct session *session;
+       /* We are single threaded, so it desn't need any protection */
        static u16 tsih = 1;
+       struct session *session;
        char *user;
+       int res = 0;
 
-       if (!(session = session_alloc(conn->tid)))
-               return;
+       res = session_alloc(conn->tid, &session);
+       if (res != 0) {
+               log_error("session_alloc() failed: %d", res);
+               goto out;
+       }
 
        session->sid = conn->sid;
        session->sid.id.tsih = tsih;
+       INIT_LIST_HEAD(&session->conn_list);
+
+       insque(&conn->clist, &session->conn_list);
+       conn->sess = session;
+
+       conn->sess->initiator = strdup(conn->initiator);
+       if (conn->sess->initiator == NULL) {
+               res = -errno;
+               log_error("strdup() failed: %d", res);
+               goto out_free;
+       }
 
        while (1) {
-               int err = session_test(conn->tid, session->sid.id64);
+               struct session *s;
 
-               if (err == -ENOENT)
+               s = session_find_id(conn->tid, session->sid.id64);
+               if (s != NULL)
                        break;
-               else if (err < 0)
-                       return;
+
+               log_debug(1, "tsih %x already exists", session->sid.id.tsih);
                session->sid.id.tsih++;
        }
        tsih = session->sid.id.tsih + 1;
 
-       conn->session = session;
-       conn->session->initiator = strdup(conn->initiator);
-
-       log_debug(1, "session_create: %#" PRIx64, session->sid.id64);
+       log_debug(1, "sid %#" PRIx64, session->sid.id64);
 
        if (conn->user != NULL)
                user = conn->user;
        else
                user = "";
 
-       ki->session_create(conn->tid, session->sid.id64, conn->exp_cmd_sn,
-                          session->initiator, user);
-       ki->param_set(conn->tid, session->sid.id64, key_session, 0,
+       res = kernel_session_create(conn->tid, session->sid.id64, conn->exp_cmd_sn,
+                       session->initiator, user);
+       if (res != 0) {
+               log_error("kernel_session_create() failed: %d", res);
+               goto out_free;
+       }
+
+       res = kernel_param_set(conn->tid, session->sid.id64, key_session, 0,
                conn->session_param);
+       if (res != 0) {
+               log_error("kernel_param_set() failed: %d", res);
+               goto out_destroy;
+       }
+
+out:
+       return res;
+
+out_destroy:
+       kernel_session_destroy(conn->tid, session->sid.id64);
+
+out_free:
+       session_free(session);
+       conn->sess = NULL;
+       goto out;
 }
 
-void session_remove(struct session *session)
+void session_free(struct session *session)
 {
-       log_debug(1, "session_remove: %#"  PRIx64, session->sid.id64);
+       log_debug(1, "Freeing session sid %#"PRIx64, session->sid.id64);
 
        if (!session->sid.id.tsih)
-               ki->session_destroy(session->target->tid, session->sid.id64);
+               kernel_session_destroy(session->target->tid, session->sid.id64);
 
-       if (session->target) {
+       if (session->target)
                remque(&session->slist);
-/*             session->target->nr_sessions--; */
-       }
 
        free(session->initiator);
        free(session);
 }
+
+struct connection *conn_find(struct session *session, u16 cid)
+{
+       struct connection *conn;
+
+       list_for_each_entry(conn, &session->conn_list, clist) {
+               if (conn->cid == cid)
+                       return conn;
+       }
+
+       return NULL;
+}
index 7c540a2..2c31ae4 100644 (file)
@@ -82,7 +82,7 @@ static void all_accounts_del(u32 tid, int dir)
 int target_del(u32 tid)
 {
        struct target *target = target_find_by_id(tid);
-       int err = ki->target_destroy(tid);
+       int err = kernel_target_destroy(tid);
 
        if (err < 0 && errno != ENOENT)
                return -errno;
@@ -114,6 +114,7 @@ int target_add(u32 *tid, char *name)
 {
        struct target *target;
        int err;
+       struct iscsi_param params[target_key_last];
 
        if (!name)
                return -EINVAL;
@@ -124,9 +125,16 @@ int target_add(u32 *tid, char *name)
        memset(target, 0, sizeof(*target));
        memcpy(target->name, name, sizeof(target->name) - 1);
 
-       if ((err = ki->target_create(tid, name)) < 0) {
+       if ((err = kernel_target_create(tid, name)) < 0) {
                log_warning("can't create a target %d %u\n", errno, *tid);
-               goto out;
+               goto out_free;
+       }
+
+       param_set_defaults(params, target_keys);
+       err = kernel_param_set(*tid, 0, key_target, 0, params);
+       if (err != 0) {
+               log_error("kernel_param_set() failed: %s", strerror(errno));
+               goto out_destroy;
        }
 
        INIT_LIST_HEAD(&target->tlist);
@@ -137,8 +145,13 @@ int target_add(u32 *tid, char *name)
 
        isns_target_register(name);
 
-       return 0;
 out:
-       free(target);
        return err;
+
+out_destroy:
+       kernel_target_destroy(*tid);
+
+out_free:
+       free(target);
+       goto out;
 }