Release 4.9 block/blk-mq-tag.c
/*
* Tag allocation using scalable bitmaps. Uses active queue tracking to support
* fairer distribution of tags between multiple submitters when a shared tag map
* is used.
*
* Copyright (C) 2013-2014 Jens Axboe
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/blk-mq.h>
#include "blk.h"
#include "blk-mq.h"
#include "blk-mq-tag.h"
bool blk_mq_has_free_tags(struct blk_mq_tags *tags)
{
if (!tags)
return true;
return sbitmap_any_bit_clear(&tags->bitmap_tags.sb);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 26 | 89.66% | 2 | 66.67% |
omar sandoval | omar sandoval | 3 | 10.34% | 1 | 33.33% |
| Total | 29 | 100.00% | 3 | 100.00% |
/*
* If a previously inactive queue goes active, bump the active user count.
*/
bool __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
{
if (!test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state) &&
!test_and_set_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state))
atomic_inc(&hctx->tags->active_queues);
return true;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 47 | 100.00% | 1 | 100.00% |
| Total | 47 | 100.00% | 1 | 100.00% |
/*
* Wakeup all potentially sleeping on tags
*/
void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags, bool include_reserve)
{
sbitmap_queue_wake_all(&tags->bitmap_tags);
if (include_reserve)
sbitmap_queue_wake_all(&tags->breserved_tags);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 29 | 87.88% | 3 | 75.00% |
omar sandoval | omar sandoval | 4 | 12.12% | 1 | 25.00% |
| Total | 33 | 100.00% | 4 | 100.00% |
/*
* If a previously busy queue goes inactive, potential waiters could now
* be allowed to queue. Wake them up and check.
*/
void __blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx)
{
struct blk_mq_tags *tags = hctx->tags;
if (!test_and_clear_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state))
return;
atomic_dec(&tags->active_queues);
blk_mq_tag_wakeup_all(tags, false);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 48 | 100.00% | 2 | 100.00% |
| Total | 48 | 100.00% | 2 | 100.00% |
/*
* For shared tag users, we track the number of currently active users
* and attempt to provide a fair share of the tag depth for each of them.
*/
static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
struct sbitmap_queue *bt)
{
unsigned int depth, users;
if (!hctx || !(hctx->flags & BLK_MQ_F_TAG_SHARED))
return true;
if (!test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state))
return true;
/*
* Don't try dividing an ant
*/
if (bt->sb.depth == 1)
return true;
users = atomic_read(&hctx->tags->active_queues);
if (!users)
return true;
/*
* Allow at least some tags
*/
depth = max((bt->sb.depth + users - 1) / users, 4U);
return atomic_read(&hctx->nr_active) < depth;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 118 | 95.93% | 1 | 50.00% |
omar sandoval | omar sandoval | 5 | 4.07% | 1 | 50.00% |
| Total | 123 | 100.00% | 2 | 100.00% |
static int __bt_get(struct blk_mq_hw_ctx *hctx, struct sbitmap_queue *bt)
{
if (!hctx_may_queue(hctx, bt))
return -1;
return __sbitmap_queue_get(bt);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 24 | 66.67% | 4 | 66.67% |
omar sandoval | omar sandoval | 12 | 33.33% | 2 | 33.33% |
| Total | 36 | 100.00% | 6 | 100.00% |
static int bt_get(struct blk_mq_alloc_data *data, struct sbitmap_queue *bt,
struct blk_mq_hw_ctx *hctx, struct blk_mq_tags *tags)
{
struct sbq_wait_state *ws;
DEFINE_WAIT(wait);
int tag;
tag = __bt_get(hctx, bt);
if (tag != -1)
return tag;
if (data->flags & BLK_MQ_REQ_NOWAIT)
return -1;
ws = bt_wait_ptr(bt, hctx);
do {
prepare_to_wait(&ws->wait, &wait, TASK_UNINTERRUPTIBLE);
tag = __bt_get(hctx, bt);
if (tag != -1)
break;
/*
* We're out of tags on this hardware queue, kick any
* pending IO submits before going to sleep waiting for
* some to complete. Note that hctx can be NULL here for
* reserved tag allocation.
*/
if (hctx)
blk_mq_run_hw_queue(hctx, false);
/*
* Retry tag allocation after running the hardware queue,
* as running the queue may also have found completions.
*/
tag = __bt_get(hctx, bt);
if (tag != -1)
break;
blk_mq_put_ctx(data->ctx);
io_schedule();
data->ctx = blk_mq_get_ctx(data->q);
data->hctx = blk_mq_map_queue(data->q, data->ctx->cpu);
if (data->flags & BLK_MQ_REQ_RESERVED) {
bt = &data->hctx->tags->breserved_tags;
} else {
hctx = data->hctx;
bt = &hctx->tags->bitmap_tags;
}
finish_wait(&ws->wait, &wait);
ws = bt_wait_ptr(bt, hctx);
} while (1);
finish_wait(&ws->wait, &wait);
return tag;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 150 | 58.14% | 4 | 36.36% |
lei ming | lei ming | 77 | 29.84% | 1 | 9.09% |
omar sandoval | omar sandoval | 8 | 3.10% | 1 | 9.09% |
bart van assche | bart van assche | 7 | 2.71% | 1 | 9.09% |
christoph hellwig | christoph hellwig | 6 | 2.33% | 1 | 9.09% |
sam bradshaw | sam bradshaw | 5 | 1.94% | 1 | 9.09% |
shaohua li | shaohua li | 4 | 1.55% | 1 | 9.09% |
linus torvalds | linus torvalds | 1 | 0.39% | 1 | 9.09% |
| Total | 258 | 100.00% | 11 | 100.00% |
static unsigned int __blk_mq_get_tag(struct blk_mq_alloc_data *data)
{
int tag;
tag = bt_get(data, &data->hctx->tags->bitmap_tags, data->hctx,
data->hctx->tags);
if (tag >= 0)
return tag + data->hctx->tags->nr_reserved_tags;
return BLK_MQ_TAG_FAIL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 42 | 68.85% | 1 | 33.33% |
lei ming | lei ming | 14 | 22.95% | 1 | 33.33% |
shaohua li | shaohua li | 5 | 8.20% | 1 | 33.33% |
| Total | 61 | 100.00% | 3 | 100.00% |
static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_alloc_data *data)
{
int tag;
if (unlikely(!data->hctx->tags->nr_reserved_tags)) {
WARN_ON_ONCE(1);
return BLK_MQ_TAG_FAIL;
}
tag = bt_get(data, &data->hctx->tags->breserved_tags, NULL,
data->hctx->tags);
if (tag < 0)
return BLK_MQ_TAG_FAIL;
return tag;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 58 | 77.33% | 1 | 33.33% |
lei ming | lei ming | 12 | 16.00% | 1 | 33.33% |
shaohua li | shaohua li | 5 | 6.67% | 1 | 33.33% |
| Total | 75 | 100.00% | 3 | 100.00% |
unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data)
{
if (data->flags & BLK_MQ_REQ_RESERVED)
return __blk_mq_get_reserved_tag(data);
return __blk_mq_get_tag(data);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 20 | 64.52% | 1 | 33.33% |
lei ming | lei ming | 6 | 19.35% | 1 | 33.33% |
christoph hellwig | christoph hellwig | 5 | 16.13% | 1 | 33.33% |
| Total | 31 | 100.00% | 3 | 100.00% |
void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
unsigned int tag)
{
struct blk_mq_tags *tags = hctx->tags;
if (tag >= tags->nr_reserved_tags) {
const int real_tag = tag - tags->nr_reserved_tags;
BUG_ON(real_tag >= tags->nr_tags);
sbitmap_queue_clear(&tags->bitmap_tags, real_tag, ctx->cpu);
} else {
BUG_ON(tag >= tags->nr_reserved_tags);
sbitmap_queue_clear(&tags->breserved_tags, tag, ctx->cpu);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 81 | 83.51% | 3 | 50.00% |
omar sandoval | omar sandoval | 14 | 14.43% | 2 | 33.33% |
shaohua li | shaohua li | 2 | 2.06% | 1 | 16.67% |
| Total | 97 | 100.00% | 6 | 100.00% |
struct bt_iter_data {
struct blk_mq_hw_ctx *hctx;
busy_iter_fn *fn;
void *data;
bool reserved;
};
static bool bt_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
{
struct bt_iter_data *iter_data = data;
struct blk_mq_hw_ctx *hctx = iter_data->hctx;
struct blk_mq_tags *tags = hctx->tags;
bool reserved = iter_data->reserved;
struct request *rq;
if (!reserved)
bitnr += tags->nr_reserved_tags;
rq = tags->rqs[bitnr];
if (rq->q == hctx->queue)
iter_data->fn(hctx, rq, iter_data->data, reserved);
return true;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
omar sandoval | omar sandoval | 52 | 50.00% | 1 | 25.00% |
jens axboe | jens axboe | 24 | 23.08% | 1 | 25.00% |
christoph hellwig | christoph hellwig | 24 | 23.08% | 1 | 25.00% |
ming lei | ming lei | 4 | 3.85% | 1 | 25.00% |
| Total | 104 | 100.00% | 4 | 100.00% |
static void bt_for_each(struct blk_mq_hw_ctx *hctx, struct sbitmap_queue *bt,
busy_iter_fn *fn, void *data, bool reserved)
{
struct bt_iter_data iter_data = {
.hctx = hctx,
.fn = fn,
.data = data,
.reserved = reserved,
};
sbitmap_for_each_set(&bt->sb, bt_iter, &iter_data);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
omar sandoval | omar sandoval | 41 | 62.12% | 1 | 50.00% |
keith busch | keith busch | 25 | 37.88% | 1 | 50.00% |
| Total | 66 | 100.00% | 2 | 100.00% |
struct bt_tags_iter_data {
struct blk_mq_tags *tags;
busy_tag_iter_fn *fn;
void *data;
bool reserved;
};
static bool bt_tags_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
{
struct bt_tags_iter_data *iter_data = data;
struct blk_mq_tags *tags = iter_data->tags;
bool reserved = iter_data->reserved;
struct request *rq;
if (!reserved)
bitnr += tags->nr_reserved_tags;
rq = tags->rqs[bitnr];
iter_data->fn(rq, iter_data->data, reserved);
return true;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
omar sandoval | omar sandoval | 57 | 68.67% | 1 | 33.33% |
keith busch | keith busch | 22 | 26.51% | 1 | 33.33% |
ming lei | ming lei | 4 | 4.82% | 1 | 33.33% |
| Total | 83 | 100.00% | 3 | 100.00% |
static void bt_tags_for_each(struct blk_mq_tags *tags, struct sbitmap_queue *bt,
busy_tag_iter_fn *fn, void *data, bool reserved)
{
struct bt_tags_iter_data iter_data = {
.tags = tags,
.fn = fn,
.data = data,
.reserved = reserved,
};
if (tags->rqs)
sbitmap_for_each_set(&bt->sb, bt_tags_iter, &iter_data);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
omar sandoval | omar sandoval | 37 | 51.39% | 1 | 20.00% |
sagi grimberg | sagi grimberg | 18 | 25.00% | 3 | 60.00% |
keith busch | keith busch | 17 | 23.61% | 1 | 20.00% |
| Total | 72 | 100.00% | 5 | 100.00% |
static void blk_mq_all_tag_busy_iter(struct blk_mq_tags *tags,
busy_tag_iter_fn *fn, void *priv)
{
if (tags->nr_reserved_tags)
bt_tags_for_each(tags, &tags->breserved_tags, fn, priv, true);
bt_tags_for_each(tags, &tags->bitmap_tags, fn, priv, false);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
omar sandoval | omar sandoval | 22 | 38.60% | 1 | 33.33% |
jens axboe | jens axboe | 20 | 35.09% | 1 | 33.33% |
christoph hellwig | christoph hellwig | 15 | 26.32% | 1 | 33.33% |
| Total | 57 | 100.00% | 3 | 100.00% |
void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset,
busy_tag_iter_fn *fn, void *priv)
{
int i;
for (i = 0; i < tagset->nr_hw_queues; i++) {
if (tagset->tags && tagset->tags[i])
blk_mq_all_tag_busy_iter(tagset->tags[i], fn, priv);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 33 | 50.77% | 2 | 66.67% |
omar sandoval | omar sandoval | 32 | 49.23% | 1 | 33.33% |
| Total | 65 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(blk_mq_tagset_busy_iter);
int blk_mq_reinit_tagset(struct blk_mq_tag_set *set)
{
int i, j, ret = 0;
if (!set->ops->reinit_request)
goto out;
for (i = 0; i < set->nr_hw_queues; i++) {
struct blk_mq_tags *tags = set->tags[i];
for (j = 0; j < tags->nr_tags; j++) {
if (!tags->rqs[j])
continue;
ret = set->ops->reinit_request(set->driver_data,
tags->rqs[j]);
if (ret)
goto out;
}
}
out:
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
omar sandoval | omar sandoval | 79 | 65.83% | 1 | 50.00% |
jens axboe | jens axboe | 41 | 34.17% | 1 | 50.00% |
| Total | 120 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(blk_mq_reinit_tagset);
void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn,
void *priv)
{
struct blk_mq_hw_ctx *hctx;
int i;
queue_for_each_hw_ctx(q, hctx, i) {
struct blk_mq_tags *tags = hctx->tags;
/*
* If not software queues are currently mapped to this
* hardware queue, there's nothing to check
*/
if (!blk_mq_hw_queue_mapped(hctx))
continue;
if (tags->nr_reserved_tags)
bt_for_each(hctx, &tags->breserved_tags, fn, priv, true);
bt_for_each(hctx, &tags->bitmap_tags, fn, priv, false);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
omar sandoval | omar sandoval | 61 | 65.59% | 1 | 25.00% |
jens axboe | jens axboe | 32 | 34.41% | 3 | 75.00% |
| Total | 93 | 100.00% | 4 | 100.00% |
static unsigned int bt_unused_tags(const struct sbitmap_queue *bt)
{
return bt->sb.depth - sbitmap_weight(&bt->sb);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
omar sandoval | omar sandoval | 16 | 57.14% | 1 | 20.00% |
jens axboe | jens axboe | 8 | 28.57% | 3 | 60.00% |
alexander gordeev | alexander gordeev | 4 | 14.29% | 1 | 20.00% |
| Total | 28 | 100.00% | 5 | 100.00% |
static int bt_alloc(struct sbitmap_queue *bt, unsigned int depth,
bool round_robin, int node)
{
return sbitmap_queue_init_node(bt, depth, -1, round_robin, GFP_KERNEL,
node);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
omar sandoval | omar sandoval | 27 | 71.05% | 2 | 50.00% |
jens axboe | jens axboe | 11 | 28.95% | 2 | 50.00% |
| Total | 38 | 100.00% | 4 | 100.00% |
static struct blk_mq_tags *blk_mq_init_bitmap_tags(struct blk_mq_tags *tags,
int node, int alloc_policy)
{
unsigned int depth = tags->nr_tags - tags->nr_reserved_tags;
bool round_robin = alloc_policy == BLK_TAG_ALLOC_RR;
if (bt_alloc(&tags->bitmap_tags, depth, round_robin, node))
goto free_tags;
if (bt_alloc(&tags->breserved_tags, tags->nr_reserved_tags, round_robin,
node))
goto free_bitmap_tags;
return tags;
free_bitmap_tags:
sbitmap_queue_free(&tags->bitmap_tags);
free_tags:
kfree(tags);
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 81 | 80.20% | 2 | 40.00% |
omar sandoval | omar sandoval | 16 | 15.84% | 2 | 40.00% |
shaohua li | shaohua li | 4 | 3.96% | 1 | 20.00% |
| Total | 101 | 100.00% | 5 | 100.00% |
struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags,
unsigned int reserved_tags,
int node, int alloc_policy)
{
struct blk_mq_tags *tags;
if (total_tags > BLK_MQ_TAG_MAX) {
pr_err("blk-mq: tag depth too large\n");
return NULL;
}
tags = kzalloc_node(sizeof(*tags), GFP_KERNEL, node);
if (!tags)
return NULL;
tags->nr_tags = total_tags;
tags->nr_reserved_tags = reserved_tags;
return blk_mq_init_bitmap_tags(tags, node, alloc_policy);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 82 | 94.25% | 2 | 66.67% |
shaohua li | shaohua li | 5 | 5.75% | 1 | 33.33% |
| Total | 87 | 100.00% | 3 | 100.00% |
void blk_mq_free_tags(struct blk_mq_tags *tags)
{
sbitmap_queue_free(&tags->bitmap_tags);
sbitmap_queue_free(&tags->breserved_tags);
kfree(tags);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 29 | 93.55% | 2 | 66.67% |
omar sandoval | omar sandoval | 2 | 6.45% | 1 | 33.33% |
| Total | 31 | 100.00% | 3 | 100.00% |
int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int tdepth)
{
tdepth -= tags->nr_reserved_tags;
if (tdepth > tags->nr_tags)
return -EINVAL;
/*
* Don't need (or can't) update reserved tags here, they remain
* static and should never need resizing.
*/
sbitmap_queue_resize(&tags->bitmap_tags, tdepth);
blk_mq_tag_wakeup_all(tags, false);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 52 | 98.11% | 2 | 66.67% |
omar sandoval | omar sandoval | 1 | 1.89% | 1 | 33.33% |
| Total | 53 | 100.00% | 3 | 100.00% |
/**
* blk_mq_unique_tag() - return a tag that is unique queue-wide
* @rq: request for which to compute a unique tag
*
* The tag field in struct request is unique per hardware queue but not over
* all hardware queues. Hence this function that returns a tag with the
* hardware context index in the upper bits and the per hardware queue tag in
* the lower bits.
*
* Note: When called for a request that is queued on a non-multiqueue request
* queue, the hardware context index is set to zero.
*/
u32 blk_mq_unique_tag(struct request *rq)
{
struct request_queue *q = rq->q;
struct blk_mq_hw_ctx *hctx;
int hwq = 0;
if (q->mq_ops) {
hctx = blk_mq_map_queue(q, rq->mq_ctx->cpu);
hwq = hctx->queue_num;
}
return (hwq << BLK_MQ_UNIQUE_TAG_BITS) |
(rq->tag & BLK_MQ_UNIQUE_TAG_MASK);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
bart van assche | bart van assche | 70 | 98.59% | 1 | 50.00% |
christoph hellwig | christoph hellwig | 1 | 1.41% | 1 | 50.00% |
| Total | 71 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(blk_mq_unique_tag);
ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page)
{
char *orig_page = page;
unsigned int free, res;
if (!tags)
return 0;
page += sprintf(page, "nr_tags=%u, reserved_tags=%u, "
"bits_per_word=%u\n",
tags->nr_tags, tags->nr_reserved_tags,
1U << tags->bitmap_tags.sb.shift);
free = bt_unused_tags(&tags->bitmap_tags);
res = bt_unused_tags(&tags->breserved_tags);
page += sprintf(page, "nr_free=%u, nr_reserved=%u\n", free, res);
page += sprintf(page, "active_queues=%u\n", atomic_read(&tags->active_queues));
return page - orig_page;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 111 | 94.87% | 4 | 66.67% |
omar sandoval | omar sandoval | 5 | 4.27% | 1 | 16.67% |
masanari iida | masanari iida | 1 | 0.85% | 1 | 16.67% |
| Total | 117 | 100.00% | 6 | 100.00% |
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jens axboe | jens axboe | 1191 | 56.58% | 9 | 32.14% |
omar sandoval | omar sandoval | 543 | 25.80% | 3 | 10.71% |
lei ming | lei ming | 109 | 5.18% | 1 | 3.57% |
bart van assche | bart van assche | 83 | 3.94% | 2 | 7.14% |
keith busch | keith busch | 64 | 3.04% | 1 | 3.57% |
christoph hellwig | christoph hellwig | 53 | 2.52% | 3 | 10.71% |
shaohua li | shaohua li | 25 | 1.19% | 1 | 3.57% |
sagi grimberg | sagi grimberg | 18 | 0.86% | 3 | 10.71% |
ming lei | ming lei | 8 | 0.38% | 1 | 3.57% |
sam bradshaw | sam bradshaw | 5 | 0.24% | 1 | 3.57% |
alexander gordeev | alexander gordeev | 4 | 0.19% | 1 | 3.57% |
masanari iida | masanari iida | 1 | 0.05% | 1 | 3.57% |
linus torvalds | linus torvalds | 1 | 0.05% | 1 | 3.57% |
| Total | 2105 | 100.00% | 28 | 100.00% |