From a08e8b8b3506a9e01fdb2a3b9267187d9e3e4ec7 Mon Sep 17 00:00:00 2001 From: Chesnokov Gleb Date: Wed, 8 Dec 2021 20:40:08 +0300 Subject: [PATCH] vdisk_fileio, async mode: Support multi-page sgv's for kernels < v5.1 --- scst/include/scst.h | 17 +++++++++++ scst/src/dev_handlers/scst_vdisk.c | 47 ++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index 5cffea355..3442bf2fb 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -5133,6 +5133,23 @@ static inline int scst_get_buf_count(struct scst_cmd *cmd) return (cmd->sg_cnt == 0) ? 1 : cmd->sg_cnt; } +/* + * Returns approximate higher rounded buffers count in pages + */ +static inline int scst_get_buf_page_count(struct scst_cmd *cmd) +{ + struct scatterlist *sg; + int page_cnt = 0, i; + + if (unlikely(cmd->sg_cnt == 0)) + return 1; + + for (i = 0, sg = cmd->sg; i < cmd->sg_cnt; i++, sg = sg_next_inline(sg)) + page_cnt += PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT; + + return page_cnt; +} + /* * Returns approximate higher rounded buffers count that * scst_get_out_buf_[first|next]() return. diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index d7d36dc4f..4a93fea82 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -3175,7 +3175,11 @@ static bool vdisk_alloc_async_bvec(struct scst_cmd *cmd, { int n; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0) + n = scst_get_buf_page_count(cmd); +#else n = scst_get_buf_count(cmd); +#endif if (n <= ARRAY_SIZE(p->async.small_bvec)) { p->async.bvec = &p->async.small_bvec[0]; return true; @@ -3191,6 +3195,42 @@ static bool vdisk_alloc_async_bvec(struct scst_cmd *cmd, return true; } +static inline +struct bio_vec *vdisk_map_pages_to_bvec(struct bio_vec *bvec, struct page *page, + ssize_t length, int offset) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0) + ssize_t page_len = min_t(ssize_t, length, PAGE_SIZE - offset); +#else + ssize_t page_len = length; +#endif + + *bvec++ = (struct bio_vec) { + .bv_page = page, + .bv_offset = offset, + .bv_len = page_len, + }; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0) + length -= page_len; + + while (length > 0) { + page++; + page_len = min_t(ssize_t, length, PAGE_SIZE); + + *bvec++ = (struct bio_vec) { + .bv_page = page, + .bv_offset = 0, + .bv_len = page_len, + }; + + length -= page_len; + } +#endif + + return bvec; +} + static void fileio_async_complete(struct kiocb *iocb, long ret #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) , long ret2 @@ -3262,11 +3302,8 @@ static enum compl_status_e fileio_exec_async(struct vdisk_cmd_params *p) bvec = p->async.bvec; length = scst_get_sg_page_first(cmd, &page, &offset); while (length) { - *bvec++ = (struct bio_vec){ - .bv_page = page, - .bv_offset = offset, - .bv_len = length, - }; + bvec = vdisk_map_pages_to_bvec(bvec, page, length, offset); + total += length; sg_cnt++; length = scst_get_sg_page_next(cmd, &page, &offset);