Move to blk-mq block interface.

Currently Open-CAS uses single queue block interface,
which is removed in kernel in version 5.0.
From this moment on Open-CAS supports only blk-mq,
and single queue is not supported any longer.

Signed-off-by: Michal Rakowski <michal.rakowski@intel.com>
This commit is contained in:
Michal Rakowski
2019-08-12 15:02:22 +02:00
parent 8d80ef5aef
commit 95af3c6f9f
5 changed files with 124 additions and 169 deletions

View File

@@ -8,6 +8,7 @@
#include <linux/string.h>
#include <linux/blkpg.h>
#include <linux/elevator.h>
#include <linux/blk-mq.h>
#include "cas_disk_defs.h"
#include "cas_disk.h"
@@ -65,47 +66,6 @@ void casdsk_deinit_exp_objs(void)
kmem_cache_destroy(casdsk_module->exp_obj_cache);
}
static int _casdsk_exp_obj_prep_rq_fn(struct request_queue *q, struct request *rq)
{
struct casdsk_disk *dsk;;
BUG_ON(!q);
BUG_ON(!q->queuedata);
dsk = q->queuedata;
BUG_ON(!dsk->exp_obj);
if (likely(dsk->exp_obj->ops && dsk->exp_obj->ops->prep_rq_fn))
return dsk->exp_obj->ops->prep_rq_fn(dsk, q, rq, dsk->private);
else
return CAS_BLKPREP_OK;
}
static void _casdsk_exp_obj_request_fn(struct request_queue *q)
{
struct casdsk_disk *dsk;
struct request *rq;
BUG_ON(!q);
BUG_ON(!q->queuedata);
dsk = q->queuedata;
BUG_ON(!dsk);
BUG_ON(!dsk->exp_obj);
if (likely(dsk->exp_obj->ops && dsk->exp_obj->ops->request_fn)) {
dsk->exp_obj->ops->request_fn(dsk, q, dsk->private);
} else {
/*
* request_fn() is required, as we can't do any default
* action in attached mode. In PT mode we handle all bios
* directly in make_request_fn(), so request_fn() will not
* be called.
*/
rq = blk_peek_request(q);
BUG_ON(rq);
}
}
static inline void _casdsk_exp_obj_handle_bio_att(struct casdsk_disk *dsk,
struct request_queue *q,
struct bio *bio)
@@ -468,6 +428,70 @@ static int _casdsk_exp_obj_init_kobject(struct casdsk_disk *dsk)
return result;
}
static CAS_BLK_STATUS_T _casdsk_exp_obj_queue_qr(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
struct casdsk_disk *dsk = hctx->driver_data;
struct casdsk_exp_obj *exp_obj = dsk->exp_obj;
struct request *rq = bd->rq;
int result = 0;
if (likely(exp_obj->ops && exp_obj->ops->queue_rq_fn)) {
exp_obj->ops->pending_rq_inc(dsk, dsk->private);
result = exp_obj->ops->queue_rq_fn(dsk, rq, dsk->private);
exp_obj->ops->pending_rq_dec(dsk, dsk->private);
} else {
/*
* queue_rq_fn() is required, as we can't do any default
* action in attached mode. In PT mode we handle all bios
* directly in make_request_fn(), so queue_rq_fn() will not
* be called.
*/
BUG_ON(rq);
}
return result;
}
static struct blk_mq_ops casdsk_mq_ops = {
.queue_rq = _casdsk_exp_obj_queue_qr,
};
static void _casdsk_init_queues(struct casdsk_disk *dsk)
{
struct request_queue *q = dsk->exp_obj->queue;
struct blk_mq_hw_ctx *hctx;
int i;
queue_for_each_hw_ctx(q, hctx, i) {
if (!hctx->nr_ctx || !hctx->tags)
continue;
hctx->driver_data = dsk;
}
}
static int _casdsk_init_tag_set(struct casdsk_disk *dsk, struct blk_mq_tag_set *set)
{
BUG_ON(!dsk);
BUG_ON(!set);
set->ops = &casdsk_mq_ops;
set->nr_hw_queues = num_online_cpus();
set->numa_node = NUMA_NO_NODE;
/*TODO: Should we inherit qd from core device? */
set->queue_depth = BLKDEV_MAX_RQ;
set->cmd_size = 0;
set->flags = BLK_MQ_F_SHOULD_MERGE;
set->driver_data = dsk;
return blk_mq_alloc_tag_set(set);
}
int casdsk_exp_obj_create(struct casdsk_disk *dsk, const char *dev_name,
struct module *owner, struct casdsk_exp_obj_ops *ops)
{
@@ -524,30 +548,28 @@ int casdsk_exp_obj_create(struct casdsk_disk *dsk, const char *dev_name,
if (result)
goto error_dev_t;
spin_lock_init(&exp_obj->rq_lock);
result = _casdsk_init_tag_set(dsk, &dsk->tag_set);
if (result) {
goto error_init_tag_set;
}
queue = blk_init_queue(_casdsk_exp_obj_request_fn, &exp_obj->rq_lock);
queue = blk_mq_init_queue(&dsk->tag_set);
if (!queue) {
result = -ENOMEM;
goto error_init_queue;
}
BUG_ON(queue->queuedata);
queue->queuedata = dsk;
exp_obj->queue = queue;
_casdsk_init_queues(dsk);
gd->fops = &_casdsk_exp_obj_ops;
gd->queue = queue;
gd->private_data = dsk;
strlcpy(gd->disk_name, exp_obj->dev_name, sizeof(gd->disk_name));
if (exp_obj->ops->prepare_queue) {
result = exp_obj->ops->prepare_queue(dsk, queue, dsk->private);
if (result)
goto error_prepare_queue;
}
blk_queue_prep_rq(queue, _casdsk_exp_obj_prep_rq_fn);
dsk->exp_obj->mk_rq_fn = queue->make_request_fn;
blk_queue_make_request(queue, _casdsk_exp_obj_make_rq_fn);
@@ -562,9 +584,9 @@ int casdsk_exp_obj_create(struct casdsk_disk *dsk, const char *dev_name,
error_set_geometry:
if (exp_obj->ops->cleanup_queue)
exp_obj->ops->cleanup_queue(dsk, queue, dsk->private);
error_prepare_queue:
blk_cleanup_queue(queue);
error_init_queue:
blk_mq_free_tag_set(&dsk->tag_set);
error_init_tag_set:
_casdsk_exp_obj_clear_dev_t(dsk);
error_dev_t:
put_disk(gd);
@@ -744,6 +766,8 @@ int casdsk_exp_obj_destroy(struct casdsk_disk *dsk)
if (exp_obj->queue)
blk_cleanup_queue(exp_obj->queue);
blk_mq_free_tag_set(&dsk->tag_set);
atomic_set(&dsk->mode, CASDSK_MODE_UNKNOWN);
put_disk(exp_obj->gd);
@@ -786,40 +810,12 @@ static void _casdsk_exp_obj_wait_for_pending_rqs(struct casdsk_disk *dsk)
schedule();
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 3, 0)
static void _casdsk_exp_obj_drain_elevator(struct request_queue *q)
{
if (q->elevator && q->elevator->elevator_type)
while (q->elevator->elevator_type->ops.
elevator_dispatch_fn(q, 1))
;
}
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(4, 10, 0)
static void _casdsk_exp_obj_drain_elevator(struct request_queue *q)
{
if (q->elevator && q->elevator->type)
while (q->elevator->type->ops.elevator_dispatch_fn(q, 1))
;
}
#else
static void _casdsk_exp_obj_drain_elevator(struct request_queue *q)
{
if (q->elevator && q->elevator->type)
while (q->elevator->type->ops.sq.elevator_dispatch_fn(q, 1))
;
}
#endif
static void _casdsk_exp_obj_flush_queue(struct casdsk_disk *dsk)
{
struct casdsk_exp_obj *exp_obj = dsk->exp_obj;
struct request_queue *q = exp_obj->queue;
spin_lock_irq(q->queue_lock);
_casdsk_exp_obj_drain_elevator(q);
spin_unlock_irq(q->queue_lock);
blk_run_queue(q);
blk_mq_run_hw_queues(q, false);
blk_sync_queue(q);
}