When __blkdev_direct_IO() splits an I/O across multiple bios and bio_integrity_map_iter() fails on a non-first bio, the function jumps to the 'fail' label which frees the current bio without accounting for the dio->ref increments from previously submitted bios. The in-flight bios complete normally but their atomic_dec_and_test() in blkdev_bio_end_io() can never bring dio->ref to zero, leaving the dio structure (and the first bio it is embedded in) permanently leaked. For synchronous I/O, the waiter is never woken, causing a hang. Fix by matching the existing error handling pattern used for blkdev_iov_iter_get_pages() failure: end the current bio with an error status and break out of the submission loop. This ensures the normal completion path properly accounts for all dio->ref references, both from the current errored bio and from any in-flight bios. The NOWAIT error path is unaffected as its goto fail only triggers on the first iteration where no bios have been submitted yet. Cc: stable@vger.kernel.org Fixes: 3d8b5a22d404 ("block: add support to pass user meta buffer") Signed-off-by: Wentao Liang --- block/fops.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/block/fops.c b/block/fops.c index bb6642b45937..9f16b995c60c 100644 --- a/block/fops.c +++ b/block/fops.c @@ -239,8 +239,11 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, } if (iocb->ki_flags & IOCB_HAS_METADATA) { ret = bio_integrity_map_iter(bio, iocb->private); - if (unlikely(ret)) - goto fail; + if (unlikely(ret)) { + bio->bi_status = errno_to_blk_status(ret); + bio_endio(bio); + break; + } } if (is_read) { -- 2.39.5 (Apple Git-154)