From: Shao Denghui shaodenghui@huawei.com
virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I94XYA
----------------------------------------------------------------------
Add CONFIG_SCSI_KWORKER to control scsi kworker code compile or not.
Signed-off-by: shaodenghui shaodenghui@huawei.com --- arch/arm64/configs/openeuler_defconfig | 1 + arch/x86/configs/openeuler_defconfig | 1 + drivers/scsi/Kconfig | 18 ++++++++++++++++++ drivers/scsi/iscsi_tcp.c | 4 ++++ drivers/scsi/libiscsi.c | 13 +++++++++++++ kernel/workqueue.c | 15 ++++++++++++++- 6 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index afde4d70ee13..3845f223efab 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -2486,6 +2486,7 @@ CONFIG_CHR_DEV_SCH=m CONFIG_SCSI_ENCLOSURE=m CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_KWORKER=y CONFIG_SCSI_SCAN_ASYNC=y
# diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index 627a08ecbf4a..9c12b2633cdf 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -2477,6 +2477,7 @@ CONFIG_CHR_DEV_SCH=m CONFIG_SCSI_ENCLOSURE=m CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_KWORKER=y CONFIG_SCSI_SCAN_ASYNC=y
# diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 695a57d894cd..5dd1f2b956f9 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -218,6 +218,22 @@ config SCSI_LOGGING there should be no noticeable performance impact as long as you have logging turned off.
+config SCSI_KWORKER + bool "kworker NUMA affinity" + default n + help + kworker: Fix the problem of ipsan performance degradation. + + When the current downstream FS tests IPSAN, it is found that the + performance on ARM is much worse than that on X86, and the test data + of IPSAN fluctuates greatly. After analysis, the reason is that when + iscsi issues IO, the task is sent to kworker for processing by + iscsi_xmitworker. + + The workqueue created by iscsi can automatically identify the CPU of + the soft interrupt currently processed by iscsi, and automatically + schedule the workqueue to the corresponding NUMA node. + config SCSI_SCAN_ASYNC bool "Asynchronous SCSI scanning" depends on SCSI diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index d68bf693162c..f47a0c37319f 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -170,7 +170,9 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk) struct iscsi_sw_tcp_conn *tcp_sw_conn; struct iscsi_tcp_conn *tcp_conn; struct iscsi_conn *conn; +#ifdef CONFIG_SCSI_KWORKER int current_cpu; +#endif
trace_sk_data_ready(sk);
@@ -182,12 +184,14 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk) } tcp_conn = conn->dd_data;
+#ifdef CONFIG_SCSI_KWORKER /* save intimate cpu when in softirq */ if (!sock_owned_by_user_nocheck(sk)) { current_cpu = smp_processor_id(); if (conn->intimate_cpu != current_cpu) conn->intimate_cpu = current_cpu; } +#endif
tcp_sw_conn = tcp_conn->dd_data;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 0a8aee8fd742..c5fe9003a994 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -89,6 +89,7 @@ inline void iscsi_conn_queue_xmit(struct iscsi_conn *conn) { struct Scsi_Host *shost = conn->session->host; struct iscsi_host *ihost = shost_priv(shost); +#ifdef CONFIG_SCSI_KWORKER int intimate_cpu = conn->intimate_cpu;
if (ihost->workq) { @@ -98,6 +99,10 @@ inline void iscsi_conn_queue_xmit(struct iscsi_conn *conn) else queue_work(ihost->workq, &conn->xmitwork); } +#else + if (ihost->workq) + queue_work(ihost->workq, &conn->xmitwork); +#endif } EXPORT_SYMBOL_GPL(iscsi_conn_queue_xmit);
@@ -2913,9 +2918,15 @@ struct Scsi_Host *iscsi_host_alloc(const struct scsi_host_template *sht, ihost = shost_priv(shost);
if (xmit_can_sleep) { +#ifdef CONFIG_SCSI_KWORKER /* this kind of workqueue only support single work */ ihost->workq = alloc_ordered_workqueue("iscsi_q_%d", __WQ_LEGACY | WQ_MEM_RECLAIM | __WQ_DYNAMIC, shost->host_no); +#else + ihost->workq = alloc_workqueue("iscsi_q_%d", + WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND, + 1, shost->host_no); +#endif if (!ihost->workq) goto free_host; } @@ -3196,7 +3207,9 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, conn->c_stage = ISCSI_CONN_INITIAL_STAGE; conn->id = conn_idx; conn->exp_statsn = 0; +#ifdef CONFIG_SCSI_KWORKER conn->intimate_cpu = -1; +#endif
timer_setup(&conn->transport_timer, iscsi_check_transport_timeouts, 0);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 4972ebbbd3f2..8ba209873b6a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -4355,8 +4355,10 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, * it even if we don't use it immediately. */ copy_workqueue_attrs(new_attrs, attrs); +#ifdef CONFIG_SCSI_KWORKER if (wq->flags & __WQ_DYNAMIC) new_attrs->ordered = false; +#endif
wqattrs_actualize_cpumask(new_attrs, unbound_cpumask); cpumask_copy(new_attrs->__pod_cpumask, new_attrs->cpumask); @@ -4594,12 +4596,19 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) cpus_read_lock(); if (wq->flags & __WQ_ORDERED) { ret = apply_workqueue_attrs(wq, ordered_wq_attrs[highpri]); +#ifdef CONFIG_SCSI_KWORKER if (!(wq->flags & __WQ_DYNAMIC)) { /* there should only be single pwq for ordering guarantee */ WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node || wq->pwqs.prev != &wq->dfl_pwq->pwqs_node), - "ordering guarantee broken for workqueue %s\n", wq->name); + "ordering guarantee broken for workqueue %s\n", wq->name); } +#else + /* there should only be single pwq for ordering guarantee */ + WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node || + wq->pwqs.prev != &wq->dfl_pwq->pwqs_node), + "ordering guarantee broken for workqueue %s\n", wq->name); +#endif } else { ret = apply_workqueue_attrs(wq, unbound_std_wq_attrs[highpri]); } @@ -5804,7 +5813,11 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
/* creating multiple pwqs breaks ordering guarantee */ if (!list_empty(&wq->pwqs)) { +#ifdef CONFIG_SCSI_KWORKER if (wq->flags & __WQ_ORDERED_EXPLICIT && !(wq->flags & __WQ_DYNAMIC)) +#else + if (wq->flags & __WQ_ORDERED_EXPLICIT) +#endif continue; wq->flags &= ~__WQ_ORDERED; }