Message ID | 20230307141520.793891-14-ming.lei@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | io_uring/ublk: add IORING_OP_FUSED_CMD | expand |
Hi Ming, I love your patch! Perhaps something to improve: [auto build test WARNING on axboe-block/for-next] [also build test WARNING on char-misc/char-misc-testing char-misc/char-misc-next char-misc/char-misc-linus linus/master v6.3-rc2 next-20230314] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Ming-Lei/io_uring-add-IO_URING_F_FUSED-and-prepare-for-supporting-OP_FUSED_CMD/20230307-222928 base: https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git for-next patch link: https://lore.kernel.org/r/20230307141520.793891-14-ming.lei%40redhat.com patch subject: [PATCH V2 13/17] block: ublk_drv: grab request reference when the request is handled by userspace config: microblaze-randconfig-s033-20230308 (https://download.01.org/0day-ci/archive/20230315/202303151232.tHK2H9T3-lkp@intel.com/config) compiler: microblaze-linux-gcc (GCC) 12.1.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # apt-get install sparse # sparse version: v0.6.4-39-gce1a6720-dirty # https://github.com/intel-lab-lkp/linux/commit/8e1a2115a8d58ff04cbc1aad6192805e29d0b63e git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Ming-Lei/io_uring-add-IO_URING_F_FUSED-and-prepare-for-supporting-OP_FUSED_CMD/20230307-222928 git checkout 8e1a2115a8d58ff04cbc1aad6192805e29d0b63e # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=microblaze olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=microblaze SHELL=/bin/bash drivers/block/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202303151232.tHK2H9T3-lkp@intel.com/ sparse warnings: (new ones prefixed by >>) >> drivers/block/ublk_drv.c:688:21: sparse: sparse: incorrect type in assignment (different base types) @@ expected int res @@ got restricted blk_status_t [usertype] @@ drivers/block/ublk_drv.c:688:21: sparse: expected int res drivers/block/ublk_drv.c:688:21: sparse: got restricted blk_status_t [usertype] drivers/block/ublk_drv.c:697:21: sparse: sparse: incorrect type in assignment (different base types) @@ expected int res @@ got restricted blk_status_t @@ drivers/block/ublk_drv.c:697:21: sparse: expected int res drivers/block/ublk_drv.c:697:21: sparse: got restricted blk_status_t drivers/block/ublk_drv.c:728:33: sparse: sparse: incorrect type in argument 2 (different base types) @@ expected restricted blk_status_t [usertype] error @@ got int res @@ drivers/block/ublk_drv.c:728:33: sparse: expected restricted blk_status_t [usertype] error drivers/block/ublk_drv.c:728:33: sparse: got int res >> drivers/block/ublk_drv.c:688:21: sparse: sparse: incorrect type in assignment (different base types) @@ expected int res @@ got restricted blk_status_t [usertype] @@ drivers/block/ublk_drv.c:688:21: sparse: expected int res drivers/block/ublk_drv.c:688:21: sparse: got restricted blk_status_t [usertype] drivers/block/ublk_drv.c:697:21: sparse: sparse: incorrect type in assignment (different base types) @@ expected int res @@ got restricted blk_status_t @@ drivers/block/ublk_drv.c:697:21: sparse: expected int res drivers/block/ublk_drv.c:697:21: sparse: got restricted blk_status_t drivers/block/ublk_drv.c:728:33: sparse: sparse: incorrect type in argument 2 (different base types) @@ expected restricted blk_status_t [usertype] error @@ got int res @@ drivers/block/ublk_drv.c:728:33: sparse: expected restricted blk_status_t [usertype] error drivers/block/ublk_drv.c:728:33: sparse: got int res >> drivers/block/ublk_drv.c:688:21: sparse: sparse: incorrect type in assignment (different base types) @@ expected int res @@ got restricted blk_status_t [usertype] @@ drivers/block/ublk_drv.c:688:21: sparse: expected int res drivers/block/ublk_drv.c:688:21: sparse: got restricted blk_status_t [usertype] drivers/block/ublk_drv.c:697:21: sparse: sparse: incorrect type in assignment (different base types) @@ expected int res @@ got restricted blk_status_t @@ drivers/block/ublk_drv.c:697:21: sparse: expected int res drivers/block/ublk_drv.c:697:21: sparse: got restricted blk_status_t drivers/block/ublk_drv.c:728:33: sparse: sparse: incorrect type in argument 2 (different base types) @@ expected restricted blk_status_t [usertype] error @@ got int res @@ drivers/block/ublk_drv.c:728:33: sparse: expected restricted blk_status_t [usertype] error drivers/block/ublk_drv.c:728:33: sparse: got int res vim +688 drivers/block/ublk_drv.c 677 678 /* todo: handle partial completion */ 679 static inline void __ublk_complete_rq(struct request *req) 680 { 681 struct ublk_queue *ubq = req->mq_hctx->driver_data; 682 struct ublk_io *io = &ubq->ios[req->tag]; 683 unsigned int unmapped_bytes; 684 int res = BLK_STS_OK; 685 686 /* called from ublk_abort_queue() code path */ 687 if (io->flags & UBLK_IO_FLAG_ABORTED) { > 688 res = BLK_STS_IOERR; 689 goto exit; 690 } 691 692 /* failed read IO if nothing is read */ 693 if (!io->res && req_op(req) == REQ_OP_READ) 694 io->res = -EIO; 695 696 if (io->res < 0) { 697 res = errno_to_blk_status(io->res); 698 goto exit; 699 } 700 701 /* 702 * FLUSH, DISCARD or WRITE_ZEROES usually won't return bytes returned, so end them 703 * directly. 704 * 705 * Both the two needn't unmap. 706 */ 707 if (req_op(req) != REQ_OP_READ && req_op(req) != REQ_OP_WRITE) 708 goto exit; 709 710 /* for READ request, writing data in iod->addr to rq buffers */ 711 unmapped_bytes = ublk_unmap_io(ubq, req, io); 712 713 /* 714 * Extremely impossible since we got data filled in just before 715 * 716 * Re-read simply for this unlikely case. 717 */ 718 if (unlikely(unmapped_bytes < io->res)) 719 io->res = unmapped_bytes; 720 721 if (blk_update_request(req, BLK_STS_OK, io->res)) 722 blk_mq_requeue_request(req, true); 723 else 724 __blk_mq_end_request(req, BLK_STS_OK); 725 726 return; 727 exit: 728 blk_mq_end_request(req, res); 729 } 730
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index f07eb8a54357..ba252932951c 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -43,6 +43,7 @@ #include <asm/page.h> #include <linux/task_work.h> #include <linux/namei.h> +#include <linux/kref.h> #include <uapi/linux/ublk_cmd.h> #define UBLK_MINORS (1U << MINORBITS) @@ -62,6 +63,17 @@ struct ublk_rq_data { struct llist_node node; struct callback_head work; + + /* + * Only for applying fused command to support zero copy: + * + * - if there is any fused command aiming at this request, not complete + * request until all fused commands are done + * + * - fused command has to fail unless this reference is grabbed + * successfully + */ + struct kref ref; }; struct ublk_uring_cmd_pdu { @@ -180,6 +192,9 @@ struct ublk_params_header { __u32 types; }; +static inline void __ublk_complete_rq(struct request *req); +static void ublk_complete_rq(struct kref *ref); + static dev_t ublk_chr_devt; static struct class *ublk_chr_class; @@ -288,6 +303,35 @@ static int ublk_apply_params(struct ublk_device *ub) return 0; } +static inline bool ublk_support_zc(const struct ublk_queue *ubq) +{ + return ubq->flags & UBLK_F_SUPPORT_ZERO_COPY; +} + +static inline bool ublk_get_req_ref(const struct ublk_queue *ubq, + struct request *req) +{ + if (ublk_support_zc(ubq)) { + struct ublk_rq_data *data = blk_mq_rq_to_pdu(req); + + return kref_get_unless_zero(&data->ref); + } + + return true; +} + +static inline void ublk_put_req_ref(const struct ublk_queue *ubq, + struct request *req) +{ + if (ublk_support_zc(ubq)) { + struct ublk_rq_data *data = blk_mq_rq_to_pdu(req); + + kref_put(&data->ref, ublk_complete_rq); + } else { + __ublk_complete_rq(req); + } +} + static inline bool ublk_can_use_task_work(const struct ublk_queue *ubq) { if (IS_BUILTIN(CONFIG_BLK_DEV_UBLK) && @@ -632,13 +676,19 @@ static inline bool ubq_daemon_is_dying(struct ublk_queue *ubq) } /* todo: handle partial completion */ -static void ublk_complete_rq(struct request *req) +static inline void __ublk_complete_rq(struct request *req) { struct ublk_queue *ubq = req->mq_hctx->driver_data; struct ublk_io *io = &ubq->ios[req->tag]; unsigned int unmapped_bytes; int res = BLK_STS_OK; + /* called from ublk_abort_queue() code path */ + if (io->flags & UBLK_IO_FLAG_ABORTED) { + res = BLK_STS_IOERR; + goto exit; + } + /* failed read IO if nothing is read */ if (!io->res && req_op(req) == REQ_OP_READ) io->res = -EIO; @@ -678,6 +728,15 @@ static void ublk_complete_rq(struct request *req) blk_mq_end_request(req, res); } +static void ublk_complete_rq(struct kref *ref) +{ + struct ublk_rq_data *data = container_of(ref, struct ublk_rq_data, + ref); + struct request *req = blk_mq_rq_from_pdu(data); + + __ublk_complete_rq(req); +} + /* * Since __ublk_rq_task_work always fails requests immediately during * exiting, __ublk_fail_req() is only called from abort context during @@ -696,7 +755,7 @@ static void __ublk_fail_req(struct ublk_queue *ubq, struct ublk_io *io, if (ublk_queue_can_use_recovery_reissue(ubq)) blk_mq_requeue_request(req, false); else - blk_mq_end_request(req, BLK_STS_IOERR); + ublk_put_req_ref(ubq, req); } } @@ -732,6 +791,7 @@ static inline void __ublk_abort_rq(struct ublk_queue *ubq, static inline void __ublk_rq_task_work(struct request *req) { struct ublk_queue *ubq = req->mq_hctx->driver_data; + struct ublk_rq_data *data = blk_mq_rq_to_pdu(req); int tag = req->tag; struct ublk_io *io = &ubq->ios[tag]; unsigned int mapped_bytes; @@ -803,6 +863,7 @@ static inline void __ublk_rq_task_work(struct request *req) mapped_bytes >> 9; } + kref_init(&data->ref); ubq_complete_io_cmd(io, UBLK_IO_RES_OK); } @@ -1013,7 +1074,7 @@ static void ublk_commit_completion(struct ublk_device *ub, req = blk_mq_tag_to_rq(ub->tag_set.tags[qid], tag); if (req && likely(!blk_should_fake_timeout(req->q))) - ublk_complete_rq(req); + ublk_put_req_ref(ubq, req); } /*
Add one reference counter into request pdu data, and hold this reference in the request's lifetime. This way is always safe. In theory, the ublk request won't be completed until fused commands are done. However, it is userspace, and application can submit fused command at will. Prepare for supporting zero copy, which needs to retrieve request buffer by fused command, so we have to guarantee: - the fused command can't succeed unless the request isn't queued - when any fused command is successful, this request can't be freed until all fused commands on this request are done. Signed-off-by: Ming Lei <ming.lei@redhat.com> --- drivers/block/ublk_drv.c | 67 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-)