Hi,
blk_mq_alloc_request_hctx() is used by NVMe fc/rdma/tcp/loop to connect
io queue. Also the sw ctx is chosen as the 1st online cpu in hctx->cpumask.
However, all cpus in hctx->cpumask may be offline.
This usage model isn't well supported by blk-mq which supposes allocator is
always done on one online CPU in hctx->cpumask. This assumption is
related with managed irq, which also requires blk-mq to drain inflight
request in this hctx when the last cpu in hctx->cpumask is going to
offline.
However, NVMe fc/rdma/tcp/loop don't use managed irq, so we should allow
them to ask for request allocation when the specified hctx is inactive
(all cpus in hctx->cpumask are offline). Fix blk_mq_alloc_request_hctx() by
allowing to allocate request when all CPUs of this hctx are offline.
Also cleans up map queues helpers, replace current pci/virtio/rdma
helpers with blk_mq_dev_map_queues(), and deal with the device
difference by passing one callback from driver, and the actual only
difference is that how to retrieve queue affinity. Finally the single helper
can meet all driver's requirement.
V3:
- cleanup map queues helpers, and remove pci/virtio/rdma queue
helpers
- store use managed irq info into qmap
V2:
- use flag of BLK_MQ_F_MANAGED_IRQ
- pass BLK_MQ_F_MANAGED_IRQ from driver explicitly
- kill BLK_MQ_F_STACKING
Ming Lei (10):
blk-mq: rename blk-mq-cpumap.c as blk-mq-map.c
blk-mq: Introduce blk_mq_dev_map_queues
blk-mq: pass use managed irq info to blk_mq_dev_map_queues
scsi: replace blk_mq_pci_map_queues with blk_mq_dev_map_queues
nvme: replace blk_mq_pci_map_queues with blk_mq_dev_map_queues
virito: add APIs for retrieving vq affinity
virtio: blk/scsi: replace blk_mq_virtio_map_queues with
blk_mq_dev_map_queues
nvme: rdma: replace blk_mq_rdma_map_queues with blk_mq_dev_map_queues
blk-mq: remove map queue helpers for pci, rdma and virtio
blk-mq: don't deactivate hctx if managed irq isn't used
block/Makefile | 5 +-
block/{blk-mq-cpumap.c => blk-mq-map.c} | 57 +++++++++++++++++++++++
block/blk-mq-pci.c | 48 -------------------
block/blk-mq-rdma.c | 44 -----------------
block/blk-mq-virtio.c | 46 ------------------
block/blk-mq.c | 27 +++++++----
block/blk-mq.h | 5 ++
drivers/block/virtio_blk.c | 12 ++++-
drivers/nvme/host/pci.c | 12 ++++-
drivers/nvme/host/rdma.c | 18 +++++--
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 21 ++++-----
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 5 +-
drivers/scsi/megaraid/megaraid_sas_base.c | 4 +-
drivers/scsi/mpi3mr/mpi3mr_os.c | 9 ++--
drivers/scsi/mpt3sas/mpt3sas_scsih.c | 6 ++-
drivers/scsi/qla2xxx/qla_os.c | 4 +-
drivers/scsi/scsi_priv.h | 9 ++++
drivers/scsi/smartpqi/smartpqi_init.c | 7 ++-
drivers/scsi/virtio_scsi.c | 11 ++++-
drivers/virtio/virtio.c | 10 ++++
include/linux/blk-mq.h | 8 +++-
include/linux/virtio.h | 2 +
22 files changed, 186 insertions(+), 184 deletions(-)
rename block/{blk-mq-cpumap.c => blk-mq-map.c} (58%)
delete mode 100644 block/blk-mq-pci.c
delete mode 100644 block/blk-mq-rdma.c
delete mode 100644 block/blk-mq-virtio.c
--
2.31.1
Firstly the name of cpumap isn't very useful because all kinds of map
helpers(pci, rdma, virtio) are for mapping cpu(s) to hw queue.
Secondly prepare for moving physical device related mapping into its
own subsystems, and we will put all map related functions/helpers into
this renamed source file.
Signed-off-by: Ming Lei <redacted>
---
block/Makefile | 2 +-
block/{blk-mq-cpumap.c => blk-mq-map.c} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename block/{blk-mq-cpumap.c => blk-mq-map.c} (100%)
Introduce blk_mq_dev_map_queues so that we can remove all kinds of
map_queues implementation(pci, virtio, rdma, ...) out of block layer.
Signed-off-by: Ming Lei <redacted>
---
block/blk-mq-map.c | 53 ++++++++++++++++++++++++++++++++++++++++++
include/linux/blk-mq.h | 5 ++++
2 files changed, 58 insertions(+)
Managed irq is special because genirq core will shut down it when all
cpus in its affinity mask are offline, so blk-mq has to drain requests
and prevent new allocation on the hw queue before its managed irq
is shutdown.
In current implementation, we drain all hctx when the last cpu in
hctx->cpumask is going to be offline. However, we need to avoid the
draining of hw queues which don't use managed irq, one kind of user
is nvme fc/rdma/tcp because these controllers require to submit connection
request successfully even though all cpus in hctx->cpumask are offline.
And we have lots of kernel panic reports on blk_mq_alloc_request_hctx().
Once we know if one qmap uses managed irq or not, we needn't to drain
requests for hctx which doesn't use managed irq, and we can allow to
allocate request on hctx in which all CPUs in hctx->cpumask are offline,
then not only fix kernel panic in blk_mq_alloc_request_hctx(), but also
meet nvme fc/rdma/tcp's requirement.
Signed-off-by: Ming Lei <redacted>
---
block/blk-mq-map.c | 6 +++++-
include/linux/blk-mq.h | 5 +++--
2 files changed, 8 insertions(+), 3 deletions(-)
Replace blk_mq_pci_map_queues with blk_mq_dev_map_queues which is more
generic from blk-mq viewpoint, so we can unify all map queue via
blk_mq_dev_map_queues().
Meantime we can pass 'use_manage_irq' info to blk-mq via
blk_mq_dev_map_queues(), this info needn't be 100% accurate, and what
we need is that true has to be passed in if the hba really uses managed
irq.
Signed-off-by: Ming Lei <redacted>
---
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 21 ++++++++++-----------
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 5 +++--
drivers/scsi/megaraid/megaraid_sas_base.c | 4 +++-
drivers/scsi/mpi3mr/mpi3mr_os.c | 9 +++++----
drivers/scsi/mpt3sas/mpt3sas_scsih.c | 6 ++++--
drivers/scsi/qla2xxx/qla_os.c | 4 +++-
drivers/scsi/scsi_priv.h | 9 +++++++++
drivers/scsi/smartpqi/smartpqi_init.c | 7 +++++--
8 files changed, 42 insertions(+), 23 deletions(-)
Replace blk_mq_pci_map_queues with blk_mq_dev_map_queues which is more
generic from blk-mq viewpoint, so we can unify all map queue via
blk_mq_dev_map_queues().
Meantime we can pass 'use_manage_irq' info to blk-mq via
blk_mq_dev_map_queues(), this info needn't be 100% accurate, and what
we need is that true has to be passed in if the hba really uses managed
irq.
Signed-off-by: Ming Lei <redacted>
---
drivers/nvme/host/pci.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
@@ -433,6 +433,14 @@ static int nvme_init_request(struct blk_mq_tag_set *set, struct request *req,return0;}+staticconststructcpumask*nvme_pci_get_queue_affinity(+void*dev_data,intoffset,intqueue)+{+structpci_dev*pdev=dev_data;++returnpci_irq_get_affinity(pdev,offset+queue);+}+staticintqueue_irq_offset(structnvme_dev*dev){/* if we have more than 1 vec, admin queue offsets us by 1 */
@@ -463,7 +471,9 @@ static int nvme_pci_map_queues(struct blk_mq_tag_set *set)*/map->queue_offset=qoff;if(i!=HCTX_TYPE_POLL&&offset)-blk_mq_pci_map_queues(map,to_pci_dev(dev->dev),offset);+blk_mq_dev_map_queues(map,to_pci_dev(dev->dev),offset,+nvme_pci_get_queue_affinity,false,+true);elseblk_mq_map_queues(map);qoff+=map->nr_queues;
Replace blk_mq_virtio_map_queues with blk_mq_dev_map_queues which is more
generic from blk-mq viewpoint, so we can unify all map queue
implementation.
Meantime we can pass 'use_manage_irq' info to blk-mq via
blk_mq_dev_map_queues(), this info needn't be 100% accurate, and what
we need is that true has to be passed in if the hba really uses managed
irq.
Signed-off-by: Ming Lei <redacted>
---
drivers/block/virtio_blk.c | 12 ++++++++++--
drivers/scsi/virtio_scsi.c | 11 ++++++++++-
2 files changed, 20 insertions(+), 3 deletions(-)
Replace blk_mq_virtio_map_queues with blk_mq_dev_map_queues which is more
generic from blk-mq viewpoint, so we can unify all map queue
implementation.
Meantime we can pass 'use_manage_irq' info to blk-mq via
blk_mq_dev_map_queues(), this info needn't be 100% accurate, and what
we need is that true has to be passed in if the hba really uses managed
irq.
Signed-off-by: Ming Lei <redacted>
---
drivers/nvme/host/rdma.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
@@ -2192,10 +2200,12 @@ static int nvme_rdma_map_queues(struct blk_mq_tag_set *set)ctrl->io_queues[HCTX_TYPE_DEFAULT];set->map[HCTX_TYPE_READ].queue_offset=0;}-blk_mq_rdma_map_queues(&set->map[HCTX_TYPE_DEFAULT],-ctrl->device->dev,0);-blk_mq_rdma_map_queues(&set->map[HCTX_TYPE_READ],-ctrl->device->dev,0);+blk_mq_dev_map_queues(&set->map[HCTX_TYPE_DEFAULT],+ctrl->device->dev,0,nvme_rdma_get_queue_affinity,+true,false);+blk_mq_dev_map_queues(&set->map[HCTX_TYPE_READ],+ctrl->device->dev,0,nvme_rdma_get_queue_affinity,+true,false);if(opts->nr_poll_queues&&ctrl->io_queues[HCTX_TYPE_POLL]){/* map dedicated poll queues only if we have queues left */
@@ -1,48 +0,0 @@-// SPDX-License-Identifier: GPL-2.0-/*- * Copyright (c) 2016 Christoph Hellwig.- */-#include <linux/kobject.h>-#include <linux/blkdev.h>-#include <linux/blk-mq.h>-#include <linux/blk-mq-pci.h>-#include <linux/pci.h>-#include <linux/module.h>--#include "blk-mq.h"--/**- * blk_mq_pci_map_queues - provide a default queue mapping for PCI device- * @qmap: CPU to hardware queue map.- * @pdev: PCI device associated with @set.- * @offset: Offset to use for the pci irq vector- *- * This function assumes the PCI device @pdev has at least as many available- * interrupt vectors as @set has queues. It will then query the vector- * corresponding to each queue for it's affinity mask and built queue mapping- * that maps a queue to the CPUs that have irq affinity for the corresponding- * vector.- */-int blk_mq_pci_map_queues(struct blk_mq_queue_map *qmap, struct pci_dev *pdev,- int offset)-{- const struct cpumask *mask;- unsigned int queue, cpu;-- for (queue = 0; queue < qmap->nr_queues; queue++) {- mask = pci_irq_get_affinity(pdev, queue + offset);- if (!mask)- goto fallback;-- for_each_cpu(cpu, mask)- qmap->mq_map[cpu] = qmap->queue_offset + queue;- }-- return 0;--fallback:- WARN_ON_ONCE(qmap->nr_queues > 1);- blk_mq_clear_mq_map(qmap);- return 0;-}-EXPORT_SYMBOL_GPL(blk_mq_pci_map_queues);
@@ -1,44 +0,0 @@-// SPDX-License-Identifier: GPL-2.0-/*- * Copyright (c) 2017 Sagi Grimberg.- */-#include <linux/blk-mq.h>-#include <linux/blk-mq-rdma.h>-#include <rdma/ib_verbs.h>--/**- * blk_mq_rdma_map_queues - provide a default queue mapping for rdma device- * @map: CPU to hardware queue map.- * @dev: rdma device to provide a mapping for.- * @first_vec: first interrupt vectors to use for queues (usually 0)- *- * This function assumes the rdma device @dev has at least as many available- * interrupt vetors as @set has queues. It will then query it's affinity mask- * and built queue mapping that maps a queue to the CPUs that have irq affinity- * for the corresponding vector.- *- * In case either the driver passed a @dev with less vectors than- * @set->nr_hw_queues, or @dev does not provide an affinity mask for a- * vector, we fallback to the naive mapping.- */-int blk_mq_rdma_map_queues(struct blk_mq_queue_map *map,- struct ib_device *dev, int first_vec)-{- const struct cpumask *mask;- unsigned int queue, cpu;-- for (queue = 0; queue < map->nr_queues; queue++) {- mask = ib_get_vector_affinity(dev, first_vec + queue);- if (!mask)- goto fallback;-- for_each_cpu(cpu, mask)- map->mq_map[cpu] = map->queue_offset + queue;- }-- return 0;--fallback:- return blk_mq_map_queues(map);-}-EXPORT_SYMBOL_GPL(blk_mq_rdma_map_queues);
@@ -1,46 +0,0 @@-// SPDX-License-Identifier: GPL-2.0-/*- * Copyright (c) 2016 Christoph Hellwig.- */-#include <linux/device.h>-#include <linux/blk-mq.h>-#include <linux/blk-mq-virtio.h>-#include <linux/virtio_config.h>-#include <linux/module.h>-#include "blk-mq.h"--/**- * blk_mq_virtio_map_queues - provide a default queue mapping for virtio device- * @qmap: CPU to hardware queue map.- * @vdev: virtio device to provide a mapping for.- * @first_vec: first interrupt vectors to use for queues (usually 0)- *- * This function assumes the virtio device @vdev has at least as many available- * interrupt vectors as @set has queues. It will then query the vector- * corresponding to each queue for it's affinity mask and built queue mapping- * that maps a queue to the CPUs that have irq affinity for the corresponding- * vector.- */-int blk_mq_virtio_map_queues(struct blk_mq_queue_map *qmap,- struct virtio_device *vdev, int first_vec)-{- const struct cpumask *mask;- unsigned int queue, cpu;-- if (!vdev->config->get_vq_affinity)- goto fallback;-- for (queue = 0; queue < qmap->nr_queues; queue++) {- mask = vdev->config->get_vq_affinity(vdev, first_vec + queue);- if (!mask)- goto fallback;-- for_each_cpu(cpu, mask)- qmap->mq_map[cpu] = qmap->queue_offset + queue;- }-- return 0;-fallback:- return blk_mq_map_queues(qmap);-}-EXPORT_SYMBOL_GPL(blk_mq_virtio_map_queues);
blk-mq deactivates one hctx when the last CPU in hctx->cpumask become
offline by draining all requests originated from this hctx and moving new
allocation on other active hctx. This way is for avoiding inflight IO in
case of managed irq because managed irq is shutdown when the last CPU in
the irq's affinity becomes offline.
However, lots of drivers(nvme fc, rdma, tcp, loop, ...) don't use managed
irq, so they needn't to deactivate hctx when the last CPU becomes offline.
Also, some of them are the only user of blk_mq_alloc_request_hctx() which
is used for connecting io queue. And their requirement is that the connect
request needs to be submitted successfully via one specified hctx even though
all CPUs in this hctx->cpumask have become offline.
Addressing the requirement for nvme fc/rdma/loop by allowing to
allocate request from one hctx when all CPUs in this hctx are offline,
since these drivers don't use managed irq.
Finally don't deactivate one hctx when it doesn't use managed irq.
Signed-off-by: Ming Lei <redacted>
---
block/blk-mq.c | 27 +++++++++++++++++----------
block/blk-mq.h | 5 +++++
2 files changed, 22 insertions(+), 10 deletions(-)
@@ -2556,6 +2559,10 @@ static int blk_mq_hctx_notify_offline(unsigned int cpu, struct hlist_node *node)structblk_mq_hw_ctx*hctx=hlist_entry_safe(node,structblk_mq_hw_ctx,cpuhp_online);+/* hctx needn't to be deactivated in case managed irq isn't used */+if(!blk_mq_hctx_use_managed_irq(hctx))+return0;+if(!cpumask_test_cpu(cpu,hctx->cpumask)||!blk_mq_last_cpu_in_hctx(cpu,hctx))return0;
From: Daniel Wagner <hidden> Date: 2021-07-09 08:25:33
On Fri, Jul 09, 2021 at 04:09:57PM +0800, Ming Lei wrote:
quoted hunk
+/**+ * blk_mq_dev_map_queues - provide generic queue mapping+ * @qmap: CPU to hardware queue map.+ * @dev_off: Offset to use for the device+ * @get_queue_affinity: Callback to retrieve queue affinity+ * @dev_data: Device data passed to get_queue_affinity()+ * @fallback: If true, fallback to default blk-mq mapping in case of+ * any failure
The docs have a different order compared to the function definition (dev_data).
quoted hunk
+ *+ * Generic function to setup each queue mapping in @qmap. It will query+ * each queue's affinity via @get_queue_affinity and built queue mapping+ * that maps a queue to the CPUs in the queue affinity.+ *+ * Driver has to set correct @dev_data, so that the driver callback+ * of @get_queue_affinity can work correctly.+ */+int blk_mq_dev_map_queues(struct blk_mq_queue_map *qmap, void *dev_data,+ int dev_off, get_queue_affinty_fn *get_queue_affinity,+ bool fallback)
drivers/scsi/mpi3mr/mpi3mr_os.c:2801:6: error: 'scsi_pci_get_queue_affinity' undeclared (first use in this function)
2801 | scsi_pci_get_queue_affinity, false, true);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/scsi/mpi3mr/mpi3mr_os.c:2801:6: note: each undeclared identifier is reported only once for each function it appears in
drivers/scsi/mpi3mr/mpi3mr_os.c:2802:1: error: control reaches end of non-void function [-Werror=return-type]
2802 | }
| ^
cc1: some warnings being treated as errors
vim +/scsi_pci_get_queue_affinity +2801 drivers/scsi/mpi3mr/mpi3mr_os.c
2785
2786 /**
2787 * mpi3mr_map_queues - Map queues callback handler
2788 * @shost: SCSI host reference
2789 *
2790 * Call the blk_mq_dev_map_queues with from which operational
2791 * queue the mapping has to be done
2792 *
2793 * Return: return of blk_mq_dev_map_queues
2794 */
2795 static int mpi3mr_map_queues(struct Scsi_Host *shost)
2796 {
2797 struct mpi3mr_ioc *mrioc = shost_priv(shost);
2798
2799 return blk_mq_dev_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
2800 mrioc->pdev, mrioc->op_reply_q_offset,
drivers/scsi/libsas/../scsi_priv.h:199:9: error: implicit declaration of function 'pci_irq_get_affinity' [-Werror,-Wimplicit-function-declaration]
return pci_irq_get_affinity(pdev, offset + queue);
^
drivers/scsi/libsas/../scsi_priv.h:199:9: note: did you mean 'irq_set_affinity'?
include/linux/interrupt.h:325:12: note: 'irq_set_affinity' declared here
extern int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask);
^
In file included from drivers/scsi/libsas/sas_scsi_host.c:27:
quoted
drivers/scsi/libsas/../scsi_priv.h:199:9: warning: incompatible integer to pointer conversion returning 'int' from a function with result type 'const struct cpumask *' [-Wint-conversion]
return pci_irq_get_affinity(pdev, offset + queue);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning and 1 error generated.
--
In file included from drivers/scsi/scsi.c:70:
quoted
drivers/scsi/scsi_priv.h:199:9: error: implicit declaration of function 'pci_irq_get_affinity' [-Werror,-Wimplicit-function-declaration]
return pci_irq_get_affinity(pdev, offset + queue);
^
drivers/scsi/scsi_priv.h:199:9: note: did you mean 'irq_set_affinity'?
include/linux/interrupt.h:325:12: note: 'irq_set_affinity' declared here
extern int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask);
^
In file included from drivers/scsi/scsi.c:70:
quoted
drivers/scsi/scsi_priv.h:199:9: warning: incompatible integer to pointer conversion returning 'int' from a function with result type 'const struct cpumask *' [-Wint-conversion]
return pci_irq_get_affinity(pdev, offset + queue);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning and 1 error generated.
vim +/pci_irq_get_affinity +199 drivers/scsi/libsas/../scsi_priv.h
193
194 static inline const struct cpumask *scsi_pci_get_queue_affinity(
195 void *dev_data, int offset, int queue)
196 {
197 struct pci_dev *pdev = dev_data;
198
> 199 return pci_irq_get_affinity(pdev, offset + queue);
200 }
201
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c:3137:10: error: 'scsi_pci_get_queue_affinity' undeclared (first use in this function)
3137 | scsi_pci_get_queue_affinity, false, true);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c:3137:10: note: each undeclared identifier is reported only once for each function it appears in
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c:3138:1: error: control reaches end of non-void function [-Werror=return-type]
3138 | }
| ^
cc1: some warnings being treated as errors
vim +/scsi_pci_get_queue_affinity +3137 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
3129
3130 static int hisi_sas_map_queues(struct Scsi_Host *shost)
3131 {
3132 struct hisi_hba *hisi_hba = shost_priv(shost);
3133 struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
3134
3135 return blk_mq_dev_map_queues(qmap, hisi_hba->pci_dev,
3136 BASE_VECTORS_V3_HW,
From: Christoph Hellwig <hch@lst.de> Date: 2021-07-12 07:32:34
On Fri, Jul 09, 2021 at 04:09:56PM +0800, Ming Lei wrote:
Firstly the name of cpumap isn't very useful because all kinds of map
helpers(pci, rdma, virtio) are for mapping cpu(s) to hw queue.
Secondly prepare for moving physical device related mapping into its
own subsystems, and we will put all map related functions/helpers into
this renamed source file.
Signed-off-by: Ming Lei <redacted>
I don't really see much of a point in this - we still create the cpu
maps, and if there is more code here that doesn't matter much, does it?
Please remove the NULL get_affinity case and let the callers handle
the fallback. Also I think it makes sense to leave the !mask fallback
case to the callers as well to simplify the calling conventions.
From: Christoph Hellwig <hch@lst.de> Date: 2021-07-12 07:42:39
As requested by me and Thomas please just add a flag in struct device
to propagate this information in a way that does not require all this
error probe boilerplate code.