On NUMA machines the kworker of iscsi created always jump around
across node boundaries. If it work on the different node even
different cpu package with the softirq of network interface, memcpy
with in iscsi_tcp_segment_recv will be slow down, and iscsi got an
terrible performance.
In this patch, we trace the cpu of softirq, and tell queue_work_on
to execute iscsi_xmitworker on the same NUMA node.
Signed-off-by: Biaoxiang Ye <
yebia...@huawei.com>
---
drivers/scsi/iscsi_tcp.c | 8 ++++++++
drivers/scsi/libiscsi.c | 12 +++++++++---
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 7bedbe8..dbac244 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -127,6 +127,7 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk)
struct iscsi_conn *conn;
struct iscsi_tcp_conn *tcp_conn;
read_descriptor_t rd_desc;
+ int current_cpu;
read_lock_bh(&sk->sk_callback_lock);
conn = sk->sk_user_data;
@@ -136,6 +137,13 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk)
}
tcp_conn = conn->dd_data;
+ /* save intimate cpu when in softirq */
+ if (!sock_owned_by_user_nocheck(sk)) {
+ current_cpu = smp_processor_id();
+ if (conn->xmitwork.intimate_cpu != current_cpu)
+ conn->xmitwork.intimate_cpu = current_cpu;
+ }
+
/*
* Use rd_desc to pass 'conn' to iscsi_tcp_recv.
* We set count to 1 because we want the network layer to
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index ebd47c0..3bbe326 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -87,9 +87,15 @@ inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
{
struct Scsi_Host *shost = conn->session->host;
struct iscsi_host *ihost = shost_priv(shost);
+ int intimate_cpu = conn->xmitwork.intimate_cpu;
- if (ihost->workq)
- queue_work(ihost->workq, &conn->xmitwork);
+ if (ihost->workq) {
+ /* we expect it to be excuted on the same numa of the intimate cpu */
+ if ((intimate_cpu >= 0) && cpu_possible(intimate_cpu))
+ queue_work_on(intimate_cpu, ihost->workq, &conn->xmitwork);
+ else
+ queue_work(ihost->workq, &conn->xmitwork);
+ }
}
EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
@@ -2627,7 +2633,7 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
if (xmit_can_sleep) {
snprintf(ihost->workq_name, sizeof(ihost->workq_name),
"iscsi_q_%d", shost->host_no);
- ihost->workq = create_singlethread_workqueue(ihost->workq_name);
+ ihost->workq = create_singlethread_dynamic_workqueue(ihost->workq_name);
if (!ihost->workq)
goto free_host;
}
--
1.8.3.1