From 9049a2dcc43bd13a67ab387b1a7a526fd8b1f5af Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Wed, 28 Jan 2015 13:15:10 +0000 Subject: [PATCH] isert: Fix race between disconnect handler and read by iscsi-scstd (merge r5896 from trunk) git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/3.0.x-iser@6005 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/isert-scst/isert_login.c | 28 ++++++++++------------ 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/iscsi-scst/kernel/isert-scst/isert_login.c b/iscsi-scst/kernel/isert-scst/isert_login.c index fae0963e3..577f83add 100644 --- a/iscsi-scst/kernel/isert-scst/isert_login.c +++ b/iscsi-scst/kernel/isert-scst/isert_login.c @@ -91,29 +91,23 @@ static void isert_del_timer(struct isert_conn_dev *dev) } } -static void release_dev(struct isert_conn_dev *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); + kref_init(&dev->kref); + dev->occupied = 0; + list_del_init(&dev->conn_list_entry); + dev->state = CS_INIT; + atomic_set(&dev->available, 1); } static void isert_dev_release(struct isert_conn_dev *dev) { + spin_lock(&isert_listen_dev.conn_lock); kref_put(&dev->kref, isert_kref_release_dev); + spin_unlock(&isert_listen_dev.conn_lock); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) @@ -338,6 +332,7 @@ static ssize_t isert_listen_read(struct file *filp, char __user *buf, TRACE_ENTRY(); if (!have_new_connection(dev)) { +wait_for_connection: if (filp->f_flags & O_NONBLOCK) return -EAGAIN; res = wait_event_freezable(dev->waitqueue, @@ -346,9 +341,12 @@ static ssize_t isert_listen_read(struct file *filp, char __user *buf, goto out; } - sBUG_ON(list_empty(&dev->new_conn_list)); - spin_lock(&dev->conn_lock); + if (list_empty(&dev->new_conn_list)) { + /* could happen if we got disconnect */ + spin_unlock(&dev->conn_lock); + goto wait_for_connection; + } 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);