isert: Fix case when iscsid is not able to handle login request on time or at all

In some cases, iscsi-scstd chooses to close the connection device and abort the connection.
This can cause invalid device state due to order of isert_conn_dev cleanup and disconnect handling.
Make sure we release isert_conn_dev only after we received disconnect event, or we passed the connection
to the kernel. This also fixes an issue if iscsi-scstd is run on very CPU intensive load and it does not receive
CPU time to serve the login requests. This may get to the extreme of initiator disconnecting before iscsi-scstd
had the chance to handle the login request.

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

git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5318 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Yan Burman
2014-02-27 06:30:33 +00:00
parent 6637df7f0c
commit d054d4a77a
2 changed files with 25 additions and 5 deletions

View File

@@ -115,6 +115,7 @@ struct isert_conn_dev {
int is_discovery;
struct timer_list tmo_timer;
int timer_active;
struct kref kref;
};
#define ISER_CONN_DEV_PREFIX "isert/conn"

View File

@@ -93,15 +93,29 @@ static void isert_del_timer(struct isert_conn_dev *dev)
static void release_dev(struct isert_conn_dev *dev)
{
isert_del_timer(dev);
kref_init(&dev->kref);
spin_lock(&isert_listen_dev.conn_lock);
dev->occupied = 0;
list_del_init(&dev->conn_list_entry);
dev->state = CS_INIT;
atomic_set(&dev->available, 1);
spin_unlock(&isert_listen_dev.conn_lock);
}
static void isert_kref_release_dev(struct kref *kref)
{
struct isert_conn_dev *dev = container_of(kref,
struct isert_conn_dev,
kref);
release_dev(dev);
}
static void isert_dev_release(struct isert_conn_dev *dev)
{
kref_put(&dev->kref, isert_kref_release_dev);
}
static void isert_conn_timer_fn(unsigned long arg)
{
struct isert_conn_dev *conn_dev = (struct isert_conn_dev *)arg;
@@ -233,9 +247,10 @@ int isert_conn_alloc(struct iscsi_session *session,
goto cleanup_iscsi_conn;
#endif
list_add_tail(&conn->conn_list_entry, &session->conn_list);
conn->rd_state = 1;
isert_dev_release(dev);
list_add_tail(&conn->conn_list_entry, &session->conn_list);
res = isert_login_rsp_tx(cmnd, true, false);
vunmap(dev->sg_virt);
dev->sg_virt = NULL;
@@ -335,6 +350,7 @@ static ssize_t isert_listen_read(struct file *filp, char __user *buf,
conn_dev = list_first_entry(&dev->new_conn_list, struct isert_conn_dev,
conn_list_entry);
list_move(&conn_dev->conn_list_entry, &dev->curr_conn_list);
kref_get(&conn_dev->kref);
spin_unlock(&dev->conn_lock);
res = snprintf(k_buff, sizeof(k_buff), "/dev/"ISER_CONN_DEV_PREFIX"%d",
@@ -423,6 +439,7 @@ int isert_connection_closed(struct iscsi_conn *iscsi_conn)
dev->conn = NULL;
wake_up(&dev->waitqueue);
isert_dev_release(dev);
}
isert_free_connection(iscsi_conn);
@@ -480,8 +497,9 @@ static int isert_release(struct inode *inode, struct file *filp)
dev->conn = NULL;
}
release_dev(dev);
atomic_inc(&dev->available);
isert_del_timer(dev);
isert_dev_release(dev);
TRACE_EXIT_RES(res);
return res;
@@ -797,6 +815,7 @@ static void __init isert_setup_cdev(struct isert_conn_dev *dev,
dev->login_rsp = NULL;
spin_lock_init(&dev->pdu_lock);
atomic_set(&dev->available, 1);
kref_init(&dev->kref);
dev->state = CS_INIT;
err = cdev_add(&dev->cdev, dev->devno, 1);
/* Fail gracefully if need be */