scsi: libsas: Abort all in-flight requests when device is gone

commit 0e4b1791d9 upstream.

When a disk is removed with in-flight I/O, the application needs to wait
for 30 seconds (depending on the timeout configuration) to hear back from
the kernel. Xingui tried to fix this issue by aborting the ATA link for
SATA devices[1], however this approach left the SAS devices unresolved.

Try to fix this issue by aborting all in-flight requests when the device is
gone. This is implemented by iterating over the tagset.

[1] https://lore.kernel.org/lkml/234e04db-7539-07e4-a6b8-c6b05f78193d@opensource.wdc.com/T/

Cc: Xingui Yang <yangxingui@huawei.com>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Cc: Hannes Reinecke <hare@suse.com>
Signed-off-by: Jason Yan <yanaijie@huawei.com>
Link: https://lore.kernel.org/r/20230330110930.175539-1-yanaijie@huawei.com
Reviewed-by: John Garry <john.g.garry@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jianping Liu <frankjpliu@tencent.com>
This commit is contained in:
Jason Yan 2023-03-30 19:09:30 +08:00 committed by Jianping Liu
parent 933e551af2
commit 13c3aa7632
1 changed files with 29 additions and 0 deletions

View File

@ -367,6 +367,33 @@ static void sas_destruct_ports(struct asd_sas_port *port)
}
}
static bool sas_abort_cmd(struct request *req, void *data, bool reserved)
{
struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req);
struct domain_device *dev = data;
if (dev == cmd_to_domain_dev(cmd))
blk_abort_request(req);
return true;
}
static void sas_abort_device_scsi_cmds(struct domain_device *dev)
{
struct sas_ha_struct *sas_ha = dev->port->ha;
struct Scsi_Host *shost = sas_ha->core.shost;
if (dev_is_expander(dev->dev_type))
return;
/*
* For removed device with active IOs, the user space applications have
* to spend very long time waiting for the timeout. This is not
* necessary because a removed device will not return the IOs.
* Abort the inflight IOs here so that EH can be quickly kicked in.
*/
blk_mq_tagset_busy_iter(&shost->tag_set, sas_abort_cmd, dev);
}
void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
{
if (!test_bit(SAS_DEV_DESTROY, &dev->state) &&
@ -379,6 +406,8 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
}
if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
if (test_bit(SAS_DEV_GONE, &dev->state))
sas_abort_device_scsi_cmds(dev);
sas_rphy_unlink(dev->rphy);
list_move_tail(&dev->disco_list_node, &port->destroy_list);
}