* [PATCHSET v3 0/4] Turn single segment imports into ITER_UBUF
@ 2023-03-27 23:27 Jens Axboe
2023-03-27 23:27 ` [PATCH 1/3] iov_iter: teach iov_iter_iovec() to deal with ITER_UBUF Jens Axboe
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Jens Axboe @ 2023-03-27 23:27 UTC (permalink / raw)
To: linux-fsdevel; +Cc: torvalds, brauner, viro
Hi,
Rather than repeat the same blurb again, see the v2 posting here:
https://lore.kernel.org/linux-fsdevel/20230327180449.87382-1-axboe@kernel.dk/
tldr - turn single segment iovecs into ITER_UBUF rather than ITER_IOVEC,
because they are more efficient.
Since v2:
- Add prep patch based on Al's suggestion on just making iov_iter_iovec()
deal with ITER_UBUF.
- Drop previous two prep patches, as they are no longer needed.
--
Jens Axboe
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] iov_iter: teach iov_iter_iovec() to deal with ITER_UBUF
2023-03-27 23:27 [PATCHSET v3 0/4] Turn single segment imports into ITER_UBUF Jens Axboe
@ 2023-03-27 23:27 ` Jens Axboe
2023-03-27 23:27 ` [PATCH 2/3] iov_iter: convert import_single_range() to ITER_UBUF Jens Axboe
2023-03-27 23:27 ` [PATCH 3/3] iov_iter: import single vector iovecs as ITER_UBUF Jens Axboe
2 siblings, 0 replies; 8+ messages in thread
From: Jens Axboe @ 2023-03-27 23:27 UTC (permalink / raw)
To: linux-fsdevel; +Cc: torvalds, brauner, viro, Jens Axboe
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.
This is done in preparation for automatically importing single segment
iovecs as ITER_UBUF.
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
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
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/3] iov_iter: convert import_single_range() to ITER_UBUF
2023-03-27 23:27 [PATCHSET v3 0/4] Turn single segment imports into ITER_UBUF Jens Axboe
2023-03-27 23:27 ` [PATCH 1/3] iov_iter: teach iov_iter_iovec() to deal with ITER_UBUF Jens Axboe
@ 2023-03-27 23:27 ` Jens Axboe
2023-03-27 23:27 ` [PATCH 3/3] iov_iter: import single vector iovecs as ITER_UBUF Jens Axboe
2 siblings, 0 replies; 8+ messages in thread
From: Jens Axboe @ 2023-03-27 23:27 UTC (permalink / raw)
To: linux-fsdevel; +Cc: torvalds, brauner, viro, Jens Axboe
Since we're just importing a single vector, we don't have to turn it
into an ITER_IOVEC. Instead turn it into an ITER_UBUF, which is cheaper
to iterate.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
lib/iov_iter.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 274014e4eafe..fc82cc42ffe6 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -1866,9 +1866,7 @@ int import_single_range(int rw, void __user *buf, size_t len,
if (unlikely(!access_ok(buf, len)))
return -EFAULT;
- iov->iov_base = buf;
- iov->iov_len = len;
- iov_iter_init(i, rw, iov, 1, len);
+ iov_iter_ubuf(i, rw, buf, len);
return 0;
}
EXPORT_SYMBOL(import_single_range);
--
2.39.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/3] iov_iter: import single vector iovecs as ITER_UBUF
2023-03-27 23:27 [PATCHSET v3 0/4] Turn single segment imports into ITER_UBUF Jens Axboe
2023-03-27 23:27 ` [PATCH 1/3] iov_iter: teach iov_iter_iovec() to deal with ITER_UBUF Jens Axboe
2023-03-27 23:27 ` [PATCH 2/3] iov_iter: convert import_single_range() to ITER_UBUF Jens Axboe
@ 2023-03-27 23:27 ` Jens Axboe
2023-03-28 0:08 ` Al Viro
2 siblings, 1 reply; 8+ messages in thread
From: Jens Axboe @ 2023-03-27 23:27 UTC (permalink / raw)
To: linux-fsdevel; +Cc: torvalds, brauner, viro, Jens Axboe
Add a special case to __import_iovec(), which imports a single segment
iovec as an ITER_UBUF rather than an ITER_IOVEC. ITER_UBUF is cheaper
to iterate than ITER_IOVEC, and for a single segment iovec, there's no
point in using a segmented iterator.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
lib/iov_iter.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index fc82cc42ffe6..63cf9997bd50 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -1780,6 +1780,30 @@ struct iovec *iovec_from_user(const struct iovec __user *uvec,
return iov;
}
+/*
+ * Single segment iovec supplied by the user, import it as ITER_UBUF.
+ */
+static ssize_t __import_iovec_ubuf(int type, const struct iovec __user *uvec,
+ struct iovec **iovp, struct iov_iter *i,
+ bool compat)
+{
+ struct iovec *iov = *iovp;
+ ssize_t ret;
+
+ if (compat)
+ ret = copy_compat_iovec_from_user(iov, uvec, 1);
+ else
+ ret = copy_iovec_from_user(iov, uvec, 1);
+ if (unlikely(ret))
+ return ret;
+
+ ret = import_ubuf(type, iov->iov_base, iov->iov_len, i);
+ if (unlikely(ret))
+ return ret;
+ *iovp = NULL;
+ return i->count;
+}
+
ssize_t __import_iovec(int type, const struct iovec __user *uvec,
unsigned nr_segs, unsigned fast_segs, struct iovec **iovp,
struct iov_iter *i, bool compat)
@@ -1788,6 +1812,9 @@ ssize_t __import_iovec(int type, const struct iovec __user *uvec,
unsigned long seg;
struct iovec *iov;
+ if (nr_segs == 1)
+ return __import_iovec_ubuf(type, uvec, iovp, i, compat);
+
iov = iovec_from_user(uvec, nr_segs, fast_segs, *iovp, compat);
if (IS_ERR(iov)) {
*iovp = NULL;
--
2.39.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] iov_iter: import single vector iovecs as ITER_UBUF
2023-03-27 23:27 ` [PATCH 3/3] iov_iter: import single vector iovecs as ITER_UBUF Jens Axboe
@ 2023-03-28 0:08 ` Al Viro
2023-03-28 0:25 ` Al Viro
2023-03-28 13:20 ` Jens Axboe
0 siblings, 2 replies; 8+ messages in thread
From: Al Viro @ 2023-03-28 0:08 UTC (permalink / raw)
To: Jens Axboe; +Cc: linux-fsdevel, torvalds, brauner
On Mon, Mar 27, 2023 at 05:27:13PM -0600, Jens Axboe wrote:
> Add a special case to __import_iovec(), which imports a single segment
> iovec as an ITER_UBUF rather than an ITER_IOVEC. ITER_UBUF is cheaper
> to iterate than ITER_IOVEC, and for a single segment iovec, there's no
> point in using a segmented iterator.
Won't that enforce the "single-segment readv() is always identical to
read()"? We'd been through that before - some of infinibarf drvivers
have two different command sets, one reached via read(), another - via
readv(). It's a userland ABI. Misdesigned one, but that's infinibarf
for you.
Does anyone really need this particular microoptimization?
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] iov_iter: import single vector iovecs as ITER_UBUF
2023-03-28 0:08 ` Al Viro
@ 2023-03-28 0:25 ` Al Viro
2023-03-28 1:20 ` Jens Axboe
2023-03-28 13:20 ` Jens Axboe
1 sibling, 1 reply; 8+ messages in thread
From: Al Viro @ 2023-03-28 0:25 UTC (permalink / raw)
To: Jens Axboe; +Cc: linux-fsdevel, torvalds, brauner
On Tue, Mar 28, 2023 at 01:08:11AM +0100, Al Viro wrote:
> On Mon, Mar 27, 2023 at 05:27:13PM -0600, Jens Axboe wrote:
> > Add a special case to __import_iovec(), which imports a single segment
> > iovec as an ITER_UBUF rather than an ITER_IOVEC. ITER_UBUF is cheaper
> > to iterate than ITER_IOVEC, and for a single segment iovec, there's no
> > point in using a segmented iterator.
>
> Won't that enforce the "single-segment readv() is always identical to
> read()"? We'd been through that before - some of infinibarf drvivers
> have two different command sets, one reached via read(), another - via
> readv(). It's a userland ABI. Misdesigned one, but that's infinibarf
> for you.
>
> Does anyone really need this particular microoptimization?
static ssize_t qib_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct qib_filedata *fp = iocb->ki_filp->private_data;
struct qib_ctxtdata *rcd = ctxt_fp(iocb->ki_filp);
struct qib_user_sdma_queue *pq = fp->pq;
if (!iter_is_iovec(from) || !from->nr_segs || !pq)
return -EINVAL;
return qib_user_sdma_writev(rcd, pq, from->iov, from->nr_segs);
}
Hit this with single-segment writev() and you've got yourself -EINVAL.
Sure, that could be adjusted for (check for user_backed_iter(), then
if it's ubuf form an iovec and pass that to qib_user_sdma_writev()),
but that's a clear regression.
Found by simple grepping for iter_is_iovec()...
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] iov_iter: import single vector iovecs as ITER_UBUF
2023-03-28 0:25 ` Al Viro
@ 2023-03-28 1:20 ` Jens Axboe
0 siblings, 0 replies; 8+ messages in thread
From: Jens Axboe @ 2023-03-28 1:20 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, torvalds, brauner
On 3/27/23 6:25 PM, Al Viro wrote:
> On Tue, Mar 28, 2023 at 01:08:11AM +0100, Al Viro wrote:
>> On Mon, Mar 27, 2023 at 05:27:13PM -0600, Jens Axboe wrote:
>>> Add a special case to __import_iovec(), which imports a single segment
>>> iovec as an ITER_UBUF rather than an ITER_IOVEC. ITER_UBUF is cheaper
>>> to iterate than ITER_IOVEC, and for a single segment iovec, there's no
>>> point in using a segmented iterator.
>>
>> Won't that enforce the "single-segment readv() is always identical to
>> read()"? We'd been through that before - some of infinibarf drvivers
>> have two different command sets, one reached via read(), another - via
>> readv(). It's a userland ABI. Misdesigned one, but that's infinibarf
>> for you.
>>
>> Does anyone really need this particular microoptimization?
>
> static ssize_t qib_write_iter(struct kiocb *iocb, struct iov_iter *from)
> {
> struct qib_filedata *fp = iocb->ki_filp->private_data;
> struct qib_ctxtdata *rcd = ctxt_fp(iocb->ki_filp);
> struct qib_user_sdma_queue *pq = fp->pq;
>
> if (!iter_is_iovec(from) || !from->nr_segs || !pq)
> return -EINVAL;
>
> return qib_user_sdma_writev(rcd, pq, from->iov, from->nr_segs);
> }
>
> Hit this with single-segment writev() and you've got yourself -EINVAL.
> Sure, that could be adjusted for (check for user_backed_iter(), then
> if it's ubuf form an iovec and pass that to qib_user_sdma_writev()),
> but that's a clear regression.
>
> Found by simple grepping for iter_is_iovec()...
Looks like there are a few of those, in fact. Guess we need to do
an iter->user_backed check for these.
--
Jens Axboe
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] iov_iter: import single vector iovecs as ITER_UBUF
2023-03-28 0:08 ` Al Viro
2023-03-28 0:25 ` Al Viro
@ 2023-03-28 13:20 ` Jens Axboe
1 sibling, 0 replies; 8+ messages in thread
From: Jens Axboe @ 2023-03-28 13:20 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, torvalds, brauner
On 3/27/23 6:08 PM, Al Viro wrote:
> On Mon, Mar 27, 2023 at 05:27:13PM -0600, Jens Axboe wrote:
>> Add a special case to __import_iovec(), which imports a single segment
>> iovec as an ITER_UBUF rather than an ITER_IOVEC. ITER_UBUF is cheaper
>> to iterate than ITER_IOVEC, and for a single segment iovec, there's no
>> point in using a segmented iterator.
>
> Won't that enforce the "single-segment readv() is always identical to
> read()"? We'd been through that before - some of infinibarf drvivers
> have two different command sets, one reached via read(), another - via
> readv(). It's a userland ABI. Misdesigned one, but that's infinibarf
> for you.
How so? We're not changing how we pick ->read vs ->read_iter, just
how the iterator is setup. Either method should be happy with either
iterator type.
--
Jens Axboe
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2023-03-28 13:20 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-27 23:27 [PATCHSET v3 0/4] Turn single segment imports into ITER_UBUF Jens Axboe
2023-03-27 23:27 ` [PATCH 1/3] iov_iter: teach iov_iter_iovec() to deal with ITER_UBUF Jens Axboe
2023-03-27 23:27 ` [PATCH 2/3] iov_iter: convert import_single_range() to ITER_UBUF Jens Axboe
2023-03-27 23:27 ` [PATCH 3/3] iov_iter: import single vector iovecs as ITER_UBUF Jens Axboe
2023-03-28 0:08 ` Al Viro
2023-03-28 0:25 ` Al Viro
2023-03-28 1:20 ` Jens Axboe
2023-03-28 13:20 ` Jens Axboe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).