Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/sys uiomove(9): Add uiopeek/uioskip operations.
details: https://anonhg.NetBSD.org/src/rev/87b81b7bbdc4
branches: trunk
changeset: 375924:87b81b7bbdc4
user: riastradh <riastradh%NetBSD.org@localhost>
date: Mon May 22 14:07:24 2023 +0000
description:
uiomove(9): Add uiopeek/uioskip operations.
This allows a caller to grab some data, consume part of it, and
atomically update the uio with only the amount it consumed. This
way, the caller can use a buffer of a size that doesn't depend on how
much it will actually consume, which it may not know in advance --
e.g., because it depends on how much an underlying hardware tty
device will accept before it decides it has had too much.
Proposed on tech-kern:
https://mail-index.netbsd.org/tech-kern/2023/05/09/msg028883.html
(Opinions were divided between `uioadvance' and `uioskip'. I stuck
with `uioskip' because that was less work for me.)
diffstat:
share/man/man9/uiomove.9 | 35 ++++++++++++++++-
sys/kern/subr_copy.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++-
sys/sys/systm.h | 4 +-
3 files changed, 124 insertions(+), 6 deletions(-)
diffs (196 lines):
diff -r 5f8f1a1564ec -r 87b81b7bbdc4 share/man/man9/uiomove.9
--- a/share/man/man9/uiomove.9 Mon May 22 12:55:44 2023 +0000
+++ b/share/man/man9/uiomove.9 Mon May 22 14:07:24 2023 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: uiomove.9,v 1.20 2019/09/01 19:08:35 wiz Exp $
+.\" $NetBSD: uiomove.9,v 1.21 2023/05/22 14:07:24 riastradh Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -24,7 +24,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd April 26, 2010
+.Dd May 9, 2023
.Dt UIOMOVE 9
.Os
.Sh NAME
@@ -34,6 +34,10 @@
.In sys/systm.h
.Ft int
.Fn uiomove "void *buf" "size_t n" "struct uio *uio"
+.Ft int
+.Fn uiopeek "void *buf" "size_t n" "struct uio *uio"
+.Ft void
+.Fn uioskip "void *buf" "size_t n" "struct uio *uio"
.Sh DESCRIPTION
The
.Fn uiomove
@@ -140,10 +144,35 @@ to point that much farther into the regi
This allows multiple calls to
.Fn uiomove
to easily be used to fill or drain the region of data.
+.Pp
+The
+.Fn uiopeek
+function copies up to
+.Fa n
+bytes of data without updating
+.Fa uio ;
+the
+.Fn uioskip
+function updates
+.Fa uio
+without copying any data, and is guaranteed never to sleep or fault
+even if the buffers are in userspace and memory access via
+.Fn uiomove
+or
+.Fn uiopeek
+would trigger paging.
+A successful
+.Fn uiomove buf n uio
+call is equivalent to a successful
+.Fn uiopeek buf n uio
+followed by
+.Fn uioskip n uio .
.Sh RETURN VALUES
Upon successful completion,
.Fn uiomove
-returns 0.
+and
+.Fn uiopeek
+return 0.
If a bad address is encountered,
.Er EFAULT
is returned.
diff -r 5f8f1a1564ec -r 87b81b7bbdc4 sys/kern/subr_copy.c
--- a/sys/kern/subr_copy.c Mon May 22 12:55:44 2023 +0000
+++ b/sys/kern/subr_copy.c Mon May 22 14:07:24 2023 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_copy.c,v 1.18 2023/04/11 10:22:04 riastradh Exp $ */
+/* $NetBSD: subr_copy.c,v 1.19 2023/05/22 14:07:24 riastradh Exp $ */
/*-
* Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008, 2019
@@ -80,7 +80,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_copy.c,v 1.18 2023/04/11 10:22:04 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_copy.c,v 1.19 2023/05/22 14:07:24 riastradh Exp $");
#define __UFETCHSTORE_PRIVATE
#define __UCAS_PRIVATE
@@ -166,6 +166,93 @@ uiomove_frombuf(void *buf, size_t buflen
return (uiomove((char *)buf + offset, buflen - offset, uio));
}
+int
+uiopeek(void *buf, size_t n, struct uio *uio)
+{
+ struct vmspace *vm = uio->uio_vmspace;
+ struct iovec *iov;
+ size_t cnt;
+ int error = 0;
+ char *cp = buf;
+ size_t resid = uio->uio_resid;
+ int iovcnt = uio->uio_iovcnt;
+ char *base;
+ size_t len;
+
+ KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE);
+
+ if (n == 0 || resid == 0)
+ return 0;
+ iov = uio->uio_iov;
+ base = iov->iov_base;
+ len = iov->iov_len;
+
+ while (n > 0 && resid > 0) {
+ KASSERT(iovcnt > 0);
+ cnt = len;
+ if (cnt == 0) {
+ KASSERT(iovcnt > 1);
+ iov++;
+ iovcnt--;
+ base = iov->iov_base;
+ len = iov->iov_len;
+ continue;
+ }
+ if (cnt > n)
+ cnt = n;
+ if (!VMSPACE_IS_KERNEL_P(vm)) {
+ preempt_point();
+ }
+
+ if (uio->uio_rw == UIO_READ) {
+ error = copyout_vmspace(vm, cp, base, cnt);
+ } else {
+ error = copyin_vmspace(vm, base, cp, cnt);
+ }
+ if (error) {
+ break;
+ }
+ base += cnt;
+ len -= cnt;
+ resid -= cnt;
+ cp += cnt;
+ KDASSERT(cnt <= n);
+ n -= cnt;
+ }
+
+ return error;
+}
+
+void
+uioskip(size_t n, struct uio *uio)
+{
+ struct iovec *iov;
+ size_t cnt;
+
+ KASSERTMSG(n <= uio->uio_resid, "n=%zu resid=%zu", n, uio->uio_resid);
+
+ KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE);
+ while (n > 0 && uio->uio_resid) {
+ KASSERT(uio->uio_iovcnt > 0);
+ iov = uio->uio_iov;
+ cnt = iov->iov_len;
+ if (cnt == 0) {
+ KASSERT(uio->uio_iovcnt > 1);
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ continue;
+ }
+ if (cnt > n)
+ cnt = n;
+ iov->iov_base = (char *)iov->iov_base + cnt;
+ iov->iov_len -= cnt;
+ uio->uio_resid -= cnt;
+ uio->uio_offset += cnt;
+ KDASSERT(cnt <= n);
+ n -= cnt;
+ }
+}
+
/*
* Give next character to user as result of read.
*/
diff -r 5f8f1a1564ec -r 87b81b7bbdc4 sys/sys/systm.h
--- a/sys/sys/systm.h Mon May 22 12:55:44 2023 +0000
+++ b/sys/sys/systm.h Mon May 22 14:07:24 2023 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: systm.h,v 1.301 2021/06/16 11:55:10 rin Exp $ */
+/* $NetBSD: systm.h,v 1.302 2023/05/22 14:07:24 riastradh Exp $ */
/*-
* Copyright (c) 1982, 1988, 1991, 1993
@@ -620,6 +620,8 @@ void trace_exit(register_t, const struct
int uiomove(void *, size_t, struct uio *);
int uiomove_frombuf(void *, size_t, struct uio *);
+int uiopeek(void *, size_t, struct uio *);
+void uioskip(size_t, struct uio *);
#ifdef _KERNEL
int setjmp(label_t *) __returns_twice;
Home |
Main Index |
Thread Index |
Old Index