@@ -270,6 +270,18 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
270270 goto abort ;
271271 }
272272
273+ if (conf -> layout == RAID0_ORIG_LAYOUT ) {
274+ for (i = 1 ; i < conf -> nr_strip_zones ; i ++ ) {
275+ sector_t first_sector = conf -> strip_zone [i - 1 ].zone_end ;
276+
277+ sector_div (first_sector , mddev -> chunk_sectors );
278+ zone = conf -> strip_zone + i ;
279+ /* disk_shift is first disk index used in the zone */
280+ zone -> disk_shift = sector_div (first_sector ,
281+ zone -> nb_dev );
282+ }
283+ }
284+
273285 pr_debug ("md/raid0:%s: done.\n" , mdname (mddev ));
274286 * private_conf = conf ;
275287
@@ -431,6 +443,20 @@ static int raid0_run(struct mddev *mddev)
431443 return ret ;
432444}
433445
446+ /*
447+ * Convert disk_index to the disk order in which it is read/written.
448+ * For example, if we have 4 disks, they are numbered 0,1,2,3. If we
449+ * write the disks starting at disk 3, then the read/write order would
450+ * be disk 3, then 0, then 1, and then disk 2 and we want map_disk_shift()
451+ * to map the disks as follows 0,1,2,3 => 1,2,3,0. So disk 0 would map
452+ * to 1, 1 to 2, 2 to 3, and 3 to 0. That way we can compare disks in
453+ * that 'output' space to understand the read/write disk ordering.
454+ */
455+ static int map_disk_shift (int disk_index , int num_disks , int disk_shift )
456+ {
457+ return ((disk_index + num_disks - disk_shift ) % num_disks );
458+ }
459+
434460static void raid0_handle_discard (struct mddev * mddev , struct bio * bio )
435461{
436462 struct r0conf * conf = mddev -> private ;
@@ -444,7 +470,9 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
444470 sector_t end_disk_offset ;
445471 unsigned int end_disk_index ;
446472 unsigned int disk ;
473+ sector_t orig_start , orig_end ;
447474
475+ orig_start = start ;
448476 zone = find_zone (conf , & start );
449477
450478 if (bio_end_sector (bio ) > zone -> zone_end ) {
@@ -458,6 +486,7 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
458486 } else
459487 end = bio_end_sector (bio );
460488
489+ orig_end = end ;
461490 if (zone != conf -> strip_zone )
462491 end = end - zone [-1 ].zone_end ;
463492
@@ -469,32 +498,49 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
469498 last_stripe_index = end ;
470499 sector_div (last_stripe_index , stripe_size );
471500
472- start_disk_index = (int )(start - first_stripe_index * stripe_size ) /
473- mddev -> chunk_sectors ;
501+ /* In the first zone the original and alternate layouts are the same */
502+ if ((conf -> layout == RAID0_ORIG_LAYOUT ) && (zone != conf -> strip_zone )) {
503+ sector_div (orig_start , mddev -> chunk_sectors );
504+ start_disk_index = sector_div (orig_start , zone -> nb_dev );
505+ start_disk_index = map_disk_shift (start_disk_index ,
506+ zone -> nb_dev ,
507+ zone -> disk_shift );
508+ sector_div (orig_end , mddev -> chunk_sectors );
509+ end_disk_index = sector_div (orig_end , zone -> nb_dev );
510+ end_disk_index = map_disk_shift (end_disk_index ,
511+ zone -> nb_dev , zone -> disk_shift );
512+ } else {
513+ start_disk_index = (int )(start - first_stripe_index * stripe_size ) /
514+ mddev -> chunk_sectors ;
515+ end_disk_index = (int )(end - last_stripe_index * stripe_size ) /
516+ mddev -> chunk_sectors ;
517+ }
474518 start_disk_offset = ((int )(start - first_stripe_index * stripe_size ) %
475519 mddev -> chunk_sectors ) +
476520 first_stripe_index * mddev -> chunk_sectors ;
477- end_disk_index = (int )(end - last_stripe_index * stripe_size ) /
478- mddev -> chunk_sectors ;
479521 end_disk_offset = ((int )(end - last_stripe_index * stripe_size ) %
480522 mddev -> chunk_sectors ) +
481523 last_stripe_index * mddev -> chunk_sectors ;
482524
483525 for (disk = 0 ; disk < zone -> nb_dev ; disk ++ ) {
484526 sector_t dev_start , dev_end ;
485527 struct md_rdev * rdev ;
528+ int compare_disk ;
529+
530+ compare_disk = map_disk_shift (disk , zone -> nb_dev ,
531+ zone -> disk_shift );
486532
487- if (disk < start_disk_index )
533+ if (compare_disk < start_disk_index )
488534 dev_start = (first_stripe_index + 1 ) *
489535 mddev -> chunk_sectors ;
490- else if (disk > start_disk_index )
536+ else if (compare_disk > start_disk_index )
491537 dev_start = first_stripe_index * mddev -> chunk_sectors ;
492538 else
493539 dev_start = start_disk_offset ;
494540
495- if (disk < end_disk_index )
541+ if (compare_disk < end_disk_index )
496542 dev_end = (last_stripe_index + 1 ) * mddev -> chunk_sectors ;
497- else if (disk > end_disk_index )
543+ else if (compare_disk > end_disk_index )
498544 dev_end = last_stripe_index * mddev -> chunk_sectors ;
499545 else
500546 dev_end = end_disk_offset ;
0 commit comments