Module Name: src Committed By: riastradh Date: Mon May 22 14:07:24 UTC 2023
Modified Files: src/share/man/man9: uiomove.9 src/sys/kern: subr_copy.c src/sys/sys: systm.h Log Message: 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.) To generate a diff of this commit: cvs rdiff -u -r1.20 -r1.21 src/share/man/man9/uiomove.9 cvs rdiff -u -r1.18 -r1.19 src/sys/kern/subr_copy.c cvs rdiff -u -r1.301 -r1.302 src/sys/sys/systm.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man9/uiomove.9 diff -u src/share/man/man9/uiomove.9:1.20 src/share/man/man9/uiomove.9:1.21 --- src/share/man/man9/uiomove.9:1.20 Sun Sep 1 19:08:35 2019 +++ src/share/man/man9/uiomove.9 Mon May 22 14:07:24 2023 @@ -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. Index: src/sys/kern/subr_copy.c diff -u src/sys/kern/subr_copy.c:1.18 src/sys/kern/subr_copy.c:1.19 --- src/sys/kern/subr_copy.c:1.18 Tue Apr 11 10:22:04 2023 +++ src/sys/kern/subr_copy.c Mon May 22 14:07:24 2023 @@ -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. */ Index: src/sys/sys/systm.h diff -u src/sys/sys/systm.h:1.301 src/sys/sys/systm.h:1.302 --- src/sys/sys/systm.h:1.301 Wed Jun 16 11:55:10 2021 +++ src/sys/sys/systm.h Mon May 22 14:07:24 2023 @@ -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;