Commit c50061f0 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

ublk: rewrite ublk_ctrl_get_queue_affinity to not rely on hctx->cpumask



Looking at the hctxs and cpumap is not safe without at very last a RCU
reference.  It also requires the queue to be set up before starting the
device, which leads to rather awkward life time rules.

Instead rewrite ublk_ctrl_get_queue_affinity to just build the cpumask
directly from the mq_map in the tag set, similar to hctx->cpumask is
built.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20220721130916.1869719-8-hch@lst.de


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent cfee7e4d
Loading
Loading
Loading
Loading
+24 −31
Original line number Diff line number Diff line
@@ -1245,26 +1245,15 @@ static int ublk_ctrl_start_dev(struct io_uring_cmd *cmd)
	return ret;
}

static struct blk_mq_hw_ctx *ublk_get_hw_queue(struct ublk_device *ub,
		unsigned int index)
{
	struct blk_mq_hw_ctx *hctx;
	unsigned long i;

	queue_for_each_hw_ctx(ub->ub_queue, hctx, i)
		if (hctx->queue_num == index)
			return hctx;
	return NULL;
}

static int ublk_ctrl_get_queue_affinity(struct io_uring_cmd *cmd)
{
	struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd;
	void __user *argp = (void __user *)(unsigned long)header->addr;
	struct blk_mq_hw_ctx *hctx;
	struct ublk_device *ub;
	cpumask_var_t cpumask;
	unsigned long queue;
	unsigned int retlen;
	unsigned int i;
	int ret = -EINVAL;
	
	if (header->len * BITS_PER_BYTE < nr_cpu_ids)
@@ -1276,29 +1265,33 @@ static int ublk_ctrl_get_queue_affinity(struct io_uring_cmd *cmd)

	ub = ublk_get_device_from_id(header->dev_id);
	if (!ub)
		goto out;
		return -EINVAL;

	queue = header->data[0];
	if (queue >= ub->dev_info.nr_hw_queues)
		goto out;
	hctx = ublk_get_hw_queue(ub, queue);
	if (!hctx)
		goto out;
		goto out_put_device;

	retlen = min_t(unsigned short, header->len, cpumask_size());
	if (copy_to_user(argp, hctx->cpumask, retlen)) {
		ret = -EFAULT;
		goto out;
	ret = -ENOMEM;
	if (!zalloc_cpumask_var(&cpumask, GFP_KERNEL))
		goto out_put_device;

	for_each_possible_cpu(i) {
		if (ub->tag_set.map[HCTX_TYPE_DEFAULT].mq_map[i] == queue)
			cpumask_set_cpu(i, cpumask);
	}
	if (retlen != header->len) {
		if (clear_user(argp + retlen, header->len - retlen)) {

	ret = -EFAULT;
			goto out;
		}
	}
	retlen = min_t(unsigned short, header->len, cpumask_size());
	if (copy_to_user(argp, cpumask, retlen))
		goto out_free_cpumask;
	if (retlen != header->len &&
	    clear_user(argp + retlen, header->len - retlen))
		goto out_free_cpumask;

	ret = 0;
 out:
	if (ub)
out_free_cpumask:
	free_cpumask_var(cpumask);
out_put_device:
	ublk_put_device(ub);
	return ret;
}