Commit b6139a6a authored by Daniel Wagner's avatar Daniel Wagner Committed by Jens Axboe
Browse files

lib/group_cpus: Let group_cpu_evenly() return the number of initialized masks



group_cpu_evenly() might have allocated less groups then requested:

group_cpu_evenly()
  __group_cpus_evenly()
    alloc_nodes_groups()
      # allocated total groups may be less than numgrps when
      # active total CPU number is less then numgrps

In this case, the caller will do an out of bound access because the
caller assumes the masks returned has numgrps.

Return the number of groups created so the caller can limit the access
range accordingly.

Acked-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Signed-off-by: default avatarDaniel Wagner <wagi@kernel.org>
Reviewed-by: default avatarChaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20250617-isolcpus-queue-counters-v1-1-13923686b54b@kernel.org


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 857f4318
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -19,9 +19,9 @@
void blk_mq_map_queues(struct blk_mq_queue_map *qmap)
{
	const struct cpumask *masks;
	unsigned int queue, cpu;
	unsigned int queue, cpu, nr_masks;

	masks = group_cpus_evenly(qmap->nr_queues);
	masks = group_cpus_evenly(qmap->nr_queues, &nr_masks);
	if (!masks) {
		for_each_possible_cpu(cpu)
			qmap->mq_map[cpu] = qmap->queue_offset;
@@ -29,7 +29,7 @@ void blk_mq_map_queues(struct blk_mq_queue_map *qmap)
	}

	for (queue = 0; queue < qmap->nr_queues; queue++) {
		for_each_cpu(cpu, &masks[queue])
		for_each_cpu(cpu, &masks[queue % nr_masks])
			qmap->mq_map[cpu] = qmap->queue_offset + queue;
	}
	kfree(masks);
+5 −4
Original line number Diff line number Diff line
@@ -329,20 +329,21 @@ create_affinity_masks(unsigned int nvecs, struct irq_affinity *affd)

	for (i = 0, usedvecs = 0; i < affd->nr_sets; i++) {
		unsigned int this_vecs = affd->set_size[i];
		unsigned int nr_masks;
		int j;
		struct cpumask *result = group_cpus_evenly(this_vecs);
		struct cpumask *result = group_cpus_evenly(this_vecs, &nr_masks);

		if (!result) {
			kfree(masks);
			return NULL;
		}

		for (j = 0; j < this_vecs; j++)
		for (j = 0; j < nr_masks; j++)
			cpumask_copy(&masks[curvec + j], &result[j]);
		kfree(result);

		curvec += this_vecs;
		usedvecs += this_vecs;
		curvec += nr_masks;
		usedvecs += nr_masks;
	}

	/* Fill out vectors at the end that don't need affinity */
+3 −3
Original line number Diff line number Diff line
@@ -862,7 +862,7 @@ static void virtio_fs_requests_done_work(struct work_struct *work)
static void virtio_fs_map_queues(struct virtio_device *vdev, struct virtio_fs *fs)
{
	const struct cpumask *mask, *masks;
	unsigned int q, cpu;
	unsigned int q, cpu, nr_masks;

	/* First attempt to map using existing transport layer affinities
	 * e.g. PCIe MSI-X
@@ -882,7 +882,7 @@ static void virtio_fs_map_queues(struct virtio_device *vdev, struct virtio_fs *f
	return;
fallback:
	/* Attempt to map evenly in groups over the CPUs */
	masks = group_cpus_evenly(fs->num_request_queues);
	masks = group_cpus_evenly(fs->num_request_queues, &nr_masks);
	/* If even this fails we default to all CPUs use first request queue */
	if (!masks) {
		for_each_possible_cpu(cpu)
@@ -891,7 +891,7 @@ static void virtio_fs_map_queues(struct virtio_device *vdev, struct virtio_fs *f
	}

	for (q = 0; q < fs->num_request_queues; q++) {
		for_each_cpu(cpu, &masks[q])
		for_each_cpu(cpu, &masks[q % nr_masks])
			fs->mq_map[cpu] = q + VQ_REQUEST;
	}
	kfree(masks);
+1 −1
Original line number Diff line number Diff line
@@ -9,6 +9,6 @@
#include <linux/kernel.h>
#include <linux/cpu.h>

struct cpumask *group_cpus_evenly(unsigned int numgrps);
struct cpumask *group_cpus_evenly(unsigned int numgrps, unsigned int *nummasks);

#endif
+5 −6
Original line number Diff line number Diff line
@@ -69,21 +69,20 @@ irq_create_affinity_masks(unsigned int nvecs, struct irq_affinity *affd)
	 * have multiple sets, build each sets affinity mask separately.
	 */
	for (i = 0, usedvecs = 0; i < affd->nr_sets; i++) {
		unsigned int this_vecs = affd->set_size[i];
		int j;
		struct cpumask *result = group_cpus_evenly(this_vecs);
		unsigned int nr_masks, this_vecs = affd->set_size[i];
		struct cpumask *result = group_cpus_evenly(this_vecs, &nr_masks);

		if (!result) {
			kfree(masks);
			return NULL;
		}

		for (j = 0; j < this_vecs; j++)
		for (int j = 0; j < nr_masks; j++)
			cpumask_copy(&masks[curvec + j].mask, &result[j]);
		kfree(result);

		curvec += this_vecs;
		usedvecs += this_vecs;
		curvec += nr_masks;
		usedvecs += nr_masks;
	}

	/* Fill out vectors at the end that don't need affinity */
Loading