From d054d4a77af3e681afdb07b6d460fa5115e05d3f Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Thu, 27 Feb 2014 06:30:33 +0000 Subject: [PATCH] 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 git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5318 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/isert-scst/isert.h | 1 + iscsi-scst/kernel/isert-scst/isert_login.c | 29 ++++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/iscsi-scst/kernel/isert-scst/isert.h b/iscsi-scst/kernel/isert-scst/isert.h index 78223527b..9570f030c 100644 --- a/iscsi-scst/kernel/isert-scst/isert.h +++ b/iscsi-scst/kernel/isert-scst/isert.h @@ -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" diff --git a/iscsi-scst/kernel/isert-scst/isert_login.c b/iscsi-scst/kernel/isert-scst/isert_login.c index 0d6ea579b..0cbfef731 100644 --- a/iscsi-scst/kernel/isert-scst/isert_login.c +++ b/iscsi-scst/kernel/isert-scst/isert_login.c @@ -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 */