diff options
author | Jonathan Brassow <jbrassow@redhat.com> | 2011-08-02 07:32:07 -0400 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2011-08-02 07:32:07 -0400 |
commit | c1084561bb85da3630540ebe951749a8cd8fc714 (patch) | |
tree | ecdefcf24dd88f4c19a873fa5d26039a0edf03a7 /drivers/md | |
parent | c0a2fa1ef1057a1e9450d6f055f1cde2ad4f85a2 (diff) |
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>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-raid.c | 82 |
1 files changed, 79 insertions, 3 deletions
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index d4e95b2e39f6..a8a1915a450d 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c | |||
@@ -52,7 +52,7 @@ struct raid_dev { | |||
52 | #define DMPF_MAX_RECOVERY_RATE 0x20 | 52 | #define DMPF_MAX_RECOVERY_RATE 0x20 |
53 | #define DMPF_MAX_WRITE_BEHIND 0x40 | 53 | #define DMPF_MAX_WRITE_BEHIND 0x40 |
54 | #define DMPF_STRIPE_CACHE 0x80 | 54 | #define DMPF_STRIPE_CACHE 0x80 |
55 | 55 | #define DMPF_REGION_SIZE 0X100 | |
56 | struct raid_set { | 56 | struct raid_set { |
57 | struct dm_target *ti; | 57 | struct dm_target *ti; |
58 | 58 | ||
@@ -237,6 +237,67 @@ static int dev_parms(struct raid_set *rs, char **argv) | |||
237 | } | 237 | } |
238 | 238 | ||
239 | /* | 239 | /* |
240 | * validate_region_size | ||
241 | * @rs | ||
242 | * @region_size: region size in sectors. If 0, pick a size (4MiB default). | ||
243 | * | ||
244 | * Set rs->md.bitmap_info.chunksize (which really refers to 'region size'). | ||
245 | * Ensure that (ti->len/region_size < 2^21) - required by MD bitmap. | ||
246 | * | ||
247 | * Returns: 0 on success, -EINVAL on failure. | ||
248 | */ | ||
249 | static int validate_region_size(struct raid_set *rs, unsigned long region_size) | ||
250 | { | ||
251 | unsigned long min_region_size = rs->ti->len / (1 << 21); | ||
252 | |||
253 | if (!region_size) { | ||
254 | /* | ||
255 | * Choose a reasonable default. All figures in sectors. | ||
256 | */ | ||
257 | if (min_region_size > (1 << 13)) { | ||
258 | DMINFO("Choosing default region size of %lu sectors", | ||
259 | region_size); | ||
260 | region_size = min_region_size; | ||
261 | } else { | ||
262 | DMINFO("Choosing default region size of 4MiB"); | ||
263 | region_size = 1 << 13; /* sectors */ | ||
264 | } | ||
265 | } else { | ||
266 | /* | ||
267 | * Validate user-supplied value. | ||
268 | */ | ||
269 | if (region_size > rs->ti->len) { | ||
270 | rs->ti->error = "Supplied region size is too large"; | ||
271 | return -EINVAL; | ||
272 | } | ||
273 | |||
274 | if (region_size < min_region_size) { | ||
275 | DMERR("Supplied region_size (%lu sectors) below minimum (%lu)", | ||
276 | region_size, min_region_size); | ||
277 | rs->ti->error = "Supplied region size is too small"; | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | if (!is_power_of_2(region_size)) { | ||
282 | rs->ti->error = "Region size is not a power of 2"; | ||
283 | return -EINVAL; | ||
284 | } | ||
285 | |||
286 | if (region_size < rs->md.chunk_sectors) { | ||
287 | rs->ti->error = "Region size is smaller than the chunk size"; | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * Convert sectors to bytes. | ||
294 | */ | ||
295 | rs->md.bitmap_info.chunksize = (region_size << 9); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /* | ||
240 | * Possible arguments are... | 301 | * Possible arguments are... |
241 | * RAID456: | 302 | * RAID456: |
242 | * <chunk_size> [optional_args] | 303 | * <chunk_size> [optional_args] |
@@ -249,12 +310,13 @@ static int dev_parms(struct raid_set *rs, char **argv) | |||
249 | * [max_recovery_rate <kB/sec/disk>] Throttle RAID initialization | 310 | * [max_recovery_rate <kB/sec/disk>] Throttle RAID initialization |
250 | * [max_write_behind <sectors>] See '-write-behind=' (man mdadm) | 311 | * [max_write_behind <sectors>] See '-write-behind=' (man mdadm) |
251 | * [stripe_cache <sectors>] Stripe cache size for higher RAIDs | 312 | * [stripe_cache <sectors>] Stripe cache size for higher RAIDs |
313 | * [region_size <sectors>] Defines granularity of bitmap | ||
252 | */ | 314 | */ |
253 | static int parse_raid_params(struct raid_set *rs, char **argv, | 315 | static int parse_raid_params(struct raid_set *rs, char **argv, |
254 | unsigned num_raid_params) | 316 | unsigned num_raid_params) |
255 | { | 317 | { |
256 | unsigned i, rebuild_cnt = 0; | 318 | unsigned i, rebuild_cnt = 0; |
257 | unsigned long value; | 319 | unsigned long value, region_size = 0; |
258 | char *key; | 320 | char *key; |
259 | 321 | ||
260 | /* | 322 | /* |
@@ -365,6 +427,9 @@ static int parse_raid_params(struct raid_set *rs, char **argv, | |||
365 | return -EINVAL; | 427 | return -EINVAL; |
366 | } | 428 | } |
367 | rs->md.sync_speed_max = (int)value; | 429 | rs->md.sync_speed_max = (int)value; |
430 | } else if (!strcasecmp(key, "region_size")) { | ||
431 | rs->print_flags |= DMPF_REGION_SIZE; | ||
432 | region_size = value; | ||
368 | } else { | 433 | } else { |
369 | DMERR("Unable to parse RAID parameter: %s", key); | 434 | DMERR("Unable to parse RAID parameter: %s", key); |
370 | rs->ti->error = "Unable to parse RAID parameters"; | 435 | rs->ti->error = "Unable to parse RAID parameters"; |
@@ -372,6 +437,14 @@ static int parse_raid_params(struct raid_set *rs, char **argv, | |||
372 | } | 437 | } |
373 | } | 438 | } |
374 | 439 | ||
440 | if (validate_region_size(rs, region_size)) | ||
441 | return -EINVAL; | ||
442 | |||
443 | if (rs->md.chunk_sectors) | ||
444 | rs->ti->split_io = rs->md.chunk_sectors; | ||
445 | else | ||
446 | rs->ti->split_io = region_size; | ||
447 | |||
375 | /* Assume there are no metadata devices until the drives are parsed */ | 448 | /* Assume there are no metadata devices until the drives are parsed */ |
376 | rs->md.persistent = 0; | 449 | rs->md.persistent = 0; |
377 | rs->md.external = 1; | 450 | rs->md.external = 1; |
@@ -469,7 +542,6 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
469 | goto bad; | 542 | goto bad; |
470 | 543 | ||
471 | INIT_WORK(&rs->md.event_work, do_table_event); | 544 | INIT_WORK(&rs->md.event_work, do_table_event); |
472 | ti->split_io = rs->md.chunk_sectors; | ||
473 | ti->private = rs; | 545 | ti->private = rs; |
474 | 546 | ||
475 | mutex_lock(&rs->md.reconfig_mutex); | 547 | mutex_lock(&rs->md.reconfig_mutex); |
@@ -596,6 +668,10 @@ static int raid_status(struct dm_target *ti, status_type_t type, | |||
596 | conf ? conf->max_nr_stripes * 2 : 0); | 668 | conf ? conf->max_nr_stripes * 2 : 0); |
597 | } | 669 | } |
598 | 670 | ||
671 | if (rs->print_flags & DMPF_REGION_SIZE) | ||
672 | DMEMIT(" region_size %lu", | ||
673 | rs->md.bitmap_info.chunksize >> 9); | ||
674 | |||
599 | DMEMIT(" %d", rs->md.raid_disks); | 675 | DMEMIT(" %d", rs->md.raid_disks); |
600 | for (i = 0; i < rs->md.raid_disks; i++) { | 676 | for (i = 0; i < rs->md.raid_disks; i++) { |
601 | DMEMIT(" -"); /* metadata device */ | 677 | DMEMIT(" -"); /* metadata device */ |