[dm-devel] multipathd: Add 'sysfs' prioritizer
Benjamin Marzinski
bmarzins at redhat.com
Tue May 24 17:06:15 UTC 2016
On Mon, May 23, 2016 at 12:20:28PM +0200, Hannes Reinecke wrote:
> Recent kernels have an 'access_state' attribute which allows
> us to read the asymmetric access state directly from sysfs.
Neat. Just some thoughts. I'm not sure if you want to add a prioritizer
option to be able to change what the pref bit does (perhaps
"no_exclusive_pref_bit"). Also, we should probably make the alua
prioritizer default to the same pref bit behavior as the sysfs
prioritizer.
ACK
-Ben
>
> Signed-off-by: Hannes Reinecke <hare at suse.de>
> ---
> libmultipath/discovery.c | 33 +++++++++++++++++++++++++++++
> libmultipath/discovery.h | 2 ++
> libmultipath/prio.h | 1 +
> libmultipath/prioritizers/Makefile | 3 ++-
> libmultipath/prioritizers/sysfs.c | 43 ++++++++++++++++++++++++++++++++++++++
> libmultipath/propsel.c | 6 +++++-
> multipath/multipath.conf.5 | 14 ++++++++++++-
> 7 files changed, 99 insertions(+), 3 deletions(-)
> create mode 100644 libmultipath/prioritizers/sysfs.c
>
> diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
> index a364056..4a4b828 100644
> --- a/libmultipath/discovery.c
> +++ b/libmultipath/discovery.c
> @@ -208,6 +208,8 @@ declare_sysfs_get_str(devtype);
> declare_sysfs_get_str(vendor);
> declare_sysfs_get_str(model);
> declare_sysfs_get_str(rev);
> +declare_sysfs_get_str(access_state);
> +declare_sysfs_get_str(preferred_path);
>
> ssize_t
> sysfs_get_vpd (struct udev_device * udev, int pg,
> @@ -483,6 +485,37 @@ int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address)
> return 1;
> }
>
> +int
> +sysfs_get_asymmetric_access_state(struct path *pp, char *buff, int buflen)
> +{
> + struct udev_device *parent = pp->udev;
> + char value[16], *eptr;
> + unsigned int preferred;
> +
> + while (parent) {
> + const char *subsys = udev_device_get_subsystem(parent);
> + if (subsys && !strncmp(subsys, "scsi", 4))
> + break;
> + parent = udev_device_get_parent(parent);
> + }
> +
> + if (!parent)
> + return -1;
> +
> + if (sysfs_get_access_state(parent, buff, buflen) <= 0)
> + return -1;
> +
> + if (sysfs_get_preferred_path(parent, value, 16) <= 0)
> + return 0;
> +
> + preferred = strtoul(value, &eptr, 0);
> + if (value == eptr || preferred == ULONG_MAX) {
> + /* Parse error, ignore */
> + return 0;
> + }
> + return preferred;
> +}
> +
> static void
> sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
> {
> diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
> index 5931bc6..b45c802 100644
> --- a/libmultipath/discovery.h
> +++ b/libmultipath/discovery.h
> @@ -47,6 +47,8 @@ int sysfs_get_host_pci_name(struct path *pp, char *pci_name);
> int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address);
> ssize_t sysfs_get_vpd (struct udev_device * udev, int pg, unsigned char * buff,
> size_t len);
> +int sysfs_get_asymmetric_access_state(struct path *pp,
> + char *buff, int buflen);
>
> /*
> * discovery bitmask
> diff --git a/libmultipath/prio.h b/libmultipath/prio.h
> index 495688f..65abf54 100644
> --- a/libmultipath/prio.h
> +++ b/libmultipath/prio.h
> @@ -29,6 +29,7 @@ struct path;
> #define PRIO_RDAC "rdac"
> #define PRIO_DATACORE "datacore"
> #define PRIO_WEIGHTED_PATH "weightedpath"
> +#define PRIO_SYSFS "sysfs"
>
> /*
> * Value used to mark the fact prio was not defined
> diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile
> index 6cfac88..0d1857f 100644
> --- a/libmultipath/prioritizers/Makefile
> +++ b/libmultipath/prioritizers/Makefile
> @@ -15,7 +15,8 @@ LIBS = \
> libpriodatacore.so \
> libpriohds.so \
> libprioweightedpath.so \
> - libprioiet.so
> + libprioiet.so \
> + libpriosysfs.so
>
> CFLAGS += -I..
>
> diff --git a/libmultipath/prioritizers/sysfs.c b/libmultipath/prioritizers/sysfs.c
> new file mode 100644
> index 0000000..35a5c83
> --- /dev/null
> +++ b/libmultipath/prioritizers/sysfs.c
> @@ -0,0 +1,43 @@
> +/*
> + * sysfs.c
> + *
> + * Copyright(c) 2016 Hannes Reinecke, SUSE Linux GmbH
> + */
> +
> +#include <stdio.h>
> +
> +#include "structs.h"
> +#include "discovery.h"
> +#include "prio.h"
> +
> +static const struct {
> + unsigned char value;
> + char *name;
> +} sysfs_access_state_map[] = {
> + { 50, "active/optimized" },
> + { 10, "active/non-optimized" },
> + { 5, "lba-dependent" },
> + { 1, "standby" },
> +};
> +
> +int getprio (struct path * pp, char * args)
> +{
> + int prio = 0, rc, i;
> + char buff[512];
> +
> + rc = sysfs_get_asymmetric_access_state(pp, buff, 512);
> + if (rc < 0)
> + return PRIO_UNDEF;
> + prio = 0;
> + for (i = 0; i < 4; i++) {
> + if (!strncmp(buff, sysfs_access_state_map[i].name,
> + strlen(sysfs_access_state_map[i].name))) {
> + prio = sysfs_access_state_map[i].value;
> + break;
> + }
> + }
> + if (rc > 0)
> + prio += 80;
> +
> + return prio;
> +}
> diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
> index 8abe360..b0182de 100644
> --- a/libmultipath/propsel.c
> +++ b/libmultipath/propsel.c
> @@ -374,6 +374,7 @@ detect_prio(struct path * pp)
> int ret;
> struct prio *p = &pp->prio;
> int tpgs = 0;
> + char buff[512];
>
> if ((tpgs = get_target_port_group_support(pp->fd)) <= 0)
> return;
> @@ -383,7 +384,10 @@ detect_prio(struct path * pp)
> return;
> if (get_asymmetric_access_state(pp->fd, ret) < 0)
> return;
> - prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS);
> + if (sysfs_get_asymmetric_access_state(pp, buff, 512) < 0)
> + prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS);
> + else
> + prio_get(p, PRIO_SYSFS, DEFAULT_PRIO_ARGS);
> }
>
> #define set_prio(src, msg) \
> diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
> index 2ff88c4..aaaa01b 100644
> --- a/multipath/multipath.conf.5
> +++ b/multipath/multipath.conf.5
> @@ -203,6 +203,10 @@ Generate the path priority for NetApp arrays.
> .B rdac
> Generate the path priority for LSI/Engenio/NetApp E-Series RDAC controller.
> .TP
> +.B sysfs
> +Use the sysfs attributes access_state and preferred_path to generate the
> +path priority.
> +.TP
> .B hp_sw
> Generate the path priority for Compaq/HP controller in
> active/standby mode.
> @@ -449,8 +453,16 @@ If set to
> .I yes
> , multipath will try to detect if the device supports ALUA. If so, the device
> will automatically use the
> +.I sysfs
> +prioritizer if the required sysfs attributes
> +.I access_state
> +and
> +.I preferred_path
> +are supported, or the
> .I alua
> -prioritizer. If not, the prioritizer will be selected as usual. Default is
> +prioritizer if not. If set to
> +.I no
> +, the prioritizer will be selected as usual. Default is
> .I no
> .TP
> .B force_sync
> --
> 2.6.6
More information about the dm-devel
mailing list