aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorSagi Grimberg <sagig@mellanox.com>2014-04-29 06:13:45 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2014-05-15 20:09:10 -0400
commit531b7bf4bd795d9a09eac92504322a472c010bc8 (patch)
tree2dfdac4bae9215493c6c293d9e638a6436bfb526 /drivers/infiniband
parent9fe63c88b1d59f1ce054d6948ccd3096496ecedb (diff)
Target/iser: Fix iscsit_accept_np and rdma_cm racy flow
RDMA CM and iSCSI target flows are asynchronous and completely uncorrelated. Relying on the fact that iscsi_accept_np will be called after CM connection request event and will wait for it is a mistake. When attempting to login to a few targets this flow is racy and unpredictable, but for parallel login to dozens of targets will race and hang every time. The correct synchronizing mechanism in this case is pending on a semaphore rather than a wait_for_event. We keep the pending interruptible for iscsi_np cleanup stage. (Squash patch to remove dead code into parent - nab) Reported-by: Slava Shwartsman <valyushash@gmail.com> Signed-off-by: Sagi Grimberg <sagig@mellanox.com> Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c25
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h2
2 files changed, 7 insertions, 20 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index fda3feb45008..826eaf5741f6 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -28,6 +28,7 @@
28#include <target/target_core_base.h> 28#include <target/target_core_base.h>
29#include <target/target_core_fabric.h> 29#include <target/target_core_fabric.h>
30#include <target/iscsi/iscsi_transport.h> 30#include <target/iscsi/iscsi_transport.h>
31#include <linux/semaphore.h>
31 32
32#include "isert_proto.h" 33#include "isert_proto.h"
33#include "ib_isert.h" 34#include "ib_isert.h"
@@ -666,8 +667,8 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
666 list_add_tail(&isert_conn->conn_accept_node, &isert_np->np_accept_list); 667 list_add_tail(&isert_conn->conn_accept_node, &isert_np->np_accept_list);
667 mutex_unlock(&isert_np->np_accept_mutex); 668 mutex_unlock(&isert_np->np_accept_mutex);
668 669
669 pr_debug("isert_connect_request() waking up np_accept_wq: %p\n", np); 670 pr_debug("isert_connect_request() up np_sem np: %p\n", np);
670 wake_up(&isert_np->np_accept_wq); 671 up(&isert_np->np_sem);
671 return 0; 672 return 0;
672 673
673out_conn_dev: 674out_conn_dev:
@@ -2999,7 +3000,7 @@ isert_setup_np(struct iscsi_np *np,
2999 pr_err("Unable to allocate struct isert_np\n"); 3000 pr_err("Unable to allocate struct isert_np\n");
3000 return -ENOMEM; 3001 return -ENOMEM;
3001 } 3002 }
3002 init_waitqueue_head(&isert_np->np_accept_wq); 3003 sema_init(&isert_np->np_sem, 0);
3003 mutex_init(&isert_np->np_accept_mutex); 3004 mutex_init(&isert_np->np_accept_mutex);
3004 INIT_LIST_HEAD(&isert_np->np_accept_list); 3005 INIT_LIST_HEAD(&isert_np->np_accept_list);
3005 init_completion(&isert_np->np_login_comp); 3006 init_completion(&isert_np->np_login_comp);
@@ -3048,18 +3049,6 @@ out:
3048} 3049}
3049 3050
3050static int 3051static int
3051isert_check_accept_queue(struct isert_np *isert_np)
3052{
3053 int empty;
3054
3055 mutex_lock(&isert_np->np_accept_mutex);
3056 empty = list_empty(&isert_np->np_accept_list);
3057 mutex_unlock(&isert_np->np_accept_mutex);
3058
3059 return empty;
3060}
3061
3062static int
3063isert_rdma_accept(struct isert_conn *isert_conn) 3052isert_rdma_accept(struct isert_conn *isert_conn)
3064{ 3053{
3065 struct rdma_cm_id *cm_id = isert_conn->conn_cm_id; 3054 struct rdma_cm_id *cm_id = isert_conn->conn_cm_id;
@@ -3151,16 +3140,14 @@ isert_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
3151 int max_accept = 0, ret; 3140 int max_accept = 0, ret;
3152 3141
3153accept_wait: 3142accept_wait:
3154 ret = wait_event_interruptible(isert_np->np_accept_wq, 3143 ret = down_interruptible(&isert_np->np_sem);
3155 !isert_check_accept_queue(isert_np) ||
3156 np->np_thread_state == ISCSI_NP_THREAD_RESET);
3157 if (max_accept > 5) 3144 if (max_accept > 5)
3158 return -ENODEV; 3145 return -ENODEV;
3159 3146
3160 spin_lock_bh(&np->np_thread_lock); 3147 spin_lock_bh(&np->np_thread_lock);
3161 if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { 3148 if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
3162 spin_unlock_bh(&np->np_thread_lock); 3149 spin_unlock_bh(&np->np_thread_lock);
3163 pr_err("ISCSI_NP_THREAD_RESET for isert_accept_np\n"); 3150 pr_debug("ISCSI_NP_THREAD_RESET for isert_accept_np\n");
3164 return -ENODEV; 3151 return -ENODEV;
3165 } 3152 }
3166 spin_unlock_bh(&np->np_thread_lock); 3153 spin_unlock_bh(&np->np_thread_lock);
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index 4c072ae34c01..da6612e68000 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -182,7 +182,7 @@ struct isert_device {
182}; 182};
183 183
184struct isert_np { 184struct isert_np {
185 wait_queue_head_t np_accept_wq; 185 struct semaphore np_sem;
186 struct rdma_cm_id *np_cm_id; 186 struct rdma_cm_id *np_cm_id;
187 struct mutex np_accept_mutex; 187 struct mutex np_accept_mutex;
188 struct list_head np_accept_list; 188 struct list_head np_accept_list;