Even if we're returning an iovec, we can trivially fill it in with the details from an ITER_UBUF as well. This enables loops that assume ITER_IOVEC to deal with ITER_UBUF transparently. Suggested-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> --- include/linux/uio.h | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/include/linux/uio.h b/include/linux/uio.h index 27e3fd942960..3b4403efcce1 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -143,13 +143,29 @@ static inline size_t iov_length(const struct iovec *iov, unsigned long nr_segs) return ret; } +/* + * Don't assume we're called with ITER_IOVEC, enable usage of ITER_UBUF + * as well by simply filling in the iovec. + */ static inline struct iovec iov_iter_iovec(const struct iov_iter *iter) { - return (struct iovec) { - .iov_base = iter->iov->iov_base + iter->iov_offset, - .iov_len = min(iter->count, - iter->iov->iov_len - iter->iov_offset), - }; + if (WARN_ON_ONCE(!iter->user_backed)) { + return (struct iovec) { + .iov_base = NULL, + .iov_len = 0 + }; + } else if (iter_is_ubuf(iter)) { + return (struct iovec) { + .iov_base = iter->ubuf + iter->iov_offset, + .iov_len = iter->count + }; + } else { + return (struct iovec) { + .iov_base = iter->iov->iov_base + iter->iov_offset, + .iov_len = min(iter->count, + iter->iov->iov_len - iter->iov_offset), + }; + } } size_t copy_page_from_iter_atomic(struct page *page, unsigned offset, -- 2.39.2