blk_mq_alloc_tag_set函数struct blk_mq_tag_set结构体学习

struct blk_mq_tag_set结构体

include/linux/blk-mq.h

struct blk_mq_tag_set {
	unsigned int		*mq_map;
	const struct blk_mq_ops	*ops;
	unsigned int		nr_hw_queues;
	unsigned int		queue_depth;	/* max hw supported */
	unsigned int		reserved_tags;
	unsigned int		cmd_size;	/* per-request extra data */
	int			numa_node;
	unsigned int		timeout;
	unsigned int		flags;		/* BLK_MQ_F_* */
	void			*driver_data;

	struct blk_mq_tags	**tags;

	struct mutex		tag_list_lock;
	struct list_head	tag_list;
};

后面再分析每个成员的作用。

blk_mq_alloc_tag_set函数分析

/*
 * Alloc a tag set to be associated with one or more request queues.
 * May fail with EINVAL for various error conditions. May adjust the
 * requested depth down, if it's too large. In that case, the set
 * value will be stored in set->queue_depth.
 */
int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
{
	int ret;
	//...
	set->tags = kcalloc_node(nr_cpu_ids, sizeof(struct blk_mq_tags *),
				 GFP_KERNEL, set->numa_node);
	if (!set->tags)
		return -ENOMEM;

	ret = -ENOMEM;
	set->mq_map = kcalloc_node(nr_cpu_ids, sizeof(*set->mq_map),
				   GFP_KERNEL, set->numa_node);
	if (!set->mq_map)
		goto out_free_tags;

	ret = blk_mq_update_queue_map(set);
	if (ret)
		goto out_free_mq_map;

	ret = blk_mq_alloc_rq_maps(set);
	if (ret)
		goto out_free_mq_map;

	mutex_init(&set->tag_list_lock);
	INIT_LIST_HEAD(&set->tag_list);

	return 0;

out_free_mq_map:
	kfree(set->mq_map);
	set->mq_map = NULL;
out_free_tags:
	kfree(set->tags);
	set->tags = NULL;
	return ret;
}
EXPORT_SYMBOL(blk_mq_alloc_tag_set);

这个函数一进来的话先是对其,这两个成员的合法性做一个检查,这两个成员的值,一般是从硬件获取的,在调用该函数时已经赋值了。

nr_hw_queues
queue_depth

然后是tags成员的赋值,申请内存,它是一个二级指针,申请的元素个数是cpu个数,可以理解是一个指针数组,数组里的每一个成员都是一个指针,例如,下面的这个小demo,

#include
#include

int main(int argc, char **argv)
{
         int **p;
         int i, j, x, y;
         p = malloc(sizeof(int) * 4);
   
        p[0] = &x;
        p[1] = &y;
 
        x = 10;
        y = 20;
 
        printf("p = %d\n", *(*(p + 0)));
        return 0;
}

然后是mq_map这个成员,它申请的内存空间也是cpu的个数。

blk_mq_update_queue_map

然后深入到这个函数,

static int blk_mq_update_queue_map(struct blk_mq_tag_set *set)
{
	if (set->ops->map_queues) {
		/*
		 * transport .map_queues is usually done in the following
		 * way:
		 *
		 * for (queue = 0; queue < set->nr_hw_queues; queue++) {
		 * 	mask = get_cpu_mask(queue)
		 * 	for_each_cpu(cpu, mask)
		 * 		set->mq_map[cpu] = queue;
		 * }
		 *
		 * When we need to remap, the table has to be cleared for
		 * killing stale mapping since one CPU may not be mapped
		 * to any hw queue.
		 */
		blk_mq_clear_mq_map(set);

		return set->ops->map_queues(set);
	} else
		return blk_mq_map_queues(set);
}

继续,

int blk_mq_map_queues(struct blk_mq_tag_set *set)
{
	unsigned int *map = set->mq_map;
	unsigned int nr_queues = set->nr_hw_queues;
	unsigned int cpu, first_sibling;

	for_each_possible_cpu(cpu) {
		/*
		 * First do sequential mapping between CPUs and queues.
		 * In case we still have CPUs to map, and we have some number of
		 * threads per cores then map sibling threads to the same queue for
		 * performace optimizations.
		 */
		if (cpu < nr_queues) {
			map[cpu] = cpu_to_queue_index(nr_queues, cpu);
		} else {
			first_sibling = get_first_sibling(cpu);
			if (first_sibling == cpu)
				map[cpu] = cpu_to_queue_index(nr_queues, cpu);
			else
				map[cpu] = map[first_sibling];
		}
	}

	return 0;
}
EXPORT_SYMBOL_GPL(blk_mq_map_queues);

前面说了mq_map其实是一个指针,这里终于看到它赋值的地方了,根据注释不难看出,这个指针(其实就是个一维数组),的下标是cpu编号,然后每个数组元素的值是硬件队列的编号。到这里这个函数就结束了,其实功能就是给mq_map赋值的。

blk_mq_alloc_rq_maps

然后到blk_mq_alloc_rq_maps这个函数的分析
待后续。。。。。

你可能感兴趣的:(#,nvme,linux)