From e5de4212c71fe34011c8a6d3eecefd0531f87560 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Wed, 10 Dec 2025 08:39:30 +0300 Subject: [PATCH 1/4] qla2x00t-32gbit: Replace use of system_unbound_wq with system_dfl_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistency cannot be addressed without refactoring the API. system_unbound_wq should be the default workqueue so as not to enforce locality constraints for random work whenever it's not required. Adding system_dfl_wq to encourage its use when unbound work should be used. The old system_unbound_wq will be kept for a few release cycles. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Link: https://patch.msgid.link/20251031095643.74246-2-marco.crivellari@suse.com Signed-off-by: Martin K. Petersen [ commit 49783aca15fb upstream ] --- qla2x00t-32gbit/qla_os.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 58bb926fd..25bdb4866 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -5402,7 +5402,11 @@ void qla24xx_sched_upd_fcport(fc_port_t *fcport) qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT); spin_unlock_irqrestore(&fcport->vha->work_lock, flags); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 19, 0) queue_work(system_unbound_wq, &fcport->reg_work); +#else + queue_work(system_dfl_wq, &fcport->reg_work); +#endif } static From 69ec43337516e519aa1d9bf29f551d7f8fc97471 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Wed, 10 Dec 2025 19:49:32 +0300 Subject: [PATCH 2/4] scst: annotate workqueues for WQ_PERCPU / WQ_UNBOUND Upstream workqueue changes introduce a new WQ_PERCPU flag and plan to switch alloc_workqueue()'s default from per-CPU to unbound To kepp SCST behaviour unchanged across kernels, this patch makes all alloc_workqueue() users explicit about whether they want per-CPU or unbound queues. --- iscsi-scst/kernel/isert-scst/iser_global.c | 7 +++++-- iscsi-scst/kernel/isert-scst/iser_rdma.c | 7 +++++-- qla2x00t-32gbit/qla_os.c | 6 +++++- qla2x00t/qla_os.c | 6 +++++- scst/src/scst_event.c | 4 +++- scst/src/scst_lib.c | 4 +++- srpt/src/ib_srpt.c | 6 +++++- 7 files changed, 31 insertions(+), 9 deletions(-) diff --git a/iscsi-scst/kernel/isert-scst/iser_global.c b/iscsi-scst/kernel/isert-scst/iser_global.c index 7f7ec72bc..a1e12fb45 100644 --- a/iscsi-scst/kernel/isert-scst/iser_global.c +++ b/iscsi-scst/kernel/isert-scst/iser_global.c @@ -138,7 +138,11 @@ int isert_global_init(void) spin_lock_init(&isert_glob.portal_lock); init_waitqueue_head(&isert_glob.portal_wq); - isert_glob.conn_wq = alloc_workqueue("isert_conn_wq", 0, 1); + isert_glob.conn_wq = alloc_workqueue("isert_conn_wq", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + , 1); if (!isert_glob.conn_wq) { PRINT_ERROR("Failed to alloc iser conn work queue"); return -ENOMEM; @@ -164,7 +168,6 @@ int isert_global_init(void) free_wq: destroy_workqueue(isert_glob.conn_wq); - return -ENOMEM; } diff --git a/iscsi-scst/kernel/isert-scst/iser_rdma.c b/iscsi-scst/kernel/isert-scst/iser_rdma.c index 6ed53bc86..dc8c45c1d 100644 --- a/iscsi-scst/kernel/isert-scst/iser_rdma.c +++ b/iscsi-scst/kernel/isert-scst/iser_rdma.c @@ -973,8 +973,11 @@ static struct isert_device *isert_device_create(struct ib_device *ib_dev) cq_desc->idx = i; INIT_WORK(&cq_desc->cq_comp_work, isert_cq_comp_work_cb); - cq_desc->cq_workqueue = alloc_workqueue("isert_cq_%p", - WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1, + cq_desc->cq_workqueue = alloc_workqueue("isert_cq_%p", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1, cq_desc); if (unlikely(!cq_desc->cq_workqueue)) { PRINT_ERROR("Failed to alloc iser cq work queue for dev:%s", diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 25bdb4866..827412a72 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -3508,7 +3508,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n", req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out); - ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 0); + ha->wq = alloc_workqueue("qla2xxx_wq", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + | WQ_MEM_RECLAIM, 0); if (unlikely(!ha->wq)) { ret = -ENOMEM; goto probe_failed; diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c index 6279b6374..f4ce5704d 100644 --- a/qla2x00t/qla_os.c +++ b/qla2x00t/qla_os.c @@ -468,7 +468,11 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) "Failed to create request queue.\n"); goto fail; } - ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1); + ha->wq = alloc_workqueue("qla2xxx_wq", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + | WQ_MEM_RECLAIM, 1); vha->req = ha->req_q_map[req]; options |= BIT_1; for (ques = 1; ques < ha->max_rsp_queues; ques++) { diff --git a/scst/src/scst_event.c b/scst/src/scst_event.c index 857155dd3..2c2ff49e8 100644 --- a/scst/src/scst_event.c +++ b/scst/src/scst_event.c @@ -1082,7 +1082,9 @@ int scst_event_init(void) TRACE_ENTRY(); - scst_event_wq = alloc_workqueue("scst_event_wq", 0, 0); + scst_event_wq = alloc_workqueue("scst_event_wq", 0 + | WQ_UNBOUND, + 0); if (unlikely(!scst_event_wq)) { PRINT_ERROR("Failed to allocate scst_event_wq"); res = -ENOMEM; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index a78b7a916..eb7f70daa 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -15747,7 +15747,9 @@ int __init scst_lib_init(void) scst_scsi_op_list_init(); - scst_release_acg_wq = alloc_workqueue("scst_release_acg", 0, 1); + scst_release_acg_wq = alloc_workqueue("scst_release_acg", 0 + | WQ_UNBOUND, + 0); if (unlikely(!scst_release_acg_wq)) { PRINT_ERROR("Failed to allocate scst_release_acg_wq"); res = -ENOMEM; diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 056ac4ec0..b999ab6c0 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -4562,7 +4562,11 @@ static int __init srpt_init_module(void) goto out; } - srpt_wq = alloc_workqueue("srpt", WQ_SYSFS, 0); + srpt_wq = alloc_workqueue("srpt", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + | WQ_SYSFS, 0); if (!srpt_wq) { pr_err("Couldn't allocate the ib_srpt workqueue\n"); ret = -ENOMEM; From 57878f7388db9228c4bd18f90290a0db218b7ede Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Wed, 10 Dec 2025 21:16:03 +0300 Subject: [PATCH 3/4] qla2x00t-32gbit: Fix improper freeing of purex item In qla2xxx_process_purls_iocb(), an item is allocated via qla27xx_copy_multiple_pkt(), which internally calls qla24xx_alloc_purex_item(). The qla24xx_alloc_purex_item() function may return a pre-allocated item from a per-adapter pool for small allocations, instead of dynamically allocating memory with kzalloc(). An error handling path in qla2xxx_process_purls_iocb() incorrectly uses kfree() to release the item. If the item was from the pre-allocated pool, calling kfree() on it is a bug that can lead to memory corruption. Fix this by using the correct deallocation function, qla24xx_free_purex_item(), which properly handles both dynamically allocated and pre-allocated items. Fixes: 875386b98857 ("scsi: qla2xxx: Add Unsolicited LS Request and Response Support for NVMe") Signed-off-by: Zilin Guan Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251113151246.762510-1-zilin@seu.edu.cn Signed-off-by: Martin K. Petersen [ commit 78b1a242fe61 upstream ] --- qla2x00t-32gbit/qla_nvme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qla2x00t-32gbit/qla_nvme.c b/qla2x00t-32gbit/qla_nvme.c index 1fd13dbe1..c6ef8e7e8 100644 --- a/qla2x00t-32gbit/qla_nvme.c +++ b/qla2x00t-32gbit/qla_nvme.c @@ -1257,7 +1257,7 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) a.reason = FCNVME_RJT_RC_LOGIC; a.explanation = FCNVME_RJT_EXP_NONE; xmt_reject = true; - kfree(item); + qla24xx_free_purex_item(item); goto out; } From 0e4401f9085c62c860533c65a2690f9600fa891b Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Wed, 10 Dec 2025 21:22:42 +0300 Subject: [PATCH 4/4] qla2x00t, qla2x00t-32gbit: Port to Linux kernel v6.19 Support for the following changes in the Linux kernel v6.19: - 383d89699c50 ("treewide: Drop pci_save_state() after pci_restore_state()") --- qla2x00t-32gbit/qla_os.c | 2 ++ qla2x00t/qla_os.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 827412a72..319d6ba2b 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -8029,10 +8029,12 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) pci_restore_state(pdev); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 19, 0) /* pci_restore_state() clears the saved_state flag of the device * save restored state which resets saved_state flag */ pci_save_state(pdev); +#endif if (ha->mem_only) rc = pci_enable_device_mem(pdev); diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c index f4ce5704d..db3dc939d 100644 --- a/qla2x00t/qla_os.c +++ b/qla2x00t/qla_os.c @@ -4692,10 +4692,12 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) pci_restore_state(pdev); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 19, 0) /* pci_restore_state() clears the saved_state flag of the device * save restored state which resets saved_state flag */ pci_save_state(pdev); +#endif if (ha->mem_only) rc = pci_enable_device_mem(pdev);