kernel - Add /dev/upmap and /dev/kpmap and sys/upmap.h (3)
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 17 Oct 2014 02:25:04 +0000 (19:25 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 17 Oct 2014 02:25:04 +0000 (19:25 -0700)
* Add upmap->invfork.  When a vforked child is trying to access the upmap
  prior to exec we must still access the parent's map and not the child's,
  which means that the stored PID will be incorrect.

  To fix this issue we add the invfork field which allows userland to
  determine whether this is a vforked child accessing the parent's map.
  If it is, getpid() will use the system call.

* Fix a bug where a vfork()d child creates p->p_upmap for itself but then
  maps it into the parent's address space as a side effect of a getpid()
  or other call.  When this situation is detected, /dev/upmap will use
  the parent's p_upmap and not the child's, and also properly set the
  invfork flag.

* Implement system call overrides for getpid(), setproctitle(), and
  clock_gettime() (*_FAST and *_SECOND clock ids).  When more than 10 calls
  are made to one of these functions the new libc upmap/kpmap support is
  activated.  /dev/upmap and /dev/kpmap will be memory-mapped into the
  address space and further accesses will run through the maps instead of
  making system calls.

  This will obviously reduce overhead for these calls by a very significant
  multiplier.

* NOTE! gettimeofday() is still a system call and will likely remain a system
call in order to return a fine-grained time value.  Third-party code
that doesn't need a fine-grained time value must use clock_gettime()
to obtain the new performance efficiencies.

16 files changed:
lib/libc/Makefile.inc
lib/libc/gen/setproctitle.c
lib/libc/upmap/Makefile.inc [new file with mode: 0644]
lib/libc/upmap/Symbol.map [new file with mode: 0644]
lib/libc/upmap/ukp_clock.c [new file with mode: 0644]
lib/libc/upmap/ukp_getpid.c [new file with mode: 0644]
lib/libc/upmap/ukp_setproctitle.c [new file with mode: 0644]
lib/libc/upmap/upmap.c [new file with mode: 0644]
lib/libc/upmap/upmap.h [new file with mode: 0644]
sys/kern/kern_exec.c
sys/kern/kern_exit.c
sys/kern/kern_fork.c
sys/kern/kern_memio.c
sys/kern/kern_proc.c
sys/sys/proc.h
sys/sys/upmap.h

index a8083cb..c94c6db 100644 (file)
@@ -19,6 +19,7 @@ WARNS=2
 .include "${.CURDIR}/../libc/compat-43/Makefile.inc"
 .include "${.CURDIR}/../libc/gdtoa/Makefile.inc"
 .include "${.CURDIR}/../libc/gen/Makefile.inc"
+.include "${.CURDIR}/../libc/upmap/Makefile.inc"
 .include "${.CURDIR}/../libc/sysvipc/Makefile.inc"
 .include "${.CURDIR}/../libc/gmon/Makefile.inc"
 .include "${.CURDIR}/../libc/iconv/Makefile.inc"
index 6d668c1..46723b7 100644 (file)
@@ -35,6 +35,7 @@
 #include "un-namespace.h"
 
 #include "libc_private.h"
+#include "../upmap/upmap.h"
 
 /*
  * Older FreeBSD 2.0, 2.1 and 2.2 had different ps_strings structures and
@@ -75,6 +76,11 @@ setproctitle(const char *fmt, ...)
        unsigned long ul_ps_strings;
        int oid[4];
 
+       va_start(ap, fmt);
+
+       if (__ukp_spt(fmt, ap) == 0)
+               return;
+
        if (buf == NULL) {
                buf = malloc(SPT_BUFSIZE);
                if (buf == NULL)
@@ -89,8 +95,6 @@ setproctitle(const char *fmt, ...)
                *obuf = '\0';
        }
 
-       va_start(ap, fmt);
-
        if (fmt) {
                buf[SPT_BUFSIZE - 1] = '\0';
 
diff --git a/lib/libc/upmap/Makefile.inc b/lib/libc/upmap/Makefile.inc
new file mode 100644 (file)
index 0000000..01b9196
--- /dev/null
@@ -0,0 +1,10 @@
+# Makefile.inc
+#
+
+.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/upmap ${.CURDIR}/../libc/upmap
+
+CFLAGS+=-I${.CURDIR}/../libc/sysvipc
+
+CMAPS+=        ${.CURDIR}/upmap/Symbol.map
+
+SRCS+= upmap.c ukp_clock.c ukp_getpid.c ukp_setproctitle.c
diff --git a/lib/libc/upmap/Symbol.map b/lib/libc/upmap/Symbol.map
new file mode 100644 (file)
index 0000000..90f45f4
--- /dev/null
@@ -0,0 +1,8 @@
+DF306.0 {
+       clock_gettime;
+       _clock_gettime;
+       __clock_gettime;
+       __upmap_map;
+       __kpmap_map;
+       __ukp_spt;
+}
diff --git a/lib/libc/upmap/ukp_clock.c b/lib/libc/upmap/ukp_clock.c
new file mode 100644 (file)
index 0000000..25a386e
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * UKP-Optimized clock_gettime().  Use the kpmap after the 10th call.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/upmap.h>
+#include <sys/time.h>
+#include <machine/cpufunc.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+/*#include "un-namespace.h"*/
+#include "libc_private.h"
+#include "upmap.h"
+
+extern int __sys_clock_gettime(clockid_t clock_id, struct timespec *ts);
+int __clock_gettime(clockid_t clock_id, struct timespec *ts);
+
+__weak_reference(__clock_gettime, clock_gettime);
+
+static int fast_clock;
+static int fast_count;
+static int *upticksp;
+static struct timespec *ts_uptime;
+static struct timespec *ts_realtime;
+
+int
+__clock_gettime(clockid_t clock_id, struct timespec *ts)
+{
+       int res;
+       int w;
+
+       if (fast_clock == 0 && fast_count++ >= 10) {
+               __kpmap_map(&upticksp, &fast_clock, KPTYPE_UPTICKS);
+               __kpmap_map(&ts_uptime, &fast_clock, KPTYPE_TS_UPTIME);
+               __kpmap_map(&ts_realtime, &fast_clock, KPTYPE_TS_REALTIME);
+               __kpmap_map(NULL, &fast_clock, 0);
+       }
+       if (fast_clock > 0) {
+               switch(clock_id) {
+               case CLOCK_UPTIME_FAST:
+               case CLOCK_MONOTONIC_FAST:
+                       do {
+                               w = *upticksp;
+                               cpu_lfence();
+                               *ts = ts_uptime[w & 1];
+                               cpu_lfence();
+                               w = *upticksp - w;
+                       } while (w > 1);
+                       res = 0;
+                       break;
+               case CLOCK_REALTIME_FAST:
+               case CLOCK_SECOND:
+                       do {
+                               w = *upticksp;
+                               cpu_lfence();
+                               *ts = ts_realtime[w & 1];
+                               cpu_lfence();
+                               w = *upticksp - w;
+                       } while (w > 1);
+
+                       if (clock_id == CLOCK_SECOND)
+                               ts->tv_nsec = 0;
+                       res = 0;
+                       break;
+               default:
+                       res = __sys_clock_gettime(clock_id, ts);
+                       break;
+               }
+       } else {
+               res = __sys_clock_gettime(clock_id, ts);
+       }
+       return res;
+}
diff --git a/lib/libc/upmap/ukp_getpid.c b/lib/libc/upmap/ukp_getpid.c
new file mode 100644 (file)
index 0000000..cba9759
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/upmap.h>
+#include <sys/time.h>
+#include <machine/cpufunc.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+/*#include "un-namespace.h"*/
+#include "libc_private.h"
+#include "upmap.h"
+
+extern pid_t __sys_getpid(void);
+int __getpid(void);
+
+__weak_reference(__getpid, getpid);
+
+static int fast_getpid_state;
+static int fast_getpid_count;
+static pid_t *pidp;
+static int   *invforkp;
+
+/*
+ * Optimize getpid() if it is called a lot.  We have to be careful when
+ * getpid() is called in a vfork child prior to exec as the shared area
+ * is still the parent's shared area.
+ */
+pid_t
+__getpid(void)
+{
+       if (fast_getpid_state == 0 && fast_getpid_count++ >= 10) {
+               __upmap_map(&pidp, &fast_getpid_state, UPTYPE_PID);
+               __upmap_map(&invforkp, &fast_getpid_state, UPTYPE_INVFORK);
+               __upmap_map(NULL, &fast_getpid_state, 0);
+       }
+       if (fast_getpid_state > 0 && *invforkp == 0)
+               return(*pidp);
+       else
+               return(__sys_getpid());
+}
+
+#if 0 /* DEBUG */
+pid_t xxx_getpid(void);
+
+pid_t
+xxx_getpid(void)
+{
+       return(__sys_getpid());
+}
+#endif
diff --git a/lib/libc/upmap/ukp_setproctitle.c b/lib/libc/upmap/ukp_setproctitle.c
new file mode 100644 (file)
index 0000000..6b1fe71
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/upmap.h>
+#include <sys/time.h>
+#include <machine/cpufunc.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+/*#include "un-namespace.h"*/
+#include "libc_private.h"
+#include "upmap.h"
+
+static int fast_spt_state;
+static int fast_spt_count;
+static char *sptbuf;
+
+/*
+ * This is called from gen/setproctitle.c
+ */
+int
+__ukp_spt(const char *fmt, va_list ap)
+{
+       size_t n;
+       size_t t;
+
+       if (fast_spt_state == 0 && fast_spt_count++ >= 10) {
+               __upmap_map(&sptbuf, &fast_spt_state, UPTYPE_PROC_TITLE);
+               __upmap_map(NULL, &fast_spt_state, 0);
+       }
+       if (fast_spt_state > 0) {
+               t = UKPLEN_DECODE(UPTYPE_PROC_TITLE);
+               n = snprintf(sptbuf, t, "%s: ", getprogname());
+               vsnprintf(sptbuf + n, t - n, fmt, ap);
+               return 0;
+       } else {
+               return -1;
+       }
+}
diff --git a/lib/libc/upmap/upmap.c b/lib/libc/upmap/upmap.c
new file mode 100644 (file)
index 0000000..7bc9762
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "namespace.h"
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/upmap.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <pthread.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "upmap.h"
+
+static pthread_mutex_t ukpmap_lock;
+static ukpheader_t *kpmap_headers;
+static ukpheader_t *upmap_headers;
+static int kpmap_ok;
+static int upmap_ok;
+
+/*
+ * Map the requested data item from the user-kernel global shared mmap
+ *
+ * *state is set to -1 on failure, else it is left alone.
+ * *datap is set to a pointer to the item on success, else it is left alone.
+ * If type == 0 this function finalizes state, setting it to 1 if it is 0.
+ */
+void
+__kpmap_map(void *datap, int *state, uint16_t type)
+{
+       ukpheader_t *head;
+
+       if (__isthreaded)
+               _pthread_mutex_lock(&ukpmap_lock);
+
+       if (kpmap_ok <= 0) {
+               int fd;
+
+               if (kpmap_ok < 0)
+                       goto failed;
+               fd = _open("/dev/kpmap", O_RDONLY);
+               if (fd < 0) {
+                       kpmap_ok = -1;
+                       goto failed;
+               }
+               kpmap_headers = mmap(NULL, KPMAP_MAPSIZE,
+                                    PROT_READ, MAP_SHARED,
+                                    fd, 0);
+               _close(fd);
+               if ((void *)kpmap_headers == MAP_FAILED) {
+                       kpmap_ok = -1;
+                       goto failed;
+               }
+               kpmap_ok = 1;
+       }
+
+       /*
+        * Special case to finalize state
+        */
+       if (type == 0) {
+               if (*state == 0)
+                       *state = 1;
+               if (__isthreaded)
+                       _pthread_mutex_unlock(&ukpmap_lock);
+               return;
+       }
+
+       /*
+        * Look for type.
+        */
+       for (head = kpmap_headers; head->type; ++head) {
+               if (head->type == type) {
+                       *(void **)datap = (char *)kpmap_headers + head->offset;
+                       if (__isthreaded)
+                               _pthread_mutex_unlock(&ukpmap_lock);
+                       return;
+               }
+       }
+failed:
+       *state = -1;
+       if (__isthreaded)
+               _pthread_mutex_unlock(&ukpmap_lock);
+}
+
+/*
+ * Map the requested data item from the user-kernel per-process shared mmap
+ *
+ * *state is set to -1 on failure, else it is left alone.
+ * *datap is set to a pointer to the item on success, else it is left alone.
+ * If type == 0 this function finalizes state, setting it to 1 if it is 0.
+ */
+void
+__upmap_map(void *datap, int *state, uint16_t type)
+{
+       ukpheader_t *head;
+
+       if (__isthreaded)
+               _pthread_mutex_lock(&ukpmap_lock);
+
+       if (upmap_ok <= 0) {
+               int fd;
+
+               if (upmap_ok < 0)
+                       goto failed;
+               fd = _open("/dev/upmap", O_RDWR);
+               if (fd < 0) {
+                       upmap_ok = -1;
+                       goto failed;
+               }
+               upmap_headers = mmap(NULL, UPMAP_MAPSIZE,
+                                    PROT_READ | PROT_WRITE, MAP_SHARED,
+                                    fd, 0);
+               _close(fd);
+               if ((void *)upmap_headers == MAP_FAILED) {
+                       upmap_ok = -1;
+                       goto failed;
+               }
+               upmap_ok = 1;
+       }
+
+       /*
+        * Special case to finalize state
+        */
+       if (type == 0) {
+               if (*state == 0)
+                       *state = 1;
+               if (__isthreaded)
+                       _pthread_mutex_unlock(&ukpmap_lock);
+               return;
+       }
+
+       /*
+        * Look for type.
+        */
+       for (head = upmap_headers; head->type; ++head) {
+               if (head->type == type) {
+                       *(void **)datap = (char *)upmap_headers + head->offset;
+                       if (__isthreaded)
+                               _pthread_mutex_unlock(&ukpmap_lock);
+                       return;
+               }
+       }
+failed:
+       *state = -1;
+       if (__isthreaded)
+               _pthread_mutex_unlock(&ukpmap_lock);
+}
diff --git a/lib/libc/upmap/upmap.h b/lib/libc/upmap/upmap.h
new file mode 100644 (file)
index 0000000..99d2cc5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef        _UPMAP_H_
+#define        _UPMAP_H_
+
+#ifndef _SYS_TYPES_H_
+#include <sys/types.h>
+#endif
+
+void __kpmap_map(void *datap, int *state, uint16_t type);
+void __upmap_map(void *datap, int *state, uint16_t type);
+int __ukp_spt(const char *fmt, va_list ap);
+
+
+#endif
index 83219f6..ffb7246 100644 (file)
@@ -424,6 +424,8 @@ interpret:
         */
        p->p_flags |= P_EXEC;
        if (p->p_pptr && (p->p_flags & P_PPWAIT)) {
+               if (p->p_pptr->p_upmap)
+                       p->p_pptr->p_upmap->invfork = 0;
                atomic_clear_int(&p->p_flags, P_PPWAIT);
                wakeup(p->p_pptr);
        }
index 9a20180..a3ce51e 100644 (file)
@@ -466,6 +466,8 @@ exit1(int rv)
         * necessary to synchronize with the parent's cpu.
         */
        if (p->p_flags & P_PPWAIT) {
+               if (p->p_pptr && p->p_pptr->p_upmap)
+                       p->p_pptr->p_upmap->invfork = 0;
                atomic_clear_int(&p->p_flags, P_PPWAIT);
                wakeup(p->p_pptr);
        }
index 9c4d98c..ef8efcf 100644 (file)
@@ -499,8 +499,12 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
        p2->p_flags |= p1->p_flags & P_SUGID;
        if (p1->p_session->s_ttyvp != NULL && (p1->p_flags & P_CONTROLT))
                p2->p_flags |= P_CONTROLT;
-       if (flags & RFPPWAIT)
+       if (flags & RFPPWAIT) {
                p2->p_flags |= P_PPWAIT;
+               if (p1->p_upmap)
+                       p1->p_upmap->invfork = 1;
+       }
+
 
        /*
         * Inherit the virtual kernel structure (allows a virtual kernel
index bf9af71..903d1f4 100644 (file)
@@ -675,11 +675,33 @@ iszerodev(cdev_t dev)
 static int
 user_kernel_mapping(int num, vm_ooffset_t offset, vm_ooffset_t *resultp)
 {
-       struct proc *p = curproc;
+       struct proc *p;
        int error;
+       int invfork;
 
-       if (p == NULL)
+       if ((p = curproc) == NULL)
                return (EINVAL);
+
+       /*
+        * If this is a child currently in vfork the pmap is shared with
+        * the parent!  We need to actually set-up the parent's p_upmap,
+        * not the child's, and we need to set the invfork flag.  Userland
+        * will probably adjust its static state so it must be consistent
+        * with the parent or userland will be really badly confused.
+        *
+        * (this situation can happen when user code in vfork() calls
+        *  libc's getpid() or some other function which then decides
+        *  it wants the upmap).
+        */
+       if (p->p_flags & P_PPWAIT) {
+               p = p->p_pptr;
+               if (p == NULL)
+                       return (EINVAL);
+               invfork = 1;
+       } else {
+               invfork = 0;
+       }
+
        error = EINVAL;
 
        switch(num) {
@@ -688,7 +710,10 @@ user_kernel_mapping(int num, vm_ooffset_t offset, vm_ooffset_t *resultp)
                 * /dev/upmap - maps RW per-process shared user-kernel area.
                 */
                if (p->p_upmap == NULL)
-                       proc_usermap(p);
+                       proc_usermap(p, invfork);
+               else if (invfork)
+                       p->p_upmap->invfork = invfork;
+
                if (p->p_upmap &&
                    offset < roundup2(sizeof(*p->p_upmap), PAGE_SIZE)) {
                        /* only good for current process */
index 950d2fa..435598e 100644 (file)
@@ -1155,7 +1155,7 @@ lwpkthreaddeferred(void)
 }
 
 void
-proc_usermap(struct proc *p)
+proc_usermap(struct proc *p, int invfork)
 {
        struct sys_upmap *upmap;
 
@@ -1173,10 +1173,13 @@ proc_usermap(struct proc *p)
                upmap->header[3].offset = offsetof(struct sys_upmap, pid);
                upmap->header[4].type = UPTYPE_PROC_TITLE;
                upmap->header[4].offset = offsetof(struct sys_upmap,proc_title);
+               upmap->header[5].type = UPTYPE_INVFORK;
+               upmap->header[5].offset = offsetof(struct sys_upmap, invfork);
 
                upmap->version = UPMAP_VERSION;
                upmap->pid = p->p_pid;
                upmap->forkid = p->p_forkid;
+               upmap->invfork = invfork;
                p->p_upmap = upmap;
        } else {
                kfree(upmap, M_PROC);
index d569ca1..f600bf2 100644 (file)
@@ -575,7 +575,7 @@ void        prelezomb (struct proc *);
 void   pstall (struct proc *, const char *, int);
 void   lwpuserret(struct lwp *);
 void   lwpkthreaddeferred(void);
-void   proc_usermap(struct proc *p);
+void   proc_usermap(struct proc *p, int invfork);
 void   proc_userunmap(struct proc *p);
 
 u_int32_t      procrunnable (void);
index 17eb9fc..2b63870 100644 (file)
@@ -71,6 +71,7 @@ typedef struct ukpheader {
 
 #define UKPLEN_TS              ((sizeof(struct timespec) == 8) ? \
                                        UKPLEN_16 : UKPLEN_32)
+#define UKPLEN_DECODE(type)    (1 << ((type >> 8) & 0x0F))
 
 #define UKPTYPE_VERSION                (0x0001 | UKPLEN_4)     /* always first */
 
@@ -78,12 +79,13 @@ typedef struct ukpheader {
 #define UPTYPE_FORKID          (0x0011 | UKPLEN_8)
 #define UPTYPE_PID             (0x0012 | UKPLEN_4)
 #define UPTYPE_PROC_TITLE      (0x0013 | UKPLEN_1024)
+#define UPTYPE_INVFORK         (0x0014 | UKPLEN_4)
 
 #define KPTYPE_UPTICKS         (0x8000 | UKPLEN_4)
 #define KPTYPE_TS_UPTIME       (0x8001 | UKPLEN_TS)
 #define KPTYPE_TS_REALTIME     (0x8002 | UKPLEN_TS)
 #define KPTYPE_TSC_FREQ                (0x8003 | UKPLEN_8)
-#define KPTYPE_TICK_FREQ       (0x8003 | UKPLEN_8)
+#define KPTYPE_TICK_FREQ       (0x8004 | UKPLEN_8)
 
 #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
 
@@ -100,7 +102,7 @@ struct sys_upmap {
        uint32_t        version;
        uint32_t        runticks;       /* running scheduler ticks */
        forkid_t        forkid;         /* unique 2^64 (fork detect) NOT MONO */
-       uint32_t        unused01;       /* cpu migrations (kpmap detect) */
+       uint32_t        invfork;        /* vfork active */
        pid_t           pid;            /* process id */
        uint32_t        reserved[16];
        char            proc_title[UPMAP_MAXPROCTITLE];