Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: iscsi: ql4xxx: Use per-session workqueue for unbinding

We currently allocate a workqueue per host and only use it for removing the
target. For the session per host case we could be using this workqueue to
be able to do recoveries (block, unblock, timeout handling) in parallel. To
also allow offload drivers to do their session recoveries in parallel, this
drops the per host workqueue and replaces it with a per session one.

Link: https://lore.kernel.org/r/20220226230435.38733-5-michael.christie@oracle.com
Reviewed-by: Lee Duncan <lduncan@suse.com>
Reviewed-by: Chris Leech <cleech@redhat.com>
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Mike Christie and committed by
Martin K. Petersen
5842ea36 d8ec5d67

+17 -6
+1 -1
drivers/scsi/qla4xxx/ql4_os.c
··· 5096 5096 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" 5097 5097 " start scan\n", ha->host_no, __func__, 5098 5098 ddb_entry->fw_ddb_index); 5099 - scsi_queue_work(ha->host, &ddb_entry->sess->scan_work); 5099 + queue_work(ddb_entry->sess->workq, &ddb_entry->sess->scan_work); 5100 5100 } 5101 5101 return QLA_SUCCESS; 5102 5102 }
+14 -5
drivers/scsi/scsi_transport_iscsi.c
··· 2032 2032 2033 2033 int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) 2034 2034 { 2035 + struct Scsi_Host *shost = iscsi_session_to_shost(session); 2035 2036 unsigned long flags; 2036 2037 int id = 0; 2037 2038 int err; 2038 2039 2039 2040 session->sid = atomic_add_return(1, &iscsi_session_nr); 2041 + 2042 + session->workq = alloc_workqueue("iscsi_ctrl_%d:%d", 2043 + WQ_SYSFS | WQ_MEM_RECLAIM | WQ_UNBOUND, 0, 2044 + shost->host_no, session->sid); 2045 + if (!session->workq) 2046 + return -ENOMEM; 2040 2047 2041 2048 if (target_id == ISCSI_MAX_TARGET) { 2042 2049 id = ida_simple_get(&iscsi_sess_ida, 0, 0, GFP_KERNEL); ··· 2051 2044 if (id < 0) { 2052 2045 iscsi_cls_session_printk(KERN_ERR, session, 2053 2046 "Failure in Target ID Allocation\n"); 2054 - return id; 2047 + err = id; 2048 + goto destroy_wq; 2055 2049 } 2056 2050 session->target_id = (unsigned int)id; 2057 2051 session->ida_used = true; ··· 2086 2078 release_ida: 2087 2079 if (session->ida_used) 2088 2080 ida_simple_remove(&iscsi_sess_ida, session->target_id); 2089 - 2081 + destroy_wq: 2082 + destroy_workqueue(session->workq); 2090 2083 return err; 2091 2084 } 2092 2085 EXPORT_SYMBOL_GPL(iscsi_add_session); ··· 2185 2176 "for session. Error %d.\n", err); 2186 2177 2187 2178 transport_unregister_device(&session->dev); 2179 + 2180 + destroy_workqueue(session->workq); 2188 2181 2189 2182 ISCSI_DBG_TRANS_SESSION(session, "Completing session removal\n"); 2190 2183 device_del(&session->dev); ··· 3844 3833 case ISCSI_UEVENT_UNBIND_SESSION: 3845 3834 session = iscsi_session_lookup(ev->u.d_session.sid); 3846 3835 if (session) 3847 - scsi_queue_work(iscsi_session_to_shost(session), 3848 - &session->unbind_work); 3836 + queue_work(session->workq, &session->unbind_work); 3849 3837 else 3850 3838 err = -EINVAL; 3851 3839 break; ··· 4717 4707 INIT_LIST_HEAD(&priv->list); 4718 4708 priv->iscsi_transport = tt; 4719 4709 priv->t.user_scan = iscsi_user_scan; 4720 - priv->t.create_work_queue = 1; 4721 4710 4722 4711 priv->dev.class = &iscsi_transport_class; 4723 4712 dev_set_name(&priv->dev, "%s", tt->name);
+2
include/scsi/scsi_transport_iscsi.h
··· 251 251 bool recovery_tmo_sysfs_override; 252 252 struct delayed_work recovery_work; 253 253 254 + struct workqueue_struct *workq; 255 + 254 256 unsigned int target_id; 255 257 bool ida_used; 256 258