Commit 92c83d79 authored by Heinz Mauelshagen's avatar Heinz Mauelshagen Committed by Mike Snitzer

dm raid: use dm_arg_set API in constructor

- use dm_arg_set API in ctr and its callees parse_raid_params() and dev_parms()

- introduce _in_range() function to check a value is in a [ min, max ] range;
  this is to support more callers in parsing parameters etc. in the future

- correct comment on MAX_RAID_DEVICES
Signed-off-by: default avatarHeinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent 73c6f239
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/device-mapper.h> #include <linux/device-mapper.h>
#define DM_MSG_PREFIX "raid" #define DM_MSG_PREFIX "raid"
#define MAX_RAID_DEVICES 253 /* raid4/5/6 limit */ #define MAX_RAID_DEVICES 253 /* md-raid kernel limit */
static bool devices_handle_discard_safely = false; static bool devices_handle_discard_safely = false;
...@@ -95,6 +95,12 @@ static struct raid_type { ...@@ -95,6 +95,12 @@ static struct raid_type {
{"raid6_nc", "RAID6 (N continue)", 2, 4, 6, ALGORITHM_ROTATING_N_CONTINUE} {"raid6_nc", "RAID6 (N continue)", 2, 4, 6, ALGORITHM_ROTATING_N_CONTINUE}
}; };
/* True, if @v is in inclusive range [@min, @max] */
static bool _in_range(long v, long min, long max)
{
return v >= min && v <= max;
}
static char *raid10_md_layout_to_format(int layout) static char *raid10_md_layout_to_format(int layout)
{ {
/* /*
...@@ -135,7 +141,7 @@ static int raid10_format_to_md_layout(char *format, unsigned copies) ...@@ -135,7 +141,7 @@ static int raid10_format_to_md_layout(char *format, unsigned copies)
return (f << 8) | n; return (f << 8) | n;
} }
static struct raid_type *get_raid_type(char *name) static struct raid_type *get_raid_type(const char *name)
{ {
int i; int i;
...@@ -220,14 +226,20 @@ static void context_free(struct raid_set *rs) ...@@ -220,14 +226,20 @@ static void context_free(struct raid_set *rs)
* This code parses those words. If there is a failure, * This code parses those words. If there is a failure,
* the caller must use context_free to unwind the operations. * the caller must use context_free to unwind the operations.
*/ */
static int dev_parms(struct raid_set *rs, char **argv) static int parse_dev_parms(struct raid_set *rs, struct dm_arg_set *as)
{ {
int i; int i;
int rebuild = 0; int rebuild = 0;
int metadata_available = 0; int metadata_available = 0;
int r = 0; int r = 0;
const char *arg;
for (i = 0; i < rs->md.raid_disks; i++, argv += 2) { /* Put off the number of raid devices argument to get to dev pairs */
arg = dm_shift_arg(as);
if (!arg)
return -EINVAL;
for (i = 0; i < rs->md.raid_disks; i++) {
rs->dev[i].rdev.raid_disk = i; rs->dev[i].rdev.raid_disk = i;
rs->dev[i].meta_dev = NULL; rs->dev[i].meta_dev = NULL;
...@@ -240,8 +252,12 @@ static int dev_parms(struct raid_set *rs, char **argv) ...@@ -240,8 +252,12 @@ static int dev_parms(struct raid_set *rs, char **argv)
rs->dev[i].rdev.data_offset = 0; rs->dev[i].rdev.data_offset = 0;
rs->dev[i].rdev.mddev = &rs->md; rs->dev[i].rdev.mddev = &rs->md;
if (strcmp(argv[0], "-")) { arg = dm_shift_arg(as);
r = dm_get_device(rs->ti, argv[0], if (!arg)
return -EINVAL;
if (strcmp(arg, "-")) {
r = dm_get_device(rs->ti, arg,
dm_table_get_mode(rs->ti->table), dm_table_get_mode(rs->ti->table),
&rs->dev[i].meta_dev); &rs->dev[i].meta_dev);
rs->ti->error = "RAID metadata device lookup failure"; rs->ti->error = "RAID metadata device lookup failure";
...@@ -253,7 +269,11 @@ static int dev_parms(struct raid_set *rs, char **argv) ...@@ -253,7 +269,11 @@ static int dev_parms(struct raid_set *rs, char **argv)
return -ENOMEM; return -ENOMEM;
} }
if (!strcmp(argv[1], "-")) { arg = dm_shift_arg(as);
if (!arg)
return -EINVAL;
if (!strcmp(arg, "-")) {
if (!test_bit(In_sync, &rs->dev[i].rdev.flags) && if (!test_bit(In_sync, &rs->dev[i].rdev.flags) &&
(!rs->dev[i].rdev.recovery_offset)) { (!rs->dev[i].rdev.recovery_offset)) {
rs->ti->error = "Drive designated for rebuild not specified"; rs->ti->error = "Drive designated for rebuild not specified";
...@@ -267,7 +287,7 @@ static int dev_parms(struct raid_set *rs, char **argv) ...@@ -267,7 +287,7 @@ static int dev_parms(struct raid_set *rs, char **argv)
continue; continue;
} }
r = dm_get_device(rs->ti, argv[1], r = dm_get_device(rs->ti, arg,
dm_table_get_mode(rs->ti->table), dm_table_get_mode(rs->ti->table),
&rs->dev[i].data_dev); &rs->dev[i].data_dev);
if (r) { if (r) {
...@@ -492,25 +512,30 @@ static int validate_raid_redundancy(struct raid_set *rs) ...@@ -492,25 +512,30 @@ static int validate_raid_redundancy(struct raid_set *rs)
* [raid10_copies <# copies>] Number of copies. (Default: 2) * [raid10_copies <# copies>] Number of copies. (Default: 2)
* [raid10_format <near|far|offset>] Layout algorithm. (Default: near) * [raid10_format <near|far|offset>] Layout algorithm. (Default: near)
*/ */
static int parse_raid_params(struct raid_set *rs, char **argv, static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
unsigned num_raid_params) unsigned num_raid_params)
{ {
char *raid10_format = "near"; char *raid10_format = "near";
unsigned raid10_copies = 2; unsigned raid10_copies = 2;
unsigned i; unsigned i;
unsigned long value, region_size = 0; unsigned value, region_size = 0;
sector_t sectors_per_dev = rs->ti->len; sector_t sectors_per_dev = rs->ti->len;
sector_t max_io_len; sector_t max_io_len;
char *key; const char *arg, *key;
arg = dm_shift_arg(as);
num_raid_params--; /* Account for chunk_size argument */
if (kstrtouint(arg, 10, &value) < 0) {
rs->ti->error = "Bad numerical argument given for chunk_size";
return -EINVAL;
}
/* /*
* First, parse the in-order required arguments * First, parse the in-order required arguments
* "chunk_size" is the only argument of this type. * "chunk_size" is the only argument of this type.
*/ */
if ((kstrtoul(argv[0], 10, &value) < 0)) { if (rs->raid_type->level == 1) {
rs->ti->error = "Bad chunk size";
return -EINVAL;
} else if (rs->raid_type->level == 1) {
if (value) if (value)
DMERR("Ignoring chunk size parameter for RAID 1"); DMERR("Ignoring chunk size parameter for RAID 1");
value = 0; value = 0;
...@@ -523,8 +548,6 @@ static int parse_raid_params(struct raid_set *rs, char **argv, ...@@ -523,8 +548,6 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
} }
rs->md.new_chunk_sectors = rs->md.chunk_sectors = value; rs->md.new_chunk_sectors = rs->md.chunk_sectors = value;
argv++;
num_raid_params--;
/* /*
* We set each individual device as In_sync with a completed * We set each individual device as In_sync with a completed
...@@ -552,12 +575,18 @@ static int parse_raid_params(struct raid_set *rs, char **argv, ...@@ -552,12 +575,18 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
* Second, parse the unordered optional arguments * Second, parse the unordered optional arguments
*/ */
for (i = 0; i < num_raid_params; i++) { for (i = 0; i < num_raid_params; i++) {
if (!strcasecmp(argv[i], "nosync")) { arg = dm_shift_arg(as);
if (!arg) {
rs->ti->error = "Not enough raid parameters given";
return -EINVAL;
}
if (!strcasecmp(arg, "nosync")) {
rs->md.recovery_cp = MaxSector; rs->md.recovery_cp = MaxSector;
rs->ctr_flags |= CTR_FLAG_NOSYNC; rs->ctr_flags |= CTR_FLAG_NOSYNC;
continue; continue;
} }
if (!strcasecmp(argv[i], "sync")) { if (!strcasecmp(arg, "sync")) {
rs->md.recovery_cp = 0; rs->md.recovery_cp = 0;
rs->ctr_flags |= CTR_FLAG_SYNC; rs->ctr_flags |= CTR_FLAG_SYNC;
continue; continue;
...@@ -569,7 +598,9 @@ static int parse_raid_params(struct raid_set *rs, char **argv, ...@@ -569,7 +598,9 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
return -EINVAL; return -EINVAL;
} }
key = argv[i++]; key = arg;
arg = dm_shift_arg(as);
i++; /* Account for the argument pairs */
/* Parameters that take a string value are checked here. */ /* Parameters that take a string value are checked here. */
if (!strcasecmp(key, "raid10_format")) { if (!strcasecmp(key, "raid10_format")) {
...@@ -577,18 +608,18 @@ static int parse_raid_params(struct raid_set *rs, char **argv, ...@@ -577,18 +608,18 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
rs->ti->error = "'raid10_format' is an invalid parameter for this RAID type"; rs->ti->error = "'raid10_format' is an invalid parameter for this RAID type";
return -EINVAL; return -EINVAL;
} }
if (strcmp("near", argv[i]) && if (strcmp("near", arg) &&
strcmp("far", argv[i]) && strcmp("far", arg) &&
strcmp("offset", argv[i])) { strcmp("offset", arg)) {
rs->ti->error = "Invalid 'raid10_format' value given"; rs->ti->error = "Invalid 'raid10_format' value given";
return -EINVAL; return -EINVAL;
} }
raid10_format = argv[i]; raid10_format = (char *) arg;
rs->ctr_flags |= CTR_FLAG_RAID10_FORMAT; rs->ctr_flags |= CTR_FLAG_RAID10_FORMAT;
continue; continue;
} }
if (kstrtoul(argv[i], 10, &value) < 0) { if (kstrtouint(arg, 10, &value) < 0) {
rs->ti->error = "Bad numerical argument given in raid params"; rs->ti->error = "Bad numerical argument given in raid params";
return -EINVAL; return -EINVAL;
} }
...@@ -1223,61 +1254,53 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -1223,61 +1254,53 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
{ {
int r; int r;
struct raid_type *rt; struct raid_type *rt;
unsigned long num_raid_params, num_raid_devs; unsigned num_raid_params, num_raid_devs;
struct raid_set *rs = NULL; struct raid_set *rs = NULL;
const char *arg;
/* Must have at least <raid_type> <#raid_params> */ struct dm_arg_set as = { argc, argv }, as_nrd;
if (argc < 2) { struct dm_arg _args[] = {
ti->error = "Too few arguments"; { 0, as.argc, "Cannot understand number of raid parameters" },
{ 1, 254, "Cannot understand number of raid devices parameters" }
};
/* Must have <raid_type> */
arg = dm_shift_arg(&as);
if (!arg) {
ti->error = "No arguments";
return -EINVAL; return -EINVAL;
} }
/* raid type */ rt = get_raid_type(arg);
rt = get_raid_type(argv[0]);
if (!rt) { if (!rt) {
ti->error = "Unrecognised raid_type"; ti->error = "Unrecognised raid_type";
return -EINVAL; return -EINVAL;
} }
argc--;
argv++;
/* number of RAID parameters */ /* Must have <#raid_params> */
if (kstrtoul(argv[0], 10, &num_raid_params) < 0) { if (dm_read_arg_group(_args, &as, &num_raid_params, &ti->error))
ti->error = "Cannot understand number of RAID parameters";
return -EINVAL; return -EINVAL;
}
argc--;
argv++;
/* Skip over RAID params for now and find out # of devices */
if (num_raid_params >= argc) {
ti->error = "Arguments do not agree with counts given";
return -EINVAL;
}
if ((kstrtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) || /* number of raid device tupples <meta_dev data_dev> */
(num_raid_devs > MAX_RAID_DEVICES)) { as_nrd = as;
ti->error = "Cannot understand number of raid devices"; dm_consume_args(&as_nrd, num_raid_params);
_args[1].max = (as_nrd.argc - 1) / 2;
if (dm_read_arg(_args + 1, &as_nrd, &num_raid_devs, &ti->error))
return -EINVAL; return -EINVAL;
}
argc -= num_raid_params + 1; /* +1: we already have num_raid_devs */ if (!_in_range(num_raid_devs, 1, MAX_RAID_DEVICES)) {
if (argc != (num_raid_devs * 2)) { ti->error = "Invalid number of supplied raid devices";
ti->error = "Supplied RAID devices does not match the count given";
return -EINVAL; return -EINVAL;
} }
rs = context_alloc(ti, rt, (unsigned)num_raid_devs); rs = context_alloc(ti, rt, num_raid_devs);
if (IS_ERR(rs)) if (IS_ERR(rs))
return PTR_ERR(rs); return PTR_ERR(rs);
r = parse_raid_params(rs, argv, (unsigned)num_raid_params); r = parse_raid_params(rs, &as, num_raid_params);
if (r) if (r)
goto bad; goto bad;
argv += num_raid_params + 1; r = parse_dev_parms(rs, &as);
r = dev_parms(rs, argv);
if (r) if (r)
goto bad; goto bad;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment