dm raid: add region_size parameter

Allow the user to specify the region_size.

Ensures that the supplied value meets md's constraints, viz. the number of
regions does not exceed 2^21.

Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
This commit is contained in:
Jonathan Brassow 2011-08-02 12:32:07 +01:00 committed by Alasdair G Kergon
parent c0a2fa1ef1
commit c1084561bb
2 changed files with 83 additions and 3 deletions

View file

@ -52,6 +52,10 @@ The target is named "raid" and it accepts the following parameters:
[max_recovery_rate <kB/sec/disk>] Throttle RAID initialization
[max_write_behind <sectors>] See '-write-behind=' (man mdadm)
[stripe_cache <sectors>] Stripe cache size (higher RAIDs only)
[region_size <sectors>]
The region_size multiplied by the number of regions is the
logical size of the array. The bitmap records the device
synchronisation state for each region.
<#raid_devs>: The number of devices composing the array.
Each device consists of two entries. The first is the device

View file

@ -52,7 +52,7 @@ struct raid_dev {
#define DMPF_MAX_RECOVERY_RATE 0x20
#define DMPF_MAX_WRITE_BEHIND 0x40
#define DMPF_STRIPE_CACHE 0x80
#define DMPF_REGION_SIZE 0X100
struct raid_set {
struct dm_target *ti;
@ -236,6 +236,67 @@ static int dev_parms(struct raid_set *rs, char **argv)
return 0;
}
/*
* validate_region_size
* @rs
* @region_size: region size in sectors. If 0, pick a size (4MiB default).
*
* Set rs->md.bitmap_info.chunksize (which really refers to 'region size').
* Ensure that (ti->len/region_size < 2^21) - required by MD bitmap.
*
* Returns: 0 on success, -EINVAL on failure.
*/
static int validate_region_size(struct raid_set *rs, unsigned long region_size)
{
unsigned long min_region_size = rs->ti->len / (1 << 21);
if (!region_size) {
/*
* Choose a reasonable default. All figures in sectors.
*/
if (min_region_size > (1 << 13)) {
DMINFO("Choosing default region size of %lu sectors",
region_size);
region_size = min_region_size;
} else {
DMINFO("Choosing default region size of 4MiB");
region_size = 1 << 13; /* sectors */
}
} else {
/*
* Validate user-supplied value.
*/
if (region_size > rs->ti->len) {
rs->ti->error = "Supplied region size is too large";
return -EINVAL;
}
if (region_size < min_region_size) {
DMERR("Supplied region_size (%lu sectors) below minimum (%lu)",
region_size, min_region_size);
rs->ti->error = "Supplied region size is too small";
return -EINVAL;
}
if (!is_power_of_2(region_size)) {
rs->ti->error = "Region size is not a power of 2";
return -EINVAL;
}
if (region_size < rs->md.chunk_sectors) {
rs->ti->error = "Region size is smaller than the chunk size";
return -EINVAL;
}
}
/*
* Convert sectors to bytes.
*/
rs->md.bitmap_info.chunksize = (region_size << 9);
return 0;
}
/*
* Possible arguments are...
* RAID456:
@ -249,12 +310,13 @@ static int dev_parms(struct raid_set *rs, char **argv)
* [max_recovery_rate <kB/sec/disk>] Throttle RAID initialization
* [max_write_behind <sectors>] See '-write-behind=' (man mdadm)
* [stripe_cache <sectors>] Stripe cache size for higher RAIDs
* [region_size <sectors>] Defines granularity of bitmap
*/
static int parse_raid_params(struct raid_set *rs, char **argv,
unsigned num_raid_params)
{
unsigned i, rebuild_cnt = 0;
unsigned long value;
unsigned long value, region_size = 0;
char *key;
/*
@ -365,6 +427,9 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
return -EINVAL;
}
rs->md.sync_speed_max = (int)value;
} else if (!strcasecmp(key, "region_size")) {
rs->print_flags |= DMPF_REGION_SIZE;
region_size = value;
} else {
DMERR("Unable to parse RAID parameter: %s", key);
rs->ti->error = "Unable to parse RAID parameters";
@ -372,6 +437,14 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
}
}
if (validate_region_size(rs, region_size))
return -EINVAL;
if (rs->md.chunk_sectors)
rs->ti->split_io = rs->md.chunk_sectors;
else
rs->ti->split_io = region_size;
/* Assume there are no metadata devices until the drives are parsed */
rs->md.persistent = 0;
rs->md.external = 1;
@ -469,7 +542,6 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
INIT_WORK(&rs->md.event_work, do_table_event);
ti->split_io = rs->md.chunk_sectors;
ti->private = rs;
mutex_lock(&rs->md.reconfig_mutex);
@ -596,6 +668,10 @@ static int raid_status(struct dm_target *ti, status_type_t type,
conf ? conf->max_nr_stripes * 2 : 0);
}
if (rs->print_flags & DMPF_REGION_SIZE)
DMEMIT(" region_size %lu",
rs->md.bitmap_info.chunksize >> 9);
DMEMIT(" %d", rs->md.raid_disks);
for (i = 0; i < rs->md.raid_disks; i++) {
DMEMIT(" -"); /* metadata device */