summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_uio.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2011-07-09 15:21:10 +0000
committerkib <kib@FreeBSD.org>2011-07-09 15:21:10 +0000
commit61e3fec296fa6c27ba164bba06c2773c8f52d5ae (patch)
tree2e4765a311744587c5b4fff81d2ac15360a89ca0 /sys/kern/subr_uio.c
parent08e1095b2da00c4acdc7a1b5d5eaec9704712578 (diff)
downloadFreeBSD-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.c63
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);
}
OpenPOWER on IntegriCloud