Remove blk request handling path

Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
This commit is contained in:
Robert Baldyga 2021-05-17 16:50:44 +02:00
parent 7343cb55fa
commit b82b338c53
5 changed files with 4 additions and 466 deletions

View File

@ -21,10 +21,10 @@ apply() {
case "$1" in
"1")
add_define "CAS_BLK_STATUS_T blk_status_t"
add_define "CAS_BLK_STS_OK BLK_STS_OK" ;;
add_define "CAS_BLK_STS_NOTSUPP BLK_STS_NOTSUPP" ;;
"2")
add_define "CAS_BLK_STATUS_T int"
add_define "CAS_BLK_STS_OK 0" ;;
add_define "CAS_BLK_STS_NOTSUPP -ENOTSUPP" ;;
*)
exit 1

View File

@ -9,17 +9,6 @@
#include "obj_blk.h"
#include "context.h"
static inline bool cas_blk_is_flush_io(unsigned long flags)
{
if ((flags & CAS_WRITE_FLUSH) == CAS_WRITE_FLUSH)
return true;
if ((flags & CAS_WRITE_FLUSH_FUA) == CAS_WRITE_FLUSH_FUA)
return true;
return false;
}
struct blkio {
int error;
atomic_t rq_remaning;

View File

@ -6,34 +6,6 @@
#include "cas_cache.h"
#include "utils/cas_err.h"
#define BLK_RQ_POS(rq) (CAS_BIO_BISECTOR((rq)->bio))
#define BLK_RQ_BYTES(rq) blk_rq_bytes(rq)
static inline void _blockdev_end_request_all(struct request *rq, int error)
{
CAS_END_REQUEST_ALL(rq, CAS_ERRNO_TO_BLK_STS(
map_cas_err_to_generic(error)));
}
static inline bool _blockdev_can_handle_rq(struct request *rq)
{
int error = 0;
if (unlikely(!cas_is_rq_type_fs(rq)))
error = __LINE__;
if (unlikely(CAS_BLK_BIDI_RQ(rq)))
error = __LINE__;
if (error != 0) {
CAS_PRINT_RL(KERN_ERR "%s cannot handle request (ERROR %d)\n",
rq->rq_disk->disk_name, error);
return false;
}
return true;
}
static void _blockdev_set_bio_data(struct blk_data *data, struct bio *bio)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
@ -80,400 +52,6 @@ void block_dev_start_bio(struct ocf_io *io)
data->start_time = _blockdev_start_io_acct(bio);
}
void block_dev_complete_rq(struct ocf_io *io, int error)
{
struct blk_data *data = ocf_io_get_data(io);
struct request *rq = data->master_io_req;
_blockdev_end_request_all(rq, error);
ocf_io_put(io);
cas_free_blk_data(data);
}
void block_dev_complete_sub_rq(struct ocf_io *io, int error)
{
struct blk_data *data = ocf_io_get_data(io);
struct ocf_io *master = data->master_io_req;
struct blk_data *master_data = ocf_io_get_data(master);
if (error)
master_data->error = error;
if (atomic_dec_return(&master_data->master_remaining) == 0) {
_blockdev_end_request_all(master_data->master_io_req,
master_data->error);
cas_free_blk_data(master_data);
ocf_io_put(master);
}
ocf_io_put(io);
cas_free_blk_data(data);
}
void block_dev_complete_flush(struct ocf_io *io, int error)
{
struct request *rq = io->priv1;
_blockdev_end_request_all(rq, error);
ocf_io_put(io);
}
bool _blockdev_is_request_barier(struct request *rq)
{
struct bio *i_bio = rq->bio;
for_each_bio(i_bio) {
if (CAS_CHECK_BARRIER(i_bio))
return true;
}
return false;
}
static int _blockdev_alloc_many_requests(ocf_core_t core,
struct list_head *list, struct request *rq,
struct ocf_io *master)
{
ocf_cache_t cache = ocf_core_get_cache(core);
struct cache_priv *cache_priv = ocf_cache_get_priv(cache);
int error = 0;
int flags = 0;
struct bio *bio;
struct ocf_io *sub_io;
struct blk_data *master_data = ocf_io_get_data(master);
struct blk_data *data;
INIT_LIST_HEAD(list);
/* Go over requests and allocate sub requests */
bio = rq->bio;
for_each_bio(bio) {
/* Setup BIO flags */
if (CAS_IS_WRITE_FLUSH_FUA(CAS_BIO_OP_FLAGS(bio))) {
/* FLUSH and FUA */
flags = CAS_WRITE_FLUSH_FUA;
} else if (CAS_IS_WRITE_FUA(CAS_BIO_OP_FLAGS(bio))) {
/* FUA */
flags = CAS_WRITE_FUA;
} else if (CAS_IS_WRITE_FLUSH(CAS_BIO_OP_FLAGS(bio))) {
/* FLUSH - It shall be handled in request handler */
error = -EINVAL;
break;
} else {
flags = 0;
}
data = cas_alloc_blk_data(bio_segments(bio), GFP_NOIO);
if (!data) {
CAS_PRINT_RL(KERN_CRIT "BIO data vector allocation error\n");
error = -ENOMEM;
break;
}
_blockdev_set_bio_data(data, bio);
data->master_io_req = master;
sub_io = ocf_core_new_io(core,
cache_priv->io_queues[smp_processor_id()],
CAS_BIO_BISECTOR(bio) << SECTOR_SHIFT,
CAS_BIO_BISIZE(bio), (bio_data_dir(bio) == READ) ?
OCF_READ : OCF_WRITE,
cas_cls_classify(cache, bio), flags);
if (!sub_io) {
cas_free_blk_data(data);
error = -ENOMEM;
break;
}
data->io = sub_io;
error = ocf_io_set_data(sub_io, data, 0);
if (error) {
ocf_io_put(sub_io);
cas_free_blk_data(data);
break;
}
ocf_io_set_cmpl(sub_io, NULL, NULL, block_dev_complete_sub_rq);
list_add_tail(&data->list, list);
atomic_inc(&master_data->master_remaining);
}
if (error) {
CAS_PRINT_RL(KERN_ERR "Cannot handle request (ERROR %d)\n", error);
/* Go over list and free all */
while (!list_empty(list)) {
data = list_first_entry(list, struct blk_data, list);
list_del(&data->list);
sub_io = data->io;
ocf_io_put(sub_io);
cas_free_blk_data(data);
}
}
return error;
}
static void _blockdev_set_request_data(struct blk_data *data, struct request *rq)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
struct req_iterator iter;
struct bio_vec *bvec;
uint32_t i = 0;
rq_for_each_segment(bvec, rq, iter) {
BUG_ON(i >= data->size);
data->vec[i] = *bvec;
i++;
}
#else
struct req_iterator iter;
struct bio_vec bvec;
uint32_t i = 0;
rq_for_each_segment(bvec, rq, iter) {
BUG_ON(i >= data->size);
data->vec[i] = bvec;
i++;
}
#endif
}
/**
* @brief push flush request upon execution queue for given core device
*/
static int _blkdev_handle_flush_request(struct request *rq, ocf_core_t core)
{
struct ocf_io *io;
ocf_cache_t cache = ocf_core_get_cache(core);
struct cache_priv *cache_priv = ocf_cache_get_priv(cache);
io = ocf_core_new_io(core, cache_priv->io_queues[smp_processor_id()],
0, 0, OCF_WRITE, 0, CAS_WRITE_FLUSH);
if (!io)
return -ENOMEM;
ocf_io_set_cmpl(io, rq, NULL, block_dev_complete_flush);
ocf_core_submit_flush(io);
return 0;
}
#ifdef RQ_CHECK_CONTINOUS
static inline bool _bvec_is_mergeable(struct bio_vec *bv1, struct bio_vec *bv2)
{
if (bv1 == NULL)
return true;
if (BIOVEC_PHYS_MERGEABLE(bv1, bv2))
return true;
return !bv2->bv_offset && !((bv1->bv_offset + bv1->bv_len) % PAGE_SIZE);
}
#endif
static uint32_t _blkdev_scan_request(ocf_cache_t cache, struct request *rq,
struct ocf_io *io, bool *single_io)
{
uint32_t size = 0;
struct req_iterator iter;
struct bio *bio_prev = NULL;
uint32_t io_class;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
struct bio_vec bvec;
#ifdef RQ_CHECK_CONTINOUS
struct bio_vec bvec_prev = { NULL, };
#endif
#else
struct bio_vec *bvec;
#ifdef RQ_CHECK_CONTINOUS
struct bio_vec *bvec_prev = NULL;
#endif
#endif
*single_io = true;
/* Scan BIOs in the request to:
* 1. Count the segments number
* 2. Check if requests contains many IO classes
* 3. Check if request is continuous (when process kernel stack is 8KB)
*/
rq_for_each_segment(bvec, rq, iter) {
/* Increase BIO data vector counter */
size++;
if (*single_io == false) {
/* Already detected complex request */
continue;
}
#ifdef RQ_CHECK_CONTINOUS
/*
* If request is not continous submit each bio as separate
* request, and prevent nvme driver from splitting requests.
* For large requests, nvme splitting causes stack overrun.
*/
if (!_bvec_is_mergeable(CAS_SEGMENT_BVEC(bvec_prev),
CAS_SEGMENT_BVEC(bvec))) {
*single_io = false;
continue;
}
bvec_prev = bvec;
#endif
if (bio_prev == iter.bio)
continue;
bio_prev = iter.bio;
/* Get class ID for given BIO */
io_class = cas_cls_classify(cache, iter.bio);
if (io->io_class != io_class) {
/*
* Request contains BIO with different IO classes and
* need to handle BIO separately
*/
*single_io = false;
}
}
return size;
}
static int __block_dev_queue_rq(struct request *rq, ocf_core_t core)
{
ocf_cache_t cache = ocf_core_get_cache(core);
struct cache_priv *cache_priv = ocf_cache_get_priv(cache);
struct ocf_io *io;
struct blk_data *data;
int master_flags = 0;
bool single_io;
uint32_t size;
int ret;
if (_blockdev_is_request_barier(rq) || !_blockdev_can_handle_rq(rq)) {
CAS_PRINT_RL(KERN_WARNING
"special bio was sent,not supported!\n");
return -ENOTSUPP;
}
if ((rq->cmd_flags & REQ_FUA) && CAS_RQ_IS_FLUSH(rq)) {
/* FLUSH and FUA */
master_flags = CAS_WRITE_FLUSH_FUA;
} else if (rq->cmd_flags & REQ_FUA) {
/* FUA */
master_flags = CAS_WRITE_FUA;
} else if (CAS_RQ_IS_FLUSH(rq)) {
/* FLUSH */
return _blkdev_handle_flush_request(rq, core);
}
io = ocf_core_new_io(core, cache_priv->io_queues[smp_processor_id()],
BLK_RQ_POS(rq) << SECTOR_SHIFT, BLK_RQ_BYTES(rq),
(rq_data_dir(rq) == CAS_RQ_DATA_DIR_WR) ?
OCF_WRITE : OCF_READ,
cas_cls_classify(cache, rq->bio), master_flags);
if (!io) {
CAS_PRINT_RL(KERN_CRIT "Out of memory. Ending IO processing.\n");
return -ENOMEM;
}
size = _blkdev_scan_request(cache, rq, io, &single_io);
if (unlikely(size == 0)) {
CAS_PRINT_RL(KERN_ERR "Empty IO request\n");
ocf_io_put(io);
return -EINVAL;
}
if (single_io) {
data = cas_alloc_blk_data(size, GFP_NOIO);
if (data == NULL) {
CAS_PRINT_RL(KERN_CRIT
"Out of memory. Ending IO processing.\n");
ocf_io_put(io);
return -ENOMEM;
}
_blockdev_set_request_data(data, rq);
data->master_io_req = rq;
ret = ocf_io_set_data(io, data, 0);
if (ret) {
ocf_io_put(io);
cas_free_blk_data(data);
return -EINVAL;
}
ocf_io_set_cmpl(io, NULL, NULL, block_dev_complete_rq);
ocf_core_submit_io(io);
} else {
struct list_head list = LIST_HEAD_INIT(list);
data = cas_alloc_blk_data(0, GFP_NOIO);
if (data == NULL) {
printk(KERN_CRIT
"Out of memory. Ending IO processing.\n");
ocf_io_put(io);
return -ENOMEM;
}
data->master_io_req = rq;
if (ocf_io_set_data(io, data, 0)) {
ocf_io_put(io);
cas_free_blk_data(data);
return -EINVAL;
}
/* Allocate setup and setup */
ret = _blockdev_alloc_many_requests(core, &list, rq, io);
if (ret < 0) {
printk(KERN_CRIT
"Out of memory. Ending IO processing.\n");
cas_free_blk_data(data);
ocf_io_put(io);
return -ENOMEM;
}
BUG_ON(list_empty(&list));
/* Go over list and push request to the engine */
while (!list_empty(&list)) {
struct ocf_io *sub_io;
data = list_first_entry(&list, struct blk_data, list);
list_del(&data->list);
sub_io = data->io;
ocf_core_submit_io(sub_io);
}
}
return ret;
}
static CAS_BLK_STATUS_T _block_dev_queue_request(struct casdsk_disk *dsk, struct request *rq, void *private)
{
ocf_core_t core = private;
int ret = __block_dev_queue_rq(rq, core);
if (ret)
_blockdev_end_request_all(rq, ret);
return CAS_ERRNO_TO_BLK_STS(ret);
}
static inline int _blkdev_can_hndl_bio(struct bio *bio)
{
if (CAS_CHECK_BARRIER(bio)) {
@ -847,7 +425,6 @@ static void _blockdev_submit_bio(struct casdsk_disk *dsk,
static struct casdsk_exp_obj_ops _blockdev_exp_obj_ops = {
.set_geometry = _blockdev_set_geometry,
.queue_rq_fn = _block_dev_queue_request,
.submit_bio = _blockdev_submit_bio,
.pending_rq_inc = _blockdev_pending_req_inc,
.pending_rq_dec = _blockdev_pending_req_dec,

View File

@ -45,13 +45,6 @@ struct casdsk_exp_obj_ops {
void (*submit_bio)(struct casdsk_disk *dsk,
struct bio *bio, void *private);
/**
* @brief queue_rq_fn of exported object (top) block device.
* Called by cas_disk when cas_disk device is in attached mode.
*/
CAS_BLK_STATUS_T (*queue_rq_fn)(struct casdsk_disk *dsk, struct request *rq,
void *private);
/**
* @brief Increment exported object pending request counter.
*/

View File

@ -461,30 +461,9 @@ static int _casdsk_exp_obj_init_kobject(struct casdsk_disk *dsk)
}
static CAS_BLK_STATUS_T _casdsk_exp_obj_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
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;
CAS_BLK_STATUS_T result = CAS_BLK_STS_OK;
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;
return CAS_BLK_STS_NOTSUPP;
}
static struct blk_mq_ops casdsk_mq_ops = {