Blame SOURCES/0090-UPBZ-1080038-reorder-paths-for-round-robin.patch

1eb31d
---
1eb31d
 libmultipath/configure.c |  229 +++++++++++++++++++++++++++++++++++++++++++++++
1eb31d
 libmultipath/configure.h |    2 
1eb31d
 libmultipath/discovery.c |   87 +++++++++++++++++
1eb31d
 libmultipath/discovery.h |    2 
1eb31d
 libmultipath/structs.c   |   84 +++++++++++++++++
1eb31d
 libmultipath/structs.h   |   25 ++++-
1eb31d
 6 files changed, 427 insertions(+), 2 deletions(-)
1eb31d
1eb31d
Index: multipath-tools-130222/libmultipath/configure.c
1eb31d
===================================================================
1eb31d
--- multipath-tools-130222.orig/libmultipath/configure.c
1eb31d
+++ multipath-tools-130222/libmultipath/configure.c
1eb31d
@@ -39,6 +39,219 @@
1eb31d
 #include "uxsock.h"
1eb31d
 #include "wwids.h"
1eb31d
 
1eb31d
+/* group paths in pg by host adapter
1eb31d
+ */
1eb31d
+int group_by_host_adapter(struct pathgroup *pgp, vector adapters)
1eb31d
+{
1eb31d
+	struct adapter_group *agp;
1eb31d
+	struct host_group *hgp;
1eb31d
+	struct path *pp, *pp1;
1eb31d
+	char adapter_name1[SLOT_NAME_SIZE];
1eb31d
+	char adapter_name2[SLOT_NAME_SIZE];
1eb31d
+	int i, j;
1eb31d
+	int found_hostgroup = 0;
1eb31d
+
1eb31d
+	while (VECTOR_SIZE(pgp->paths) > 0) {
1eb31d
+
1eb31d
+		pp = VECTOR_SLOT(pgp->paths, 0);
1eb31d
+
1eb31d
+		if (sysfs_get_host_adapter_name(pp, adapter_name1))
1eb31d
+			goto out;
1eb31d
+		/* create a new host adapter group
1eb31d
+		 */
1eb31d
+		agp = alloc_adaptergroup();
1eb31d
+		if (!agp)
1eb31d
+			goto out;
1eb31d
+		agp->pgp = pgp;
1eb31d
+
1eb31d
+		strncpy(agp->adapter_name, adapter_name1, SLOT_NAME_SIZE);
1eb31d
+		store_adaptergroup(adapters, agp);
1eb31d
+
1eb31d
+		/* create a new host port group
1eb31d
+		 */
1eb31d
+		hgp = alloc_hostgroup();
1eb31d
+		if (!hgp)
1eb31d
+			goto out;
1eb31d
+		if (store_hostgroup(agp->host_groups, hgp))
1eb31d
+			goto out;
1eb31d
+
1eb31d
+		hgp->host_no = pp->sg_id.host_no;
1eb31d
+		agp->num_hosts++;
1eb31d
+		if (store_path(hgp->paths, pp))
1eb31d
+			goto out;
1eb31d
+
1eb31d
+		hgp->num_paths++;
1eb31d
+		/* delete path from path group
1eb31d
+		 */
1eb31d
+		vector_del_slot(pgp->paths, 0);
1eb31d
+
1eb31d
+		/* add all paths belonging to same host adapter
1eb31d
+		 */
1eb31d
+		vector_foreach_slot(pgp->paths, pp1, i) {
1eb31d
+			if (sysfs_get_host_adapter_name(pp1, adapter_name2))
1eb31d
+				goto out;
1eb31d
+			if (strcmp(adapter_name1, adapter_name2) == 0) {
1eb31d
+				found_hostgroup = 0;
1eb31d
+				vector_foreach_slot(agp->host_groups, hgp, j) {
1eb31d
+					if (hgp->host_no == pp1->sg_id.host_no) {
1eb31d
+						if (store_path(hgp->paths, pp1))
1eb31d
+							goto out;
1eb31d
+						hgp->num_paths++;
1eb31d
+						found_hostgroup = 1;
1eb31d
+						break;
1eb31d
+					}
1eb31d
+				}
1eb31d
+				if (!found_hostgroup) {
1eb31d
+					/* this path belongs to new host port
1eb31d
+					 * within this adapter
1eb31d
+					 */
1eb31d
+					hgp = alloc_hostgroup();
1eb31d
+					if (!hgp)
1eb31d
+						goto out;
1eb31d
+
1eb31d
+					if (store_hostgroup(agp->host_groups, hgp))
1eb31d
+						goto out;
1eb31d
+
1eb31d
+					agp->num_hosts++;
1eb31d
+					if (store_path(hgp->paths, pp1))
1eb31d
+						goto out;
1eb31d
+
1eb31d
+					hgp->host_no = pp1->sg_id.host_no;
1eb31d
+					hgp->num_paths++;
1eb31d
+				}
1eb31d
+				/* delete paths from original path_group
1eb31d
+				 * as they are added into adapter group now
1eb31d
+				 */
1eb31d
+				vector_del_slot(pgp->paths, i);
1eb31d
+				i--;
1eb31d
+			}
1eb31d
+		}
1eb31d
+	}
1eb31d
+	return 0;
1eb31d
+
1eb31d
+out:	/* add back paths into pg as re-ordering failed
1eb31d
+	 */
1eb31d
+	vector_foreach_slot(adapters, agp, i) {
1eb31d
+			vector_foreach_slot(agp->host_groups, hgp, j) {
1eb31d
+				while (VECTOR_SIZE(hgp->paths) > 0) {
1eb31d
+					pp = VECTOR_SLOT(hgp->paths, 0);
1eb31d
+					if (store_path(pgp->paths, pp))
1eb31d
+						condlog(3, "failed to restore "
1eb31d
+						"path %s into path group",
1eb31d
+						 pp->dev);
1eb31d
+					vector_del_slot(hgp->paths, 0);
1eb31d
+				}
1eb31d
+			}
1eb31d
+		}
1eb31d
+	free_adaptergroup(adapters);
1eb31d
+	return 1;
1eb31d
+}
1eb31d
+
1eb31d
+/* re-order paths in pg by alternating adapters and host ports
1eb31d
+ * for optimized selection
1eb31d
+ */
1eb31d
+int order_paths_in_pg_by_alt_adapters(struct pathgroup *pgp, vector adapters,
1eb31d
+		 int total_paths)
1eb31d
+{
1eb31d
+	int next_adapter_index = 0;
1eb31d
+	struct adapter_group *agp;
1eb31d
+	struct host_group *hgp;
1eb31d
+	struct path *pp;
1eb31d
+
1eb31d
+	while (total_paths > 0) {
1eb31d
+		agp = VECTOR_SLOT(adapters, next_adapter_index);
1eb31d
+		if (!agp) {
1eb31d
+			condlog(0, "can't get adapter group %d", next_adapter_index);
1eb31d
+			return 1;
1eb31d
+		}
1eb31d
+
1eb31d
+		hgp = VECTOR_SLOT(agp->host_groups, agp->next_host_index);
1eb31d
+		if (!hgp) {
1eb31d
+			condlog(0, "can't get host group %d of adapter group %d", next_adapter_index, agp->next_host_index);
1eb31d
+			return 1;
1eb31d
+		}
1eb31d
+
1eb31d
+		if (!hgp->num_paths) {
1eb31d
+			agp->next_host_index++;
1eb31d
+			agp->next_host_index %= agp->num_hosts;
1eb31d
+			next_adapter_index++;
1eb31d
+			next_adapter_index %= VECTOR_SIZE(adapters);
1eb31d
+			continue;
1eb31d
+		}
1eb31d
+
1eb31d
+		pp  = VECTOR_SLOT(hgp->paths, 0);
1eb31d
+
1eb31d
+		if (store_path(pgp->paths, pp))
1eb31d
+			return 1;
1eb31d
+
1eb31d
+		total_paths--;
1eb31d
+
1eb31d
+		vector_del_slot(hgp->paths, 0);
1eb31d
+
1eb31d
+		hgp->num_paths--;
1eb31d
+
1eb31d
+		agp->next_host_index++;
1eb31d
+		agp->next_host_index %= agp->num_hosts;
1eb31d
+		next_adapter_index++;
1eb31d
+		next_adapter_index %= VECTOR_SIZE(adapters);
1eb31d
+	}
1eb31d
+
1eb31d
+	/* all paths are added into path_group
1eb31d
+	 * in crafted child order
1eb31d
+	 */
1eb31d
+	return 0;
1eb31d
+}
1eb31d
+
1eb31d
+/* round-robin: order paths in path group to alternate
1eb31d
+ * between all host adapters
1eb31d
+ */
1eb31d
+int rr_optimize_path_order(struct pathgroup *pgp)
1eb31d
+{
1eb31d
+	vector adapters;
1eb31d
+	struct path *pp;
1eb31d
+	int total_paths;
1eb31d
+	int i;
1eb31d
+
1eb31d
+	total_paths = VECTOR_SIZE(pgp->paths);
1eb31d
+	vector_foreach_slot(pgp->paths, pp, i) {
1eb31d
+		if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP &&
1eb31d
+			pp->sg_id.proto_id != SCSI_PROTOCOL_SAS &&
1eb31d
+			pp->sg_id.proto_id != SCSI_PROTOCOL_ISCSI &&
1eb31d
+			pp->sg_id.proto_id != SCSI_PROTOCOL_SRP) {
1eb31d
+			/* return success as default path order
1eb31d
+			 * is maintained in path group
1eb31d
+			 */
1eb31d
+			return 0;
1eb31d
+		}
1eb31d
+	}
1eb31d
+	adapters = vector_alloc();
1eb31d
+	if (!adapters)
1eb31d
+		return 0;
1eb31d
+
1eb31d
+	/* group paths in path group by host adapters
1eb31d
+	 */
1eb31d
+	if (group_by_host_adapter(pgp, adapters)) {
1eb31d
+		/* already freed adapters */
1eb31d
+		condlog(3, "Failed to group paths by adapters");
1eb31d
+		return 0;
1eb31d
+	}
1eb31d
+
1eb31d
+	/* re-order paths in pg to alternate between adapters and host ports
1eb31d
+	 */
1eb31d
+	if (order_paths_in_pg_by_alt_adapters(pgp, adapters, total_paths)) {
1eb31d
+		condlog(3, "Failed to re-order paths in pg by adapters "
1eb31d
+			"and host ports");
1eb31d
+		free_adaptergroup(adapters);
1eb31d
+		/* return failure as original paths are
1eb31d
+		 * removed form pgp
1eb31d
+		 */
1eb31d
+		return 1;
1eb31d
+	}
1eb31d
+
1eb31d
+	free_adaptergroup(adapters);
1eb31d
+	return 0;
1eb31d
+}
1eb31d
+
1eb31d
 extern int
1eb31d
 setup_map (struct multipath * mpp, char * params, int params_size)
1eb31d
 {
1eb31d
@@ -101,6 +314,22 @@ setup_map (struct multipath * mpp, char
1eb31d
 	 */
1eb31d
 	mpp->bestpg = select_path_group(mpp);
1eb31d
 
1eb31d
+	/* re-order paths in all path groups in an optimized way
1eb31d
+	 * for round-robin path selectors to get maximum throughput.
1eb31d
+	 */
1eb31d
+	if (!strncmp(mpp->selector, "round-robin", 11)) {
1eb31d
+		vector_foreach_slot(mpp->pg, pgp, i) {
1eb31d
+			if (VECTOR_SIZE(pgp->paths) <= 2)
1eb31d
+				continue;
1eb31d
+			if (rr_optimize_path_order(pgp)) {
1eb31d
+				condlog(2, "cannot re-order paths for "
1eb31d
+					"optimization: %s",
1eb31d
+					mpp->alias);
1eb31d
+				return 1;
1eb31d
+			}
1eb31d
+		}
1eb31d
+	}
1eb31d
+
1eb31d
 	/*
1eb31d
 	 * transform the mp->pg vector of vectors of paths
1eb31d
 	 * into a mp->params strings to feed the device-mapper
1eb31d
Index: multipath-tools-130222/libmultipath/configure.h
1eb31d
===================================================================
1eb31d
--- multipath-tools-130222.orig/libmultipath/configure.h
1eb31d
+++ multipath-tools-130222/libmultipath/configure.h
1eb31d
@@ -29,4 +29,4 @@ int reinstate_paths (struct multipath *m
1eb31d
 int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload);
1eb31d
 int get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid);
1eb31d
 int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh);
1eb31d
-
1eb31d
+int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name);
1eb31d
Index: multipath-tools-130222/libmultipath/discovery.c
1eb31d
===================================================================
1eb31d
--- multipath-tools-130222.orig/libmultipath/discovery.c
1eb31d
+++ multipath-tools-130222/libmultipath/discovery.c
1eb31d
@@ -310,6 +310,93 @@ sysfs_get_tgt_nodename (struct path *pp,
1eb31d
 	return 1;
1eb31d
 }
1eb31d
 
1eb31d
+int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name)
1eb31d
+{
1eb31d
+	int proto_id;
1eb31d
+
1eb31d
+	if (!pp || !adapter_name)
1eb31d
+		return 1;
1eb31d
+
1eb31d
+	proto_id = pp->sg_id.proto_id;
1eb31d
+
1eb31d
+	if (proto_id != SCSI_PROTOCOL_FCP &&
1eb31d
+	    proto_id != SCSI_PROTOCOL_SAS &&
1eb31d
+	    proto_id != SCSI_PROTOCOL_ISCSI &&
1eb31d
+	    proto_id != SCSI_PROTOCOL_SRP) {
1eb31d
+		return 1;
1eb31d
+	}
1eb31d
+	/* iscsi doesn't have adapter info in sysfs
1eb31d
+	 * get ip_address for grouping paths
1eb31d
+	 */
1eb31d
+	if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
1eb31d
+		return sysfs_get_iscsi_ip_address(pp, adapter_name);
1eb31d
+
1eb31d
+	/* fetch adapter pci name for other protocols
1eb31d
+	 */
1eb31d
+	return sysfs_get_host_pci_name(pp, adapter_name);
1eb31d
+}
1eb31d
+
1eb31d
+int sysfs_get_host_pci_name(struct path *pp, char *pci_name)
1eb31d
+{
1eb31d
+	struct udev_device *hostdev, *parent;
1eb31d
+	char host_name[HOST_NAME_LEN];
1eb31d
+	const char *driver_name, *value;
1eb31d
+
1eb31d
+	if (!pp || !pci_name)
1eb31d
+		return 1;
1eb31d
+
1eb31d
+	sprintf(host_name, "host%d", pp->sg_id.host_no);
1eb31d
+	hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
1eb31d
+			"scsi_host", host_name);
1eb31d
+	if (!hostdev)
1eb31d
+		return 1;
1eb31d
+
1eb31d
+	parent = udev_device_get_parent(hostdev);
1eb31d
+	while (parent) {
1eb31d
+		driver_name = udev_device_get_driver(parent);
1eb31d
+		if (!driver_name) {
1eb31d
+			parent = udev_device_get_parent(parent);
1eb31d
+			continue;
1eb31d
+		}
1eb31d
+		if (!strcmp(driver_name, "pcieport"))
1eb31d
+			break;
1eb31d
+		parent = udev_device_get_parent(parent);
1eb31d
+	}
1eb31d
+	if (parent) {
1eb31d
+		/* pci_device found
1eb31d
+		 */
1eb31d
+		value = udev_device_get_sysname(parent);
1eb31d
+
1eb31d
+		strncpy(pci_name, value, SLOT_NAME_SIZE);
1eb31d
+		udev_device_unref(hostdev);
1eb31d
+		return 0;
1eb31d
+	}
1eb31d
+	udev_device_unref(hostdev);
1eb31d
+	return 1;
1eb31d
+}
1eb31d
+
1eb31d
+int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address)
1eb31d
+{
1eb31d
+	struct udev_device *hostdev;
1eb31d
+	char host_name[HOST_NAME_LEN];
1eb31d
+	const char *value;
1eb31d
+
1eb31d
+	sprintf(host_name, "host%d", pp->sg_id.host_no);
1eb31d
+	hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
1eb31d
+			"iscsi_host", host_name);
1eb31d
+	if (hostdev) {
1eb31d
+		value = udev_device_get_sysattr_value(hostdev,
1eb31d
+				"ipaddress");
1eb31d
+		if (value) {
1eb31d
+			strncpy(ip_address, value, SLOT_NAME_SIZE);
1eb31d
+			udev_device_unref(hostdev);
1eb31d
+			return 0;
1eb31d
+		} else
1eb31d
+			udev_device_unref(hostdev);
1eb31d
+	}
1eb31d
+	return 1;
1eb31d
+}
1eb31d
+
1eb31d
 static void
1eb31d
 sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
1eb31d
 {
1eb31d
Index: multipath-tools-130222/libmultipath/discovery.h
1eb31d
===================================================================
1eb31d
--- multipath-tools-130222.orig/libmultipath/discovery.h
1eb31d
+++ multipath-tools-130222/libmultipath/discovery.h
1eb31d
@@ -38,6 +38,8 @@ int store_pathinfo (vector pathvec, vect
1eb31d
 		    struct path **pp_ptr);
1eb31d
 int sysfs_set_scsi_tmo (struct multipath *mpp);
1eb31d
 int sysfs_get_timeout(struct path *pp, unsigned int *timeout);
1eb31d
+int sysfs_get_host_pci_name(struct path *pp, char *pci_name);
1eb31d
+int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address);
1eb31d
 
1eb31d
 /*
1eb31d
  * discovery bitmask
1eb31d
Index: multipath-tools-130222/libmultipath/structs.c
1eb31d
===================================================================
1eb31d
--- multipath-tools-130222.orig/libmultipath/structs.c
1eb31d
+++ multipath-tools-130222/libmultipath/structs.c
1eb31d
@@ -18,6 +18,70 @@
1eb31d
 #include "blacklist.h"
1eb31d
 #include "prio.h"
1eb31d
 
1eb31d
+struct adapter_group *
1eb31d
+alloc_adaptergroup(void)
1eb31d
+{
1eb31d
+	struct adapter_group *agp;
1eb31d
+
1eb31d
+	agp = (struct adapter_group *)MALLOC(sizeof(struct adapter_group));
1eb31d
+
1eb31d
+	if (!agp)
1eb31d
+		return NULL;
1eb31d
+
1eb31d
+	agp->host_groups = vector_alloc();
1eb31d
+	if (!agp->host_groups) {
1eb31d
+		FREE(agp);
1eb31d
+		agp = NULL;
1eb31d
+	}
1eb31d
+	return agp;
1eb31d
+}
1eb31d
+
1eb31d
+void free_adaptergroup(vector adapters)
1eb31d
+{
1eb31d
+	int i;
1eb31d
+	struct adapter_group *agp;
1eb31d
+
1eb31d
+	vector_foreach_slot(adapters, agp, i) {
1eb31d
+		free_hostgroup(agp->host_groups);
1eb31d
+		FREE(agp);
1eb31d
+	}
1eb31d
+	vector_free(adapters);
1eb31d
+}
1eb31d
+
1eb31d
+void free_hostgroup(vector hostgroups)
1eb31d
+{
1eb31d
+	int i;
1eb31d
+	struct host_group *hgp;
1eb31d
+
1eb31d
+	if (!hostgroups)
1eb31d
+		return;
1eb31d
+
1eb31d
+	vector_foreach_slot(hostgroups, hgp, i) {
1eb31d
+		vector_free(hgp->paths);
1eb31d
+		FREE(hgp);
1eb31d
+	}
1eb31d
+	vector_free(hostgroups);
1eb31d
+}
1eb31d
+
1eb31d
+struct host_group *
1eb31d
+alloc_hostgroup(void)
1eb31d
+{
1eb31d
+	struct host_group *hgp;
1eb31d
+
1eb31d
+	hgp = (struct host_group *)MALLOC(sizeof(struct host_group));
1eb31d
+
1eb31d
+	if (!hgp)
1eb31d
+		return NULL;
1eb31d
+
1eb31d
+	hgp->paths = vector_alloc();
1eb31d
+
1eb31d
+	if (!hgp->paths) {
1eb31d
+		FREE(hgp);
1eb31d
+		hgp = NULL;
1eb31d
+	}
1eb31d
+	return hgp;
1eb31d
+}
1eb31d
+
1eb31d
 struct path *
1eb31d
 alloc_path (void)
1eb31d
 {
1eb31d
@@ -242,6 +306,26 @@ store_pathgroup (vector pgvec, struct pa
1eb31d
 	return 0;
1eb31d
 }
1eb31d
 
1eb31d
+int
1eb31d
+store_hostgroup(vector hostgroupvec, struct host_group * hgp)
1eb31d
+{
1eb31d
+	if (!vector_alloc_slot(hostgroupvec))
1eb31d
+		return 1;
1eb31d
+
1eb31d
+	vector_set_slot(hostgroupvec, hgp);
1eb31d
+	return 0;
1eb31d
+}
1eb31d
+
1eb31d
+int
1eb31d
+store_adaptergroup(vector adapters, struct adapter_group * agp)
1eb31d
+{
1eb31d
+	if (!vector_alloc_slot(adapters))
1eb31d
+		return 1;
1eb31d
+
1eb31d
+	vector_set_slot(adapters, agp);
1eb31d
+	return 0;
1eb31d
+}
1eb31d
+
1eb31d
 struct multipath *
1eb31d
 find_mp_by_minor (vector mpvec, int minor)
1eb31d
 {
1eb31d
Index: multipath-tools-130222/libmultipath/structs.h
1eb31d
===================================================================
1eb31d
--- multipath-tools-130222.orig/libmultipath/structs.h
1eb31d
+++ multipath-tools-130222/libmultipath/structs.h
1eb31d
@@ -15,7 +15,8 @@
1eb31d
 #define BLK_DEV_SIZE		33
1eb31d
 #define PATH_SIZE		512
1eb31d
 #define NAME_SIZE		512
1eb31d
-
1eb31d
+#define HOST_NAME_LEN		8
1eb31d
+#define SLOT_NAME_SIZE		40
1eb31d
 
1eb31d
 #define SCSI_VENDOR_SIZE	9
1eb31d
 #define SCSI_PRODUCT_SIZE	17
1eb31d
@@ -251,6 +252,20 @@ struct pathgroup {
1eb31d
 	char * selector;
1eb31d
 };
1eb31d
 
1eb31d
+struct adapter_group {
1eb31d
+	char adapter_name[SLOT_NAME_SIZE];
1eb31d
+	struct pathgroup *pgp;
1eb31d
+	int num_hosts;
1eb31d
+	vector host_groups;
1eb31d
+	int next_host_index;
1eb31d
+};
1eb31d
+
1eb31d
+struct host_group {
1eb31d
+	int host_no;
1eb31d
+	int num_paths;
1eb31d
+	vector paths;
1eb31d
+};
1eb31d
+
1eb31d
 struct path * alloc_path (void);
1eb31d
 struct pathgroup * alloc_pathgroup (void);
1eb31d
 struct multipath * alloc_multipath (void);
1eb31d
@@ -263,6 +278,14 @@ void free_multipath_attributes (struct m
1eb31d
 void drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths);
1eb31d
 void free_multipathvec (vector mpvec, enum free_path_mode free_paths);
1eb31d
 
1eb31d
+struct adapter_group * alloc_adaptergroup(void);
1eb31d
+struct host_group * alloc_hostgroup(void);
1eb31d
+void free_adaptergroup(vector adapters);
1eb31d
+void free_hostgroup(vector hostgroups);
1eb31d
+
1eb31d
+int store_adaptergroup(vector adapters, struct adapter_group *agp);
1eb31d
+int store_hostgroup(vector hostgroupvec, struct host_group *hgp);
1eb31d
+
1eb31d
 int store_path (vector pathvec, struct path * pp);
1eb31d
 int store_pathgroup (vector pgvec, struct pathgroup * pgp);
1eb31d