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