diff mbox series

[v2,2/8] blk-mq: Keep set->nr_hw_queues and set->map[].nr_queues in sync

Message ID 20200220024441.11558-3-bvanassche@acm.org (mailing list archive)
State New, archived
Headers show
Series Eight patches related to changing the number of hardware queues | expand

Commit Message

Bart Van Assche Feb. 20, 2020, 2:44 a.m. UTC
blk_mq_map_queues() and multiple .map_queues() implementations expect that
set->map[HCTX_TYPE_DEFAULT].nr_queues is set to the number of hardware
queues. Hence set .nr_queues before calling these functions. This patch
fixes the following kernel warning:

WARNING: CPU: 0 PID: 2501 at include/linux/cpumask.h:137
Call Trace:
 blk_mq_run_hw_queue+0x19d/0x350 block/blk-mq.c:1508
 blk_mq_run_hw_queues+0x112/0x1a0 block/blk-mq.c:1525
 blk_mq_requeue_work+0x502/0x780 block/blk-mq.c:775
 process_one_work+0x9af/0x1740 kernel/workqueue.c:2269
 worker_thread+0x98/0xe40 kernel/workqueue.c:2415
 kthread+0x361/0x430 kernel/kthread.c:255

Cc: Christoph Hellwig <hch@infradead.org>
Cc: Ming Lei <ming.lei@redhat.com>
Cc: Hannes Reinecke <hare@suse.com>
Cc: Johannes Thumshirn <jth@kernel.org>
Reported-by: syzbot+d44e1b26ce5c3e77458d@syzkaller.appspotmail.com
Fixes: ed76e329d74a ("blk-mq: abstract out queue map") # v5.0
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
 block/blk-mq.c | 7 +++++++
 1 file changed, 7 insertions(+)

Comments

Ming Lei Feb. 20, 2020, 10:05 a.m. UTC | #1
On Wed, Feb 19, 2020 at 06:44:35PM -0800, Bart Van Assche wrote:
> blk_mq_map_queues() and multiple .map_queues() implementations expect that
> set->map[HCTX_TYPE_DEFAULT].nr_queues is set to the number of hardware

Only single queue mapping expects set->map[HCTX_TYPE_DEFAULT].nr_queues
to be set->nr_hw_queues. For multiple mapping, set->nr_hw_queues should
be sum of each mapping's nr_queue.


Thanks, 
Ming
Bart Van Assche Feb. 20, 2020, 4:14 p.m. UTC | #2
On 2/20/20 2:05 AM, Ming Lei wrote:
> On Wed, Feb 19, 2020 at 06:44:35PM -0800, Bart Van Assche wrote:
>> blk_mq_map_queues() and multiple .map_queues() implementations expect that
>> set->map[HCTX_TYPE_DEFAULT].nr_queues is set to the number of hardware
> 
> Only single queue mapping expects set->map[HCTX_TYPE_DEFAULT].nr_queues
> to be set->nr_hw_queues. For multiple mapping, set->nr_hw_queues should
> be sum of each mapping's nr_queue.

That's how it should work but that doesn't match what I found in the 
kernel tree. Here is an example of a .map_queues() implementation that 
depends on .nr_queues being set before it is called:

static int scsi_map_queues(struct blk_mq_tag_set *set)
{
	struct Scsi_Host *shost = container_of(set, struct Scsi_Host,
					       tag_set);

	if (shost->hostt->map_queues)
		return shost->hostt->map_queues(shost);
	return blk_mq_map_queues(&set->map[HCTX_TYPE_DEFAULT]);
}

If shost->hostt->map_queues == NULL, the above function only works 
correctly if .nr_queues is set before this function is called. 
Additionally, scsi_map_queues() may call e.g. the following function:

static int qla2xxx_map_queues(struct Scsi_Host *shost)
{
	int rc;
	scsi_qla_host_t *vha = (scsi_qla_host_t *)shost->hostdata;
	struct blk_mq_queue_map *qmap =
		&shost->tag_set.map[HCTX_TYPE_DEFAULT];

	if (USER_CTRL_IRQ(vha->hw) || !vha->hw->mqiobase)
		rc = blk_mq_map_queues(qmap);
	else
		rc = blk_mq_pci_map_queues(qmap, vha->hw->pdev,
			vha->irq_offset);
	return rc;
}

Both blk_mq_map_queues() and blk_mq_pci_map_queues() assume that 
blk_mq_queue_map.nr_queues is set before these functions are called.

Bart.
Ming Lei Feb. 20, 2020, 8:47 p.m. UTC | #3
On Thu, Feb 20, 2020 at 08:14:11AM -0800, Bart Van Assche wrote:
> On 2/20/20 2:05 AM, Ming Lei wrote:
> > On Wed, Feb 19, 2020 at 06:44:35PM -0800, Bart Van Assche wrote:
> > > blk_mq_map_queues() and multiple .map_queues() implementations expect that
> > > set->map[HCTX_TYPE_DEFAULT].nr_queues is set to the number of hardware
> > 
> > Only single queue mapping expects set->map[HCTX_TYPE_DEFAULT].nr_queues
> > to be set->nr_hw_queues. For multiple mapping, set->nr_hw_queues should
> > be sum of each mapping's nr_queue.
> 
> That's how it should work but that doesn't match what I found in the kernel
> tree. Here is an example of a .map_queues() implementation that depends on
> .nr_queues being set before it is called:
> 
> static int scsi_map_queues(struct blk_mq_tag_set *set)
> {
> 	struct Scsi_Host *shost = container_of(set, struct Scsi_Host,
> 					       tag_set);
> 
> 	if (shost->hostt->map_queues)
> 		return shost->hostt->map_queues(shost);
> 	return blk_mq_map_queues(&set->map[HCTX_TYPE_DEFAULT]);
> }
> 
> If shost->hostt->map_queues == NULL, the above function only works correctly
> if .nr_queues is set before this function is called. Additionally,
> scsi_map_queues() may call e.g. the following function:
> 
> static int qla2xxx_map_queues(struct Scsi_Host *shost)
> {
> 	int rc;
> 	scsi_qla_host_t *vha = (scsi_qla_host_t *)shost->hostdata;
> 	struct blk_mq_queue_map *qmap =
> 		&shost->tag_set.map[HCTX_TYPE_DEFAULT];
> 
> 	if (USER_CTRL_IRQ(vha->hw) || !vha->hw->mqiobase)
> 		rc = blk_mq_map_queues(qmap);
> 	else
> 		rc = blk_mq_pci_map_queues(qmap, vha->hw->pdev,
> 			vha->irq_offset);
> 	return rc;
> }
> 
> Both blk_mq_map_queues() and blk_mq_pci_map_queues() assume that
> blk_mq_queue_map.nr_queues is set before these functions are called.

Actually, I suggested to do the following way:

if (set->nr_maps == 1)
	set->map[HCTX_TYPE_DEFAULT].nr_queues = set->nr_hw_queues;

then people won't be confused wrt. relation between set->nr_hw_queues
and .nr_queues of each mapping.

Thanks, 
Ming
Bart Van Assche Feb. 21, 2020, 2:50 a.m. UTC | #4
On 2020-02-20 12:47, Ming Lei wrote:
> Actually, I suggested to do the following way:
> 
> if (set->nr_maps == 1)
> 	set->map[HCTX_TYPE_DEFAULT].nr_queues = set->nr_hw_queues;
> 
> then people won't be confused wrt. relation between set->nr_hw_queues
> and .nr_queues of each mapping.

Ah, thanks for the clarification. I will make that change.

Bart.
diff mbox series

Patch

diff --git a/block/blk-mq.c b/block/blk-mq.c
index f298500e6dda..7f996e427733 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -3023,6 +3023,13 @@  static int blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
 
 static int blk_mq_update_queue_map(struct blk_mq_tag_set *set)
 {
+	/*
+	 * blk_mq_map_queues() and multiple .map_queues() implementations
+	 * expect that set->map[HCTX_TYPE_DEFAULT].nr_queues is set to the
+	 * number of hardware queues.
+	 */
+	set->map[HCTX_TYPE_DEFAULT].nr_queues = set->nr_hw_queues;
+
 	if (set->ops->map_queues && !is_kdump_kernel()) {
 		int i;