|
@@ -22,7 +22,6 @@
|
|
|
#include <linux/atomic.h>
|
|
|
|
|
|
#define DM_MSG_PREFIX "multipath"
|
|
|
-#define MESG_STR(x) x, sizeof(x)
|
|
|
#define DM_PG_INIT_DELAY_MSECS 2000
|
|
|
#define DM_PG_INIT_DELAY_DEFAULT ((unsigned) -1)
|
|
|
|
|
@@ -505,80 +504,29 @@ static void trigger_event(struct work_struct *work)
|
|
|
* <#paths> <#per-path selector args>
|
|
|
* [<path> [<arg>]* ]+ ]+
|
|
|
*---------------------------------------------------------------*/
|
|
|
-struct param {
|
|
|
- unsigned min;
|
|
|
- unsigned max;
|
|
|
- char *error;
|
|
|
-};
|
|
|
-
|
|
|
-static int read_param(struct param *param, char *str, unsigned *v, char **error)
|
|
|
-{
|
|
|
- if (!str ||
|
|
|
- (sscanf(str, "%u", v) != 1) ||
|
|
|
- (*v < param->min) ||
|
|
|
- (*v > param->max)) {
|
|
|
- *error = param->error;
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-struct arg_set {
|
|
|
- unsigned argc;
|
|
|
- char **argv;
|
|
|
-};
|
|
|
-
|
|
|
-static char *shift(struct arg_set *as)
|
|
|
-{
|
|
|
- char *r;
|
|
|
-
|
|
|
- if (as->argc) {
|
|
|
- as->argc--;
|
|
|
- r = *as->argv;
|
|
|
- as->argv++;
|
|
|
- return r;
|
|
|
- }
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-static void consume(struct arg_set *as, unsigned n)
|
|
|
-{
|
|
|
- BUG_ON (as->argc < n);
|
|
|
- as->argc -= n;
|
|
|
- as->argv += n;
|
|
|
-}
|
|
|
-
|
|
|
-static int parse_path_selector(struct arg_set *as, struct priority_group *pg,
|
|
|
+static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg,
|
|
|
struct dm_target *ti)
|
|
|
{
|
|
|
int r;
|
|
|
struct path_selector_type *pst;
|
|
|
unsigned ps_argc;
|
|
|
|
|
|
- static struct param _params[] = {
|
|
|
+ static struct dm_arg _args[] = {
|
|
|
{0, 1024, "invalid number of path selector args"},
|
|
|
};
|
|
|
|
|
|
- pst = dm_get_path_selector(shift(as));
|
|
|
+ pst = dm_get_path_selector(dm_shift_arg(as));
|
|
|
if (!pst) {
|
|
|
ti->error = "unknown path selector type";
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- r = read_param(_params, shift(as), &ps_argc, &ti->error);
|
|
|
+ r = dm_read_arg_group(_args, as, &ps_argc, &ti->error);
|
|
|
if (r) {
|
|
|
dm_put_path_selector(pst);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- if (ps_argc > as->argc) {
|
|
|
- dm_put_path_selector(pst);
|
|
|
- ti->error = "not enough arguments for path selector";
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
r = pst->create(&pg->ps, ps_argc, as->argv);
|
|
|
if (r) {
|
|
|
dm_put_path_selector(pst);
|
|
@@ -587,12 +535,12 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg,
|
|
|
}
|
|
|
|
|
|
pg->ps.type = pst;
|
|
|
- consume(as, ps_argc);
|
|
|
+ dm_consume_args(as, ps_argc);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
|
|
|
+static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps,
|
|
|
struct dm_target *ti)
|
|
|
{
|
|
|
int r;
|
|
@@ -609,7 +557,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
|
|
|
if (!p)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
- r = dm_get_device(ti, shift(as), dm_table_get_mode(ti->table),
|
|
|
+ r = dm_get_device(ti, dm_shift_arg(as), dm_table_get_mode(ti->table),
|
|
|
&p->path.dev);
|
|
|
if (r) {
|
|
|
ti->error = "error getting device";
|
|
@@ -660,16 +608,16 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
|
|
|
return ERR_PTR(r);
|
|
|
}
|
|
|
|
|
|
-static struct priority_group *parse_priority_group(struct arg_set *as,
|
|
|
+static struct priority_group *parse_priority_group(struct dm_arg_set *as,
|
|
|
struct multipath *m)
|
|
|
{
|
|
|
- static struct param _params[] = {
|
|
|
+ static struct dm_arg _args[] = {
|
|
|
{1, 1024, "invalid number of paths"},
|
|
|
{0, 1024, "invalid number of selector args"}
|
|
|
};
|
|
|
|
|
|
int r;
|
|
|
- unsigned i, nr_selector_args, nr_params;
|
|
|
+ unsigned i, nr_selector_args, nr_args;
|
|
|
struct priority_group *pg;
|
|
|
struct dm_target *ti = m->ti;
|
|
|
|
|
@@ -693,26 +641,26 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
|
|
|
/*
|
|
|
* read the paths
|
|
|
*/
|
|
|
- r = read_param(_params, shift(as), &pg->nr_pgpaths, &ti->error);
|
|
|
+ r = dm_read_arg(_args, as, &pg->nr_pgpaths, &ti->error);
|
|
|
if (r)
|
|
|
goto bad;
|
|
|
|
|
|
- r = read_param(_params + 1, shift(as), &nr_selector_args, &ti->error);
|
|
|
+ r = dm_read_arg(_args + 1, as, &nr_selector_args, &ti->error);
|
|
|
if (r)
|
|
|
goto bad;
|
|
|
|
|
|
- nr_params = 1 + nr_selector_args;
|
|
|
+ nr_args = 1 + nr_selector_args;
|
|
|
for (i = 0; i < pg->nr_pgpaths; i++) {
|
|
|
struct pgpath *pgpath;
|
|
|
- struct arg_set path_args;
|
|
|
+ struct dm_arg_set path_args;
|
|
|
|
|
|
- if (as->argc < nr_params) {
|
|
|
+ if (as->argc < nr_args) {
|
|
|
ti->error = "not enough path parameters";
|
|
|
r = -EINVAL;
|
|
|
goto bad;
|
|
|
}
|
|
|
|
|
|
- path_args.argc = nr_params;
|
|
|
+ path_args.argc = nr_args;
|
|
|
path_args.argv = as->argv;
|
|
|
|
|
|
pgpath = parse_path(&path_args, &pg->ps, ti);
|
|
@@ -723,7 +671,7 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
|
|
|
|
|
|
pgpath->pg = pg;
|
|
|
list_add_tail(&pgpath->list, &pg->pgpaths);
|
|
|
- consume(as, nr_params);
|
|
|
+ dm_consume_args(as, nr_args);
|
|
|
}
|
|
|
|
|
|
return pg;
|
|
@@ -733,28 +681,23 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
|
|
|
return ERR_PTR(r);
|
|
|
}
|
|
|
|
|
|
-static int parse_hw_handler(struct arg_set *as, struct multipath *m)
|
|
|
+static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m)
|
|
|
{
|
|
|
unsigned hw_argc;
|
|
|
int ret;
|
|
|
struct dm_target *ti = m->ti;
|
|
|
|
|
|
- static struct param _params[] = {
|
|
|
+ static struct dm_arg _args[] = {
|
|
|
{0, 1024, "invalid number of hardware handler args"},
|
|
|
};
|
|
|
|
|
|
- if (read_param(_params, shift(as), &hw_argc, &ti->error))
|
|
|
+ if (dm_read_arg_group(_args, as, &hw_argc, &ti->error))
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (!hw_argc)
|
|
|
return 0;
|
|
|
|
|
|
- if (hw_argc > as->argc) {
|
|
|
- ti->error = "not enough arguments for hardware handler";
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- m->hw_handler_name = kstrdup(shift(as), GFP_KERNEL);
|
|
|
+ m->hw_handler_name = kstrdup(dm_shift_arg(as), GFP_KERNEL);
|
|
|
request_module("scsi_dh_%s", m->hw_handler_name);
|
|
|
if (scsi_dh_handler_exist(m->hw_handler_name) == 0) {
|
|
|
ti->error = "unknown hardware handler type";
|
|
@@ -778,7 +721,7 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m)
|
|
|
for (i = 0, p+=j+1; i <= hw_argc - 2; i++, p+=j+1)
|
|
|
j = sprintf(p, "%s", as->argv[i]);
|
|
|
}
|
|
|
- consume(as, hw_argc - 1);
|
|
|
+ dm_consume_args(as, hw_argc - 1);
|
|
|
|
|
|
return 0;
|
|
|
fail:
|
|
@@ -787,52 +730,45 @@ fail:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int parse_features(struct arg_set *as, struct multipath *m)
|
|
|
+static int parse_features(struct dm_arg_set *as, struct multipath *m)
|
|
|
{
|
|
|
int r;
|
|
|
unsigned argc;
|
|
|
struct dm_target *ti = m->ti;
|
|
|
- const char *param_name;
|
|
|
+ const char *arg_name;
|
|
|
|
|
|
- static struct param _params[] = {
|
|
|
+ static struct dm_arg _args[] = {
|
|
|
{0, 5, "invalid number of feature args"},
|
|
|
{1, 50, "pg_init_retries must be between 1 and 50"},
|
|
|
{0, 60000, "pg_init_delay_msecs must be between 0 and 60000"},
|
|
|
};
|
|
|
|
|
|
- r = read_param(_params, shift(as), &argc, &ti->error);
|
|
|
+ r = dm_read_arg_group(_args, as, &argc, &ti->error);
|
|
|
if (r)
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (!argc)
|
|
|
return 0;
|
|
|
|
|
|
- if (argc > as->argc) {
|
|
|
- ti->error = "not enough arguments for features";
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
do {
|
|
|
- param_name = shift(as);
|
|
|
+ arg_name = dm_shift_arg(as);
|
|
|
argc--;
|
|
|
|
|
|
- if (!strnicmp(param_name, MESG_STR("queue_if_no_path"))) {
|
|
|
+ if (!strcasecmp(arg_name, "queue_if_no_path")) {
|
|
|
r = queue_if_no_path(m, 1, 0);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- if (!strnicmp(param_name, MESG_STR("pg_init_retries")) &&
|
|
|
+ if (!strcasecmp(arg_name, "pg_init_retries") &&
|
|
|
(argc >= 1)) {
|
|
|
- r = read_param(_params + 1, shift(as),
|
|
|
- &m->pg_init_retries, &ti->error);
|
|
|
+ r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error);
|
|
|
argc--;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- if (!strnicmp(param_name, MESG_STR("pg_init_delay_msecs")) &&
|
|
|
+ if (!strcasecmp(arg_name, "pg_init_delay_msecs") &&
|
|
|
(argc >= 1)) {
|
|
|
- r = read_param(_params + 2, shift(as),
|
|
|
- &m->pg_init_delay_msecs, &ti->error);
|
|
|
+ r = dm_read_arg(_args + 2, as, &m->pg_init_delay_msecs, &ti->error);
|
|
|
argc--;
|
|
|
continue;
|
|
|
}
|
|
@@ -847,15 +783,15 @@ static int parse_features(struct arg_set *as, struct multipath *m)
|
|
|
static int multipath_ctr(struct dm_target *ti, unsigned int argc,
|
|
|
char **argv)
|
|
|
{
|
|
|
- /* target parameters */
|
|
|
- static struct param _params[] = {
|
|
|
+ /* target arguments */
|
|
|
+ static struct dm_arg _args[] = {
|
|
|
{0, 1024, "invalid number of priority groups"},
|
|
|
{0, 1024, "invalid initial priority group number"},
|
|
|
};
|
|
|
|
|
|
int r;
|
|
|
struct multipath *m;
|
|
|
- struct arg_set as;
|
|
|
+ struct dm_arg_set as;
|
|
|
unsigned pg_count = 0;
|
|
|
unsigned next_pg_num;
|
|
|
|
|
@@ -876,11 +812,11 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
|
|
|
if (r)
|
|
|
goto bad;
|
|
|
|
|
|
- r = read_param(_params, shift(&as), &m->nr_priority_groups, &ti->error);
|
|
|
+ r = dm_read_arg(_args, &as, &m->nr_priority_groups, &ti->error);
|
|
|
if (r)
|
|
|
goto bad;
|
|
|
|
|
|
- r = read_param(_params + 1, shift(&as), &next_pg_num, &ti->error);
|
|
|
+ r = dm_read_arg(_args + 1, &as, &next_pg_num, &ti->error);
|
|
|
if (r)
|
|
|
goto bad;
|
|
|
|
|
@@ -1510,10 +1446,10 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
|
|
|
}
|
|
|
|
|
|
if (argc == 1) {
|
|
|
- if (!strnicmp(argv[0], MESG_STR("queue_if_no_path"))) {
|
|
|
+ if (!strcasecmp(argv[0], "queue_if_no_path")) {
|
|
|
r = queue_if_no_path(m, 1, 0);
|
|
|
goto out;
|
|
|
- } else if (!strnicmp(argv[0], MESG_STR("fail_if_no_path"))) {
|
|
|
+ } else if (!strcasecmp(argv[0], "fail_if_no_path")) {
|
|
|
r = queue_if_no_path(m, 0, 0);
|
|
|
goto out;
|
|
|
}
|
|
@@ -1524,18 +1460,18 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (!strnicmp(argv[0], MESG_STR("disable_group"))) {
|
|
|
+ if (!strcasecmp(argv[0], "disable_group")) {
|
|
|
r = bypass_pg_num(m, argv[1], 1);
|
|
|
goto out;
|
|
|
- } else if (!strnicmp(argv[0], MESG_STR("enable_group"))) {
|
|
|
+ } else if (!strcasecmp(argv[0], "enable_group")) {
|
|
|
r = bypass_pg_num(m, argv[1], 0);
|
|
|
goto out;
|
|
|
- } else if (!strnicmp(argv[0], MESG_STR("switch_group"))) {
|
|
|
+ } else if (!strcasecmp(argv[0], "switch_group")) {
|
|
|
r = switch_pg_num(m, argv[1]);
|
|
|
goto out;
|
|
|
- } else if (!strnicmp(argv[0], MESG_STR("reinstate_path")))
|
|
|
+ } else if (!strcasecmp(argv[0], "reinstate_path"))
|
|
|
action = reinstate_path;
|
|
|
- else if (!strnicmp(argv[0], MESG_STR("fail_path")))
|
|
|
+ else if (!strcasecmp(argv[0], "fail_path"))
|
|
|
action = fail_path;
|
|
|
else {
|
|
|
DMWARN("Unrecognised multipath message received.");
|