Merged revisions 5859, 5861-5864, 5866-5868, 5871 from iser branch

[r5871] by yanb123

isert: Fix page leak if alloc_page fails

[r5868] by yanb123

isert: Do not leak workqueues if ib_create_cq failed

[r5867] by yanb123

isert: Document performance considerations for iSER

[r5866] by yanb123

isert: Fix use-after-free when killing iscsi-scstd

Our portal may be destroyed while there are connections alive.
This means we are doing list_del() from list_head that no longer exists

[r5864] by yanb123

isert: Fix crash on device removal when iscsi-scstd is started with explicit address

[r5863] by yanb123

isert: Make sure we decrement CQ QP counters if QP creation fails

[r5862] by yanb123

isert: Fix closing devices when connection allocation fails

We need to dereference isert_device structures whether
we created them or not if connection creation fails

[r5861] by yanb123

isert: Warn user of potential compilation issue

[r5859] by yanb123

isert: Fix resource leak upon unreachable event

Unreachable event caused by crash of initiator while in
connection establishment flow, would cause leak of connections.





git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/3.0.x-iser@5877 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Yan Burman
2014-11-18 12:07:35 +00:00
parent 303efb6b11
commit 7733ce346a
4 changed files with 102 additions and 25 deletions

View File

@@ -15,6 +15,12 @@ In order to achieve better performance, it is recommended to specify
"QueuedCommands 128" parameter per iSER target, since the transport
is very fast and you usually want to connect it to fast backstorage.
For performance tuning of initiator and target machines, see
http://community.mellanox.com/docs/DOC-1483
Note that if you have an SSD controller that is close to a particular
NUMA node, you want the HCA to be close to the same node.
Limitations:
-------------
* Bidirectional commands are not supported

View File

@@ -9,12 +9,18 @@
#include "iser_hdr.h"
enum isert_portal_state {
ISERT_PORTAL_ACTIVE,
ISERT_PORTAL_INACTIVE
};
struct isert_portal {
struct rdma_cm_id *cm_id;
struct sockaddr_storage addr;
struct list_head list_node; /* in portals list */
/* protected by dev_list_mutex */
struct list_head conn_list; /* head of conns list */
enum isert_portal_state state;
};
struct isert_buf {
@@ -165,6 +171,7 @@ struct isert_connection {
struct isert_wr drain_wr;
struct kref kref;
struct isert_portal *portal;
void *priv_data; /* for connection tracking */
};

View File

@@ -84,7 +84,7 @@ static int isert_buf_alloc_pg(struct ib_device *ib_dev,
goto out;
out_map_failed:
for (; i > 0; --i)
for (; i >= 0; --i)
__free_page(sg_page(&isert_buf->sg[i]));
kfree(isert_buf->sg);
isert_buf->sg = NULL;

View File

@@ -45,6 +45,8 @@
static DEFINE_MUTEX(dev_list_mutex);
void isert_portal_free(struct isert_portal *portal);
static int isert_num_recv_posted_on_err(struct ib_recv_wr *first_ib_wr,
struct ib_recv_wr *bad_wr)
{
@@ -813,6 +815,11 @@ static struct isert_device *isert_device_create(struct ib_device *ib_dev)
cqe_num = min(isert_dev->device_attr.max_cqe, ISER_CQ_ENTRIES);
cqe_num = cqe_num / isert_dev->num_cqs;
#ifdef CONFIG_SCST_EXTRACHECKS
if (isert_dev->device_attr.max_cqe == 0)
pr_err("Zero max_cqe encountered: you may have a compilation problem\n");
#endif
for (i = 0; i < isert_dev->num_cqs; ++i) {
struct isert_cq *cq_desc = &isert_dev->cq_desc[i];
@@ -852,6 +859,7 @@ static struct isert_device *isert_device_create(struct ib_device *ib_dev)
cqe_num,
i); /* completion vector */
if (IS_ERR(cq)) {
cq_desc->cq = NULL;
err = PTR_ERR(cq);
pr_err("Failed to create iser dev cq, err:%d\n", err);
goto fail_cq;
@@ -879,7 +887,7 @@ static struct isert_device *isert_device_create(struct ib_device *ib_dev)
return isert_dev;
fail_cq:
for (j = 0; j < i; ++j) {
for (j = 0; j <= i; ++j) {
if (isert_dev->cq_desc[j].cq)
ib_destroy_cq(isert_dev->cq_desc[j].cq);
if (isert_dev->cq_desc[j].cq_workqueue)
@@ -1009,7 +1017,7 @@ static int isert_conn_qp_create(struct isert_connection *isert_conn)
err = rdma_create_qp(cm_id, isert_dev->pd, &qp_attr);
if (unlikely(err)) {
pr_err("Failed to create qp, err:%d\n", err);
goto out;
goto fail_create_qp;
}
isert_conn->qp = cm_id->qp;
@@ -1018,6 +1026,12 @@ static int isert_conn_qp_create(struct isert_connection *isert_conn)
out:
TRACE_EXIT_RES(err);
return err;
fail_create_qp:
mutex_lock(&dev_list_mutex);
isert_dev->cq_qps[cq_idx]--;
mutex_unlock(&dev_list_mutex);
goto out;
}
static void isert_conn_qp_destroy(struct isert_connection *isert_conn)
@@ -1031,6 +1045,7 @@ static struct isert_connection *isert_conn_create(struct rdma_cm_id *cm_id,
{
struct isert_connection *isert_conn;
int err;
struct isert_cq *cq;
TRACE_ENTRY();
@@ -1082,12 +1097,15 @@ static struct isert_connection *isert_conn_create(struct rdma_cm_id *cm_id,
}
kref_init(&isert_conn->kref);
kref_get(&isert_conn->kref);
TRACE_EXIT();
return isert_conn;
fail_post_recv:
cq = isert_conn->qp->recv_cq->cq_context;
mutex_lock(&dev_list_mutex);
isert_dev->cq_qps[cq->idx]--;
mutex_unlock(&dev_list_mutex);
isert_conn_qp_destroy(isert_conn);
fail_qp:
isert_pdu_free(isert_conn->login_rsp_pdu);
@@ -1102,6 +1120,13 @@ fail_get:
return ERR_PTR(err);
}
static void isert_deref_device(struct isert_device *isert_dev)
{
isert_dev->refcnt--;
if (isert_dev->refcnt == 0)
isert_device_release(isert_dev);
}
static void isert_kref_free(struct kref *kref)
{
struct isert_connection *isert_conn = container_of(kref,
@@ -1122,9 +1147,9 @@ static void isert_kref_free(struct kref *kref)
isert_dev->cq_qps[cq->idx]--;
list_del(&isert_conn->portal_node);
list_del(&isert_conn->dev_node);
isert_dev->refcnt--;
if (isert_dev->refcnt == 0)
isert_device_release(isert_dev);
isert_deref_device(isert_dev);
if (unlikely(isert_conn->portal->state == ISERT_PORTAL_INACTIVE))
isert_portal_free(isert_conn->portal);
mutex_unlock(&dev_list_mutex);
rdma_destroy_id(isert_conn->cm_id);
@@ -1186,7 +1211,6 @@ static int isert_cm_conn_req_handler(struct rdma_cm_id *cm_id,
/* passed in rdma_create_id */
struct isert_portal *portal = cm_id->context;
struct ib_device *ib_dev = cm_id->device;
struct isert_device *new_isert_dev = NULL;
struct isert_device *isert_dev;
struct isert_connection *isert_conn;
struct rdma_conn_param *ini_conn_param;
@@ -1198,13 +1222,12 @@ static int isert_cm_conn_req_handler(struct rdma_cm_id *cm_id,
mutex_lock(&dev_list_mutex);
isert_dev = isert_device_find(ib_dev);
if (!isert_dev) {
new_isert_dev = isert_device_create(ib_dev);
if (unlikely(IS_ERR(new_isert_dev))) {
err = PTR_ERR(new_isert_dev);
isert_dev = isert_device_create(ib_dev);
if (unlikely(IS_ERR(isert_dev))) {
err = PTR_ERR(isert_dev);
mutex_unlock(&dev_list_mutex);
goto fail_dev_create;
}
isert_dev = new_isert_dev;
}
isert_dev->refcnt++;
mutex_unlock(&dev_list_mutex);
@@ -1216,6 +1239,7 @@ static int isert_cm_conn_req_handler(struct rdma_cm_id *cm_id,
}
isert_conn->state = ISER_CONN_HANDSHAKE;
isert_conn->portal = portal;
mutex_lock(&dev_list_mutex);
list_add_tail(&isert_conn->portal_node, &portal->conn_list);
@@ -1287,13 +1311,9 @@ fail_accept:
goto out;
fail_conn_create:
if (new_isert_dev) {
mutex_lock(&dev_list_mutex);
new_isert_dev->refcnt--;
if (new_isert_dev->refcnt == 0)
isert_device_release(new_isert_dev);
mutex_unlock(&dev_list_mutex);
}
mutex_lock(&dev_list_mutex);
isert_deref_device(isert_dev);
mutex_unlock(&dev_list_mutex);
fail_dev_create:
rdma_reject(cm_id, NULL, 0);
goto out;
@@ -1318,6 +1338,7 @@ static int isert_cm_connect_handler(struct rdma_cm_id *cm_id,
if (unlikely(ret))
goto out;
kref_get(&isert_conn->kref);
kref_get(&isert_conn->kref);
/* notify upper layer */
ret = isert_conn_established(&isert_conn->iscsi,
@@ -1396,6 +1417,31 @@ static int isert_handle_failure(struct isert_connection *conn)
return 0;
}
static int isert_cm_evt_listener_handler(struct rdma_cm_id *cm_id,
struct rdma_cm_event *cm_ev)
{
enum rdma_cm_event_type ev_type;
struct isert_portal *portal;
int err = 0;
ev_type = cm_ev->event;
portal = cm_id->context;
switch (ev_type) {
case RDMA_CM_EVENT_DEVICE_REMOVAL:
portal->cm_id = NULL;
err = -EINVAL;
break;
default:
pr_info("Listener event:%s(%d), ignored\n",
cm_event_type_str(ev_type), ev_type);
break;
}
return err;
}
static int isert_cm_evt_handler(struct rdma_cm_id *cm_id,
struct rdma_cm_event *cm_ev)
{
@@ -1415,6 +1461,11 @@ static int isert_cm_evt_handler(struct rdma_cm_id *cm_id,
cm_event_type_str(ev_type), ev_type, cm_ev->status,
portal, cm_id);
if (portal->cm_id == cm_id) {
err = isert_cm_evt_listener_handler(cm_id, cm_ev);
goto out;
}
switch (ev_type) {
case RDMA_CM_EVENT_CONNECT_REQUEST:
err = isert_cm_conn_req_handler(cm_id, cm_ev);
@@ -1591,23 +1642,36 @@ out:
return err;
}
void isert_portal_free(struct isert_portal *portal)
{
lockdep_assert_held(&dev_list_mutex);
if (!list_empty(&portal->conn_list))
return;
kfree(portal);
module_put(THIS_MODULE);
}
void isert_portal_release(struct isert_portal *portal)
{
struct isert_connection *conn;
pr_info("iser portal cm_id:%p releasing\n", portal->cm_id);
rdma_destroy_id(portal->cm_id);
if (portal->cm_id) {
rdma_destroy_id(portal->cm_id);
portal->cm_id = NULL;
}
isert_portal_list_remove(portal);
mutex_lock(&dev_list_mutex);
list_for_each_entry(conn, &portal->conn_list, portal_node)
isert_conn_disconnect(conn);
portal->state = ISERT_PORTAL_INACTIVE;
isert_portal_free(portal);
mutex_unlock(&dev_list_mutex);
isert_portal_list_remove(portal);
kfree(portal);
module_put(THIS_MODULE);
}
struct isert_portal *isert_portal_start(struct sockaddr *sa, size_t addr_len)