| .. | .. |
|---|
| 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; |
|---|