diff options
author | kib <kib@FreeBSD.org> | 2011-07-09 15:21:10 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2011-07-09 15:21:10 +0000 |
commit | 61e3fec296fa6c27ba164bba06c2773c8f52d5ae (patch) | |
tree | 2e4765a311744587c5b4fff81d2ac15360a89ca0 /sys/kern/subr_uio.c | |
parent | 08e1095b2da00c4acdc7a1b5d5eaec9704712578 (diff) | |
download | FreeBSD-src-61e3fec296fa6c27ba164bba06c2773c8f52d5ae.zip FreeBSD-src-61e3fec296fa6c27ba164bba06c2773c8f52d5ae.tar.gz |
Add a facility to disable processing page faults. When activated,
uiomove generates EFAULT if any accessed address is not mapped, as
opposed to handling the fault.
Sponsored by: The FreeBSD Foundation
Reviewed by: alc (previous version)
Diffstat (limited to 'sys/kern/subr_uio.c')
-rw-r--r-- | sys/kern/subr_uio.c | 63 |
1 files changed, 53 insertions, 10 deletions
diff --git a/sys/kern/subr_uio.c b/sys/kern/subr_uio.c index 9385dc4..6e81328 100644 --- a/sys/kern/subr_uio.c +++ b/sys/kern/subr_uio.c @@ -64,6 +64,8 @@ __FBSDID("$FreeBSD$"); SYSCTL_INT(_kern, KERN_IOV_MAX, iov_max, CTLFLAG_RD, NULL, UIO_MAXIOV, "Maximum number of elements in an I/O vector; sysconf(_SC_IOV_MAX)"); +static int uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault); + #ifdef ZERO_COPY_SOCKETS /* Declared in uipc_socket.c */ extern int so_zero_copy_receive; @@ -129,23 +131,65 @@ retry: #endif /* ZERO_COPY_SOCKETS */ int +copyin_nofault(const void *udaddr, void *kaddr, size_t len) +{ + int error, save; + + save = vm_fault_disable_pagefaults(); + error = copyin(udaddr, kaddr, len); + vm_fault_enable_pagefaults(save); + return (error); +} + +int +copyout_nofault(const void *kaddr, void *udaddr, size_t len) +{ + int error, save; + + save = vm_fault_disable_pagefaults(); + error = copyout(kaddr, udaddr, len); + vm_fault_enable_pagefaults(save); + return (error); +} + +int uiomove(void *cp, int n, struct uio *uio) { - struct thread *td = curthread; + + return (uiomove_faultflag(cp, n, uio, 0)); +} + +int +uiomove_nofault(void *cp, int n, struct uio *uio) +{ + + return (uiomove_faultflag(cp, n, uio, 1)); +} + +static int +uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault) +{ + struct thread *td; struct iovec *iov; u_int cnt; - int error = 0; - int save = 0; + int error, newflags, save; + + td = curthread; + error = 0; KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, ("uiomove: mode")); - KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread, + KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == td, ("uiomove proc")); - WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, - "Calling uiomove()"); + if (!nofault) + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, + "Calling uiomove()"); - save = td->td_pflags & TDP_DEADLKTREAT; - td->td_pflags |= TDP_DEADLKTREAT; + /* XXX does it make a sense to set TDP_DEADLKTREAT for UIO_SYSSPACE ? */ + newflags = TDP_DEADLKTREAT; + if (uio->uio_segflg == UIO_USERSPACE && nofault) + newflags |= TDP_NOFAULTING; + save = curthread_pflags_set(newflags); while (n > 0 && uio->uio_resid) { iov = uio->uio_iov; @@ -187,8 +231,7 @@ uiomove(void *cp, int n, struct uio *uio) n -= cnt; } out: - if (save == 0) - td->td_pflags &= ~TDP_DEADLKTREAT; + curthread_pflags_restore(save); return (error); } |