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