Author: kib
Date: Sat Jul  9 15:21:10 2011
New Revision: 223889
URL: http://svn.freebsd.org/changeset/base/223889

Log:
  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)

Modified:
  head/sys/kern/subr_uio.c
  head/sys/sys/proc.h
  head/sys/sys/systm.h
  head/sys/sys/uio.h
  head/sys/vm/vm_extern.h
  head/sys/vm/vm_fault.c

Modified: head/sys/kern/subr_uio.c
==============================================================================
--- head/sys/kern/subr_uio.c    Sat Jul  9 15:16:07 2011        (r223888)
+++ head/sys/kern/subr_uio.c    Sat Jul  9 15:21:10 2011        (r223889)
@@ -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()");
-
-       save = td->td_pflags & TDP_DEADLKTREAT;
-       td->td_pflags |= TDP_DEADLKTREAT;
+       if (!nofault)
+               WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+                   "Calling uiomove()");
+
+       /* 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);
 }
 

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h Sat Jul  9 15:16:07 2011        (r223888)
+++ head/sys/sys/proc.h Sat Jul  9 15:21:10 2011        (r223889)
@@ -393,7 +393,7 @@ do {                                                        
                \
 #define        TDP_COWINPROGRESS 0x00000010 /* Snapshot copy-on-write in 
progress. */
 #define        TDP_ALTSTACK    0x00000020 /* Have alternate signal stack. */
 #define        TDP_DEADLKTREAT 0x00000040 /* Lock aquisition - deadlock 
treatment. */
-#define        TDP_UNUSED80    0x00000080 /* available. */
+#define        TDP_NOFAULTING  0x00000080 /* Do not handle page faults. */
 #define        TDP_NOSLEEPING  0x00000100 /* Thread is not allowed to sleep on 
a sq. */
 #define        TDP_OWEUPC      0x00000200 /* Call addupc() at next AST. */
 #define        TDP_ITHREAD     0x00000400 /* Thread is an interrupt thread. */

Modified: head/sys/sys/systm.h
==============================================================================
--- head/sys/sys/systm.h        Sat Jul  9 15:16:07 2011        (r223888)
+++ head/sys/sys/systm.h        Sat Jul  9 15:21:10 2011        (r223889)
@@ -217,8 +217,12 @@ int        copyinstr(const void * __restrict ud
            __nonnull(1) __nonnull(2);
 int    copyin(const void * __restrict udaddr, void * __restrict kaddr,
            size_t len) __nonnull(1) __nonnull(2);
+int    copyin_nofault(const void * __restrict udaddr, void * __restrict kaddr,
+           size_t len) __nonnull(1) __nonnull(2);
 int    copyout(const void * __restrict kaddr, void * __restrict udaddr,
            size_t len) __nonnull(1) __nonnull(2);
+int    copyout_nofault(const void * __restrict kaddr, void * __restrict udaddr,
+           size_t len) __nonnull(1) __nonnull(2);
 
 int    fubyte(const void *base);
 long   fuword(const void *base);

Modified: head/sys/sys/uio.h
==============================================================================
--- head/sys/sys/uio.h  Sat Jul  9 15:16:07 2011        (r223888)
+++ head/sys/sys/uio.h  Sat Jul  9 15:21:10 2011        (r223889)
@@ -100,6 +100,7 @@ int uiomove(void *cp, int n, struct uio 
 int    uiomove_frombuf(void *buf, int buflen, struct uio *uio);
 int    uiomove_fromphys(struct vm_page *ma[], vm_offset_t offset, int n,
            struct uio *uio);
+int    uiomove_nofault(void *cp, int n, struct uio *uio);
 int    uiomoveco(void *cp, int n, struct uio *uio, int disposable);
 
 #else /* !_KERNEL */

Modified: head/sys/vm/vm_extern.h
==============================================================================
--- head/sys/vm/vm_extern.h     Sat Jul  9 15:16:07 2011        (r223888)
+++ head/sys/vm/vm_extern.h     Sat Jul  9 15:21:10 2011        (r223889)
@@ -61,6 +61,8 @@ int useracc(void *, int, int);
 int vm_fault(vm_map_t, vm_offset_t, vm_prot_t, int);
 void vm_fault_copy_entry(vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t,
     vm_ooffset_t *);
+int vm_fault_disable_pagefaults(void);
+void vm_fault_enable_pagefaults(int save);
 int vm_fault_hold(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type,
     int fault_flags, vm_page_t *m_hold);
 int vm_fault_quick_hold_pages(vm_map_t map, vm_offset_t addr, vm_size_t len,

Modified: head/sys/vm/vm_fault.c
==============================================================================
--- head/sys/vm/vm_fault.c      Sat Jul  9 15:16:07 2011        (r223888)
+++ head/sys/vm/vm_fault.c      Sat Jul  9 15:21:10 2011        (r223889)
@@ -209,6 +209,8 @@ vm_fault(vm_map_t map, vm_offset_t vaddr
     int fault_flags)
 {
 
+       if ((curthread->td_pflags & TDP_NOFAULTING) != 0)
+               return (KERN_PROTECTION_FAILURE);
        return (vm_fault_hold(map, vaddr, fault_type, fault_flags, NULL));
 }
 
@@ -1475,3 +1477,17 @@ vm_fault_additional_pages(m, rbehind, ra
        /* return number of pages */
        return i;
 }
+
+int
+vm_fault_disable_pagefaults(void)
+{
+
+       return (curthread_pflags_set(TDP_NOFAULTING));
+}
+
+void
+vm_fault_enable_pagefaults(int save)
+{
+
+       curthread_pflags_restore(save);
+}
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to