[PATCH] Infiniband srp fast failover patch. Currently ib_srp doesnot do anything on receiving a DREQ from the target, itonly sends a response back. Further it also does notmonitor port (down) events. I have patched srp to removescsi devices when a port down event is received or if thetarget sends a DREQ. Currently even though the targetnotifies the initiator of its intentions of going away, theinitiator ignores that information. Later the initiatorgets upset when the devices "suddenly" disappear resultingin srp initiating an error recovery process which takes along time. This caused high failover latencies as comparedto fibre channel. In my experiments with RHEL 6.0 and 6.2 Iencountered failover time that exceeded 2 minutes and 20seconds (despite tweaking /etc/multipath.conf and/sys/block/<>/timeout). With this patch the failover takes30 seconds. I have tested this patch with and without aswitch.

From: Karandeep Chahal
Date: Tue May 29 2012 - 16:48:20 EST



Signed-off-by: Karandeep Chahal <kchahal@xxxxxxx>
---
drivers/infiniband/ulp/srp/ib_srp.c | 64 +++++++++++++++++++++++++++++++++++
drivers/infiniband/ulp/srp/ib_srp.h | 1 +
2 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index bcbf22e..088215b 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1524,6 +1524,37 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
}
}

+static void srp_mark_all_devices_dead(int port_num, struct srp_device *srp_dev,
+ struct ib_cm_id *cm_id)
+{
+ struct srp_host *host, *tmp_host;
+ struct srp_target_port *target;
+
+ list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) {
+ /*
+ * Mark all target ports as removed, so we stop queueing
+ * commands and don't try to reconnect.
+ */
+ if ((port_num != -1) && (port_num != host->port))
+ continue;
+
+ spin_lock(&host->target_lock);
+ list_for_each_entry(target, &host->target_list, list) {
+ if (!cm_id || (target->cm_id == cm_id)) {
+
+ shost_printk(KERN_WARNING, target->scsi_host,
+ PFX "Removing all scsi devices\n");
+ spin_lock_irq(&target->lock);
+ target->state = SRP_TARGET_DEAD;
+ INIT_WORK(&target->work, srp_remove_work);
+ queue_work(ib_wq, &target->work);
+ spin_unlock_irq(&target->lock);
+ }
+ }
+ spin_unlock(&host->target_lock);
+ }
+}
+
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
{
struct srp_target_port *target = cm_id->context;
@@ -1555,6 +1586,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
if (ib_send_cm_drep(cm_id, NULL, 0))
shost_printk(KERN_ERR, target->scsi_host,
PFX "Sending CM DREP failed\n");
+ srp_mark_all_devices_dead(-1, target->srp_host->srp_dev,
+ cm_id);
break;

case IB_CM_TIMEWAIT_EXIT:
@@ -2284,6 +2317,31 @@ free_host:
return NULL;
}

+static void srp_event_handler(struct ib_event_handler *handler,
+ struct ib_event *event)
+{
+ struct srp_device *srp_dev;
+
+ switch (event->event) {
+
+ case IB_EVENT_DEVICE_FATAL:
+ case IB_EVENT_PORT_ERR:
+ srp_dev = container_of(handler, struct srp_device,
+ event_handler);
+
+ printk(KERN_INFO PFX "%s port %d down detected\n",
+ srp_dev->dev->name,
+ event->element.port_num);
+
+ srp_mark_all_devices_dead(event->element.port_num,
+ srp_dev, NULL);
+ break;
+
+ default:
+ break;
+ }
+}
+
static void srp_add_one(struct ib_device *device)
{
struct srp_device *srp_dev;
@@ -2366,6 +2424,10 @@ static void srp_add_one(struct ib_device *device)

ib_set_client_data(device, &srp_client, srp_dev);

+ INIT_IB_EVENT_HANDLER(&srp_dev->event_handler, device,
+ srp_event_handler);
+ ib_register_event_handler(&srp_dev->event_handler);
+
goto free_attr;

err_pd:
@@ -2387,6 +2449,8 @@ static void srp_remove_one(struct ib_device *device)

srp_dev = ib_get_client_data(device, &srp_client);

+ ib_unregister_event_handler(&srp_dev->event_handler);
+
list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) {
device_unregister(&host->dev);
/*
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 020caf0..e0737a1 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -97,6 +97,7 @@ struct srp_device {
struct ib_pd *pd;
struct ib_mr *mr;
struct ib_fmr_pool *fmr_pool;
+ struct ib_event_handler event_handler;
u64 fmr_page_mask;
int fmr_page_size;
int fmr_max_size;
--
1.7.7.6


--------------000800000401030407040103--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/