diff -rupN a/libmultipath/prio.h b/libmultipath/prio.h --- a/libmultipath/prio.h 2010-05-22 15:01:58.000000000 +0300 +++ b/libmultipath/prio.h 2013-05-16 18:44:40.000000000 +0300 @@ -25,6 +25,7 @@ #define PRIO_RANDOM "random" #define PRIO_RDAC "rdac" #define PRIO_DATACORE "datacore" +#define PRIO_SG_ID "sg_id" /* * Value used to mark the fact prio was not defined diff -rupN a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile --- a/libmultipath/prioritizers/Makefile 2010-05-22 15:01:58.000000000 +0300 +++ b/libmultipath/prioritizers/Makefile 2013-05-16 18:45:18.000000000 +0300 @@ -13,7 +13,8 @@ LIBS = \ libprioalua.so \ libprionetapp.so \ libpriodatacore.so \ - libpriohds.so + libpriohds.so \ + libpriosg_id.so \ CFLAGS += -I.. diff -rupN a/libmultipath/prioritizers/sg_id.c b/libmultipath/prioritizers/sg_id.c --- a/libmultipath/prioritizers/sg_id.c 1970-01-01 03:00:00.000000000 +0300 +++ b/libmultipath/prioritizers/sg_id.c 2013-05-17 18:52:24.015193457 +0300 @@ -0,0 +1,212 @@ +/* + * sg_id.c + * Version 0.1 + * + * (c) 2013 Viktor Larionov + * Salva Kindlustuse AS, Tallinn, Estonia + * + * A basic prioritizer, for setting dm-multipath path + * priorities based on the corresponding SCSI device IDs. + * + * Usage: in /etc/multipath.conf set prio to "sg_id", + * and pass priority values to be set via + * prio_args. The format is: + * + * prio_sg_id()= + * + * eg. prio_sg_id(^[1-2]:0)=10 will set up, priority of + * 10 to all paths which reside on SCSI hosts 1 and 2, + * channel 0. + * + * prio_sg_id(default) sets fallback priority if none + * of other patterns matches. + * + * Note: Patterns are case insensitive. + * The first pattern matched in a row, wins. + * + * + * This work is made available on the basis of the + * GPLv2 for detials see . + * + */ + +#include +#include +#include +#include +#include + +#include "sg_id.h" + +#define pp_sg_id_log(prio, fmt, args...) \ + condlog(prio, "%s: sg_id prio: " fmt, dev, ##args) + +void debug_regex_error(int ret, regex_t * preg, const char * dev) +{ + char * re_msg = malloc(129 * sizeof(char)); + memset(re_msg, '\0', 129); + + regerror(ret, preg, re_msg, 128); + + pp_sg_id_log(3, "regex error: %s", re_msg); + free(re_msg); +} + +int sg_id_parse_args(char * args_txt, sg_id_arg * * pargs, int * nargs, int * prio, const char * dev) +{ + int ret; + regex_t preg; + regex_t preg_def; + int nmatch; + regmatch_t * pmatch; + + ret = regcomp(&preg, "prio_sg_id\\(([^()]+)\\)=([0-9]+)", REG_ICASE|REG_EXTENDED); + if(ret!=0) + { + debug_regex_error(ret, &preg, dev); + pp_sg_id_log(0, "failed to parse prio_args."); + return(0); + } + + ret = regcomp(&preg_def, "[ ]*default[ ]*", REG_ICASE|REG_EXTENDED); + if(ret!=0) + { + debug_regex_error(ret, &preg_def, dev); + pp_sg_id_log(0, "failed to parse prio_args."); + regfree(&preg); + return(0); + } + + nmatch = preg.re_nsub + 1; + pmatch = malloc(nmatch * sizeof(regmatch_t)); + + char buf[MAX_SG_ID_PATTERN_LENGTH]; + int readpos; + + int i = 0; + sg_id_arg * args; + + for(readpos=0; readpos<(strlen(args_txt)) && + regexec(&preg, &args_txt[readpos], nmatch, pmatch, REG_ICASE|REG_EXTENDED)==0; i++) + { + if(i==0) + { + args = malloc(sizeof(sg_id_arg)); + } else + { + args = realloc(args, (sizeof(sg_id_arg) * (i + 1))); + } + + /* Pattern match. */ + memset(args[i].text, '\0', MAX_SG_ID_PATTERN_LENGTH); + args[i].text_length = MAX_SG_ID_PATTERN_LENGTH < (pmatch[1].rm_eo - pmatch[1].rm_so) ? + MAX_SG_ID_PATTERN_LENGTH : (pmatch[1].rm_eo - pmatch[1].rm_so); + memcpy(args[i].text, &args_txt[readpos+pmatch[1].rm_so], args[i].text_length); + + /* Priority match. */ + memset(buf, '\0', MAX_SG_ID_PATTERN_LENGTH); + memcpy(buf, &args_txt[readpos+pmatch[2].rm_so], + (MAX_SG_ID_PATTERN_LENGTH < (pmatch[2].rm_eo - pmatch[2].rm_so) ? + MAX_SG_ID_PATTERN_LENGTH : (pmatch[2].rm_eo - pmatch[2].rm_so))); + args[i].prio = atoi(buf); + + args[i].compiled = 0; + if(regexec(&preg_def, args[i].text, 0, NULL, REG_ICASE|REG_EXTENDED)!=0) + { + ret = regcomp(&args[i].pattern, args[i].text, REG_ICASE); + if(ret!=0) + { + debug_regex_error(ret, &args[i].pattern, dev); + } else { + args[i].compiled = 1; + } + + } else + { + (*prio) = args[i].prio; + i--; + args = realloc(args, (sizeof(sg_id_arg) * (i + 1))); + } + + readpos+=pmatch[0].rm_eo; + } + + free(pmatch); + + regfree(&preg); + regfree(&preg_def); + + (*pargs) = args; + (*nargs) = i; + + return(0); +} + +int sg_id_prio(char * args_txt, struct sg_id * sg_id, const char * dev) +{ + int prio = -1; + + int nargs; + sg_id_arg * args; + + /* Prepare the device SG_ID string. */ + char dev_sg_id[64]; + memset(dev_sg_id, '\0', 64); + sprintf(dev_sg_id, "%d:%d:%d:%d", sg_id->host_no, + sg_id->channel, + sg_id->scsi_id, + sg_id->lun); + + /* Parse the arguments, in case arguments parsing fails, back off with -1. */ + if(sg_id_parse_args(args_txt, &args, &nargs, &prio, dev)==0) + { + int i; + short sg_id_matched = 0; + + for(i=0;i0;i--) + { + if(args[i-1].compiled==1) + { + regfree(&args[i-1].pattern); + } + } + + if(nargs>0) + { + free(args); + } + } + + return(prio); +} + +int getprio (struct path * pp, char * args) +{ + return(sg_id_prio(args, &pp->sg_id, pp->dev)); +} diff -rupN a/libmultipath/prioritizers/sg_id.h b/libmultipath/prioritizers/sg_id.h --- a/libmultipath/prioritizers/sg_id.h 1970-01-01 03:00:00.000000000 +0300 +++ b/libmultipath/prioritizers/sg_id.h 2013-05-17 12:52:22.000000000 +0300 @@ -0,0 +1,9 @@ +#define MAX_SG_ID_PATTERN_LENGTH 128 + +typedef struct sg_id_arg { + char text[MAX_SG_ID_PATTERN_LENGTH]; + int text_length; + short compiled; + regex_t pattern; + int prio; +} sg_id_arg;