From: "wangqiang (AY)" <wangqiang62@xxxxxxxxxx> sd_remove() waits for the completion of async threads executing sd_probe_async of disks on unrelated host adapters, rather than just the the async thread associated with the scsi_disk being removed. This patch makes sd_remove() just wait for the the async thread associated with the scsi_disk being removed. And makes the operation of iscsid after received ISCSI_KEVENT_CONN_ERROR be asynchronous by put the __iscsi_destroy_session() in work queue. Signed-off-by: "wangqiang (AY)" <wangqiang62@xxxxxxxxxx> Signed-off-by: Ming Lin <mlin@xxxxxxxxxx> --- drivers/scsi/scsi_transport_iscsi.c | 14 +++++++++++++- drivers/scsi/sd.c | 5 +++-- drivers/scsi/sd.h | 3 +++ include/scsi/scsi_transport_iscsi.h | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 0a82e93566dc..7e5782eb527b 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2005,6 +2005,16 @@ void iscsi_block_session(struct iscsi_cls_session *session) } EXPORT_SYMBOL_GPL(iscsi_block_session); +static void __iscsi_destroy_session(struct work_struct *work) +{ + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, + destroy_work); + struct iscsi_transport *transport = session->transport; + + transport->destroy_session(session); +} + static void __iscsi_unbind_session(struct work_struct *work) { struct iscsi_cls_session *session = @@ -2061,6 +2071,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, INIT_WORK(&session->block_work, __iscsi_block_session); INIT_WORK(&session->unbind_work, __iscsi_unbind_session); INIT_WORK(&session->scan_work, iscsi_scan_session); + INIT_WORK(&session->destroy_work, __iscsi_destroy_session); spin_lock_init(&session->lock); /* this is released in the dev's release function */ @@ -3536,7 +3547,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) case ISCSI_UEVENT_DESTROY_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); if (session) - transport->destroy_session(session); + scsi_queue_work(iscsi_session_to_shost(session), + &session->destroy_work); else err = -EINVAL; break; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2b2bc4b49d78..378f57142183 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3436,7 +3436,8 @@ static int sd_probe(struct device *dev) dev_set_drvdata(dev, sdkp); get_device(&sdkp->dev); /* prevent release before async_schedule */ - async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain); + INIT_LIST_HEAD(&sdkp->sd_probe_domain.pending); + async_schedule_domain(sd_probe_async, sdkp, &sdkp->sd_probe_domain); return 0; @@ -3472,7 +3473,7 @@ static int sd_remove(struct device *dev) scsi_autopm_get_device(sdkp->device); async_synchronize_full_domain(&scsi_sd_pm_domain); - async_synchronize_full_domain(&scsi_sd_probe_domain); + async_synchronize_full_domain(&sdkp->sd_probe_domain); device_del(&sdkp->dev); del_gendisk(sdkp->disk); sd_shutdown(dev); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 5796ace76225..f46a87ebd759 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -2,6 +2,8 @@ #ifndef _SCSI_DISK_H #define _SCSI_DISK_H +#include <linux/async.h> + /* * More than enough for everybody ;) The huge number of majors * is a leftover from 16bit dev_t days, we don't really need that @@ -73,6 +75,7 @@ struct scsi_disk { struct device dev; struct gendisk *disk; struct opal_dev *opal_dev; + struct async_domain sd_probe_domain; #ifdef CONFIG_BLK_DEV_ZONED u32 nr_zones; u32 zone_blocks; diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index b266d2a3bcb1..7830e1596ef3 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -238,6 +238,7 @@ struct iscsi_cls_session { struct work_struct unblock_work; struct work_struct scan_work; struct work_struct unbind_work; + struct work_struct destroy_work; /* recovery fields */ int recovery_tmo; -- 2.14.4.52.g320db32