isert: Rework disconnect handling

Instead of waiting for TIMEDWAIT event when disconnecting and blocking,
start the disconnect process when TIMEDWAIT event is received
and only perform the actual rdma_disconnect upon disconnect request.
Note that rdma_disconnect can not be called from atomic context, so need
to execute it from workqueue.

Signed-off-by: Yan Burman <yanb@mellanox.com>

git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5317 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Yan Burman
2014-02-27 06:30:26 +00:00
parent 8d6b96edbc
commit 6637df7f0c
7 changed files with 41 additions and 115 deletions

View File

@@ -310,6 +310,7 @@ struct iscsi_conn {
#else
struct work_struct nop_in_delayed_work;
#endif
struct work_struct close_work;
unsigned int nop_in_interval; /* in jiffies */
unsigned int nop_in_timeout; /* in jiffies */
struct list_head nop_req_list;

View File

@@ -102,8 +102,7 @@ struct isert_cq {
int idx;
};
#define ISERT_TIMEWAIT_RECEIVED 0
#define ISERT_CONNECTION_ABORTED 1
#define ISERT_CONNECTION_ABORTED 0
struct isert_connection {
struct iscsi_conn iscsi ____cacheline_aligned;
@@ -157,7 +156,6 @@ struct isert_connection {
struct list_head dev_node;
struct list_head portal_node;
wait_queue_head_t waitQ;
unsigned long flags;
struct work_struct close_work;
struct kref kref;
@@ -227,8 +225,8 @@ int isert_post_send(struct isert_connection *isert_conn,
int isert_alloc_conn_resources(struct isert_connection *isert_conn);
void isert_free_conn_resources(struct isert_connection *isert_conn);
void isert_conn_close(struct isert_connection *isert_conn, int do_flush);
void isert_conn_free(struct isert_connection *isert_conn);
void isert_conn_disconnect(struct isert_connection *isert_conn);
static inline struct isert_connection *isert_conn_alloc(void)
{

View File

@@ -272,7 +272,8 @@ int isert_close_connection(struct iscsi_conn *iscsi_conn)
{
struct isert_connection *isert_conn = (struct isert_connection *)iscsi_conn;
isert_conn_close(isert_conn, 1);
isert_conn_disconnect(isert_conn);
return 0;
}

View File

@@ -118,7 +118,7 @@ int isert_post_send(struct isert_connection *isert_conn,
return err;
}
static void isert_conn_disconnect(struct isert_connection *isert_conn)
void isert_conn_disconnect(struct isert_connection *isert_conn)
{
int err = rdma_disconnect(isert_conn->cm_id);
if (unlikely(err))
@@ -310,7 +310,7 @@ static void isert_recv_completion_handler(struct isert_wr *wr)
if (unlikely(err)) {
pr_err("err:%d while handling iser pdu\n", err);
isert_conn_close(wr->conn, 0);
isert_conn_disconnect(wr->conn);
}
TRACE_EXIT();
@@ -1022,8 +1022,6 @@ static struct isert_connection *isert_conn_create(struct rdma_cm_id *cm_id,
kref_init(&isert_conn->kref);
init_waitqueue_head(&isert_conn->waitQ);
pr_info("iser created connection cm_id:%p\n", cm_id);
TRACE_EXIT();
return isert_conn;
@@ -1045,17 +1043,6 @@ fail_get:
/* start closing process;
* only when all buffers released, can free */
void isert_conn_close(struct isert_connection *isert_conn, int do_flush)
{
isert_conn_disconnect(isert_conn);
if (do_flush) {
wait_event_interruptible(isert_conn->waitQ,
test_bit(ISERT_TIMEWAIT_RECEIVED,
&isert_conn->flags));
flush_workqueue(isert_conn->cq_desc->cq_workqueue);
}
}
static void isert_kref_free(struct kref *kref)
{
struct isert_connection *isert_conn = container_of(kref,
@@ -1068,6 +1055,8 @@ static void isert_kref_free(struct kref *kref)
pr_info("isert_conn_free conn:%p\n", isert_conn);
flush_workqueue(isert_conn->cq_desc->cq_workqueue);
isert_free_conn_resources(isert_conn);
isert_conn_qp_destroy(isert_conn);
@@ -1100,9 +1089,6 @@ static void isert_conn_closed_do_work(struct work_struct *work)
struct isert_connection *isert_conn =
container_of(work, struct isert_connection, close_work);
set_bit(ISERT_TIMEWAIT_RECEIVED, &isert_conn->flags);
wake_up_interruptible(&isert_conn->waitQ);
/* notify upper layer */
if (!test_bit(ISERT_CONNECTION_ABORTED, &isert_conn->flags))
isert_connection_closed(&isert_conn->iscsi);

View File

@@ -52,41 +52,8 @@ module_param(isert_nr_devs, uint, S_IRUGO);
MODULE_PARM_DESC(isert_nr_devs,
"Maximum concurrent number of connection requests to handle.");
static void isert_do_close_conn(struct iscsi_conn *conn)
{
isert_close_connection(conn);
start_close_conn(conn);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static void isert_close_conn_fn(void *ctx)
#else
static void isert_close_conn_fn(struct work_struct *work)
#endif
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
struct isert_close_conn_work *conn_work = ctx;
#else
struct isert_close_conn_work *conn_work = container_of(work,
struct isert_close_conn_work, close_work);
#endif
struct iscsi_conn *conn = conn_work->conn;
/* Take care of case where our connection is being closed
* without being connected to a session - if connection allocation
* failed for some reason */
if (unlikely(!conn->session))
isert_free_connection(conn);
else
isert_do_close_conn(conn);
kfree(conn_work);
}
static void isert_mark_conn_closed(struct iscsi_conn *conn, int flags)
{
struct isert_close_conn_work *conn_work;
TRACE_ENTRY();
if (flags & ISCSI_CONN_ACTIVE_CLOSE)
conn->active_close = 1;
@@ -97,25 +64,9 @@ static void isert_mark_conn_closed(struct iscsi_conn *conn, int flags)
if (!conn->closing) {
conn->closing = 1;
conn_work = kmalloc(sizeof(*conn_work), GFP_ATOMIC);
if (unlikely(!conn_work)) {
PRINT_CRIT_ERROR("Unable to allocate isert_close_conn_work for conn %p\n",
conn);
goto out;
}
conn_work->conn = conn;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
INIT_WORK(&conn_work->close_work, isert_close_conn_fn,
conn_work);
#else
INIT_WORK(&conn_work->close_work, isert_close_conn_fn);
#endif
schedule_work(&conn_work->close_work);
schedule_work(&conn->close_work);
}
out:
TRACE_EXIT();
}
@@ -326,6 +277,13 @@ static void isert_conn_free(struct iscsi_conn *conn)
int isert_handle_close_connection(struct iscsi_conn *conn)
{
isert_mark_conn_closed(conn, 0);
/* Take care of case where our connection is being closed
* without being connected to a session - if connection allocation
* failed for some reason */
if (unlikely(!conn->session))
isert_free_connection(conn);
else
start_close_conn(conn);
return 0;
}

View File

@@ -81,11 +81,6 @@ struct isert_listener_dev {
int free_portal_idx;
};
struct isert_close_conn_work {
struct work_struct close_work;
struct iscsi_conn *conn;
};
enum isert_conn_dev_state {
CS_INIT,
CS_REQ_BHS,

View File

@@ -35,7 +35,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/poll.h>
@@ -103,29 +102,10 @@ static void release_dev(struct isert_conn_dev *dev)
spin_unlock(&isert_listen_dev.conn_lock);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static void isert_login_close_conn_fn(void *ctx)
#else
static void isert_login_close_conn_fn(struct work_struct *work)
#endif
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
struct isert_close_conn_work *conn_work = ctx;
#else
struct isert_close_conn_work *conn_work = container_of(work,
struct isert_close_conn_work, close_work);
#endif
struct iscsi_conn *conn = conn_work->conn;
isert_close_connection(conn);
kfree(conn_work);
}
static void isert_conn_timer_fn(unsigned long arg)
{
struct isert_conn_dev *conn_dev = (struct isert_conn_dev *)arg;
struct isert_close_conn_work *conn_work;
struct iscsi_conn *conn = conn_dev->conn;
TRACE_ENTRY();
@@ -133,23 +113,8 @@ static void isert_conn_timer_fn(unsigned long arg)
PRINT_ERROR("Timeout on connection %p\n", conn_dev->conn);
conn_work = kmalloc(sizeof(*conn_work), GFP_ATOMIC);
if (unlikely(!conn_work)) {
PRINT_CRIT_ERROR("Unable to allocate isert_close_conn_work for conn %p\n",
conn_dev->conn);
goto out;
}
schedule_work(&conn->close_work);
conn_work->conn = conn_dev->conn;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
INIT_WORK(&conn_work->close_work, isert_login_close_conn_fn,
conn_work);
#else
INIT_WORK(&conn_work->close_work, isert_login_close_conn_fn);
#endif
schedule_work(&conn_work->close_work);
out:
TRACE_EXIT();
}
@@ -191,6 +156,22 @@ static bool have_new_connection(struct isert_listener_dev *dev)
return ret;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static void isert_close_conn_fn(void *ctx)
#else
static void isert_close_conn_fn(struct work_struct *work)
#endif
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
struct iscsi_conn *conn = ctx;
#else
struct iscsi_conn *conn = container_of(work,
struct iscsi_conn, close_work);
#endif
isert_close_connection(conn);
}
int isert_conn_alloc(struct iscsi_session *session,
struct iscsi_kern_conn_info *info,
struct iscsi_conn **new_conn,
@@ -236,6 +217,12 @@ int isert_conn_alloc(struct iscsi_session *session,
conn->transport = t;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
INIT_WORK(&conn->close_work, isert_close_conn_fn, conn);
#else
INIT_WORK(&conn->close_work, isert_close_conn_fn);
#endif
res = iscsi_init_conn(session, info, conn);
if (unlikely(res))
goto cleanup_conn;