From: John Garry <[email protected]> Failover occurs when the scsi_cmnd has failed and it is discovered that the target scsi_device has transport down.
For a scsi command which suffers failover, requeue the master bio of each bio attached to its request. A bio which for which failover occurs is handled in scsi_mpath_clone_end_io(). Failover is detected for blk_path_error() occuring, same as how dm-mpath detects this. Signed-off-by: John Garry <[email protected]> --- drivers/scsi/scsi_multipath.c | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/scsi/scsi_multipath.c b/drivers/scsi/scsi_multipath.c index b896d28a7dd9a..a482b6ede21aa 100644 --- a/drivers/scsi/scsi_multipath.c +++ b/drivers/scsi/scsi_multipath.c @@ -248,11 +248,53 @@ void scsi_mpath_dev_clear_path(struct scsi_mpath_device *scsi_mpath_dev) mpath_synchronize(mpath_head); } +static inline void bio_list_add_clone(struct bio_list *bl, + struct bio *clone) +{ + struct bio *master_bio = clone->bi_private; + + if (bl->tail) + bl->tail->bi_next = master_bio; + else + bl->head = master_bio; + bl->tail = master_bio; + bio_put(clone); +} + static void scsi_mpath_clone_end_io(struct bio *clone) { struct bio *master_bio = clone->bi_private; master_bio->bi_status = clone->bi_status; + + if (clone->bi_status && blk_path_error(clone->bi_status)) { + struct block_device *bi_bdev = clone->bi_bdev; + struct request_queue *q = bi_bdev->bd_queue; + struct scsi_device *sdev = scsi_device_from_queue(q); + struct scsi_mpath_device *scsi_mpath_dev; + struct mpath_device *mpath_device; + struct mpath_head *mpath_head; + unsigned long flags; + + if (!sdev) { + master_bio->bi_status = clone->bi_status; + goto end_bio; + } + + scsi_mpath_dev = sdev->scsi_mpath_dev; + mpath_device = &scsi_mpath_dev->mpath_device; + mpath_head = mpath_device->mpath_head; + + spin_lock_irqsave(&mpath_head->requeue_lock, flags); + bio_list_add_clone(&mpath_head->requeue_list, clone); + spin_unlock_irqrestore(&mpath_head->requeue_lock, flags); + + mpath_schedule_requeue_work(mpath_head); + scsi_device_put(sdev); + return; + } + +end_bio: bio_put(clone); bio_endio(master_bio); } -- 2.43.7

