.. | .. |
---|
274 | 274 | goto abort; |
---|
275 | 275 | } |
---|
276 | 276 | |
---|
| 277 | + if (conf->layout == RAID0_ORIG_LAYOUT) { |
---|
| 278 | + for (i = 1; i < conf->nr_strip_zones; i++) { |
---|
| 279 | + sector_t first_sector = conf->strip_zone[i-1].zone_end; |
---|
| 280 | + |
---|
| 281 | + sector_div(first_sector, mddev->chunk_sectors); |
---|
| 282 | + zone = conf->strip_zone + i; |
---|
| 283 | + /* disk_shift is first disk index used in the zone */ |
---|
| 284 | + zone->disk_shift = sector_div(first_sector, |
---|
| 285 | + zone->nb_dev); |
---|
| 286 | + } |
---|
| 287 | + } |
---|
| 288 | + |
---|
277 | 289 | pr_debug("md/raid0:%s: done.\n", mdname(mddev)); |
---|
278 | 290 | *private_conf = conf; |
---|
279 | 291 | |
---|
.. | .. |
---|
427 | 439 | kfree(conf); |
---|
428 | 440 | } |
---|
429 | 441 | |
---|
| 442 | +/* |
---|
| 443 | + * Convert disk_index to the disk order in which it is read/written. |
---|
| 444 | + * For example, if we have 4 disks, they are numbered 0,1,2,3. If we |
---|
| 445 | + * write the disks starting at disk 3, then the read/write order would |
---|
| 446 | + * be disk 3, then 0, then 1, and then disk 2 and we want map_disk_shift() |
---|
| 447 | + * to map the disks as follows 0,1,2,3 => 1,2,3,0. So disk 0 would map |
---|
| 448 | + * to 1, 1 to 2, 2 to 3, and 3 to 0. That way we can compare disks in |
---|
| 449 | + * that 'output' space to understand the read/write disk ordering. |
---|
| 450 | + */ |
---|
| 451 | +static int map_disk_shift(int disk_index, int num_disks, int disk_shift) |
---|
| 452 | +{ |
---|
| 453 | + return ((disk_index + num_disks - disk_shift) % num_disks); |
---|
| 454 | +} |
---|
| 455 | + |
---|
430 | 456 | static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) |
---|
431 | 457 | { |
---|
432 | 458 | struct r0conf *conf = mddev->private; |
---|
.. | .. |
---|
440 | 466 | sector_t end_disk_offset; |
---|
441 | 467 | unsigned int end_disk_index; |
---|
442 | 468 | unsigned int disk; |
---|
| 469 | + sector_t orig_start, orig_end; |
---|
443 | 470 | |
---|
| 471 | + orig_start = start; |
---|
444 | 472 | zone = find_zone(conf, &start); |
---|
445 | 473 | |
---|
446 | 474 | if (bio_end_sector(bio) > zone->zone_end) { |
---|
.. | .. |
---|
454 | 482 | } else |
---|
455 | 483 | end = bio_end_sector(bio); |
---|
456 | 484 | |
---|
| 485 | + orig_end = end; |
---|
457 | 486 | if (zone != conf->strip_zone) |
---|
458 | 487 | end = end - zone[-1].zone_end; |
---|
459 | 488 | |
---|
.. | .. |
---|
465 | 494 | last_stripe_index = end; |
---|
466 | 495 | sector_div(last_stripe_index, stripe_size); |
---|
467 | 496 | |
---|
468 | | - start_disk_index = (int)(start - first_stripe_index * stripe_size) / |
---|
469 | | - mddev->chunk_sectors; |
---|
| 497 | + /* In the first zone the original and alternate layouts are the same */ |
---|
| 498 | + if ((conf->layout == RAID0_ORIG_LAYOUT) && (zone != conf->strip_zone)) { |
---|
| 499 | + sector_div(orig_start, mddev->chunk_sectors); |
---|
| 500 | + start_disk_index = sector_div(orig_start, zone->nb_dev); |
---|
| 501 | + start_disk_index = map_disk_shift(start_disk_index, |
---|
| 502 | + zone->nb_dev, |
---|
| 503 | + zone->disk_shift); |
---|
| 504 | + sector_div(orig_end, mddev->chunk_sectors); |
---|
| 505 | + end_disk_index = sector_div(orig_end, zone->nb_dev); |
---|
| 506 | + end_disk_index = map_disk_shift(end_disk_index, |
---|
| 507 | + zone->nb_dev, zone->disk_shift); |
---|
| 508 | + } else { |
---|
| 509 | + start_disk_index = (int)(start - first_stripe_index * stripe_size) / |
---|
| 510 | + mddev->chunk_sectors; |
---|
| 511 | + end_disk_index = (int)(end - last_stripe_index * stripe_size) / |
---|
| 512 | + mddev->chunk_sectors; |
---|
| 513 | + } |
---|
470 | 514 | start_disk_offset = ((int)(start - first_stripe_index * stripe_size) % |
---|
471 | 515 | mddev->chunk_sectors) + |
---|
472 | 516 | first_stripe_index * mddev->chunk_sectors; |
---|
473 | | - end_disk_index = (int)(end - last_stripe_index * stripe_size) / |
---|
474 | | - mddev->chunk_sectors; |
---|
475 | 517 | end_disk_offset = ((int)(end - last_stripe_index * stripe_size) % |
---|
476 | 518 | mddev->chunk_sectors) + |
---|
477 | 519 | last_stripe_index * mddev->chunk_sectors; |
---|
.. | .. |
---|
480 | 522 | sector_t dev_start, dev_end; |
---|
481 | 523 | struct bio *discard_bio = NULL; |
---|
482 | 524 | struct md_rdev *rdev; |
---|
| 525 | + int compare_disk; |
---|
483 | 526 | |
---|
484 | | - if (disk < start_disk_index) |
---|
| 527 | + compare_disk = map_disk_shift(disk, zone->nb_dev, |
---|
| 528 | + zone->disk_shift); |
---|
| 529 | + |
---|
| 530 | + if (compare_disk < start_disk_index) |
---|
485 | 531 | dev_start = (first_stripe_index + 1) * |
---|
486 | 532 | mddev->chunk_sectors; |
---|
487 | | - else if (disk > start_disk_index) |
---|
| 533 | + else if (compare_disk > start_disk_index) |
---|
488 | 534 | dev_start = first_stripe_index * mddev->chunk_sectors; |
---|
489 | 535 | else |
---|
490 | 536 | dev_start = start_disk_offset; |
---|
491 | 537 | |
---|
492 | | - if (disk < end_disk_index) |
---|
| 538 | + if (compare_disk < end_disk_index) |
---|
493 | 539 | dev_end = (last_stripe_index + 1) * mddev->chunk_sectors; |
---|
494 | | - else if (disk > end_disk_index) |
---|
| 540 | + else if (compare_disk > end_disk_index) |
---|
495 | 541 | dev_end = last_stripe_index * mddev->chunk_sectors; |
---|
496 | 542 | else |
---|
497 | 543 | dev_end = end_disk_offset; |
---|