kfree(map);
return NULL;
}
+
+/*
+ * We have no quick way of doing reverse lookups. This is only used at
+ * queue init time, so runtime isn't important.
+ */
+int blk_mq_hw_queue_to_node(unsigned int *mq_map, unsigned int index)
+{
+ int i;
+
+ for_each_possible_cpu(i) {
+ if (index == mq_map[i])
+ return cpu_to_node(i);
+ }
+
+ return NUMA_NO_NODE;
+}
EXPORT_SYMBOL(blk_mq_map_queue);
struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_tag_set *set,
- unsigned int hctx_index)
+ unsigned int hctx_index,
+ int node)
{
- return kzalloc_node(sizeof(struct blk_mq_hw_ctx), GFP_KERNEL,
- set->numa_node);
+ return kzalloc_node(sizeof(struct blk_mq_hw_ctx), GFP_KERNEL, node);
}
EXPORT_SYMBOL(blk_mq_alloc_single_hw_queue);
struct blk_mq_hw_ctx **hctxs;
struct blk_mq_ctx *ctx;
struct request_queue *q;
+ unsigned int *map;
int i;
ctx = alloc_percpu(struct blk_mq_ctx);
if (!hctxs)
goto err_percpu;
+ map = blk_mq_make_queue_map(set);
+ if (!map)
+ goto err_map;
+
for (i = 0; i < set->nr_hw_queues; i++) {
- hctxs[i] = set->ops->alloc_hctx(set, i);
+ int node = blk_mq_hw_queue_to_node(map, i);
+
+ hctxs[i] = set->ops->alloc_hctx(set, i, node);
if (!hctxs[i])
goto err_hctxs;
goto err_hctxs;
atomic_set(&hctxs[i]->nr_active, 0);
- hctxs[i]->numa_node = NUMA_NO_NODE;
+ hctxs[i]->numa_node = node;
hctxs[i]->queue_num = i;
}
if (percpu_counter_init(&q->mq_usage_counter, 0))
goto err_map;
- q->mq_map = blk_mq_make_queue_map(set);
- if (!q->mq_map)
- goto err_map;
-
setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q);
blk_queue_rq_timeout(q, 30000);
q->nr_queues = nr_cpu_ids;
q->nr_hw_queues = set->nr_hw_queues;
+ q->mq_map = map;
q->queue_ctx = ctx;
q->queue_hw_ctx = hctxs;
err_flush_rq:
kfree(q->flush_rq);
err_hw:
- kfree(q->mq_map);
-err_map:
blk_cleanup_queue(q);
err_hctxs:
+ kfree(map);
for (i = 0; i < set->nr_hw_queues; i++) {
if (!hctxs[i])
break;
free_cpumask_var(hctxs[i]->cpumask);
set->ops->free_hctx(hctxs[i], i);
}
+err_map:
kfree(hctxs);
err_percpu:
free_percpu(ctx);
*/
extern unsigned int *blk_mq_make_queue_map(struct blk_mq_tag_set *set);
extern int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues);
+extern int blk_mq_hw_queue_to_node(unsigned int *map, unsigned int);
/*
* Basic implementation of sparser bitmap, allowing the user to spread
}
static struct blk_mq_hw_ctx *null_alloc_hctx(struct blk_mq_tag_set *set,
- unsigned int hctx_index)
+ unsigned int hctx_index,
+ int node)
{
- int b_size = DIV_ROUND_UP(set->nr_hw_queues, nr_online_nodes);
- int tip = (set->nr_hw_queues % nr_online_nodes);
- int node = 0, i, n;
-
- /*
- * Split submit queues evenly wrt to the number of nodes. If uneven,
- * fill the first buckets with one extra, until the rest is filled with
- * no extra.
- */
- for (i = 0, n = 1; i < hctx_index; i++, n++) {
- if (n % b_size == 0) {
- n = 0;
- node++;
-
- tip--;
- if (!tip)
- b_size = set->nr_hw_queues / nr_online_nodes;
- }
- }
-
- /*
- * A node might not be online, therefore map the relative node id to the
- * real node id.
- */
- for_each_online_node(n) {
- if (!node)
- break;
- node--;
- }
-
- return kzalloc_node(sizeof(struct blk_mq_hw_ctx), GFP_KERNEL, n);
+ return kzalloc_node(sizeof(struct blk_mq_hw_ctx), GFP_KERNEL, node);
}
static void null_free_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_index)
typedef int (queue_rq_fn)(struct blk_mq_hw_ctx *, struct request *);
typedef struct blk_mq_hw_ctx *(map_queue_fn)(struct request_queue *, const int);
typedef struct blk_mq_hw_ctx *(alloc_hctx_fn)(struct blk_mq_tag_set *,
- unsigned int);
+ unsigned int, int);
typedef void (free_hctx_fn)(struct blk_mq_hw_ctx *, unsigned int);
typedef int (init_hctx_fn)(struct blk_mq_hw_ctx *, void *, unsigned int);
typedef void (exit_hctx_fn)(struct blk_mq_hw_ctx *, unsigned int);
struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag);
struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *, const int ctx_index);
-struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_tag_set *, unsigned int);
+struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_tag_set *, unsigned int, int);
void blk_mq_free_single_hw_queue(struct blk_mq_hw_ctx *, unsigned int);
void blk_mq_end_io(struct request *rq, int error);