Target/iser: Fix iscsit_accept_np and rdma_cm racy flow
authorSagi Grimberg <sagig@mellanox.com>
Tue, 29 Apr 2014 10:13:45 +0000 (13:13 +0300)
committerJiri Slaby <jslaby@suse.cz>
Mon, 9 Jun 2014 13:53:44 +0000 (15:53 +0200)
commit 531b7bf4bd795d9a09eac92504322a472c010bc8 upstream.

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>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h

index d62b61cc61750a481ecc553032b5b199e1d00b70..e6737607a088bb41d250710f5333500e082fad57 100644 (file)
@@ -27,6 +27,7 @@
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
 #include <target/iscsi/iscsi_transport.h>
+#include <linux/semaphore.h>
 
 #include "isert_proto.h"
 #include "ib_isert.h"
@@ -575,8 +576,8 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        list_add_tail(&isert_conn->conn_accept_node, &isert_np->np_accept_list);
        mutex_unlock(&isert_np->np_accept_mutex);
 
-       pr_debug("isert_connect_request() waking up np_accept_wq: %p\n", np);
-       wake_up(&isert_np->np_accept_wq);
+       pr_debug("isert_connect_request() up np_sem np: %p\n", np);
+       up(&isert_np->np_sem);
        return 0;
 
 out_conn_dev:
@@ -2477,7 +2478,7 @@ isert_setup_np(struct iscsi_np *np,
                pr_err("Unable to allocate struct isert_np\n");
                return -ENOMEM;
        }
-       init_waitqueue_head(&isert_np->np_accept_wq);
+       sema_init(&isert_np->np_sem, 0);
        mutex_init(&isert_np->np_accept_mutex);
        INIT_LIST_HEAD(&isert_np->np_accept_list);
        init_completion(&isert_np->np_login_comp);
@@ -2525,18 +2526,6 @@ out:
        return ret;
 }
 
-static int
-isert_check_accept_queue(struct isert_np *isert_np)
-{
-       int empty;
-
-       mutex_lock(&isert_np->np_accept_mutex);
-       empty = list_empty(&isert_np->np_accept_list);
-       mutex_unlock(&isert_np->np_accept_mutex);
-
-       return empty;
-}
-
 static int
 isert_rdma_accept(struct isert_conn *isert_conn)
 {
@@ -2629,16 +2618,14 @@ isert_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
        int max_accept = 0, ret;
 
 accept_wait:
-       ret = wait_event_interruptible(isert_np->np_accept_wq,
-                       !isert_check_accept_queue(isert_np) ||
-                       np->np_thread_state == ISCSI_NP_THREAD_RESET);
+       ret = down_interruptible(&isert_np->np_sem);
        if (max_accept > 5)
                return -ENODEV;
 
        spin_lock_bh(&np->np_thread_lock);
        if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
                spin_unlock_bh(&np->np_thread_lock);
-               pr_err("ISCSI_NP_THREAD_RESET for isert_accept_np\n");
+               pr_debug("ISCSI_NP_THREAD_RESET for isert_accept_np\n");
                return -ENODEV;
        }
        spin_unlock_bh(&np->np_thread_lock);
index 52f4bf0d1a0feae6be55e1ed9f49b3cb5a3388c3..ba695c33a2df6b56d6f6ddc4dba3787f3b095401 100644 (file)
@@ -154,7 +154,7 @@ struct isert_device {
 };
 
 struct isert_np {
-       wait_queue_head_t       np_accept_wq;
+       struct semaphore        np_sem;
        struct rdma_cm_id       *np_cm_id;
        struct mutex            np_accept_mutex;
        struct list_head        np_accept_list;