[Midnightbsd-cvs] src [10147] trunk/sys/compat/linux: sync with freebsd 10

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Wed May 30 16:41:36 EDT 2018


Revision: 10147
          http://svnweb.midnightbsd.org/src/?rev=10147
Author:   laffer1
Date:     2018-05-30 16:41:36 -0400 (Wed, 30 May 2018)
Log Message:
-----------
sync with freebsd 10

Modified Paths:
--------------
    trunk/sys/compat/linux/check_error.d
    trunk/sys/compat/linux/check_internal_locks.d
    trunk/sys/compat/linux/linux_dtrace.h
    trunk/sys/compat/linux/linux_emul.c
    trunk/sys/compat/linux/linux_emul.h
    trunk/sys/compat/linux/linux_file.c
    trunk/sys/compat/linux/linux_file.h
    trunk/sys/compat/linux/linux_fork.c
    trunk/sys/compat/linux/linux_futex.c
    trunk/sys/compat/linux/linux_futex.h
    trunk/sys/compat/linux/linux_getcwd.c
    trunk/sys/compat/linux/linux_ioctl.c
    trunk/sys/compat/linux/linux_ioctl.h
    trunk/sys/compat/linux/linux_ipc.c
    trunk/sys/compat/linux/linux_ipc.h
    trunk/sys/compat/linux/linux_mib.c
    trunk/sys/compat/linux/linux_mib.h
    trunk/sys/compat/linux/linux_misc.c
    trunk/sys/compat/linux/linux_misc.h
    trunk/sys/compat/linux/linux_signal.c
    trunk/sys/compat/linux/linux_signal.h
    trunk/sys/compat/linux/linux_socket.c
    trunk/sys/compat/linux/linux_socket.h
    trunk/sys/compat/linux/linux_stats.c
    trunk/sys/compat/linux/linux_sysctl.c
    trunk/sys/compat/linux/linux_sysproto.h
    trunk/sys/compat/linux/linux_time.c
    trunk/sys/compat/linux/linux_uid16.c
    trunk/sys/compat/linux/linux_util.c
    trunk/sys/compat/linux/linux_util.h
    trunk/sys/compat/linux/linux_videodev2_compat.h
    trunk/sys/compat/linux/linux_videodev_compat.h
    trunk/sys/compat/linux/stats_timing.d
    trunk/sys/compat/linux/trace_futexes.d

Added Paths:
-----------
    trunk/sys/compat/linux/linux.c
    trunk/sys/compat/linux/linux.h
    trunk/sys/compat/linux/linux_common.c
    trunk/sys/compat/linux/linux_event.c
    trunk/sys/compat/linux/linux_event.h
    trunk/sys/compat/linux/linux_mmap.c
    trunk/sys/compat/linux/linux_mmap.h
    trunk/sys/compat/linux/linux_persona.h
    trunk/sys/compat/linux/linux_timer.c
    trunk/sys/compat/linux/linux_timer.h
    trunk/sys/compat/linux/linux_vdso.c
    trunk/sys/compat/linux/linux_vdso.h

Modified: trunk/sys/compat/linux/check_error.d
===================================================================
--- trunk/sys/compat/linux/check_error.d	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/check_error.d	2018-05-30 20:41:36 UTC (rev 10147)
@@ -25,7 +25,8 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/check_error.d 293493 2016-01-09 15:16:13Z dchagin $
  */
 
 /*
@@ -36,8 +37,8 @@
  */
 
 linuxulator*:dummy::not_implemented,
-linuxulator*:emul:proc_exit:child_clear_tid_error,
-linuxulator*:emul:proc_exit:futex_failed,
+linuxulator*:emul:linux_thread_detach:child_clear_tid_error,
+linuxulator*:emul:linux_thread_detach:futex_failed,
 linuxulator*:emul:linux_schedtail:copyout_error,
 linuxulator*:futex:futex_get:error,
 linuxulator*:futex:futex_sleep:requeue_error,

Modified: trunk/sys/compat/linux/check_internal_locks.d
===================================================================
--- trunk/sys/compat/linux/check_internal_locks.d	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/check_internal_locks.d	2018-05-30 20:41:36 UTC (rev 10147)
@@ -25,7 +25,8 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/check_internal_locks.d 299705 2016-05-14 00:35:49Z pfg $
  */
 
 /**
@@ -41,14 +42,9 @@
 
 BEGIN
 {
-	check["emul_lock"] = 0;
-	check["emul_shared_rlock"] = 0;
-	check["emul_shared_wlock"] = 0;
 	check["futex_mtx"] = 0;
 }
 
-linuxulator*:locks:emul_lock:locked,
-linuxulator*:locks:emul_shared_wlock:locked,
 linuxulator*:locks:futex_mtx:locked
 /check[probefunc] > 0/
 {
@@ -57,9 +53,6 @@
 	stack();
 }
 
-linuxulator*:locks:emul_lock:locked,
-linuxulator*:locks:emul_shared_rlock:locked,
-linuxulator*:locks:emul_shared_wlock:locked,
 linuxulator*:locks:futex_mtx:locked
 {
 	++check[probefunc];
@@ -69,13 +62,10 @@
 	spec[probefunc] = speculation();
 }
 
-linuxulator*:locks:emul_lock:unlock,
-linuxulator*:locks:emul_shared_rlock:unlock,
-linuxulator*:locks:emul_shared_wlock:unlock,
 linuxulator*:locks:futex_mtx:unlock
 /check[probefunc] == 0/
 {
-	printf("ERROR: unlock attemt of unlocked %s (%p),", probefunc, arg0);
+	printf("ERROR: unlock attempt of unlocked %s (%p),", probefunc, arg0);
 	printf("       missing SDT probe in kernel, or dtrace program started");
 	printf("       while the %s was already held (race condition).", probefunc);
 	printf("       Stack trace follows:");
@@ -82,9 +72,6 @@
 	stack();
 }
 
-linuxulator*:locks:emul_lock:unlock,
-linuxulator*:locks:emul_shared_rlock:unlock,
-linuxulator*:locks:emul_shared_wlock:unlock,
 linuxulator*:locks:futex_mtx:unlock
 {
 	discard(spec[probefunc]);
@@ -95,27 +82,6 @@
 /* Timeout handling */
 
 tick-10s
-/spec["emul_lock"] != 0 && timestamp - ts["emul_lock"] >= 9999999000/
-{
-	commit(spec["emul_lock"]);
-	spec["emul_lock"] = 0;
-}
-
-tick-10s
-/spec["emul_shared_wlock"] != 0 && timestamp - ts["emul_shared_wlock"] >= 9999999000/
-{
-	commit(spec["emul_shared_wlock"]);
-	spec["emul_shared_wlock"] = 0;
-}
-
-tick-10s
-/spec["emul_shared_rlock"] != 0 && timestamp - ts["emul_shared_rlock"] >= 9999999000/
-{
-	commit(spec["emul_shared_rlock"]);
-	spec["emul_shared_rlock"] = 0;
-}
-
-tick-10s
 /spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/
 {
 	commit(spec["futex_mtx"]);

Added: trunk/sys/compat/linux/linux.c
===================================================================
--- trunk/sys/compat/linux/linux.c	                        (rev 0)
+++ trunk/sys/compat/linux/linux.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,206 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2015 Dmitry Chagin
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux.c 293575 2016-01-09 17:29:08Z dchagin $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/signalvar.h>
+
+#include <compat/linux/linux.h>
+
+
+static int bsd_to_linux_sigtbl[LINUX_SIGTBLSZ] = {
+	LINUX_SIGHUP,	/* SIGHUP */
+	LINUX_SIGINT,	/* SIGINT */
+	LINUX_SIGQUIT,	/* SIGQUIT */
+	LINUX_SIGILL,	/* SIGILL */
+	LINUX_SIGTRAP,	/* SIGTRAP */
+	LINUX_SIGABRT,	/* SIGABRT */
+	0,		/* SIGEMT */
+	LINUX_SIGFPE,	/* SIGFPE */
+	LINUX_SIGKILL,	/* SIGKILL */
+	LINUX_SIGBUS,	/* SIGBUS */
+	LINUX_SIGSEGV,	/* SIGSEGV */
+	LINUX_SIGSYS,	/* SIGSYS */
+	LINUX_SIGPIPE,	/* SIGPIPE */
+	LINUX_SIGALRM,	/* SIGALRM */
+	LINUX_SIGTERM,	/* SIGTERM */
+	LINUX_SIGURG,	/* SIGURG */
+	LINUX_SIGSTOP,	/* SIGSTOP */
+	LINUX_SIGTSTP,	/* SIGTSTP */
+	LINUX_SIGCONT,	/* SIGCONT */
+	LINUX_SIGCHLD,	/* SIGCHLD */
+	LINUX_SIGTTIN,	/* SIGTTIN */
+	LINUX_SIGTTOU,	/* SIGTTOU */
+	LINUX_SIGIO,	/* SIGIO */
+	LINUX_SIGXCPU,	/* SIGXCPU */
+	LINUX_SIGXFSZ,	/* SIGXFSZ */
+	LINUX_SIGVTALRM,/* SIGVTALRM */
+	LINUX_SIGPROF,	/* SIGPROF */
+	LINUX_SIGWINCH,	/* SIGWINCH */
+	0,		/* SIGINFO */
+	LINUX_SIGUSR1,	/* SIGUSR1 */
+	LINUX_SIGUSR2	/* SIGUSR2 */
+};
+
+static int linux_to_bsd_sigtbl[LINUX_SIGTBLSZ] = {
+	SIGHUP,		/* LINUX_SIGHUP */
+	SIGINT,		/* LINUX_SIGINT */
+	SIGQUIT,	/* LINUX_SIGQUIT */
+	SIGILL,		/* LINUX_SIGILL */
+	SIGTRAP,	/* LINUX_SIGTRAP */
+	SIGABRT,	/* LINUX_SIGABRT */
+	SIGBUS,		/* LINUX_SIGBUS */
+	SIGFPE,		/* LINUX_SIGFPE */
+	SIGKILL,	/* LINUX_SIGKILL */
+	SIGUSR1,	/* LINUX_SIGUSR1 */
+	SIGSEGV,	/* LINUX_SIGSEGV */
+	SIGUSR2,	/* LINUX_SIGUSR2 */
+	SIGPIPE,	/* LINUX_SIGPIPE */
+	SIGALRM,	/* LINUX_SIGALRM */
+	SIGTERM,	/* LINUX_SIGTERM */
+	SIGBUS,		/* LINUX_SIGSTKFLT */
+	SIGCHLD,	/* LINUX_SIGCHLD */
+	SIGCONT,	/* LINUX_SIGCONT */
+	SIGSTOP,	/* LINUX_SIGSTOP */
+	SIGTSTP,	/* LINUX_SIGTSTP */
+	SIGTTIN,	/* LINUX_SIGTTIN */
+	SIGTTOU,	/* LINUX_SIGTTOU */
+	SIGURG,		/* LINUX_SIGURG */
+	SIGXCPU,	/* LINUX_SIGXCPU */
+	SIGXFSZ,	/* LINUX_SIGXFSZ */
+	SIGVTALRM,	/* LINUX_SIGVTALARM */
+	SIGPROF,	/* LINUX_SIGPROF */
+	SIGWINCH,	/* LINUX_SIGWINCH */
+	SIGIO,		/* LINUX_SIGIO */
+	/*
+	 * FreeBSD does not have SIGPWR signal, map Linux SIGPWR signal
+	 * to the first unused FreeBSD signal number. Since Linux supports
+	 * signals from 1 to 64 we are ok here as our SIGRTMIN = 65.
+	 */
+	SIGRTMIN,	/* LINUX_SIGPWR */
+	SIGSYS		/* LINUX_SIGSYS */
+};
+
+/*
+ * Map Linux RT signals to the FreeBSD RT signals.
+ */
+static inline int
+linux_to_bsd_rt_signal(int sig)
+{
+
+	return (SIGRTMIN + 1 + sig - LINUX_SIGRTMIN);
+}
+
+static inline int
+bsd_to_linux_rt_signal(int sig)
+{
+
+	return (sig - SIGRTMIN - 1 + LINUX_SIGRTMIN);
+}
+
+int
+linux_to_bsd_signal(int sig)
+{
+
+	KASSERT(sig > 0 && sig <= LINUX_SIGRTMAX, ("Invalid Linux signal\n"));
+
+	if (sig < LINUX_SIGRTMIN)
+		return (linux_to_bsd_sigtbl[_SIG_IDX(sig)]);
+
+	return (linux_to_bsd_rt_signal(sig));
+}
+
+int
+bsd_to_linux_signal(int sig)
+{
+
+	if (sig <= LINUX_SIGTBLSZ)
+		return (bsd_to_linux_sigtbl[_SIG_IDX(sig)]);
+	if (sig == SIGRTMIN)
+		return (LINUX_SIGPWR);
+
+	return (bsd_to_linux_rt_signal(sig));
+}
+
+int
+linux_to_bsd_sigaltstack(int lsa)
+{
+	int bsa = 0;
+
+	if (lsa & LINUX_SS_DISABLE)
+		bsa |= SS_DISABLE;
+	/*
+	 * Linux ignores SS_ONSTACK flag for ss
+	 * parameter while FreeBSD prohibits it.
+	 */
+	return (bsa);
+}
+
+int
+bsd_to_linux_sigaltstack(int bsa)
+{
+	int lsa = 0;
+
+	if (bsa & SS_DISABLE)
+		lsa |= LINUX_SS_DISABLE;
+	if (bsa & SS_ONSTACK)
+		lsa |= LINUX_SS_ONSTACK;
+	return (lsa);
+}
+
+void
+linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
+{
+	int b, l;
+
+	SIGEMPTYSET(*bss);
+	for (l = 1; l <= LINUX_SIGRTMAX; l++) {
+		if (LINUX_SIGISMEMBER(*lss, l)) {
+			b = linux_to_bsd_signal(l);
+			if (b)
+				SIGADDSET(*bss, b);
+		}
+	}
+}
+
+void
+bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
+{
+	int b, l;
+
+	LINUX_SIGEMPTYSET(*lss);
+	for (b = 1; b <= SIGRTMAX; b++) {
+		if (SIGISMEMBER(*bss, b)) {
+			l = bsd_to_linux_signal(b);
+			if (l)
+				LINUX_SIGADDSET(*lss, l);
+		}
+	}
+}


Property changes on: trunk/sys/compat/linux/linux.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/compat/linux/linux.h
===================================================================
--- trunk/sys/compat/linux/linux.h	                        (rev 0)
+++ trunk/sys/compat/linux/linux.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,96 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2015 Dmitry Chagin
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/10/sys/compat/linux/linux.h 293575 2016-01-09 17:29:08Z dchagin $
+ */
+
+#ifndef _LINUX_MI_H_
+#define _LINUX_MI_H_
+
+/* sigaltstack */
+#define	LINUX_SS_ONSTACK	1
+#define	LINUX_SS_DISABLE	2
+
+int linux_to_bsd_sigaltstack(int lsa);
+int bsd_to_linux_sigaltstack(int bsa);
+
+/* sigset */
+typedef struct {
+	uint64_t	__mask;
+} l_sigset_t;
+
+/* primitives to manipulate sigset_t */
+#define	LINUX_SIGEMPTYSET(set)		(set).__mask = 0
+#define	LINUX_SIGISMEMBER(set, sig)	(1UL & ((set).__mask >> _SIG_IDX(sig)))
+#define	LINUX_SIGADDSET(set, sig)	(set).__mask |= 1UL << _SIG_IDX(sig)
+
+void linux_to_bsd_sigset(l_sigset_t *, sigset_t *);
+void bsd_to_linux_sigset(sigset_t *, l_sigset_t *);
+
+/* signaling */
+#define	LINUX_SIGHUP		1
+#define	LINUX_SIGINT		2
+#define	LINUX_SIGQUIT		3
+#define	LINUX_SIGILL		4
+#define	LINUX_SIGTRAP		5
+#define	LINUX_SIGABRT		6
+#define	LINUX_SIGIOT		LINUX_SIGABRT
+#define	LINUX_SIGBUS		7
+#define	LINUX_SIGFPE		8
+#define	LINUX_SIGKILL		9
+#define	LINUX_SIGUSR1		10
+#define	LINUX_SIGSEGV		11
+#define	LINUX_SIGUSR2		12
+#define	LINUX_SIGPIPE		13
+#define	LINUX_SIGALRM		14
+#define	LINUX_SIGTERM		15
+#define	LINUX_SIGSTKFLT		16
+#define	LINUX_SIGCHLD		17
+#define	LINUX_SIGCONT		18
+#define	LINUX_SIGSTOP		19
+#define	LINUX_SIGTSTP		20
+#define	LINUX_SIGTTIN		21
+#define	LINUX_SIGTTOU		22
+#define	LINUX_SIGURG		23
+#define	LINUX_SIGXCPU		24
+#define	LINUX_SIGXFSZ		25
+#define	LINUX_SIGVTALRM		26
+#define	LINUX_SIGPROF		27
+#define	LINUX_SIGWINCH		28
+#define	LINUX_SIGIO		29
+#define	LINUX_SIGPOLL		LINUX_SIGIO
+#define	LINUX_SIGPWR		30
+#define	LINUX_SIGSYS		31
+#define	LINUX_SIGTBLSZ		31
+#define	LINUX_SIGRTMIN		32
+#define	LINUX_SIGRTMAX		64
+
+#define LINUX_SIG_VALID(sig)	((sig) <= LINUX_SIGRTMAX && (sig) > 0)
+
+int linux_to_bsd_signal(int sig);
+int bsd_to_linux_signal(int sig);
+
+#endif /* _LINUX_MI_H_ */


Property changes on: trunk/sys/compat/linux/linux.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/compat/linux/linux_common.c
===================================================================
--- trunk/sys/compat/linux/linux_common.c	                        (rev 0)
+++ trunk/sys/compat/linux/linux_common.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,94 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 Vassilis Laganakos
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_common.c 293529 2016-01-09 16:12:37Z dchagin $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/imgact_elf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/eventhandler.h>
+#include <sys/sysctl.h>
+
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_util.h>
+
+FEATURE(linuxulator_v4l, "V4L ioctl wrapper support in the linuxulator");
+FEATURE(linuxulator_v4l2, "V4L2 ioctl wrapper support in the linuxulator");
+
+MODULE_VERSION(linux_common, 1);
+
+SET_DECLARE(linux_device_handler_set, struct linux_device_handler);
+
+static eventhandler_tag linux_exec_tag;
+static eventhandler_tag linux_thread_dtor_tag;
+static eventhandler_tag	linux_exit_tag;
+
+
+static int
+linux_common_modevent(module_t mod, int type, void *data)
+{
+	struct linux_device_handler **ldhp;
+
+	switch(type) {
+	case MOD_LOAD:
+		linux_osd_jail_register();
+		linux_exit_tag = EVENTHANDLER_REGISTER(process_exit,
+		    linux_proc_exit, NULL, 1000);
+		linux_exec_tag = EVENTHANDLER_REGISTER(process_exec,
+		    linux_proc_exec, NULL, 1000);
+		linux_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor,
+		    linux_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
+		SET_FOREACH(ldhp, linux_device_handler_set)
+			linux_device_register_handler(*ldhp);
+		break;
+	case MOD_UNLOAD:
+		linux_osd_jail_deregister();
+		SET_FOREACH(ldhp, linux_device_handler_set)
+			linux_device_unregister_handler(*ldhp);
+		EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag);
+		EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag);
+		EVENTHANDLER_DEREGISTER(thread_dtor, linux_thread_dtor_tag);
+		break;
+	default:
+		return (EOPNOTSUPP);
+	}
+	return (0);
+}
+
+static moduledata_t linux_common_mod = {
+	"linuxcommon",
+	linux_common_modevent,
+	0
+};
+
+DECLARE_MODULE(linuxcommon, linux_common_mod, SI_SUB_EXEC, SI_ORDER_ANY);


Property changes on: trunk/sys/compat/linux/linux_common.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/compat/linux/linux_dtrace.h
===================================================================
--- trunk/sys/compat/linux/linux_dtrace.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_dtrace.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2008-2012 Alexander Leidinger <netchild at FreeBSD.org>
  * All rights reserved.
@@ -23,7 +24,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_dtrace.h 302237 2016-06-27 22:10:07Z bdrewery $
  */
 
 #ifndef _LINUX_DTRACE_H_
@@ -48,37 +49,32 @@
     LINUX_DTRACE, a, b, c)
 
 #define	_LIN_SDT_PROBE_DEFINE0(a, b, c, d)		SDT_PROBE_DEFINE(a, \
-    b, c, d, d)
+    b, c, d)
 #define	LIN_SDT_PROBE_DEFINE0(a, b, c)			_LIN_SDT_PROBE_DEFINE0(\
     LINUX_DTRACE, a, b, c)
 #define	_LIN_SDT_PROBE_DEFINE1(a, b, c, d, e)		SDT_PROBE_DEFINE1(a, \
-    b, c, d, d, e)
+    b, c, d, e)
 #define	LIN_SDT_PROBE_DEFINE1(a, b, c, d)		_LIN_SDT_PROBE_DEFINE1(\
     LINUX_DTRACE, a, b, c, d)
 #define	_LIN_SDT_PROBE_DEFINE2(a, b, c, d, e, f)	SDT_PROBE_DEFINE2(a, \
-    b, c, d, d, e, f)
+    b, c, d, e, f)
 #define	LIN_SDT_PROBE_DEFINE2(a, b, c, d, e)		_LIN_SDT_PROBE_DEFINE2(\
     LINUX_DTRACE, a, b, c, d, e)
 #define	_LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f, g)	SDT_PROBE_DEFINE3(a, \
-    b, c, d, d, e, f, g)
+    b, c, d, e, f, g)
 #define	LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f)		_LIN_SDT_PROBE_DEFINE3(\
     LINUX_DTRACE, a, b, c, d, e, f)
 #define	_LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g, h)	SDT_PROBE_DEFINE4(a, \
-    b, c, d, d, e, f, g, h)
+    b, c, d, e, f, g, h)
 #define	LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g)	_LIN_SDT_PROBE_DEFINE4(\
     LINUX_DTRACE, a, b, c, d, e, f, g)
 #define	_LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h, i) \
-    SDT_PROBE_DEFINE5(a, b, c, d, d, e, f, g, h, i)
+    SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h, i)
 #define	LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h)	_LIN_SDT_PROBE_DEFINE5(\
     LINUX_DTRACE, a, b, c, d, e, f, g, h)
 
-#define	_LIN_SDT_PROBE_ARGTYPE(a, b, c, d, e, f)	SDT_PROBE_ARGTYPE(a, b,\
-    c, d, e, f)
-#define LIN_SDT_PROBE_ARGTYPE(a, b, c, d, e)	_LIN_SDT_PROBE_ARGTYPE( \
-    LINUX_DTRACE, a, b, c, d, e)
-
-#define	LIN_SDT_PROBE0(a, b, c)			SDT_PROBE1(LINUX_DTRACE, a, b, \
-    c, 0)
+#define	LIN_SDT_PROBE0(a, b, c)			SDT_PROBE0(LINUX_DTRACE, a, b, \
+    c)
 #define	LIN_SDT_PROBE1(a, b, c, d)		SDT_PROBE1(LINUX_DTRACE, a, b, \
     c, d)
 #define	LIN_SDT_PROBE2(a, b, c, d, e)		SDT_PROBE2(LINUX_DTRACE, a, b, \
@@ -87,7 +83,7 @@
     c, d, e, f)
 #define	LIN_SDT_PROBE4(a, b, c, d, e, f, g)	SDT_PROBE4(LINUX_DTRACE, a, b, \
     c, d, e, f, g)
-#define	_LIN_SDT_PROBE5(a, b, c, d, e, f, g, h, i)	SDT_PROBE(a, b, c, d, \
+#define	_LIN_SDT_PROBE5(a, b, c, d, e, f, g, h, i)	SDT_PROBE5(a, b, c, d, \
     e, f, g, h, i)
 #define	LIN_SDT_PROBE5(a, b, c, d, e, f, g, h)	_LIN_SDT_PROBE5(LINUX_DTRACE, \
     a, b, c, d, e, f, g, h)

Modified: trunk/sys/compat/linux/linux_emul.c
===================================================================
--- trunk/sys/compat/linux/linux_emul.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_emul.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2006 Roman Divacky
+ * Copyright (c) 2013 Dmitry Chagin
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,365 +29,252 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_emul.c 302962 2016-07-17 15:07:33Z dchagin $");
 
-#include "opt_compat.h"
-#include "opt_kdtrace.h"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/imgact.h>
 #include <sys/kernel.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mutex.h>
-#include <sys/sdt.h>
 #include <sys/sx.h>
 #include <sys/proc.h>
 #include <sys/syscallsubr.h>
 #include <sys/sysent.h>
-#include <sys/sysproto.h>
-#include <sys/unistd.h>
 
-#ifdef COMPAT_LINUX32
-#include <machine/../linux32/linux.h>
-#include <machine/../linux32/linux32_proto.h>
-#else
-#include <machine/../linux/linux.h>
-#include <machine/../linux/linux_proto.h>
-#endif
-
-#include <compat/linux/linux_dtrace.h>
 #include <compat/linux/linux_emul.h>
-#include <compat/linux/linux_futex.h>
+#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_persona.h>
+#include <compat/linux/linux_util.h>
 
-/**
- * Special DTrace provider for the linuxulator.
+
+/*
+ * This returns reference to the thread emuldata entry (if found)
  *
- * In this file we define the provider for the entire linuxulator. All
- * modules (= files of the linuxulator) use it.
- *
- * We define a different name depending on the emulated bitsize, see
- * ../../<ARCH>/linux{,32}/linux.h, e.g.:
- *      native bitsize          = linuxulator
- *      amd64, 32bit emulation  = linuxulator32
+ * Hold PROC_LOCK when referencing emuldata from other threads.
  */
-LIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE);
-
-/**
- * Special DTrace module "locks", it covers some linuxulator internal
- * locks.
- */
-LIN_SDT_PROBE_DEFINE1(locks, emul_lock, locked, "struct mtx *");
-LIN_SDT_PROBE_DEFINE1(locks, emul_lock, unlock, "struct mtx *");
-LIN_SDT_PROBE_DEFINE1(locks, emul_shared_rlock, locked, "struct sx *");
-LIN_SDT_PROBE_DEFINE1(locks, emul_shared_rlock, unlock, "struct sx *");
-LIN_SDT_PROBE_DEFINE1(locks, emul_shared_wlock, locked, "struct sx *");
-LIN_SDT_PROBE_DEFINE1(locks, emul_shared_wlock, unlock, "struct sx *");
-
-/**
- * DTrace probes in this module.
- */
-LIN_SDT_PROBE_DEFINE2(emul, em_find, entry, "struct proc *", "int");
-LIN_SDT_PROBE_DEFINE0(emul, em_find, return);
-LIN_SDT_PROBE_DEFINE3(emul, proc_init, entry, "struct thread *", "pid_t",
-    "int");
-LIN_SDT_PROBE_DEFINE0(emul, proc_init, create_thread);
-LIN_SDT_PROBE_DEFINE0(emul, proc_init, fork);
-LIN_SDT_PROBE_DEFINE0(emul, proc_init, exec);
-LIN_SDT_PROBE_DEFINE0(emul, proc_init, return);
-LIN_SDT_PROBE_DEFINE1(emul, proc_exit, entry, "struct proc *");
-LIN_SDT_PROBE_DEFINE0(emul, proc_exit, futex_failed);
-LIN_SDT_PROBE_DEFINE3(emul, proc_exit, reparent, "pid_t", "pid_t",
-    "struct proc *");
-LIN_SDT_PROBE_DEFINE1(emul, proc_exit, child_clear_tid_error, "int");
-LIN_SDT_PROBE_DEFINE0(emul, proc_exit, return);
-LIN_SDT_PROBE_DEFINE2(emul, proc_exec, entry, "struct proc *",
-    "struct image_params *");
-LIN_SDT_PROBE_DEFINE0(emul, proc_exec, return);
-LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, entry);
-LIN_SDT_PROBE_DEFINE1(emul, linux_schedtail, copyout_error, "int");
-LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, return);
-LIN_SDT_PROBE_DEFINE1(emul, linux_set_tid_address, entry, "int *");
-LIN_SDT_PROBE_DEFINE0(emul, linux_set_tid_address, return);
-LIN_SDT_PROBE_DEFINE2(emul, linux_kill_threads, entry, "struct thread *",
-    "int");
-LIN_SDT_PROBE_DEFINE1(emul, linux_kill_threads, kill, "pid_t");
-LIN_SDT_PROBE_DEFINE0(emul, linux_kill_threads, return);
-
-struct sx	emul_shared_lock;
-struct mtx	emul_lock;
-
-/* this returns locked reference to the emuldata entry (if found) */
 struct linux_emuldata *
-em_find(struct proc *p, int locked)
+em_find(struct thread *td)
 {
 	struct linux_emuldata *em;
 
-	LIN_SDT_PROBE2(emul, em_find, entry, p, locked);
+	em = td->td_emuldata;
 
-	if (locked == EMUL_DOLOCK)
-		EMUL_LOCK(&emul_lock);
+	return (em);
+}
 
-	em = p->p_emuldata;
+/*
+ * This returns reference to the proc pemuldata entry (if found)
+ *
+ * Hold PROC_LOCK when referencing proc pemuldata from other threads.
+ * Hold LINUX_PEM_LOCK wher referencing pemuldata members.
+ */
+struct linux_pemuldata *
+pem_find(struct proc *p)
+{
+	struct linux_pemuldata *pem;
 
-	if (em == NULL && locked == EMUL_DOLOCK)
-		EMUL_UNLOCK(&emul_lock);
+	pem = p->p_emuldata;
 
-	LIN_SDT_PROBE1(emul, em_find, return, em);
-	return (em);
+	return (pem);
 }
 
-int
-linux_proc_init(struct thread *td, pid_t child, int flags)
+void
+linux_proc_init(struct thread *td, struct thread *newtd, int flags)
 {
-	struct linux_emuldata *em, *p_em;
+	struct linux_emuldata *em;
+	struct linux_pemuldata *pem;
+	struct epoll_emuldata *emd;
 	struct proc *p;
 
-	LIN_SDT_PROBE3(emul, proc_init, entry, td, child, flags);
+	if (newtd != NULL) {
+		p = newtd->td_proc;
 
-	if (child != 0) {
-		/* fork or create a thread */
-		em = malloc(sizeof *em, M_LINUX, M_WAITOK | M_ZERO);
-		em->pid = child;
-		em->pdeath_signal = 0;
-		em->flags = 0;
-		em->robust_futexes = NULL;
+		/* non-exec call */
+		em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
 		if (flags & LINUX_CLONE_THREAD) {
-			/* handled later in the code */
-			LIN_SDT_PROBE0(emul, proc_init, create_thread);
+			LINUX_CTR1(proc_init, "thread newtd(%d)",
+			    newtd->td_tid);
+
+			em->em_tid = newtd->td_tid;
 		} else {
-			struct linux_emuldata_shared *s;
+			LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid);
 
-			LIN_SDT_PROBE0(emul, proc_init, fork);
+			em->em_tid = p->p_pid;
 
-			s = malloc(sizeof *s, M_LINUX, M_WAITOK | M_ZERO);
-			s->refs = 1;
-			s->group_pid = child;
-
-			LIST_INIT(&s->threads);
-			em->shared = s;
+			pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO);
+			sx_init(&pem->pem_sx, "lpemlk");
+			p->p_emuldata = pem;
 		}
+		newtd->td_emuldata = em;
 	} else {
+		p = td->td_proc;
+
 		/* exec */
-		LIN_SDT_PROBE0(emul, proc_init, exec);
+		LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid);
 
 		/* lookup the old one */
-		em = em_find(td->td_proc, EMUL_DOLOCK);
+		em = em_find(td);
 		KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
-	}
 
-	em->child_clear_tid = NULL;
-	em->child_set_tid = NULL;
+		em->em_tid = p->p_pid;
+		em->flags = 0;
+		em->pdeath_signal = 0;
+		em->robust_futexes = NULL;
+		em->child_clear_tid = NULL;
+		em->child_set_tid = NULL;
 
-	/*
-	 * allocate the shared struct only in clone()/fork cases in the case
-	 * of clone() td = calling proc and child = pid of the newly created
-	 * proc
-	 */
-	if (child != 0) {
-		if (flags & LINUX_CLONE_THREAD) {
-			/* lookup the parent */
-			/* 
-			 * we dont have to lock the p_em because
-			 * its waiting for us in linux_clone so
-			 * there is no chance of it changing the
-			 * p_em->shared address
-			 */
-			p_em = em_find(td->td_proc, EMUL_DONTLOCK);
-			KASSERT(p_em != NULL, ("proc_init: parent emuldata not found for CLONE_THREAD\n"));
-			em->shared = p_em->shared;
-			EMUL_SHARED_WLOCK(&emul_shared_lock);
-			em->shared->refs++;
-			EMUL_SHARED_WUNLOCK(&emul_shared_lock);
-		} else {
-			/*
-			 * handled earlier to avoid malloc(M_WAITOK) with
-			 * rwlock held
-			 */
+		 /* epoll should be destroyed in a case of exec. */
+		pem = pem_find(p);
+		KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n"));
+		pem->persona = 0;
+		if (pem->epoll != NULL) {
+			emd = pem->epoll;
+			pem->epoll = NULL;
+			free(emd, M_EPOLL);
 		}
+	}
 
-		EMUL_SHARED_WLOCK(&emul_shared_lock);
-		LIST_INSERT_HEAD(&em->shared->threads, em, threads);
-		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
-
-		p = pfind(child);
-		KASSERT(p != NULL, ("process not found in proc_init\n"));
-		p->p_emuldata = em;
-		PROC_UNLOCK(p);
-	} else
-		EMUL_UNLOCK(&emul_lock);
-
-	LIN_SDT_PROBE0(emul, proc_init, return);
-	return (0);
 }
 
-void
+void 
 linux_proc_exit(void *arg __unused, struct proc *p)
 {
-	struct linux_emuldata *em;
-	int error, shared_flags, shared_xstat;
-	struct thread *td = FIRST_THREAD_IN_PROC(p);
-	int *child_clear_tid;
-	struct proc *q, *nq;
+	struct linux_pemuldata *pem;
+	struct epoll_emuldata *emd;
+	struct thread *td = curthread;
 
-	if (__predict_true(p->p_sysent != &elf_linux_sysvec))
+	if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX))
 		return;
 
-	LIN_SDT_PROBE1(emul, proc_exit, entry, p);
+	LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p",
+	    td->td_tid, p->p_pid, p);
 
-	release_futexes(p);
+	pem = pem_find(p);
+	if (pem == NULL)
+		return;	
+	(p->p_sysent->sv_thread_detach)(td);
 
-	/* find the emuldata */
-	em = em_find(p, EMUL_DOLOCK);
+	p->p_emuldata = NULL;
 
-	KASSERT(em != NULL, ("proc_exit: emuldata not found.\n"));
-
-	/* reparent all procs that are not a thread leader to initproc */
-	if (em->shared->group_pid != p->p_pid) {
-		LIN_SDT_PROBE3(emul, proc_exit, reparent,
-		    em->shared->group_pid, p->p_pid, p);
-
-		child_clear_tid = em->child_clear_tid;
-		EMUL_UNLOCK(&emul_lock);
-		sx_xlock(&proctree_lock);
-		wakeup(initproc);
-		PROC_LOCK(p);
-		proc_reparent(p, initproc);
-		p->p_sigparent = SIGCHLD;
-		PROC_UNLOCK(p);
-		sx_xunlock(&proctree_lock);
-	} else {
-		child_clear_tid = em->child_clear_tid;
-		EMUL_UNLOCK(&emul_lock);	
+	if (pem->epoll != NULL) {
+		emd = pem->epoll;
+		pem->epoll = NULL;
+		free(emd, M_EPOLL);
 	}
 
-	EMUL_SHARED_WLOCK(&emul_shared_lock);
-	shared_flags = em->shared->flags;
-	shared_xstat = em->shared->xstat;
-	LIST_REMOVE(em, threads);
+	sx_destroy(&pem->pem_sx);
+	free(pem, M_LINUX);
+}
 
-	em->shared->refs--;
-	if (em->shared->refs == 0) {
-		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
-		free(em->shared, M_LINUX);
-	} else	
-		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
+int 
+linux_common_execve(struct thread *td, struct image_args *eargs)
+{
+	struct linux_pemuldata *pem;
+	struct epoll_emuldata *emd;
+	struct vmspace *oldvmspace;
+	struct linux_emuldata *em;
+	struct proc *p;
+	int error;
 
-	if ((shared_flags & EMUL_SHARED_HASXSTAT) != 0)
-		p->p_xstat = shared_xstat;
+	p = td->td_proc;
 
-	if (child_clear_tid != NULL) {
-		struct linux_sys_futex_args cup;
-		int null = 0;
+	error = pre_execve(td, &oldvmspace);
+	if (error != 0)
+		return (error);
 
-		error = copyout(&null, child_clear_tid, sizeof(null));
-		if (error) {
-			LIN_SDT_PROBE1(emul, proc_exit,
-			    child_clear_tid_error, error);
+	error = kern_execve(td, eargs, NULL);
+	post_execve(td, error, oldvmspace);
+	if (error != 0)
+		return (error);
 
-			free(em, M_LINUX);
+	/*
+	 * In a case of transition from Linux binary execing to
+	 * FreeBSD binary we destroy linux emuldata thread & proc entries.
+	 */
+	if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
+		PROC_LOCK(p);
+		em = em_find(td);
+		KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n"));
+		td->td_emuldata = NULL;
 
-			LIN_SDT_PROBE0(emul, proc_exit, return);
-			return;
-		}
+		pem = pem_find(p);
+		KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n"));
+		p->p_emuldata = NULL;
+		PROC_UNLOCK(p);
 
-		/* futexes stuff */
-		cup.uaddr = child_clear_tid;
-		cup.op = LINUX_FUTEX_WAKE;
-		cup.val = 0x7fffffff;	/* Awake everyone */
-		cup.timeout = NULL;
-		cup.uaddr2 = NULL;
-		cup.val3 = 0;
-		error = linux_sys_futex(FIRST_THREAD_IN_PROC(p), &cup);
-		/*
-		 * this cannot happen at the moment and if this happens it
-		 * probably means there is a user space bug
-		 */
-		if (error) {
-			LIN_SDT_PROBE0(emul, proc_exit, futex_failed);
-			printf(LMSG("futex stuff in proc_exit failed.\n"));
+		if (pem->epoll != NULL) {
+			emd = pem->epoll;
+			pem->epoll = NULL;
+			free(emd, M_EPOLL);
 		}
-	}
 
-	/* clean the stuff up */
-	free(em, M_LINUX);
-
-	/* this is a little weird but rewritten from exit1() */
-	sx_xlock(&proctree_lock);
-	q = LIST_FIRST(&p->p_children);
-	for (; q != NULL; q = nq) {
-		nq = LIST_NEXT(q, p_sibling);
-		if (q->p_flag & P_WEXIT)
-			continue;
-		if (__predict_false(q->p_sysent != &elf_linux_sysvec))
-			continue;
-		em = em_find(q, EMUL_DOLOCK);
-		KASSERT(em != NULL, ("linux_reparent: emuldata not found: %i\n", q->p_pid));
-		PROC_LOCK(q);
-		if ((q->p_flag & P_WEXIT) == 0 && em->pdeath_signal != 0) {
-			kern_psignal(q, em->pdeath_signal);
-		}
-		PROC_UNLOCK(q);
-		EMUL_UNLOCK(&emul_lock);
+		free(em, M_TEMP);
+		free(pem, M_LINUX);
 	}
-	sx_xunlock(&proctree_lock);
-
-	LIN_SDT_PROBE0(emul, proc_exit, return);
+	return (0);
 }
 
-/*
- * This is used in a case of transition from FreeBSD binary execing to linux binary
- * in this case we create linux emuldata proc entry with the pid of the currently running
- * process.
- */
 void 
 linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
 {
-	if (__predict_false(imgp->sysent == &elf_linux_sysvec)) {
-		LIN_SDT_PROBE2(emul, proc_exec, entry, p, imgp);
+	struct thread *td = curthread;
+	struct thread *othertd;
+#if defined(__amd64__)
+	struct linux_pemuldata *pem;
+#endif
+
+	/*
+	 * In a case of execing from linux binary properly detach
+	 * other threads from the user space.
+	 */
+	if (__predict_false(SV_PROC_ABI(p) == SV_ABI_LINUX)) {
+		FOREACH_THREAD_IN_PROC(p, othertd) {
+			if (td != othertd)
+				(p->p_sysent->sv_thread_detach)(othertd);
+		}
 	}
-	if (__predict_false(imgp->sysent == &elf_linux_sysvec
-	    && p->p_sysent != &elf_linux_sysvec))
-		linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0);
-	if (__predict_false((p->p_sysent->sv_flags & SV_ABI_MASK) ==
-	    SV_ABI_LINUX))
-		/* Kill threads regardless of imgp->sysent value */
-		linux_kill_threads(FIRST_THREAD_IN_PROC(p), SIGKILL);
-	if (__predict_false(imgp->sysent != &elf_linux_sysvec
-	    && p->p_sysent == &elf_linux_sysvec)) {
-		struct linux_emuldata *em;
 
-		/* 
-		 * XXX:There's a race because here we assign p->p_emuldata NULL
-		 * but the process is still counted as linux one for a short
- 		 * time so some other process might reference it and try to
- 		 * access its p->p_emuldata and panicing on a NULL reference.
+	/*
+	 * In a case of execing to linux binary we create linux
+	 * emuldata thread entry.
+	 */
+	if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) ==
+	    SV_ABI_LINUX)) {
+
+		if (SV_PROC_ABI(p) == SV_ABI_LINUX)
+			linux_proc_init(td, NULL, 0);
+		else
+			linux_proc_init(td, td, 0);
+#if defined(__amd64__)
+		/*
+		 * An IA32 executable which has executable stack will have the
+		 * READ_IMPLIES_EXEC personality flag set automatically.
 		 */
-		em = em_find(p, EMUL_DONTLOCK);
+		if (SV_PROC_FLAG(td->td_proc, SV_ILP32) &&
+		    imgp->stack_prot & VM_PROT_EXECUTE) {
+			pem = pem_find(p);
+			pem->persona |= LINUX_READ_IMPLIES_EXEC;
+		}
+#endif
+	}
+}
 
-		KASSERT(em != NULL, ("proc_exec: emuldata not found.\n"));
+void
+linux_thread_dtor(void *arg __unused, struct thread *td)
+{
+	struct linux_emuldata *em;
 
-		EMUL_SHARED_WLOCK(&emul_shared_lock);
-		LIST_REMOVE(em, threads);
+	em = em_find(td);
+	if (em == NULL)
+		return;
+	td->td_emuldata = NULL;
 
-		PROC_LOCK(p);
-		p->p_emuldata = NULL;
-		PROC_UNLOCK(p);
+	LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid);
 
-		em->shared->refs--;
-		if (em->shared->refs == 0) {
-			EMUL_SHARED_WUNLOCK(&emul_shared_lock);
-			free(em->shared, M_LINUX);
-		} else
-			EMUL_SHARED_WUNLOCK(&emul_shared_lock);
-
-		free(em, M_LINUX);
-	}
-
-	if (__predict_false(imgp->sysent == &elf_linux_sysvec)) {
-		LIN_SDT_PROBE0(emul, proc_exec, return);
-	}
+	free(em, M_TEMP);
 }
 
 void
@@ -398,76 +287,15 @@
 
 	p = td->td_proc;
 
-	LIN_SDT_PROBE1(emul, linux_schedtail, entry, p);
-
-	/* find the emuldata */
-	em = em_find(p, EMUL_DOLOCK);
-
-	KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n"));
+	em = em_find(td);
+	KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n"));
 	child_set_tid = em->child_set_tid;
-	EMUL_UNLOCK(&emul_lock);
 
 	if (child_set_tid != NULL) {
-		error = copyout(&p->p_pid, (int *)child_set_tid,
-		    sizeof(p->p_pid));
-
-		if (error != 0) {
-			LIN_SDT_PROBE1(emul, linux_schedtail, copyout_error,
-			    error);
-		}
-	}
-
-	LIN_SDT_PROBE0(emul, linux_schedtail, return);
-
-	return;
+		error = copyout(&em->em_tid, child_set_tid,
+		    sizeof(em->em_tid));
+		LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d",
+		    td->td_tid, child_set_tid, em->em_tid, error);
+	} else
+		LINUX_CTR1(schedtail, "thread(%d)", em->em_tid);
 }
-
-int
-linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
-{
-	struct linux_emuldata *em;
-
-	LIN_SDT_PROBE1(emul, linux_set_tid_address, entry, args->tidptr);
-
-	/* find the emuldata */
-	em = em_find(td->td_proc, EMUL_DOLOCK);
-
-	KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
-
-	em->child_clear_tid = args->tidptr;
-	td->td_retval[0] = td->td_proc->p_pid;
-
-	EMUL_UNLOCK(&emul_lock);
-
-	LIN_SDT_PROBE0(emul, linux_set_tid_address, return);
-	return 0;
-}
-
-void
-linux_kill_threads(struct thread *td, int sig)
-{
-	struct linux_emuldata *em, *td_em, *tmp_em;
-	struct proc *sp;
-
-	LIN_SDT_PROBE2(emul, linux_kill_threads, entry, td, sig);
-
-	td_em = em_find(td->td_proc, EMUL_DONTLOCK);
-
-	KASSERT(td_em != NULL, ("linux_kill_threads: emuldata not found.\n"));
-
-	EMUL_SHARED_RLOCK(&emul_shared_lock);
-	LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
-		if (em->pid == td_em->pid)
-			continue;
-
-		sp = pfind(em->pid);
-		if ((sp->p_flag & P_WEXIT) == 0)
-			kern_psignal(sp, sig);
-		PROC_UNLOCK(sp);
-
-		LIN_SDT_PROBE1(emul, linux_kill_threads, kill, em->pid);
-	}
-	EMUL_SHARED_RUNLOCK(&emul_shared_lock);
-
-	LIN_SDT_PROBE0(emul, linux_kill_threads, return);
-}

Modified: trunk/sys/compat/linux/linux_emul.h
===================================================================
--- trunk/sys/compat/linux/linux_emul.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_emul.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2006 Roman Divacky
+ * Copyright (c) 2013 Dmitry Chagin
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,97 +27,55 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_emul.h 302962 2016-07-17 15:07:33Z dchagin $
  */
 
 #ifndef _LINUX_EMUL_H_
 #define	_LINUX_EMUL_H_
 
-#define EMUL_SHARED_HASXSTAT	0x01
-
-struct linux_emuldata_shared {
-	int	refs;
-	int	flags;
-	int	xstat;
-	pid_t	group_pid;
-
-	LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */
-};
-
 /*
  * modeled after similar structure in NetBSD
  * this will be extended as we need more functionality
  */
 struct linux_emuldata {
-	pid_t	pid;
-
 	int    *child_set_tid;	/* in clone(): Child's TID to set on clone */
 	int    *child_clear_tid;/* in clone(): Child's TID to clear on exit */
 
-	struct linux_emuldata_shared *shared;
-
 	int	pdeath_signal;		/* parent death signal */
-	int	flags;			/* different emuldata flags */
+	int	flags;			/* thread emuldata flags */
+	int	em_tid;			/* thread id */
 
 	struct	linux_robust_list_head	*robust_futexes;
-
-	LIST_ENTRY(linux_emuldata) threads;	/* list of linux threads */
 };
 
-struct linux_emuldata	*em_find(struct proc *, int locked);
+struct linux_emuldata	*em_find(struct thread *);
 
-/*
- * DTrace probes for locks should be fired after locking and before releasing
- * to prevent races (to provide data/function stability in dtrace, see the
- * output of "dtrace -v ..." and the corresponding dtrace docs).
- */
-#define	EMUL_LOCK(l)		do { \
-				    mtx_lock(l); \
-				    LIN_SDT_PROBE1(locks, emul_lock, \
-					locked, l); \
-				} while (0)
-#define	EMUL_UNLOCK(l)		do { \
-				    LIN_SDT_PROBE1(locks, emul_lock, \
-					unlock, l); \
-				    mtx_unlock(l); \
-				} while (0)
+void	linux_proc_init(struct thread *, struct thread *, int);
+void	linux_proc_exit(void *, struct proc *);
+void	linux_schedtail(struct thread *);
+void	linux_proc_exec(void *, struct proc *, struct image_params *);
+void	linux_thread_dtor(void *arg __unused, struct thread *);
+void	linux_thread_detach(struct thread *);
+int	linux_common_execve(struct thread *, struct image_args *);
 
-#define	EMUL_SHARED_RLOCK(l)	do { \
-				    sx_slock(l); \
-				    LIN_SDT_PROBE1(locks, emul_shared_rlock, \
-					locked, l); \
-				} while (0)
-#define	EMUL_SHARED_RUNLOCK(l)	do { \
-				    LIN_SDT_PROBE1(locks, emul_shared_rlock, \
-					unlock, l); \
-				    sx_sunlock(l); \
-				} while (0)
-#define	EMUL_SHARED_WLOCK(l)	do { \
-				    sx_xlock(l); \
-				    LIN_SDT_PROBE1(locks, emul_shared_wlock, \
-					locked, l); \
-				} while (0)
-#define	EMUL_SHARED_WUNLOCK(l)	do { \
-				    LIN_SDT_PROBE1(locks, emul_shared_wlock, \
-					unlock, l); \
-				    sx_xunlock(l); \
-				} while (0)
-
-/* for em_find use */
-#define	EMUL_DOLOCK		1
-#define	EMUL_DONTLOCK		0
-
-/* emuldata flags */
+/* process emuldata flags */
 #define	LINUX_XDEPR_REQUEUEOP	0x00000001	/* uses deprecated
 						   futex REQUEUE op*/
+#define	LINUX_XUNSUP_EPOLL	0x00000002	/* unsupported epoll events */
+#define	LINUX_XUNSUP_FUTEXPIOP	0x00000004	/* uses unsupported pi futex */
 
-int	linux_proc_init(struct thread *, pid_t, int);
-void	linux_proc_exit(void *, struct proc *);
-void	linux_schedtail(struct thread *);
-void	linux_proc_exec(void *, struct proc *, struct image_params *);
-void	linux_kill_threads(struct thread *, int);
+struct linux_pemuldata {
+	uint32_t	flags;		/* process emuldata flags */
+	struct sx	pem_sx;		/* lock for this struct */
+	void		*epoll;		/* epoll data */
+	uint32_t	persona;	/* process execution domain */
+};
 
-extern struct sx	emul_shared_lock;
-extern struct mtx	emul_lock;
+#define	LINUX_PEM_XLOCK(p)	sx_xlock(&(p)->pem_sx)
+#define	LINUX_PEM_XUNLOCK(p)	sx_xunlock(&(p)->pem_sx)
+#define	LINUX_PEM_SLOCK(p)	sx_slock(&(p)->pem_sx)
+#define	LINUX_PEM_SUNLOCK(p)	sx_sunlock(&(p)->pem_sx)
 
+struct linux_pemuldata	*pem_find(struct proc *);
+
 #endif	/* !_LINUX_EMUL_H_ */

Added: trunk/sys/compat/linux/linux_event.c
===================================================================
--- trunk/sys/compat/linux/linux_event.c	                        (rev 0)
+++ trunk/sys/compat/linux/linux_event.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,902 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2007 Roman Divacky
+ * Copyright (c) 2014 Dmitry Chagin
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_event.c 321026 2017-07-15 18:25:59Z dchagin $");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/capsicum.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/filio.h>
+#include <sys/errno.h>
+#include <sys/event.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/selinfo.h>
+#include <sys/sx.h>
+#include <sys/syscallsubr.h>
+#include <sys/timespec.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_event.h>
+#include <compat/linux/linux_file.h>
+#include <compat/linux/linux_util.h>
+
+/*
+ * epoll defines 'struct epoll_event' with the field 'data' as 64 bits
+ * on all architectures. But on 32 bit architectures BSD 'struct kevent' only
+ * has 32 bit opaque pointer as 'udata' field. So we can't pass epoll supplied
+ * data verbatuim. Therefore we allocate 64-bit memory block to pass
+ * user supplied data for every file descriptor.
+ */
+
+typedef uint64_t	epoll_udata_t;
+
+struct epoll_emuldata {
+	uint32_t	fdc;		/* epoll udata max index */
+	epoll_udata_t	udata[1];	/* epoll user data vector */
+};
+
+#define	EPOLL_DEF_SZ		16
+#define	EPOLL_SIZE(fdn)			\
+	(sizeof(struct epoll_emuldata)+(fdn) * sizeof(epoll_udata_t))
+
+struct epoll_event {
+	uint32_t	events;
+	epoll_udata_t	data;
+}
+#if defined(__amd64__)
+__attribute__((packed))
+#endif
+;
+
+#define	LINUX_MAX_EVENTS	(INT_MAX / sizeof(struct epoll_event))
+
+static void	epoll_fd_install(struct thread *td, int fd, epoll_udata_t udata);
+static int	epoll_to_kevent(struct thread *td, struct file *epfp,
+		    int fd, struct epoll_event *l_event, int *kev_flags,
+		    struct kevent *kevent, int *nkevents);
+static void	kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event);
+static int	epoll_kev_copyout(void *arg, struct kevent *kevp, int count);
+static int	epoll_kev_copyin(void *arg, struct kevent *kevp, int count);
+static int	epoll_delete_event(struct thread *td, struct file *epfp,
+		    int fd, int filter);
+static int	epoll_delete_all_events(struct thread *td, struct file *epfp,
+		    int fd);
+
+struct epoll_copyin_args {
+	struct kevent	*changelist;
+};
+
+struct epoll_copyout_args {
+	struct epoll_event	*leventlist;
+	struct proc		*p;
+	uint32_t		count;
+	int			error;
+};
+
+/* eventfd */
+typedef uint64_t	eventfd_t;
+
+static fo_rdwr_t	eventfd_read;
+static fo_rdwr_t	eventfd_write;
+static fo_truncate_t	eventfd_truncate;
+static fo_ioctl_t	eventfd_ioctl;
+static fo_poll_t	eventfd_poll;
+static fo_kqfilter_t	eventfd_kqfilter;
+static fo_stat_t	eventfd_stat;
+static fo_close_t	eventfd_close;
+
+static struct fileops eventfdops = {
+	.fo_read = eventfd_read,
+	.fo_write = eventfd_write,
+	.fo_truncate = eventfd_truncate,
+	.fo_ioctl = eventfd_ioctl,
+	.fo_poll = eventfd_poll,
+	.fo_kqfilter = eventfd_kqfilter,
+	.fo_stat = eventfd_stat,
+	.fo_close = eventfd_close,
+	.fo_chmod = invfo_chmod,
+	.fo_chown = invfo_chown,
+	.fo_sendfile = invfo_sendfile,
+	.fo_flags = DFLAG_PASSABLE
+};
+
+static void	filt_eventfddetach(struct knote *kn);
+static int	filt_eventfdread(struct knote *kn, long hint);
+static int	filt_eventfdwrite(struct knote *kn, long hint);
+
+static struct filterops eventfd_rfiltops = {
+	.f_isfd = 1,
+	.f_detach = filt_eventfddetach,
+	.f_event = filt_eventfdread
+};
+static struct filterops eventfd_wfiltops = {
+	.f_isfd = 1,
+	.f_detach = filt_eventfddetach,
+	.f_event = filt_eventfdwrite
+};
+
+struct eventfd {
+	eventfd_t	efd_count;
+	uint32_t	efd_flags;
+	struct selinfo	efd_sel;
+	struct mtx	efd_lock;
+};
+
+static int	eventfd_create(struct thread *td, uint32_t initval, int flags);
+
+
+static void
+epoll_fd_install(struct thread *td, int fd, epoll_udata_t udata)
+{
+	struct linux_pemuldata *pem;
+	struct epoll_emuldata *emd;
+	struct proc *p;
+
+	p = td->td_proc;
+
+	pem = pem_find(p);
+	KASSERT(pem != NULL, ("epoll proc emuldata not found.\n"));
+
+	LINUX_PEM_XLOCK(pem);
+	if (pem->epoll == NULL) {
+		emd = malloc(EPOLL_SIZE(fd), M_EPOLL, M_WAITOK);
+		emd->fdc = fd;
+		pem->epoll = emd;
+	} else {
+		emd = pem->epoll;
+		if (fd > emd->fdc) {
+			emd = realloc(emd, EPOLL_SIZE(fd), M_EPOLL, M_WAITOK);
+			emd->fdc = fd;
+			pem->epoll = emd;
+		}
+	}
+	emd->udata[fd] = udata;
+	LINUX_PEM_XUNLOCK(pem);
+}
+
+static int
+epoll_create_common(struct thread *td, int flags)
+{
+	int error;
+
+	error = kern_kqueue(td, flags);
+	if (error)
+		return (error);
+
+	epoll_fd_install(td, EPOLL_DEF_SZ, 0);
+
+	return (0);
+}
+
+int
+linux_epoll_create(struct thread *td, struct linux_epoll_create_args *args)
+{
+
+	/*
+	 * args->size is unused. Linux just tests it
+	 * and then forgets it as well.
+	 */
+	if (args->size <= 0)
+		return (EINVAL);
+
+	return (epoll_create_common(td, 0));
+}
+
+int
+linux_epoll_create1(struct thread *td, struct linux_epoll_create1_args *args)
+{
+	int flags;
+
+	if ((args->flags & ~(LINUX_O_CLOEXEC)) != 0)
+		return (EINVAL);
+
+	flags = 0;
+	if ((args->flags & LINUX_O_CLOEXEC) != 0)
+		flags |= O_CLOEXEC;
+
+	return (epoll_create_common(td, flags));
+}
+
+/* Structure converting function from epoll to kevent. */
+static int
+epoll_to_kevent(struct thread *td, struct file *epfp,
+    int fd, struct epoll_event *l_event, int *kev_flags,
+    struct kevent *kevent, int *nkevents)
+{
+	uint32_t levents = l_event->events;
+	struct linux_pemuldata *pem;
+	struct proc *p;
+
+	/* flags related to how event is registered */
+	if ((levents & LINUX_EPOLLONESHOT) != 0)
+		*kev_flags |= EV_ONESHOT;
+	if ((levents & LINUX_EPOLLET) != 0)
+		*kev_flags |= EV_CLEAR;
+	if ((levents & LINUX_EPOLLERR) != 0)
+		*kev_flags |= EV_ERROR;
+	if ((levents & LINUX_EPOLLRDHUP) != 0)
+		*kev_flags |= EV_EOF;
+
+	/* flags related to what event is registered */
+	if ((levents & LINUX_EPOLL_EVRD) != 0) {
+		EV_SET(kevent++, fd, EVFILT_READ, *kev_flags, 0, 0, 0);
+		++(*nkevents);
+	}
+	if ((levents & LINUX_EPOLL_EVWR) != 0) {
+		EV_SET(kevent++, fd, EVFILT_WRITE, *kev_flags, 0, 0, 0);
+		++(*nkevents);
+	}
+
+	if ((levents & ~(LINUX_EPOLL_EVSUP)) != 0) {
+		p = td->td_proc;
+
+		pem = pem_find(p);
+		KASSERT(pem != NULL, ("epoll proc emuldata not found.\n"));
+		KASSERT(pem->epoll != NULL, ("epoll proc epolldata not found.\n"));
+
+		LINUX_PEM_XLOCK(pem);
+		if ((pem->flags & LINUX_XUNSUP_EPOLL) == 0) {
+			pem->flags |= LINUX_XUNSUP_EPOLL;
+			LINUX_PEM_XUNLOCK(pem);
+			linux_msg(td, "epoll_ctl unsupported flags: 0x%x\n",
+			    levents);
+		} else
+			LINUX_PEM_XUNLOCK(pem);
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+/* 
+ * Structure converting function from kevent to epoll. In a case
+ * this is called on error in registration we store the error in
+ * event->data and pick it up later in linux_epoll_ctl().
+ */
+static void
+kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event)
+{
+
+	if ((kevent->flags & EV_ERROR) != 0) {
+		l_event->events = LINUX_EPOLLERR;
+		return;
+	}
+
+	switch (kevent->filter) {
+	case EVFILT_READ:
+		l_event->events = LINUX_EPOLLIN|LINUX_EPOLLRDNORM|LINUX_EPOLLPRI;
+		if ((kevent->flags & EV_EOF) != 0)
+			l_event->events |= LINUX_EPOLLRDHUP;
+	break;
+	case EVFILT_WRITE:
+		l_event->events = LINUX_EPOLLOUT|LINUX_EPOLLWRNORM;
+	break;
+	}
+}
+
+/* 
+ * Copyout callback used by kevent. This converts kevent
+ * events to epoll events and copies them back to the
+ * userspace. This is also called on error on registering
+ * of the filter.
+ */
+static int
+epoll_kev_copyout(void *arg, struct kevent *kevp, int count)
+{
+	struct epoll_copyout_args *args;
+	struct linux_pemuldata *pem;
+	struct epoll_emuldata *emd;
+	struct epoll_event *eep;
+	int error, fd, i;
+
+	args = (struct epoll_copyout_args*) arg;
+	eep = malloc(sizeof(*eep) * count, M_EPOLL, M_WAITOK | M_ZERO);
+
+	pem = pem_find(args->p);
+	KASSERT(pem != NULL, ("epoll proc emuldata not found.\n"));
+	LINUX_PEM_SLOCK(pem);
+	emd = pem->epoll;
+	KASSERT(emd != NULL, ("epoll proc epolldata not found.\n"));
+
+	for (i = 0; i < count; i++) {
+		kevent_to_epoll(&kevp[i], &eep[i]);
+
+		fd = kevp[i].ident;
+		KASSERT(fd <= emd->fdc, ("epoll user data vector"
+						    " is too small.\n"));
+		eep[i].data = emd->udata[fd];
+	}
+	LINUX_PEM_SUNLOCK(pem);
+
+	error = copyout(eep, args->leventlist, count * sizeof(*eep));
+	if (error == 0) {
+		args->leventlist += count;
+		args->count += count;
+	} else if (args->error == 0)
+		args->error = error;
+
+	free(eep, M_EPOLL);
+	return (error);
+}
+
+/*
+ * Copyin callback used by kevent. This copies already
+ * converted filters from kernel memory to the kevent 
+ * internal kernel memory. Hence the memcpy instead of
+ * copyin.
+ */
+static int
+epoll_kev_copyin(void *arg, struct kevent *kevp, int count)
+{
+	struct epoll_copyin_args *args;
+
+	args = (struct epoll_copyin_args*) arg;
+	
+	memcpy(kevp, args->changelist, count * sizeof(*kevp));
+	args->changelist += count;
+
+	return (0);
+}
+
+/*
+ * Load epoll filter, convert it to kevent filter
+ * and load it into kevent subsystem.
+ */
+int
+linux_epoll_ctl(struct thread *td, struct linux_epoll_ctl_args *args)
+{
+	struct file *epfp, *fp;
+	struct epoll_copyin_args ciargs;
+	struct kevent kev[2];
+	struct kevent_copyops k_ops = { &ciargs,
+					NULL,
+					epoll_kev_copyin};
+	struct epoll_event le;
+	cap_rights_t rights;
+	int kev_flags;
+	int nchanges = 0;
+	int error;
+
+	if (args->op != LINUX_EPOLL_CTL_DEL) {
+		error = copyin(args->event, &le, sizeof(le));
+		if (error != 0)
+			return (error);
+	}
+
+	error = fget(td, args->epfd,
+	    cap_rights_init(&rights, CAP_KQUEUE_CHANGE), &epfp);
+	if (error != 0)
+		return (error);
+	if (epfp->f_type != DTYPE_KQUEUE)
+		goto leave1;
+
+	 /* Protect user data vector from incorrectly supplied fd. */
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_POLL_EVENT), &fp);
+	if (error != 0)
+		goto leave1;
+
+	/* Linux disallows spying on himself */
+	if (epfp == fp) {
+		error = EINVAL;
+		goto leave0;
+	}
+
+	ciargs.changelist = kev;
+
+	switch (args->op) {
+	case LINUX_EPOLL_CTL_MOD:
+		/*
+		 * We don't memorize which events were set for this FD
+		 * on this level, so just delete all we could have set:
+		 * EVFILT_READ and EVFILT_WRITE, ignoring any errors
+		 */
+		error = epoll_delete_all_events(td, epfp, args->fd);
+		if (error)
+			goto leave0;
+		/* FALLTHROUGH */
+
+	case LINUX_EPOLL_CTL_ADD:
+			kev_flags = EV_ADD | EV_ENABLE;
+		break;
+
+	case LINUX_EPOLL_CTL_DEL:
+		/* CTL_DEL means unregister this fd with this epoll */
+		error = epoll_delete_all_events(td, epfp, args->fd);
+		goto leave0;
+
+	default:
+		error = EINVAL;
+		goto leave0;
+	}
+
+	error = epoll_to_kevent(td, epfp, args->fd, &le, &kev_flags,
+	    kev, &nchanges);
+	if (error)
+		goto leave0;
+
+	epoll_fd_install(td, args->fd, le.data);
+
+	error = kern_kevent_fp(td, epfp, nchanges, 0, &k_ops, NULL);
+
+leave0:
+	fdrop(fp, td);
+
+leave1:
+	fdrop(epfp, td);
+	return (error);
+}
+
+/*
+ * Wait for a filter to be triggered on the epoll file descriptor.
+ */
+static int
+linux_epoll_wait_common(struct thread *td, int epfd, struct epoll_event *events,
+    int maxevents, int timeout, sigset_t *uset)
+{
+	struct file *epfp;
+	struct timespec ts, *tsp;
+	cap_rights_t rights;
+	struct epoll_copyout_args coargs;
+	struct kevent_copyops k_ops = { &coargs,
+					epoll_kev_copyout,
+					NULL};
+	int error;
+
+	if (maxevents <= 0 || maxevents > LINUX_MAX_EVENTS)
+		return (EINVAL);
+
+	if (uset != NULL) {
+		error = kern_sigprocmask(td, SIG_SETMASK, uset,
+		    &td->td_oldsigmask, 0);
+		if (error != 0)
+			return (error);
+		td->td_pflags |= TDP_OLDMASK;
+		/*
+		 * Make sure that ast() is called on return to
+		 * usermode and TDP_OLDMASK is cleared, restoring old
+		 * sigmask.
+		 */
+		thread_lock(td);
+		td->td_flags |= TDF_ASTPENDING;
+		thread_unlock(td);
+	}
+
+	error = fget(td, epfd,
+	    cap_rights_init(&rights, CAP_KQUEUE_EVENT), &epfp);
+	if (error != 0)
+		return (error);
+
+	coargs.leventlist = events;
+	coargs.p = td->td_proc;
+	coargs.count = 0;
+	coargs.error = 0;
+
+	if (timeout != -1) {
+		if (timeout < 0) {
+			error = EINVAL;
+			goto leave;
+		}
+		/* Convert from milliseconds to timespec. */
+		ts.tv_sec = timeout / 1000;
+		ts.tv_nsec = (timeout % 1000) * 1000000;
+		tsp = &ts;
+	} else {
+		tsp = NULL;
+	}
+
+	error = kern_kevent_fp(td, epfp, 0, maxevents, &k_ops, tsp);
+	if (error == 0 && coargs.error != 0)
+		error = coargs.error;
+
+	/* 
+	 * kern_kevent might return ENOMEM which is not expected from epoll_wait.
+	 * Maybe we should translate that but I don't think it matters at all.
+	 */
+	if (error == 0)
+		td->td_retval[0] = coargs.count;
+leave:
+	fdrop(epfp, td);
+	return (error);
+}
+
+int
+linux_epoll_wait(struct thread *td, struct linux_epoll_wait_args *args)
+{
+
+	return (linux_epoll_wait_common(td, args->epfd, args->events,
+	    args->maxevents, args->timeout, NULL));
+}
+
+int
+linux_epoll_pwait(struct thread *td, struct linux_epoll_pwait_args *args)
+{
+	sigset_t mask, *pmask;
+	l_sigset_t lmask;
+	int error;
+
+	if (args->mask != NULL) {
+		error = copyin(args->mask, &lmask, sizeof(l_sigset_t));
+		if (error != 0)
+			return (error);
+		linux_to_bsd_sigset(&lmask, &mask);
+		pmask = &mask;
+	} else
+		pmask = NULL;
+	return (linux_epoll_wait_common(td, args->epfd, args->events,
+	    args->maxevents, args->timeout, pmask));
+}
+
+static int
+epoll_delete_event(struct thread *td, struct file *epfp, int fd, int filter)
+{
+	struct epoll_copyin_args ciargs;
+	struct kevent kev;
+	struct kevent_copyops k_ops = { &ciargs,
+					NULL,
+					epoll_kev_copyin};
+	int error;
+
+	ciargs.changelist = &kev;
+	EV_SET(&kev, fd, filter, EV_DELETE | EV_DISABLE, 0, 0, 0);
+
+	error = kern_kevent_fp(td, epfp, 1, 0, &k_ops, NULL);
+
+	/*
+	 * here we ignore ENONT, because we don't keep track of events here
+	 */
+	if (error == ENOENT)
+		error = 0;
+	return (error);
+}
+
+static int
+epoll_delete_all_events(struct thread *td, struct file *epfp, int fd)
+{
+	int error1, error2;
+
+	error1 = epoll_delete_event(td, epfp, fd, EVFILT_READ);
+	error2 = epoll_delete_event(td, epfp, fd, EVFILT_WRITE);
+
+	/* report any errors we got */
+	return (error1 == 0 ? error2 : error1);
+}
+
+static int
+eventfd_create(struct thread *td, uint32_t initval, int flags)
+{
+	struct filedesc *fdp;
+	struct eventfd *efd;
+	struct file *fp;
+	int fflags, fd, error;
+
+	fflags = 0;
+	if ((flags & LINUX_O_CLOEXEC) != 0)
+		fflags |= O_CLOEXEC;
+
+	fdp = td->td_proc->p_fd;
+	error = falloc(td, &fp, &fd, fflags);
+	if (error)
+		return (error);
+
+	efd = malloc(sizeof(*efd), M_EPOLL, M_WAITOK | M_ZERO);
+	efd->efd_flags = flags;
+	efd->efd_count = initval;
+	mtx_init(&efd->efd_lock, "eventfd", NULL, MTX_DEF);
+
+	knlist_init_mtx(&efd->efd_sel.si_note, &efd->efd_lock);
+
+	fflags = FREAD | FWRITE; 
+	if ((flags & LINUX_O_NONBLOCK) != 0)
+		fflags |= FNONBLOCK;
+
+	finit(fp, fflags, DTYPE_LINUXEFD, efd, &eventfdops);
+	fdrop(fp, td);
+
+	td->td_retval[0] = fd;
+	return (error);
+}
+
+int
+linux_eventfd(struct thread *td, struct linux_eventfd_args *args)
+{
+
+	return (eventfd_create(td, args->initval, 0));
+}
+
+int
+linux_eventfd2(struct thread *td, struct linux_eventfd2_args *args)
+{
+
+	if ((args->flags & ~(LINUX_O_CLOEXEC|LINUX_O_NONBLOCK|LINUX_EFD_SEMAPHORE)) != 0)
+		return (EINVAL);
+
+	return (eventfd_create(td, args->initval, args->flags));
+}
+
+static int
+eventfd_close(struct file *fp, struct thread *td)
+{
+	struct eventfd *efd;
+
+	efd = fp->f_data;
+	if (fp->f_type != DTYPE_LINUXEFD || efd == NULL)
+		return (EBADF);
+
+	seldrain(&efd->efd_sel);
+	knlist_destroy(&efd->efd_sel.si_note);
+
+	fp->f_ops = &badfileops;
+	mtx_destroy(&efd->efd_lock);
+	free(efd, M_EPOLL);
+
+	return (0);
+}
+
+static int
+eventfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
+	int flags, struct thread *td)
+{
+	struct eventfd *efd;
+	eventfd_t count;
+	int error;
+
+	efd = fp->f_data;
+	if (fp->f_type != DTYPE_LINUXEFD || efd == NULL)
+		return (EBADF);
+
+	if (uio->uio_resid < sizeof(eventfd_t))
+		return (EINVAL);
+
+	error = 0;
+	mtx_lock(&efd->efd_lock);
+retry:
+	if (efd->efd_count == 0) {
+		if ((efd->efd_flags & LINUX_O_NONBLOCK) != 0) {
+			mtx_unlock(&efd->efd_lock);
+			return (EAGAIN);
+		}
+		error = mtx_sleep(&efd->efd_count, &efd->efd_lock, PCATCH, "lefdrd", 0);
+		if (error == 0)
+			goto retry;
+	}
+	if (error == 0) {
+		if ((efd->efd_flags & LINUX_EFD_SEMAPHORE) != 0) {
+			count = 1;
+			--efd->efd_count;
+		} else {
+			count = efd->efd_count;
+			efd->efd_count = 0;
+		}
+		KNOTE_LOCKED(&efd->efd_sel.si_note, 0);
+		selwakeup(&efd->efd_sel);
+		wakeup(&efd->efd_count);
+		mtx_unlock(&efd->efd_lock);
+		error = uiomove(&count, sizeof(eventfd_t), uio);
+	} else
+		mtx_unlock(&efd->efd_lock);
+
+	return (error);
+}
+
+static int
+eventfd_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
+	 int flags, struct thread *td)
+{
+	struct eventfd *efd;
+	eventfd_t count;
+	int error;
+
+	efd = fp->f_data;
+	if (fp->f_type != DTYPE_LINUXEFD || efd == NULL)
+		return (EBADF);
+
+	if (uio->uio_resid < sizeof(eventfd_t))
+		return (EINVAL);
+
+	error = uiomove(&count, sizeof(eventfd_t), uio);
+	if (error)
+		return (error);
+	if (count == UINT64_MAX)
+		return (EINVAL);
+
+	mtx_lock(&efd->efd_lock);
+retry:
+	if (UINT64_MAX - efd->efd_count <= count) {
+		if ((efd->efd_flags & LINUX_O_NONBLOCK) != 0) {
+			mtx_unlock(&efd->efd_lock);
+			/* Do not not return the number of bytes written */
+			uio->uio_resid += sizeof(eventfd_t);
+			return (EAGAIN);
+		}
+		error = mtx_sleep(&efd->efd_count, &efd->efd_lock,
+		    PCATCH, "lefdwr", 0);
+		if (error == 0)
+			goto retry;
+	}
+	if (error == 0) {
+		efd->efd_count += count;
+		KNOTE_LOCKED(&efd->efd_sel.si_note, 0);
+		selwakeup(&efd->efd_sel);
+		wakeup(&efd->efd_count);
+	}
+	mtx_unlock(&efd->efd_lock);
+
+	return (error);
+}
+
+static int
+eventfd_poll(struct file *fp, int events, struct ucred *active_cred,
+	struct thread *td)
+{
+	struct eventfd *efd;
+	int revents = 0;
+
+	efd = fp->f_data;
+	if (fp->f_type != DTYPE_LINUXEFD || efd == NULL)
+		return (POLLERR);
+
+	mtx_lock(&efd->efd_lock);
+	if ((events & (POLLIN|POLLRDNORM)) && efd->efd_count > 0)
+		revents |= events & (POLLIN|POLLRDNORM);
+	if ((events & (POLLOUT|POLLWRNORM)) && UINT64_MAX - 1 > efd->efd_count)
+		revents |= events & (POLLOUT|POLLWRNORM);
+	if (revents == 0)
+		selrecord(td, &efd->efd_sel);
+	mtx_unlock(&efd->efd_lock);
+
+	return (revents);
+}
+
+/*ARGSUSED*/
+static int
+eventfd_kqfilter(struct file *fp, struct knote *kn)
+{
+	struct eventfd *efd;
+
+	efd = fp->f_data;
+	if (fp->f_type != DTYPE_LINUXEFD || efd == NULL)
+		return (EINVAL);
+
+	mtx_lock(&efd->efd_lock);
+	switch (kn->kn_filter) {
+	case EVFILT_READ:
+		kn->kn_fop = &eventfd_rfiltops;
+		break;
+	case EVFILT_WRITE:
+		kn->kn_fop = &eventfd_wfiltops;
+		break;
+	default:
+		mtx_unlock(&efd->efd_lock);
+		return (EINVAL);
+	}
+
+	kn->kn_hook = efd;
+	knlist_add(&efd->efd_sel.si_note, kn, 1);
+	mtx_unlock(&efd->efd_lock);
+
+	return (0);
+}
+
+static void
+filt_eventfddetach(struct knote *kn)
+{
+	struct eventfd *efd = kn->kn_hook;
+
+	mtx_lock(&efd->efd_lock);
+	knlist_remove(&efd->efd_sel.si_note, kn, 1);
+	mtx_unlock(&efd->efd_lock);
+}
+
+/*ARGSUSED*/
+static int
+filt_eventfdread(struct knote *kn, long hint)
+{
+	struct eventfd *efd = kn->kn_hook;
+	int ret;
+
+	mtx_assert(&efd->efd_lock, MA_OWNED);
+	ret = (efd->efd_count > 0);
+
+	return (ret);
+}
+
+/*ARGSUSED*/
+static int
+filt_eventfdwrite(struct knote *kn, long hint)
+{
+	struct eventfd *efd = kn->kn_hook;
+	int ret;
+
+	mtx_assert(&efd->efd_lock, MA_OWNED);
+	ret = (UINT64_MAX - 1 > efd->efd_count);
+
+	return (ret);
+}
+
+/*ARGSUSED*/
+static int
+eventfd_truncate(struct file *fp, off_t length, struct ucred *active_cred,
+	struct thread *td)
+{
+
+	return (ENXIO);
+}
+
+/*ARGSUSED*/
+static int
+eventfd_ioctl(struct file *fp, u_long cmd, void *data,
+	struct ucred *active_cred, struct thread *td)
+{
+	struct eventfd *efd;
+
+	efd = fp->f_data;
+	if (fp->f_type != DTYPE_LINUXEFD || efd == NULL)
+		return (EINVAL);
+
+	switch (cmd)
+	{
+	case FIONBIO:
+		if (*(int *)data)
+			efd->efd_flags |= LINUX_O_NONBLOCK;
+		else
+			efd->efd_flags &= ~LINUX_O_NONBLOCK;
+	case FIOASYNC:
+		return (0);
+	default:
+		return (ENXIO);
+	}
+}
+
+/*ARGSUSED*/
+static int
+eventfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred,
+	struct thread *td)
+{
+
+	return (ENXIO);
+}


Property changes on: trunk/sys/compat/linux/linux_event.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/compat/linux/linux_event.h
===================================================================
--- trunk/sys/compat/linux/linux_event.h	                        (rev 0)
+++ trunk/sys/compat/linux/linux_event.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,61 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2007 Roman Divacky
+ * Copyright (c) 2014 Dmitry Chagin
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/10/sys/compat/linux/linux_event.h 293606 2016-01-09 18:23:34Z dchagin $
+ */
+
+#ifndef _LINUX_EVENT_H_
+#define	_LINUX_EVENT_H_
+
+#define	LINUX_EPOLLIN		0x001
+#define	LINUX_EPOLLPRI		0x002
+#define	LINUX_EPOLLOUT		0x004
+#define	LINUX_EPOLLRDNORM	0x040
+#define	LINUX_EPOLLRDBAND	0x080
+#define	LINUX_EPOLLWRNORM	0x100
+#define	LINUX_EPOLLWRBAND	0x200
+#define	LINUX_EPOLLMSG		0x400
+#define	LINUX_EPOLLERR		0x008
+#define	LINUX_EPOLLHUP		0x010
+#define	LINUX_EPOLLRDHUP	0x2000
+#define	LINUX_EPOLLWAKEUP	1u<<29
+#define	LINUX_EPOLLONESHOT	1u<<30
+#define	LINUX_EPOLLET		1u<<31
+
+#define	LINUX_EPOLL_EVRD	(LINUX_EPOLLIN|LINUX_EPOLLRDNORM	\
+		|LINUX_EPOLLHUP|LINUX_EPOLLERR|LINUX_EPOLLPRI)
+#define	LINUX_EPOLL_EVWR	(LINUX_EPOLLOUT|LINUX_EPOLLWRNORM)
+#define	LINUX_EPOLL_EVSUP	(LINUX_EPOLLET|LINUX_EPOLLONESHOT	\
+		|LINUX_EPOLL_EVRD|LINUX_EPOLL_EVWR|LINUX_EPOLLRDHUP)
+
+#define	LINUX_EPOLL_CTL_ADD	1
+#define	LINUX_EPOLL_CTL_DEL	2
+#define	LINUX_EPOLL_CTL_MOD	3
+
+#define	LINUX_EFD_SEMAPHORE	(1 << 0)
+
+#endif	/* !_LINUX_EVENT_H_ */


Property changes on: trunk/sys/compat/linux/linux_event.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/compat/linux/linux_file.c
===================================================================
--- trunk/sys/compat/linux/linux_file.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_file.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 1994-1995 S\xF8ren Schmidt
+ * Copyright (c) 1994-1995 Søren Schmidt
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,13 +28,13 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_file.c 301424 2016-06-05 06:02:37Z dchagin $");
 
 #include "opt_compat.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/capability.h>
+#include <sys/capsicum.h>
 #include <sys/conf.h>
 #include <sys/dirent.h>
 #include <sys/fcntl.h>
@@ -55,10 +56,6 @@
 
 #include <security/mac/mac_framework.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/ufsmount.h>
-
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
 #include <machine/../linux32/linux32_proto.h>
@@ -66,27 +63,25 @@
 #include <machine/../linux/linux.h>
 #include <machine/../linux/linux_proto.h>
 #endif
+#include <compat/linux/linux_misc.h>
 #include <compat/linux/linux_util.h>
 #include <compat/linux/linux_file.h>
 
-extern int do_pipe(struct thread *td, int fildes[2], int flags);
-
 int
 linux_creat(struct thread *td, struct linux_creat_args *args)
 {
-    char *path;
-    int error;
+	char *path;
+	int error;
 
-    LCONVPATHEXIST(td, args->path, &path);
-
+	LCONVPATHEXIST(td, args->path, &path);
 #ifdef DEBUG
 	if (ldebug(creat))
 		printf(ARGS(creat, "%s, %d"), path, args->mode);
 #endif
-    error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
-	args->mode);
-    LFREEPATH(path);
-    return (error);
+	error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
+	    O_WRONLY | O_CREAT | O_TRUNC, args->mode);
+	LFREEPATH(path);
+	return (error);
 }
 
 
@@ -93,87 +88,88 @@
 static int
 linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
 {
-    struct proc *p = td->td_proc;
-    struct file *fp;
-    int fd;
-    int bsd_flags, error;
+	cap_rights_t rights;
+	struct proc *p = td->td_proc;
+	struct file *fp;
+	int fd;
+	int bsd_flags, error;
 
-    bsd_flags = 0;
-    switch (l_flags & LINUX_O_ACCMODE) {
-    case LINUX_O_WRONLY:
-	bsd_flags |= O_WRONLY;
-	break;
-    case LINUX_O_RDWR:
-	bsd_flags |= O_RDWR;
-	break;
-    default:
-	bsd_flags |= O_RDONLY;
-    }
-    if (l_flags & LINUX_O_NDELAY)
-	bsd_flags |= O_NONBLOCK;
-    if (l_flags & LINUX_O_APPEND)
-	bsd_flags |= O_APPEND;
-    if (l_flags & LINUX_O_SYNC)
-	bsd_flags |= O_FSYNC;
-    if (l_flags & LINUX_O_NONBLOCK)
-	bsd_flags |= O_NONBLOCK;
-    if (l_flags & LINUX_FASYNC)
-	bsd_flags |= O_ASYNC;
-    if (l_flags & LINUX_O_CREAT)
-	bsd_flags |= O_CREAT;
-    if (l_flags & LINUX_O_TRUNC)
-	bsd_flags |= O_TRUNC;
-    if (l_flags & LINUX_O_EXCL)
-	bsd_flags |= O_EXCL;
-    if (l_flags & LINUX_O_NOCTTY)
-	bsd_flags |= O_NOCTTY;
-    if (l_flags & LINUX_O_DIRECT)
-	bsd_flags |= O_DIRECT;
-    if (l_flags & LINUX_O_NOFOLLOW)
-	bsd_flags |= O_NOFOLLOW;
-    if (l_flags & LINUX_O_DIRECTORY)
-	bsd_flags |= O_DIRECTORY;
-    /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
+	bsd_flags = 0;
+	switch (l_flags & LINUX_O_ACCMODE) {
+	case LINUX_O_WRONLY:
+		bsd_flags |= O_WRONLY;
+		break;
+	case LINUX_O_RDWR:
+		bsd_flags |= O_RDWR;
+		break;
+	default:
+		bsd_flags |= O_RDONLY;
+	}
+	if (l_flags & LINUX_O_NDELAY)
+		bsd_flags |= O_NONBLOCK;
+	if (l_flags & LINUX_O_APPEND)
+		bsd_flags |= O_APPEND;
+	if (l_flags & LINUX_O_SYNC)
+		bsd_flags |= O_FSYNC;
+	if (l_flags & LINUX_O_NONBLOCK)
+		bsd_flags |= O_NONBLOCK;
+	if (l_flags & LINUX_FASYNC)
+		bsd_flags |= O_ASYNC;
+	if (l_flags & LINUX_O_CREAT)
+		bsd_flags |= O_CREAT;
+	if (l_flags & LINUX_O_TRUNC)
+		bsd_flags |= O_TRUNC;
+	if (l_flags & LINUX_O_EXCL)
+		bsd_flags |= O_EXCL;
+	if (l_flags & LINUX_O_NOCTTY)
+		bsd_flags |= O_NOCTTY;
+	if (l_flags & LINUX_O_DIRECT)
+		bsd_flags |= O_DIRECT;
+	if (l_flags & LINUX_O_NOFOLLOW)
+		bsd_flags |= O_NOFOLLOW;
+	if (l_flags & LINUX_O_DIRECTORY)
+		bsd_flags |= O_DIRECTORY;
+	/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
 
-    error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
+	error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
+	if (error != 0)
+		goto done;
+	if (bsd_flags & O_NOCTTY)
+		goto done;
 
-    if (!error) {
-	    fd = td->td_retval[0];
-	    /*
-	     * XXX In between kern_open() and fget(), another process
-	     * having the same filedesc could use that fd without
-	     * checking below.
-	     */
-	    error = fget(td, fd, CAP_IOCTL, &fp);
-	    if (!error) {
-		    sx_slock(&proctree_lock);
-		    PROC_LOCK(p);
-		    if (!(bsd_flags & O_NOCTTY) &&
-			SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
-			    PROC_UNLOCK(p);
-			    sx_unlock(&proctree_lock);
-			    if (fp->f_type == DTYPE_VNODE)
-				    (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
-					     td->td_ucred, td);
-		    } else {
-			    PROC_UNLOCK(p);
-			    sx_sunlock(&proctree_lock);
-		    }
-		    fdrop(fp, td);
-		    /*
-		     * XXX as above, fdrop()/kern_close() pair is racy.
-		     */
-		    if (error)
-			    kern_close(td, fd);
-	    }
-    }
+	/*
+	 * XXX In between kern_open() and fget(), another process
+	 * having the same filedesc could use that fd without
+	 * checking below.
+	*/
+	fd = td->td_retval[0];
+	if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) {
+		if (fp->f_type != DTYPE_VNODE) {
+			fdrop(fp, td);
+			goto done;
+		}
+		sx_slock(&proctree_lock);
+		PROC_LOCK(p);
+		if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
+			PROC_UNLOCK(p);
+			sx_sunlock(&proctree_lock);
+			/* XXXPJD: Verify if TIOCSCTTY is allowed. */
+			(void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
+			    td->td_ucred, td);
+		} else {
+			PROC_UNLOCK(p);
+			sx_sunlock(&proctree_lock);
+		}
+		fdrop(fp, td);
+	}
 
+done:
 #ifdef DEBUG
-    if (ldebug(open))
-	    printf(LMSG("open returns error %d"), error);
+	if (ldebug(open))
+		printf(LMSG("open returns error %d"), error);
 #endif
-    LFREEPATH(path);
-    return (error);
+	LFREEPATH(path);
+	return (error);
 }
 
 int
@@ -198,19 +194,17 @@
 int
 linux_open(struct thread *td, struct linux_open_args *args)
 {
-    char *path;
+	char *path;
 
-    if (args->flags & LINUX_O_CREAT)
-	LCONVPATHCREAT(td, args->path, &path);
-    else
-	LCONVPATHEXIST(td, args->path, &path);
-
+	if (args->flags & LINUX_O_CREAT)
+		LCONVPATHCREAT(td, args->path, &path);
+	else
+		LCONVPATHEXIST(td, args->path, &path);
 #ifdef DEBUG
 	if (ldebug(open))
 		printf(ARGS(open, "%s, 0x%x, 0x%x"),
 		    path, args->flags, args->mode);
 #endif
-
 	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
 }
 
@@ -217,27 +211,27 @@
 int
 linux_lseek(struct thread *td, struct linux_lseek_args *args)
 {
+	struct lseek_args /* {
+		int fd;
+		int pad;
+		off_t offset;
+		int whence;
+	} */ tmp_args;
+	int error;
 
-    struct lseek_args /* {
-	int fd;
-	int pad;
-	off_t offset;
-	int whence;
-    } */ tmp_args;
-    int error;
-
 #ifdef DEBUG
 	if (ldebug(lseek))
 		printf(ARGS(lseek, "%d, %ld, %d"),
 		    args->fdes, (long)args->off, args->whence);
 #endif
-    tmp_args.fd = args->fdes;
-    tmp_args.offset = (off_t)args->off;
-    tmp_args.whence = args->whence;
-    error = sys_lseek(td, &tmp_args);
-    return error;
+	tmp_args.fd = args->fdes;
+	tmp_args.offset = (off_t)args->off;
+	tmp_args.whence = args->whence;
+	error = sys_lseek(td, &tmp_args);
+	return (error);
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_llseek(struct thread *td, struct linux_llseek_args *args)
 {
@@ -257,13 +251,13 @@
 	bsd_args.whence = args->whence;
 
 	if ((error = sys_lseek(td, &bsd_args)))
-		return error;
+		return (error);
 
 	if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
-		return error;
+		return (error);
 
 	td->td_retval[0] = 0;
-	return 0;
+	return (0);
 }
 
 int
@@ -274,8 +268,9 @@
 	lda.fd = args->fd;
 	lda.dent = args->dent;
 	lda.count = 1;
-	return linux_getdents(td, &lda);
+	return (linux_getdents(td, &lda));
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 /*
  * Note that linux_getdents(2) and linux_getdents64(2) have the same
@@ -306,11 +301,10 @@
  * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
  */
 #define LINUX_RECLEN(namlen)						\
-    roundup((offsetof(struct l_dirent, d_name) + (namlen) + 2),		\
-    sizeof(l_ulong))
+    roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
 
 #define LINUX_RECLEN64(namlen)						\
-    roundup((offsetof(struct l_dirent64, d_name) + (namlen) + 1),	\
+    roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1,		\
     sizeof(uint64_t))
 
 #define LINUX_MAXRECLEN		max(LINUX_RECLEN(LINUX_NAME_MAX),	\
@@ -328,6 +322,7 @@
 	caddr_t outp;			/* Linux-format */
 	int resid, linuxreclen=0;	/* Linux-format */
 	caddr_t lbuf;			/* Linux-format */
+	cap_rights_t rights;
 	struct file *fp;
 	struct uio auio;
 	struct iovec aiov;
@@ -336,7 +331,7 @@
 	struct l_dirent64 *linux_dirent64;
 	int buflen, error, eofflag, nbytes, justone;
 	u_long *cookies = NULL, *cookiep;
-	int ncookies, vfslocked;
+	int ncookies;
 
 	nbytes = args->count;
 	if (nbytes == 1) {
@@ -348,7 +343,9 @@
 	} else
 		justone = 0;
 
-	if ((error = getvnode(td->td_proc->p_fd, args->fd, CAP_READ, &fp)) != 0)
+	error = getvnode(td->td_proc->p_fd, args->fd,
+	    cap_rights_init(&rights, CAP_READ), &fp);
+	if (error != 0)
 		return (error);
 
 	if ((fp->f_flag & FREAD) == 0) {
@@ -358,9 +355,7 @@
 
 	off = foffset_lock(fp, 0);
 	vp = fp->f_vnode;
-	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	if (vp->v_type != VDIR) {
-		VFS_UNLOCK_GIANT(vfslocked);
 		foffset_unlock(fp, off, 0);
 		fdrop(fp, td);
 		return (EINVAL);
@@ -369,8 +364,8 @@
 
 	buflen = max(LINUX_DIRBLKSIZ, nbytes);
 	buflen = min(buflen, MAXBSIZE);
-	buf = malloc(buflen, M_TEMP, M_WAITOK);
-	lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO);
+	buf = malloc(buflen, M_LINUX, M_WAITOK);
+	lbuf = malloc(LINUX_MAXRECLEN, M_LINUX, M_WAITOK | M_ZERO);
 	vn_lock(vp, LK_SHARED | LK_RETRY);
 
 	aiov.iov_base = buf;
@@ -516,15 +511,13 @@
 	td->td_retval[0] = nbytes - resid;
 
 out:
-	if (cookies)
-		free(cookies, M_TEMP);
+	free(cookies, M_TEMP);
 
 	VOP_UNLOCK(vp, 0);
-	VFS_UNLOCK_GIANT(vfslocked);
 	foffset_unlock(fp, off, 0);
 	fdrop(fp, td);
-	free(buf, M_TEMP);
-	free(lbuf, M_TEMP);
+	free(buf, M_LINUX);
+	free(lbuf, M_LINUX);
 	return (error);
 }
 
@@ -596,8 +589,7 @@
 		printf(ARGS(access, "%s, %d"), path, args->amode);
 #endif
 
-	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0 /* XXX */,
-	    args->amode);
+	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode);
 	LFREEPATH(path);
 
 	return (error);
@@ -921,6 +913,7 @@
 	return (error);
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
 {
@@ -938,6 +931,8 @@
 	LFREEPATH(path);
 	return (error);
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
 int
 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
 {
@@ -946,7 +941,7 @@
 		int pad;
 		off_t length;
 		} */ nuap;
-	   
+
 	nuap.fd = args->fd;
 	nuap.length = args->length;
 	return (sys_ftruncate(td, &nuap));
@@ -980,13 +975,9 @@
 linux_linkat(struct thread *td, struct linux_linkat_args *args)
 {
 	char *path, *to;
-	int error, olddfd, newdfd;
+	int error, olddfd, newdfd, follow;
 
-	/*
-	 * They really introduced flags argument which is forbidden to
-	 * use.
-	 */
-	if (args->flags != 0)
+	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
 		return (EINVAL);
 
 	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
@@ -1002,10 +993,12 @@
 #ifdef DEBUG
 	if (ldebug(linkat))
 		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
-			args->newdfd, to, args->flags);
+			args->newdfd, to, args->flag);
 #endif
 
-	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, FOLLOW);
+	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
+	    FOLLOW;
+	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
 	LFREEPATH(path);
 	LFREEPATH(to);
 	return (error);
@@ -1019,7 +1012,7 @@
 	struct fsync_args bsd;
 
 	bsd.fd = uap->fd;
-	return sys_fsync(td, &bsd);
+	return (sys_fsync(td, &bsd));
 }
 
 int
@@ -1028,6 +1021,7 @@
 	struct linux_pread_args *uap;
 {
 	struct pread_args bsd;
+	cap_rights_t rights;
 	struct vnode *vp;
 	int error;
 
@@ -1035,20 +1029,19 @@
 	bsd.buf = uap->buf;
 	bsd.nbyte = uap->nbyte;
 	bsd.offset = uap->offset;
-
 	error = sys_pread(td, &bsd);
-
 	if (error == 0) {
-   	   	/* This seems to violate POSIX but linux does it */
-		if ((error = fgetvp(td, uap->fd, CAP_READ, &vp)) != 0)
-   		   	return (error);
+		/* This seems to violate POSIX but linux does it */
+		error = fgetvp(td, uap->fd,
+		    cap_rights_init(&rights, CAP_PREAD), &vp);
+		if (error != 0)
+			return (error);
 		if (vp->v_type == VDIR) {
-   		   	vrele(vp);
+			vrele(vp);
 			return (EISDIR);
 		}
 		vrele(vp);
 	}
-
 	return (error);
 }
 
@@ -1063,18 +1056,16 @@
 	bsd.buf = uap->buf;
 	bsd.nbyte = uap->nbyte;
 	bsd.offset = uap->offset;
-	return sys_pwrite(td, &bsd);
+	return (sys_pwrite(td, &bsd));
 }
 
 int
 linux_mount(struct thread *td, struct linux_mount_args *args)
 {
-	struct ufs_args ufs;
 	char fstypename[MFSNAMELEN];
 	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
 	int error;
 	int fsflags;
-	void *fsdata;
 
 	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
 	    NULL);
@@ -1095,20 +1086,10 @@
 
 	if (strcmp(fstypename, "ext2") == 0) {
 		strcpy(fstypename, "ext2fs");
-		fsdata = &ufs;
-		ufs.fspec = mntfromname;
-#define DEFAULT_ROOTID		-2
-		ufs.export.ex_root = DEFAULT_ROOTID;
-		ufs.export.ex_flags =
-		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
 	} else if (strcmp(fstypename, "proc") == 0) {
 		strcpy(fstypename, "linprocfs");
-		fsdata = NULL;
 	} else if (strcmp(fstypename, "vfat") == 0) {
 		strcpy(fstypename, "msdosfs");
-		fsdata = NULL;
-	} else {
-		return (ENODEV);
 	}
 
 	fsflags = 0;
@@ -1128,22 +1109,15 @@
 			fsflags |= MNT_UPDATE;
 	}
 
-	if (strcmp(fstypename, "linprocfs") == 0) {
-		error = kernel_vmount(fsflags,
-			"fstype", fstypename,
-			"fspath", mntonname,
-			NULL);
-	} else if (strcmp(fstypename, "msdosfs") == 0) {
-		error = kernel_vmount(fsflags,
-			"fstype", fstypename,
-			"fspath", mntonname,
-			"from", mntfromname,
-			NULL);
-	} else
-		error = EOPNOTSUPP;
+	error = kernel_vmount(fsflags,
+	    "fstype", fstypename,
+	    "fspath", mntonname,
+	    "from", mntfromname,
+	    NULL);
 	return (error);
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
 {
@@ -1153,6 +1127,7 @@
 	args2.flags = 0;
 	return (linux_umount(td, &args2));
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 int
 linux_umount(struct thread *td, struct linux_umount_args *args)
@@ -1283,10 +1258,11 @@
 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 static int
-fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
+fcntl_common(struct thread *td, struct linux_fcntl_args *args)
 {
 	struct l_flock linux_flock;
 	struct flock bsd_flock;
+	cap_rights_t rights;
 	struct file *fp;
 	long arg;
 	int error, result;
@@ -1389,7 +1365,8 @@
 		 * significant effect for pipes (SIGIO is not delivered for
 		 * pipes under Linux-2.2.35 at least).
 		 */
-		error = fget(td, args->fd, CAP_FCNTL, &fp);
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_FCNTL), &fp);
 		if (error)
 			return (error);
 		if (fp->f_type == DTYPE_PIPE) {
@@ -1399,6 +1376,9 @@
 		fdrop(fp, td);
 
 		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
+
+	case LINUX_F_DUPFD_CLOEXEC:
+		return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
 	}
 
 	return (EINVAL);
@@ -1407,7 +1387,6 @@
 int
 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
 {
-	struct linux_fcntl64_args args64;
 
 #ifdef DEBUG
 	if (ldebug(fcntl))
@@ -1414,10 +1393,7 @@
 		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
 #endif
 
-	args64.fd = args->fd;
-	args64.cmd = args->cmd;
-	args64.arg = args->arg;
-	return (fcntl_common(td, &args64));
+	return (fcntl_common(td, args));
 }
 
 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
@@ -1426,6 +1402,7 @@
 {
 	struct l_flock64 linux_flock;
 	struct flock bsd_flock;
+	struct linux_fcntl_args fcntl_args;
 	int error;
 
 #ifdef DEBUG
@@ -1466,7 +1443,10 @@
 		    (intptr_t)&bsd_flock));
 	}
 
-	return (fcntl_common(td, args));
+	fcntl_args.fd = args->fd;
+	fcntl_args.cmd = args->cmd;
+	fcntl_args.arg = args->arg;
+	return (fcntl_common(td, &fcntl_args));
 }
 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
@@ -1491,7 +1471,7 @@
 linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
 {
 	char *path;
-	int error, dfd, follow;
+	int error, dfd, flag;
 
 	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
 		return (EINVAL);
@@ -1504,10 +1484,10 @@
 		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
 #endif
 
-	follow = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
+	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
 	    AT_SYMLINK_NOFOLLOW;
 	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
-	    follow);
+	    flag);
 	LFREEPATH(path);
 	return (error);
 }
@@ -1562,6 +1542,7 @@
 	    advice));
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
 {
@@ -1573,6 +1554,7 @@
 	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
 	    advice));
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 int
 linux_pipe(struct thread *td, struct linux_pipe_args *args)
@@ -1585,7 +1567,7 @@
 		printf(ARGS(pipe, "*"));
 #endif
 
-	error = kern_pipe(td, fildes);
+	error = kern_pipe2(td, fildes, 0);
 	if (error)
 		return (error);
 
@@ -1612,7 +1594,7 @@
 		flags |= O_NONBLOCK;
 	if ((args->flags & LINUX_O_CLOEXEC) != 0)
 		flags |= O_CLOEXEC;
-	error = do_pipe(td, fildes, flags);
+	error = kern_pipe2(td, fildes, flags);
 	if (error)
 		return (error);
 
@@ -1619,3 +1601,37 @@
 	/* XXX: Close descriptors on error. */
 	return (copyout(fildes, args->pipefds, sizeof(fildes)));
 }
+
+int
+linux_dup3(struct thread *td, struct linux_dup3_args *args)
+{
+	int cmd;
+	intptr_t newfd;
+
+	if (args->oldfd == args->newfd)
+		return (EINVAL);
+	if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
+		return (EINVAL);
+	if (args->flags & LINUX_O_CLOEXEC)
+		cmd = F_DUP2FD_CLOEXEC;
+	else
+		cmd = F_DUP2FD;
+
+	newfd = args->newfd;
+	return (kern_fcntl(td, args->oldfd, cmd, newfd));
+}
+
+int
+linux_fallocate(struct thread *td, struct linux_fallocate_args *args)
+{
+
+	/*
+	 * We emulate only posix_fallocate system call for which
+	 * mode should be 0.
+	 */
+	if (args->mode != 0)
+		return (ENOSYS);
+
+	return (kern_posix_fallocate(td, args->fd, args->offset,
+	    args->len));
+}

Modified: trunk/sys/compat/linux/linux_file.h
===================================================================
--- trunk/sys/compat/linux/linux_file.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_file.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2007 Roman Divacky
  * All rights reserved.
@@ -23,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_file.h 293542 2016-01-09 16:32:35Z dchagin $
  */
 
 #ifndef _LINUX_FILE_H_
@@ -31,6 +32,98 @@
 
 #define	LINUX_AT_FDCWD			-100
 #define	LINUX_AT_SYMLINK_NOFOLLOW	0x100
+#define	LINUX_AT_EACCESS		0x200
 #define	LINUX_AT_REMOVEDIR		0x200
+#define	LINUX_AT_SYMLINK_FOLLOW		0x400
 
+/*
+ * posix_fadvise advice
+ */
+#define	LINUX_POSIX_FADV_NORMAL		0
+#define	LINUX_POSIX_FADV_RANDOM		1
+#define	LINUX_POSIX_FADV_SEQUENTIAL    	2
+#define	LINUX_POSIX_FADV_WILLNEED      	3
+#define	LINUX_POSIX_FADV_DONTNEED      	4
+#define	LINUX_POSIX_FADV_NOREUSE       	5
+
+/*
+ * mount flags
+ */
+#define	LINUX_MS_RDONLY		0x0001
+#define	LINUX_MS_NOSUID		0x0002
+#define	LINUX_MS_NODEV		0x0004
+#define	LINUX_MS_NOEXEC		0x0008
+#define	LINUX_MS_REMOUNT	0x0020
+
+/*
+ * common open/fcntl flags
+ */
+#define	LINUX_O_RDONLY		00000000
+#define	LINUX_O_WRONLY		00000001
+#define	LINUX_O_RDWR		00000002
+#define	LINUX_O_ACCMODE		00000003
+#define	LINUX_O_CREAT		00000100
+#define	LINUX_O_EXCL		00000200
+#define	LINUX_O_NOCTTY		00000400
+#define	LINUX_O_TRUNC		00001000
+#define	LINUX_O_APPEND		00002000
+#define	LINUX_O_NONBLOCK	00004000
+#define	LINUX_O_NDELAY		LINUX_O_NONBLOCK
+#define	LINUX_O_SYNC		00010000
+#define	LINUX_FASYNC		00020000
+#define	LINUX_O_DIRECT		00040000	/* Direct disk access hint */
+#define	LINUX_O_LARGEFILE	00100000
+#define	LINUX_O_DIRECTORY	00200000	/* Must be a directory */
+#define	LINUX_O_NOFOLLOW	00400000	/* Do not follow links */
+#define	LINUX_O_NOATIME		01000000
+#define	LINUX_O_CLOEXEC		02000000
+
+#define	LINUX_F_DUPFD		0
+#define	LINUX_F_GETFD		1
+#define	LINUX_F_SETFD		2
+#define	LINUX_F_GETFL		3
+#define	LINUX_F_SETFL		4
+#ifndef LINUX_F_GETLK
+#define	LINUX_F_GETLK		5
+#define	LINUX_F_SETLK		6
+#define	LINUX_F_SETLKW		7
+#endif
+#ifndef LINUX_F_SETOWN
+#define	LINUX_F_SETOWN		8
+#define	LINUX_F_GETOWN		9
+#endif
+#ifndef LINUX_F_SETSIG
+#define	LINUX_F_SETSIG		10
+#define	LINUX_F_GETSIG		11
+#endif
+#ifndef LINUX_F_SETOWN_EX
+#define	LINUX_F_SETOWN_EX	15
+#define	LINUX_F_GETOWN_EX	16
+#define	LINUX_F_GETOWNER_UIDS	17
+#endif
+
+#define	LINUX_F_SPECIFIC_BASE	1024
+
+#define	LINUX_F_SETLEASE	(LINUX_F_SPECIFIC_BASE + 0)
+#define	LINUX_F_GETLEASE	(LINUX_F_SPECIFIC_BASE + 1)
+#define	LINUX_F_CANCELLK	(LINUX_F_SPECIFIC_BASE + 5)
+#define	LINUX_F_DUPFD_CLOEXEC	(LINUX_F_SPECIFIC_BASE + 6)
+#define	LINUX_F_NOTIFY		(LINUX_F_SPECIFIC_BASE + 2)
+#define	LINUX_F_SETPIPE_SZ	(LINUX_F_SPECIFIC_BASE + 7)
+#define	LINUX_F_GETPIPE_SZ	(LINUX_F_SPECIFIC_BASE + 8)
+
+#define	LINUX_F_GETLKP		36
+#define	LINUX_F_SETLKP		37
+#define	LINUX_F_SETLKPW		38
+
+#define	LINUX_F_OWNER_TID	0
+#define	LINUX_F_OWNER_PID	1
+#define	LINUX_F_OWNER_PGRP	2
+
+#ifndef LINUX_F_RDLCK
+#define	LINUX_F_RDLCK		0
+#define	LINUX_F_WRLCK		1
+#define	LINUX_F_UNLCK		2
+#endif
+
 #endif	/* !_LINUX_FILE_H_ */

Modified: trunk/sys/compat/linux/linux_fork.c
===================================================================
--- trunk/sys/compat/linux/linux_fork.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_fork.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2004 Tim J. Robbins
  * Copyright (c) 2002 Doug Rabson
@@ -27,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_fork.c 299705 2016-05-14 00:35:49Z pfg $");
 
 #include "opt_compat.h"
 #include "opt_kdtrace.h"
@@ -35,14 +36,21 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/imgact.h>
+#include <sys/ktr.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
+#include <sys/racct.h>
 #include <sys/sched.h>
-#include <sys/sdt.h>
+#include <sys/syscallsubr.h>
 #include <sys/sx.h>
 #include <sys/unistd.h>
+#include <sys/wait.h>
 
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
 #include <machine/../linux32/linux32_proto.h>
@@ -50,18 +58,11 @@
 #include <machine/../linux/linux.h>
 #include <machine/../linux/linux_proto.h>
 #endif
-#include <compat/linux/linux_dtrace.h>
-#include <compat/linux/linux_signal.h>
 #include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_futex.h>
+#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_util.h>
 
-/* DTrace init */
-LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
-
-/* Linuxulator-global DTrace probes */
-LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked);
-LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock);
-
-
 int
 linux_fork(struct thread *td, struct linux_fork_args *args)
 {
@@ -78,14 +79,11 @@
 	    != 0)
 		return (error);
 
-	td->td_retval[0] = p2->p_pid;
-	td->td_retval[1] = 0;
+	td2 = FIRST_THREAD_IN_PROC(p2);
 
-	error = linux_proc_init(td, td->td_retval[0], 0);
-	if (error)
-		return (error);
+	linux_proc_init(td, td2, 0);
 
-	td2 = FIRST_THREAD_IN_PROC(p2);
+	td->td_retval[0] = p2->p_pid;
 
 	/*
 	 * Make this runnable after we are finished with it.
@@ -110,23 +108,16 @@
 		printf(ARGS(vfork, ""));
 #endif
 
-	/* Exclude RFPPWAIT */
-	if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFSTOPPED, 0, &p2,
-	    NULL, 0)) != 0)
+	if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFPPWAIT | RFSTOPPED,
+	    0, &p2, NULL, 0)) != 0)
 		return (error);
 
-   	td->td_retval[0] = p2->p_pid;
+	td2 = FIRST_THREAD_IN_PROC(p2);
 
-	error = linux_proc_init(td, td->td_retval[0], 0);
-	if (error)
-		return (error);
+	linux_proc_init(td, td2, 0);
 
-	PROC_LOCK(p2);
-	p2->p_flag |= P_PPWAIT;
-	PROC_UNLOCK(p2);
+   	td->td_retval[0] = p2->p_pid;
 
-	td2 = FIRST_THREAD_IN_PROC(p2);
-
 	/*
 	 * Make this runnable after we are finished with it.
 	 */
@@ -135,17 +126,11 @@
 	sched_add(td2, SRQ_BORING);
 	thread_unlock(td2);
 
-	/* wait for the children to exit, ie. emulate vfork */
-	PROC_LOCK(p2);
-	while (p2->p_flag & P_PPWAIT)
-		cv_wait(&p2->p_pwait, &p2->p_mtx);
-	PROC_UNLOCK(p2);
-
 	return (0);
 }
 
-int
-linux_clone(struct thread *td, struct linux_clone_args *args)
+static int
+linux_clone_proc(struct thread *td, struct linux_clone_args *args)
 {
 	int error, ff = RFPROC | RFSTOPPED;
 	struct proc *p2;
@@ -163,9 +148,7 @@
 
 	exit_signal = args->flags & 0x000000ff;
 	if (LINUX_SIG_VALID(exit_signal)) {
-		if (exit_signal <= LINUX_SIGTBLSZ)
-			exit_signal =
-			    linux_to_bsd_signal[_SIG_IDX(exit_signal)];
+		exit_signal = linux_to_bsd_signal(exit_signal);
 	} else if (exit_signal != 0)
 		return (EINVAL);
 
@@ -175,7 +158,7 @@
 		ff |= RFSIGSHARE;
 	/*
 	 * XXX: In Linux, sharing of fs info (chroot/cwd/umask)
-	 * and open files is independant.  In FreeBSD, its in one
+	 * and open files is independent.  In FreeBSD, its in one
 	 * structure but in reality it does not cause any problems
 	 * because both of these flags are usually set together.
 	 */
@@ -182,53 +165,24 @@
 	if (!(args->flags & (LINUX_CLONE_FILES | LINUX_CLONE_FS)))
 		ff |= RFFDG;
 
-	/*
-	 * Attempt to detect when linux_clone(2) is used for creating
-	 * kernel threads. Unfortunately despite the existence of the
-	 * CLONE_THREAD flag, version of linuxthreads package used in
-	 * most popular distros as of beginning of 2005 doesn't make
-	 * any use of it. Therefore, this detection relies on
-	 * empirical observation that linuxthreads sets certain
-	 * combination of flags, so that we can make more or less
-	 * precise detection and notify the FreeBSD kernel that several
-	 * processes are in fact part of the same threading group, so
-	 * that special treatment is necessary for signal delivery
-	 * between those processes and fd locking.
-	 */
-	if ((args->flags & 0xffffff00) == LINUX_THREADING_FLAGS)
-		ff |= RFTHREAD;
-
 	if (args->flags & LINUX_CLONE_PARENT_SETTID)
 		if (args->parent_tidptr == NULL)
 			return (EINVAL);
 
+	if (args->flags & LINUX_CLONE_VFORK)
+		ff |= RFPPWAIT;
+
 	error = fork1(td, ff, 0, &p2, NULL, 0);
 	if (error)
 		return (error);
 
-	if (args->flags & (LINUX_CLONE_PARENT | LINUX_CLONE_THREAD)) {
-	   	sx_xlock(&proctree_lock);
-		PROC_LOCK(p2);
-		proc_reparent(p2, td->td_proc->p_pptr);
-		PROC_UNLOCK(p2);
-		sx_xunlock(&proctree_lock);
-	}
+	td2 = FIRST_THREAD_IN_PROC(p2);
 
 	/* create the emuldata */
-	error = linux_proc_init(td, p2->p_pid, args->flags);
-	/* reference it - no need to check this */
-	em = em_find(p2, EMUL_DOLOCK);
-	KASSERT(em != NULL, ("clone: emuldata not found."));
-	/* and adjust it */
+	linux_proc_init(td, td2, args->flags);
 
-	if (args->flags & LINUX_CLONE_THREAD) {
-#ifdef notyet
-	   	PROC_LOCK(p2);
-	   	p2->p_pgrp = td->td_proc->p_pgrp;
-	   	PROC_UNLOCK(p2);
-#endif
-		exit_signal = 0;
-	}
+	em = em_find(td2);
+	KASSERT(em != NULL, ("clone_proc: emuldata not found.\n"));
 
 	if (args->flags & LINUX_CLONE_CHILD_SETTID)
 		em->child_set_tid = args->child_tidptr;
@@ -240,8 +194,6 @@
 	else
 	   	em->child_clear_tid = NULL;
 
-	EMUL_UNLOCK(&emul_lock);
-
 	if (args->flags & LINUX_CLONE_PARENT_SETTID) {
 		error = copyout(&p2->p_pid, args->parent_tidptr,
 		    sizeof(p2->p_pid));
@@ -252,18 +204,28 @@
 	PROC_LOCK(p2);
 	p2->p_sigparent = exit_signal;
 	PROC_UNLOCK(p2);
-	td2 = FIRST_THREAD_IN_PROC(p2);
 	/*
 	 * In a case of stack = NULL, we are supposed to COW calling process
 	 * stack. This is what normal fork() does, so we just keep tf_rsp arg
 	 * intact.
 	 */
-	if (args->stack)
-		linux_set_upcall_kse(td2, PTROUT(args->stack));
+	linux_set_upcall_kse(td2, PTROUT(args->stack));
 
 	if (args->flags & LINUX_CLONE_SETTLS)
 		linux_set_cloned_tls(td2, args->tls);
 
+	/*
+	 * If CLONE_PARENT is set, then the parent of the new process will be 
+	 * the same as that of the calling process.
+	 */
+	if (args->flags & LINUX_CLONE_PARENT) {
+		sx_xlock(&proctree_lock);
+		PROC_LOCK(p2);
+		proc_reparent(p2, td->td_proc->p_pptr);
+		PROC_UNLOCK(p2);
+		sx_xunlock(&proctree_lock);
+	}
+
 #ifdef DEBUG
 	if (ldebug(clone))
 		printf(LMSG("clone: successful rfork to %d, "
@@ -270,11 +232,6 @@
 		    "stack %p sig = %d"), (int)p2->p_pid, args->stack,
 		    exit_signal);
 #endif
-	if (args->flags & LINUX_CLONE_VFORK) {
-	   	PROC_LOCK(p2);
-	   	p2->p_flag |= P_PPWAIT;
-	   	PROC_UNLOCK(p2);
-	}
 
 	/*
 	 * Make this runnable after we are finished with it.
@@ -285,15 +242,233 @@
 	thread_unlock(td2);
 
 	td->td_retval[0] = p2->p_pid;
-	td->td_retval[1] = 0;
 
-	if (args->flags & LINUX_CLONE_VFORK) {
-		/* wait for the children to exit, ie. emulate vfork */
-		PROC_LOCK(p2);
-		while (p2->p_flag & P_PPWAIT)
-			cv_wait(&p2->p_pwait, &p2->p_mtx);
-		PROC_UNLOCK(p2);
+	return (0);
+}
+
+static int
+linux_clone_thread(struct thread *td, struct linux_clone_args *args)
+{
+	struct linux_emuldata *em;
+	struct thread *newtd;
+	struct proc *p;
+	int error;
+
+#ifdef DEBUG
+	if (ldebug(clone)) {
+		printf(ARGS(clone, "thread: flags %x, stack %p, parent tid: %p, "
+		    "child tid: %p"), (unsigned)args->flags,
+		    args->stack, args->parent_tidptr, args->child_tidptr);
 	}
+#endif
 
+	LINUX_CTR4(clone_thread, "thread(%d) flags %x ptid %p ctid %p",
+	    td->td_tid, (unsigned)args->flags,
+	    args->parent_tidptr, args->child_tidptr);
+
+	if (args->flags & LINUX_CLONE_PARENT_SETTID)
+		if (args->parent_tidptr == NULL)
+			return (EINVAL);
+
+	/* Threads should be created with own stack */
+	if (args->stack == NULL)
+		return (EINVAL);
+
+	p = td->td_proc;
+
+#ifdef RACCT
+	if (racct_enable) {
+		PROC_LOCK(p);
+		error = racct_add(p, RACCT_NTHR, 1);
+		PROC_UNLOCK(p);
+		if (error != 0)
+			return (EPROCLIM);
+	}
+#endif
+
+	/* Initialize our td */
+	error = kern_thr_alloc(p, 0, &newtd);
+	if (error)
+		goto fail;
+														
+	cpu_set_upcall(newtd, td);
+
+	bzero(&newtd->td_startzero,
+	    __rangeof(struct thread, td_startzero, td_endzero));
+	bcopy(&td->td_startcopy, &newtd->td_startcopy,
+	    __rangeof(struct thread, td_startcopy, td_endcopy));
+
+	newtd->td_proc = p;
+	newtd->td_ucred = crhold(td->td_ucred);
+
+	/* create the emuldata */
+	linux_proc_init(td, newtd, args->flags);
+
+	em = em_find(newtd);
+	KASSERT(em != NULL, ("clone_thread: emuldata not found.\n"));
+
+	if (args->flags & LINUX_CLONE_SETTLS)
+		linux_set_cloned_tls(newtd, args->tls);
+
+	if (args->flags & LINUX_CLONE_CHILD_SETTID)
+		em->child_set_tid = args->child_tidptr;
+	else
+	   	em->child_set_tid = NULL;
+
+	if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
+		em->child_clear_tid = args->child_tidptr;
+	else
+	   	em->child_clear_tid = NULL;
+
+	cpu_thread_clean(newtd);
+	
+	linux_set_upcall_kse(newtd, PTROUT(args->stack));
+
+	PROC_LOCK(p);
+	p->p_flag |= P_HADTHREADS;
+	bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
+
+	if (args->flags & LINUX_CLONE_PARENT)
+		thread_link(newtd, p->p_pptr);
+	else
+		thread_link(newtd, p);
+
+	thread_lock(td);
+	/* let the scheduler know about these things. */
+	sched_fork_thread(td, newtd);
+	thread_unlock(td);
+	if (P_SHOULDSTOP(p))
+		newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
+	PROC_UNLOCK(p);
+
+	tidhash_add(newtd);
+
+#ifdef DEBUG
+	if (ldebug(clone))
+		printf(ARGS(clone, "successful clone to %d, stack %p"),
+		(int)newtd->td_tid, args->stack);
+#endif
+
+	LINUX_CTR2(clone_thread, "thread(%d) successful clone to %d",
+	    td->td_tid, newtd->td_tid);
+
+	if (args->flags & LINUX_CLONE_PARENT_SETTID) {
+		error = copyout(&newtd->td_tid, args->parent_tidptr,
+		    sizeof(newtd->td_tid));
+		if (error)
+			printf(LMSG("clone_thread: copyout failed!"));
+	}
+
+	/*
+	 * Make this runnable after we are finished with it.
+	 */
+	thread_lock(newtd);
+	TD_SET_CAN_RUN(newtd);
+	sched_add(newtd, SRQ_BORING);
+	thread_unlock(newtd);
+
+	td->td_retval[0] = newtd->td_tid;
+
 	return (0);
+
+fail:
+#ifdef RACCT
+	if (racct_enable) {
+		PROC_LOCK(p);
+		racct_sub(p, RACCT_NTHR, 1);
+		PROC_UNLOCK(p);
+	}
+#endif
+	return (error);
 }
+
+int
+linux_clone(struct thread *td, struct linux_clone_args *args)
+{
+
+	if (args->flags & LINUX_CLONE_THREAD)
+		return (linux_clone_thread(td, args));
+	else
+		return (linux_clone_proc(td, args));
+}
+
+int
+linux_exit(struct thread *td, struct linux_exit_args *args)
+{
+	struct linux_emuldata *em;
+
+	em = em_find(td);
+	KASSERT(em != NULL, ("exit: emuldata not found.\n"));
+
+	LINUX_CTR2(exit, "thread(%d) (%d)", em->em_tid, args->rval);
+
+	linux_thread_detach(td);
+
+	/*
+	 * XXX. When the last two threads of a process
+	 * exit via pthread_exit() try thr_exit() first.
+	 */
+	kern_thr_exit(td);
+	exit1(td, W_EXITCODE(args->rval, 0));
+		/* NOTREACHED */
+}
+
+int
+linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
+{
+	struct linux_emuldata *em;
+
+	em = em_find(td);
+	KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
+
+	em->child_clear_tid = args->tidptr;
+
+	td->td_retval[0] = em->em_tid;
+
+	LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d",
+	    em->em_tid, args->tidptr, td->td_retval[0]);
+
+	return (0);
+}
+
+void
+linux_thread_detach(struct thread *td)
+{
+	struct linux_sys_futex_args cup;
+	struct linux_emuldata *em;
+	int *child_clear_tid;
+	int error;
+
+	em = em_find(td);
+	KASSERT(em != NULL, ("thread_detach: emuldata not found.\n"));
+
+	LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid);
+
+	release_futexes(td, em);
+
+	child_clear_tid = em->child_clear_tid;
+
+	if (child_clear_tid != NULL) {
+
+		LINUX_CTR2(thread_detach, "thread(%d) %p",
+		    em->em_tid, child_clear_tid);
+	
+		error = suword32(child_clear_tid, 0);
+		if (error != 0)
+			return;
+
+		cup.uaddr = child_clear_tid;
+		cup.op = LINUX_FUTEX_WAKE;
+		cup.val = 1;		/* wake one */
+		cup.timeout = NULL;
+		cup.uaddr2 = NULL;
+		cup.val3 = 0;
+		error = linux_sys_futex(td, &cup);
+		/*
+		 * this cannot happen at the moment and if this happens it
+		 * probably means there is a user space bug
+		 */
+		if (error != 0)
+			linux_msg(td, "futex stuff in thread_detach failed.");
+	}
+}

Modified: trunk/sys/compat/linux/linux_futex.c
===================================================================
--- trunk/sys/compat/linux/linux_futex.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_futex.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,7 +1,10 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $ */
 
 /*-
- * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
+ * Copyright (c) 2009-2016 Dmitry Chagin
+ * Copyright (c) 2005 Emmanuel Dreyfus
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_futex.c 301426 2016-06-05 06:06:55Z dchagin $");
 #if 0
 __KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $");
 #endif
@@ -53,9 +56,10 @@
 #include <sys/queue.h>
 #include <sys/sched.h>
 #include <sys/sdt.h>
-#include <sys/sx.h>
 #include <sys/umtx.h>
 
+#include <vm/vm_extern.h>
+
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
 #include <machine/../linux32/linux32_proto.h>
@@ -66,15 +70,12 @@
 #include <compat/linux/linux_dtrace.h>
 #include <compat/linux/linux_emul.h>
 #include <compat/linux/linux_futex.h>
+#include <compat/linux/linux_timer.h>
 #include <compat/linux/linux_util.h>
 
 /* DTrace init */
 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
 
-/* Linuxulator-global DTrace probes */
-LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked);
-LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock);
-
 /**
  * Futex part for the special DTrace module "locks".
  */
@@ -110,7 +111,7 @@
 LIN_SDT_PROBE_DEFINE0(futex, futex_get, error);
 LIN_SDT_PROBE_DEFINE1(futex, futex_get, return, "int");
 LIN_SDT_PROBE_DEFINE3(futex, futex_sleep, entry, "struct futex *",
-    "struct waiting_proc **", "int");
+    "struct waiting_proc **", "struct timespec *");
 LIN_SDT_PROBE_DEFINE5(futex, futex_sleep, requeue_error, "int", "uint32_t *",
     "struct waiting_proc *", "uint32_t *", "uint32_t");
 LIN_SDT_PROBE_DEFINE3(futex, futex_sleep, sleep_error, "int", "uint32_t *",
@@ -119,7 +120,7 @@
 LIN_SDT_PROBE_DEFINE3(futex, futex_wake, entry, "struct futex *", "int",
     "uint32_t");
 LIN_SDT_PROBE_DEFINE3(futex, futex_wake, iterate, "uint32_t",
-    "struct waiting_proc *", "uin32_t");
+    "struct waiting_proc *", "uint32_t");
 LIN_SDT_PROBE_DEFINE1(futex, futex_wake, wakeup, "struct waiting_proc *");
 LIN_SDT_PROBE_DEFINE1(futex, futex_wake, return, "int");
 LIN_SDT_PROBE_DEFINE4(futex, futex_requeue, entry, "struct futex *", "int",
@@ -129,9 +130,7 @@
     "struct waiting_proc *", "uint32_t");
 LIN_SDT_PROBE_DEFINE1(futex, futex_requeue, return, "int");
 LIN_SDT_PROBE_DEFINE4(futex, futex_wait, entry, "struct futex *",
-    "struct waiting_proc **", "struct l_timespec *", "uint32_t");
-LIN_SDT_PROBE_DEFINE1(futex, futex_wait, copyin_error, "int");
-LIN_SDT_PROBE_DEFINE1(futex, futex_wait, itimerfix_error, "int");
+    "struct waiting_proc **", "struct timespec *", "uint32_t");
 LIN_SDT_PROBE_DEFINE1(futex, futex_wait, sleep_error, "int");
 LIN_SDT_PROBE_DEFINE1(futex, futex_wait, return, "int");
 LIN_SDT_PROBE_DEFINE3(futex, futex_atomic_op, entry, "struct thread *",
@@ -176,21 +175,20 @@
     "struct linux_get_robust_list_args *");
 LIN_SDT_PROBE_DEFINE1(futex, linux_get_robust_list, copyout_error, "int");
 LIN_SDT_PROBE_DEFINE1(futex, linux_get_robust_list, return, "int");
-LIN_SDT_PROBE_DEFINE3(futex, handle_futex_death, entry, "struct proc *",
-    "uint32_t *", "int");
+LIN_SDT_PROBE_DEFINE3(futex, handle_futex_death, entry,
+    "struct linux_emuldata *", "uint32_t *", "unsigned int");
 LIN_SDT_PROBE_DEFINE1(futex, handle_futex_death, copyin_error, "int");
 LIN_SDT_PROBE_DEFINE1(futex, handle_futex_death, return, "int");
 LIN_SDT_PROBE_DEFINE3(futex, fetch_robust_entry, entry,
-    "struct linux_robust_list **", "struct linux_robust_list **", "int *");
+    "struct linux_robust_list **", "struct linux_robust_list **",
+    "unsigned int *");
 LIN_SDT_PROBE_DEFINE1(futex, fetch_robust_entry, copyin_error, "int");
 LIN_SDT_PROBE_DEFINE1(futex, fetch_robust_entry, return, "int");
-LIN_SDT_PROBE_DEFINE1(futex, release_futexes, entry, "struct proc *");
+LIN_SDT_PROBE_DEFINE2(futex, release_futexes, entry, "struct thread *",
+    "struct linux_emuldata *");
 LIN_SDT_PROBE_DEFINE1(futex, release_futexes, copyin_error, "int");
 LIN_SDT_PROBE_DEFINE0(futex, release_futexes, return);
 
-static MALLOC_DEFINE(M_FUTEX, "futex", "Linux futexes");
-static MALLOC_DEFINE(M_FUTEX_WP, "futex wp", "Linux futexes wp");
-
 struct futex;
 
 struct waiting_proc {
@@ -200,7 +198,7 @@
 };
 
 struct futex {
-	struct sx	f_lck;
+	struct mtx	f_lck;
 	uint32_t	*f_uaddr;	/* user-supplied value, for debug */
 	struct umtx_key	f_key;
 	uint32_t	f_refcount;
@@ -211,11 +209,12 @@
 
 struct futex_list futex_list;
 
-#define FUTEX_LOCK(f)		sx_xlock(&(f)->f_lck)
-#define FUTEX_UNLOCK(f)		sx_xunlock(&(f)->f_lck)
+#define FUTEX_LOCK(f)		mtx_lock(&(f)->f_lck)
+#define FUTEX_LOCKED(f)		mtx_owned(&(f)->f_lck)
+#define FUTEX_UNLOCK(f)		mtx_unlock(&(f)->f_lck)
 #define FUTEX_INIT(f)		do { \
-				    sx_init_flags(&(f)->f_lck, "ftlk", \
-					SX_DUPOK); \
+				    mtx_init(&(f)->f_lck, "ftlk", NULL, \
+					MTX_DUPOK); \
 				    LIN_SDT_PROBE1(futex, futex, create, \
 					&(f)->f_lck); \
 				} while (0)
@@ -222,9 +221,10 @@
 #define FUTEX_DESTROY(f)	do { \
 				    LIN_SDT_PROBE1(futex, futex, destroy, \
 					&(f)->f_lck); \
-				    sx_destroy(&(f)->f_lck); \
+				    mtx_destroy(&(f)->f_lck); \
 				} while (0)
-#define FUTEX_ASSERT_LOCKED(f)	sx_assert(&(f)->f_lck, SA_XLOCKED)
+#define FUTEX_ASSERT_LOCKED(f)	mtx_assert(&(f)->f_lck, MA_OWNED)
+#define FUTEX_ASSERT_UNLOCKED(f) mtx_assert(&(f)->f_lck, MA_NOTOWNED)
 
 struct mtx futex_mtx;			/* protects the futex list */
 #define FUTEXES_LOCK		do { \
@@ -243,6 +243,7 @@
 #define FUTEX_DONTCREATE	0x2	/* don't create futex if not exists */
 #define FUTEX_DONTEXISTS	0x4	/* return EINVAL if futex exists */
 #define	FUTEX_SHARED		0x8	/* shared futex */
+#define	FUTEX_DONTLOCK		0x10	/* don't lock futex */
 
 /* wp_flags */
 #define FUTEX_WP_REQUEUED	0x1	/* wp requeued - wp moved from wp_list
@@ -253,6 +254,25 @@
 					 * wp_list to prevent double wakeup.
 					 */
 
+static void futex_put(struct futex *, struct waiting_proc *);
+static int futex_get0(uint32_t *, struct futex **f, uint32_t);
+static int futex_get(uint32_t *, struct waiting_proc **, struct futex **,
+    uint32_t);
+static int futex_sleep(struct futex *, struct waiting_proc *, struct timespec *);
+static int futex_wake(struct futex *, int, uint32_t);
+static int futex_requeue(struct futex *, int, struct futex *, int);
+static int futex_copyin_timeout(int, struct l_timespec *, int,
+    struct timespec *);
+static int futex_wait(struct futex *, struct waiting_proc *, struct timespec *,
+    uint32_t);
+static void futex_lock(struct futex *);
+static void futex_unlock(struct futex *);
+static int futex_atomic_op(struct thread *, int, uint32_t *);
+static int handle_futex_death(struct linux_emuldata *, uint32_t *,
+    unsigned int);
+static int fetch_robust_entry(struct linux_robust_list **,
+    struct linux_robust_list **, unsigned int *);
+
 /* support.s */
 int futex_xchgl(int oparg, uint32_t *uaddr, int *oldval);
 int futex_addl(int oparg, uint32_t *uaddr, int *oldval);
@@ -260,12 +280,40 @@
 int futex_andl(int oparg, uint32_t *uaddr, int *oldval);
 int futex_xorl(int oparg, uint32_t *uaddr, int *oldval);
 
+
+static int
+futex_copyin_timeout(int op, struct l_timespec *luts, int clockrt,
+    struct timespec *ts)
+{
+	struct l_timespec lts;
+	struct timespec kts;
+	int error;
+
+	error = copyin(luts, &lts, sizeof(lts));
+	if (error)
+		return (error);
+
+	error = linux_to_native_timespec(ts, &lts);
+	if (error)
+		return (error);
+	if (ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000)
+		return (EINVAL);
+
+	if (clockrt) {
+		nanotime(&kts);
+		timespecsub(ts, &kts);
+	} else if (op == LINUX_FUTEX_WAIT_BITSET) {
+		nanouptime(&kts);
+		timespecsub(ts, &kts);
+	}
+	return (error);
+}
+
 static void
 futex_put(struct futex *f, struct waiting_proc *wp)
 {
 	LIN_SDT_PROBE2(futex, futex_put, entry, f, wp);
 
-	FUTEX_ASSERT_LOCKED(f);
 	if (wp != NULL) {
 		if ((wp->wp_flags & FUTEX_WP_REMOVED) == 0)
 			TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
@@ -276,7 +324,8 @@
 	if (--f->f_refcount == 0) {
 		LIST_REMOVE(f, f_list);
 		FUTEXES_UNLOCK;
-		FUTEX_UNLOCK(f);
+		if (FUTEX_LOCKED(f))
+			futex_unlock(f);
 
 		LIN_SDT_PROBE3(futex, futex_put, destroy, f->f_uaddr,
 		    f->f_refcount, f->f_key.shared);
@@ -295,7 +344,8 @@
 	LINUX_CTR3(sys_futex, "futex_put uaddr %p ref %d shared %d",
 	    f->f_uaddr, f->f_refcount, f->f_key.shared);
 	FUTEXES_UNLOCK;
-	FUTEX_UNLOCK(f);
+	if (FUTEX_LOCKED(f))
+		futex_unlock(f);
 
 	LIN_SDT_PROBE0(futex, futex_put, return);
 }
@@ -323,7 +373,8 @@
 	LIST_FOREACH(f, &futex_list, f_list) {
 		if (umtx_key_match(&f->f_key, &key)) {
 			if (tmpf != NULL) {
-				FUTEX_UNLOCK(tmpf);
+				if (FUTEX_LOCKED(tmpf))
+					futex_unlock(tmpf);
 				FUTEX_DESTROY(tmpf);
 				free(tmpf, M_FUTEX);
 			}
@@ -344,7 +395,8 @@
 			FUTEXES_UNLOCK;
 			umtx_key_release(&key);
 
-			FUTEX_LOCK(f);
+			if ((flags & FUTEX_DONTLOCK) == 0)
+				futex_lock(f);
 			*newf = f;
 			LIN_SDT_PROBE3(futex, futex_get0, shared, uaddr,
 			    f->f_refcount, f->f_key.shared);
@@ -380,7 +432,8 @@
 		 * Lock the new futex before an insert into the futex_list
 		 * to prevent futex usage by other.
 		 */
-		FUTEX_LOCK(tmpf);
+		if ((flags & FUTEX_DONTLOCK) == 0)
+			futex_lock(tmpf);
 		goto retry;
 	}
 
@@ -428,16 +481,56 @@
 	return (error);
 }
 
+static inline void
+futex_lock(struct futex *f)
+{
+
+	LINUX_CTR3(sys_futex, "futex_lock uaddr %p ref %d shared %d",
+	    f->f_uaddr, f->f_refcount, f->f_key.shared);
+	FUTEX_ASSERT_UNLOCKED(f);
+	FUTEX_LOCK(f);
+}
+
+static inline void
+futex_unlock(struct futex *f)
+{
+
+	LINUX_CTR3(sys_futex, "futex_unlock uaddr %p ref %d shared %d",
+	    f->f_uaddr, f->f_refcount, f->f_key.shared);
+	FUTEX_ASSERT_LOCKED(f);
+	FUTEX_UNLOCK(f);
+}
+
 static int
-futex_sleep(struct futex *f, struct waiting_proc *wp, int timeout)
+futex_sleep(struct futex *f, struct waiting_proc *wp, struct timespec *ts)
 {
+	struct timespec uts;
+	sbintime_t sbt, prec, tmp;
+	time_t over;
 	int error;
 
 	FUTEX_ASSERT_LOCKED(f);
-	LIN_SDT_PROBE3(futex, futex_sleep, entry, f, wp, timeout);
-	LINUX_CTR4(sys_futex, "futex_sleep enter uaddr %p wp %p timo %d ref %d",
-	    f->f_uaddr, wp, timeout, f->f_refcount);
-	error = sx_sleep(wp, &f->f_lck, PCATCH, "futex", timeout);
+	if (ts != NULL) {
+		uts = *ts;
+		if (uts.tv_sec > INT32_MAX / 2) {
+			over = uts.tv_sec - INT32_MAX / 2;
+			uts.tv_sec -= over;
+		}
+		tmp = tstosbt(uts);
+		if (TIMESEL(&sbt, tmp))
+			sbt += tc_tick_sbt;
+		sbt += tmp;
+		prec = tmp;
+		prec >>= tc_precexp;
+	} else {
+		sbt = 0;
+		prec = 0;
+	}
+	LIN_SDT_PROBE3(futex, futex_sleep, entry, f, wp, sbt);
+	LINUX_CTR4(sys_futex, "futex_sleep enter uaddr %p wp %p timo %ld ref %d",
+	    f->f_uaddr, wp, sbt, f->f_refcount);
+
+	error = msleep_sbt(wp, &f->f_lck, PCATCH, "futex", sbt, prec, C_ABSOLUTE);
 	if (wp->wp_flags & FUTEX_WP_REQUEUED) {
 		KASSERT(f != wp->wp_futex, ("futex != wp_futex"));
 
@@ -453,7 +546,7 @@
 		    wp->wp_futex->f_refcount);
 		futex_put(f, NULL);
 		f = wp->wp_futex;
-		FUTEX_LOCK(f);
+		futex_lock(f);
 	} else {
 		if (error) {
 			LIN_SDT_PROBE3(futex, futex_sleep, sleep_error, error,
@@ -555,12 +648,9 @@
 }
 
 static int
-futex_wait(struct futex *f, struct waiting_proc *wp, struct l_timespec *ts,
+futex_wait(struct futex *f, struct waiting_proc *wp, struct timespec *ts,
     uint32_t bitset)
 {
-	struct l_timespec timeout;
-	struct timeval tv;
-	int timeout_hz;
 	int error;
 
 	LIN_SDT_PROBE4(futex, futex_wait, entry, f, wp, ts, bitset);
@@ -571,30 +661,9 @@
 	}
 
 	f->f_bitset = bitset;
-
-	if (ts != NULL) {
-		error = copyin(ts, &timeout, sizeof(timeout));
-		if (error) {
-			LIN_SDT_PROBE1(futex, futex_wait, copyin_error, error);
-			LIN_SDT_PROBE1(futex, futex_wait, return, error);
-			return (error);
-		}
-		TIMESPEC_TO_TIMEVAL(&tv, &timeout);
-		error = itimerfix(&tv);
-		if (error) {
-			LIN_SDT_PROBE1(futex, futex_wait, itimerfix_error,
-			    error);
-			LIN_SDT_PROBE1(futex, futex_wait, return, error);
-			return (error);
-		}
-		timeout_hz = tvtohz(&tv);
-	} else
-		timeout_hz = 0;
-
-	error = futex_sleep(f, wp, timeout_hz);
-	if (error) {
+	error = futex_sleep(f, wp, ts);
+	if (error)
 		LIN_SDT_PROBE1(futex, futex_wait, sleep_error, error);
-	}
 	if (error == EWOULDBLOCK)
 		error = ETIMEDOUT;
 
@@ -618,7 +687,7 @@
 
 	LIN_SDT_PROBE4(futex, futex_atomic_op, decoded_op, op, cmp, oparg,
 	    cmparg);
-	
+
 	/* XXX: Linux verifies access here and returns EFAULT */
 	LIN_SDT_PROBE0(futex, futex_atomic_op, missing_access_check);
 
@@ -680,12 +749,13 @@
 int
 linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
 {
-	int clockrt, nrwake, op_ret, ret, val;
-	struct linux_emuldata *em;
+	int clockrt, nrwake, op_ret, ret;
+	struct linux_pemuldata *pem;
 	struct waiting_proc *wp;
 	struct futex *f, *f2;
-	int error;
-	uint32_t flags;
+	struct timespec uts, *ts;
+	int error, save;
+	uint32_t flags, val;
 
 	LIN_SDT_PROBE2(futex, linux_sys_futex, entry, td, args);
 
@@ -722,9 +792,23 @@
 	case LINUX_FUTEX_WAIT_BITSET:
 		LIN_SDT_PROBE3(futex, linux_sys_futex, debug_wait, args->uaddr,
 		    args->val, args->val3);
-		LINUX_CTR3(sys_futex, "WAIT uaddr %p val %d val3 %d",
+		LINUX_CTR3(sys_futex, "WAIT uaddr %p val 0x%x bitset 0x%x",
 		    args->uaddr, args->val, args->val3);
 
+		if (args->timeout != NULL) {
+			error = futex_copyin_timeout(args->op, args->timeout,
+			    clockrt, &uts);
+			if (error) {
+				LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error,
+				    error);
+				LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+				return (error);
+			}
+			ts = &uts;
+		} else
+			ts = NULL;
+
+retry0:
 		error = futex_get(args->uaddr, &wp, &f,
 		    flags | FUTEX_CREATE_WP);
 		if (error) {
@@ -732,14 +816,16 @@
 			return (error);
 		}
 
-		error = copyin(args->uaddr, &val, sizeof(val));
+		error = copyin_nofault(args->uaddr, &val, sizeof(val));
 		if (error) {
+			futex_put(f, wp);
+			error = copyin(args->uaddr, &val, sizeof(val));
+			if (error == 0)
+				goto retry0;
 			LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error,
 			    error);
 			LINUX_CTR1(sys_futex, "WAIT copyin failed %d",
 			    error);
-			futex_put(f, wp);
-
 			LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
 			return (error);
 		}
@@ -747,9 +833,9 @@
 			LIN_SDT_PROBE4(futex, linux_sys_futex,
 			    debug_wait_value_neq, args->uaddr, args->val, val,
 			    args->val3);
-			LINUX_CTR4(sys_futex,
-			    "WAIT uaddr %p val %d != uval %d val3 %d",
-			    args->uaddr, args->val, val, args->val3);
+			LINUX_CTR3(sys_futex,
+			    "WAIT uaddr %p val 0x%x != uval 0x%x",
+			    args->uaddr, args->val, val);
 			futex_put(f, wp);
 
 			LIN_SDT_PROBE1(futex, linux_sys_futex, return,
@@ -757,7 +843,7 @@
 			return (EWOULDBLOCK);
 		}
 
-		error = futex_wait(f, wp, args->timeout, args->val3);
+		error = futex_wait(f, wp, ts, args->val3);
 		break;
 
 	case LINUX_FUTEX_WAKE:
@@ -767,7 +853,7 @@
 	case LINUX_FUTEX_WAKE_BITSET:
 		LIN_SDT_PROBE3(futex, linux_sys_futex, debug_wake, args->uaddr,
 		    args->val, args->val3);
-		LINUX_CTR3(sys_futex, "WAKE uaddr %p val % d val3 %d",
+		LINUX_CTR3(sys_futex, "WAKE uaddr %p nrwake 0x%x bitset 0x%x",
 		    args->uaddr, args->val, args->val3);
 
 		error = futex_get(args->uaddr, NULL, &f,
@@ -792,9 +878,9 @@
 		    args->uaddr, args->val, args->val3, args->uaddr2,
 		    args->timeout);
 		LINUX_CTR5(sys_futex, "CMP_REQUEUE uaddr %p "
-		    "val %d val3 %d uaddr2 %p val2 %d",
+		    "nrwake 0x%x uval 0x%x uaddr2 %p nrequeue 0x%x",
 		    args->uaddr, args->val, args->val3, args->uaddr2,
-		    (int)(unsigned long)args->timeout);
+		    args->timeout);
 
 		/*
 		 * Linux allows this, we would not, it is an incorrect
@@ -807,7 +893,8 @@
 			return (EINVAL);
 		}
 
-		error = futex_get(args->uaddr, NULL, &f, flags);
+retry1:
+		error = futex_get(args->uaddr, NULL, &f, flags | FUTEX_DONTLOCK);
 		if (error) {
 			LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
 			return (error);
@@ -821,7 +908,7 @@
 		 * returned by FUTEX_CMP_REQUEUE.
 		 */
 		error = futex_get(args->uaddr2, NULL, &f2,
-		    flags | FUTEX_DONTEXISTS);
+		    flags | FUTEX_DONTEXISTS | FUTEX_DONTLOCK);
 		if (error) {
 			futex_put(f, NULL);
 
@@ -828,15 +915,19 @@
 			LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
 			return (error);
 		}
-		error = copyin(args->uaddr, &val, sizeof(val));
+		futex_lock(f);
+		futex_lock(f2);
+		error = copyin_nofault(args->uaddr, &val, sizeof(val));
 		if (error) {
+			futex_put(f2, NULL);
+			futex_put(f, NULL);
+			error = copyin(args->uaddr, &val, sizeof(val));
+			if (error == 0)
+				goto retry1;
 			LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error,
 			    error);
 			LINUX_CTR1(sys_futex, "CMP_REQUEUE copyin failed %d",
 			    error);
-			futex_put(f2, NULL);
-			futex_put(f, NULL);
-
 			LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
 			return (error);
 		}
@@ -843,7 +934,7 @@
 		if (val != args->val3) {
 			LIN_SDT_PROBE2(futex, linux_sys_futex,
 			    debug_cmp_requeue_value_neq, args->val, val);
-			LINUX_CTR2(sys_futex, "CMP_REQUEUE val %d != uval %d",
+			LINUX_CTR2(sys_futex, "CMP_REQUEUE val 0x%x != uval 0x%x",
 			    args->val, val);
 			futex_put(f2, NULL);
 			futex_put(f, NULL);
@@ -862,11 +953,12 @@
 		LIN_SDT_PROBE5(futex, linux_sys_futex, debug_wake_op,
 		    args->uaddr, args->op, args->val, args->uaddr2, args->val3);
 		LINUX_CTR5(sys_futex, "WAKE_OP "
-		    "uaddr %p op %d val %x uaddr2 %p val3 %x",
-		    args->uaddr, args->op, args->val,
-		    args->uaddr2, args->val3);
+		    "uaddr %p nrwake 0x%x uaddr2 %p op 0x%x nrwake2 0x%x",
+		    args->uaddr, args->val, args->uaddr2, args->val3,
+		    args->timeout);
 
-		error = futex_get(args->uaddr, NULL, &f, flags);
+retry2:
+		error = futex_get(args->uaddr, NULL, &f, flags | FUTEX_DONTLOCK);
 		if (error) {
 			LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
 			return (error);
@@ -873,7 +965,8 @@
 		}
 
 		if (args->uaddr != args->uaddr2)
-			error = futex_get(args->uaddr2, NULL, &f2, flags);
+			error = futex_get(args->uaddr2, NULL, &f2,
+			    flags | FUTEX_DONTLOCK);
 		if (error) {
 			futex_put(f, NULL);
 
@@ -880,33 +973,29 @@
 			LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
 			return (error);
 		}
+		futex_lock(f);
+		futex_lock(f2);
 
 		/*
 		 * This function returns positive number as results and
 		 * negative as errors
 		 */
+		save = vm_fault_disable_pagefaults();
 		op_ret = futex_atomic_op(td, args->val3, args->uaddr2);
+		vm_fault_enable_pagefaults(save);
 
+		LINUX_CTR2(sys_futex, "WAKE_OP atomic_op uaddr %p ret 0x%x",
+		    args->uaddr, op_ret);
+
 		if (op_ret < 0) {
-			/* XXX: We don't handle the EFAULT yet. */
-			if (op_ret != -EFAULT) {
-				if (f2 != NULL)
-					futex_put(f2, NULL);
-				futex_put(f, NULL);
-
-				LIN_SDT_PROBE1(futex, linux_sys_futex, return,
-				    -op_ret);
-				return (-op_ret);
-			} else {
-				LIN_SDT_PROBE0(futex, linux_sys_futex,
-				    unhandled_efault);
-			}
 			if (f2 != NULL)
 				futex_put(f2, NULL);
 			futex_put(f, NULL);
-
-			LIN_SDT_PROBE1(futex, linux_sys_futex, return, EFAULT);
-			return (EFAULT);
+			error = copyin(args->uaddr2, &val, sizeof(val));
+			if (error == 0)
+				goto retry2;
+			LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+			return (error);
 		}
 
 		ret = futex_wake(f, args->val, args->val3);
@@ -930,34 +1019,47 @@
 
 	case LINUX_FUTEX_LOCK_PI:
 		/* not yet implemented */
-		linux_msg(td,
-			  "linux_sys_futex: "
-			  "op LINUX_FUTEX_LOCK_PI not implemented\n");
-		LIN_SDT_PROBE0(futex, linux_sys_futex, unimplemented_lock_pi);
+		pem = pem_find(td->td_proc);
+		if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+			linux_msg(td,
+				  "linux_sys_futex: "
+				  "unsupported futex_pi op\n");
+			pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+			LIN_SDT_PROBE0(futex, linux_sys_futex,
+			    unimplemented_lock_pi);
+		}
 		LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
 		return (ENOSYS);
 
 	case LINUX_FUTEX_UNLOCK_PI:
 		/* not yet implemented */
-		linux_msg(td,
-			  "linux_sys_futex: "
-			  "op LINUX_FUTEX_UNLOCK_PI not implemented\n");
-		LIN_SDT_PROBE0(futex, linux_sys_futex, unimplemented_unlock_pi);
+		pem = pem_find(td->td_proc);
+		if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+			linux_msg(td,
+				  "linux_sys_futex: "
+				  "unsupported futex_pi op\n");
+			pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+			LIN_SDT_PROBE0(futex, linux_sys_futex,
+			    unimplemented_unlock_pi);
+		}
 		LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
 		return (ENOSYS);
 
 	case LINUX_FUTEX_TRYLOCK_PI:
 		/* not yet implemented */
-		linux_msg(td,
-			  "linux_sys_futex: "
-			  "op LINUX_FUTEX_TRYLOCK_PI not implemented\n");
-		LIN_SDT_PROBE0(futex, linux_sys_futex,
-		    unimplemented_trylock_pi);
+		pem = pem_find(td->td_proc);
+		if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+			linux_msg(td,
+				  "linux_sys_futex: "
+				  "unsupported futex_pi op\n");
+			pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+			LIN_SDT_PROBE0(futex, linux_sys_futex,
+			    unimplemented_trylock_pi);
+		}
 		LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
 		return (ENOSYS);
 
 	case LINUX_FUTEX_REQUEUE:
-
 		/*
 		 * Glibc does not use this operation since version 2.3.3,
 		 * as it is racy and replaced by FUTEX_CMP_REQUEUE operation.
@@ -964,12 +1066,12 @@
 		 * Glibc versions prior to 2.3.3 fall back to FUTEX_WAKE when
 		 * FUTEX_REQUEUE returned EINVAL.
 		 */
-		em = em_find(td->td_proc, EMUL_DONTLOCK);
-		if ((em->flags & LINUX_XDEPR_REQUEUEOP) == 0) {
+		pem = pem_find(td->td_proc);
+		if ((pem->flags & LINUX_XDEPR_REQUEUEOP) == 0) {
 			linux_msg(td,
 				  "linux_sys_futex: "
 				  "unsupported futex_requeue op\n");
-			em->flags |= LINUX_XDEPR_REQUEUEOP;
+			pem->flags |= LINUX_XDEPR_REQUEUEOP;
 			LIN_SDT_PROBE0(futex, linux_sys_futex,
 			    deprecated_requeue);
 		}
@@ -979,21 +1081,29 @@
 
 	case LINUX_FUTEX_WAIT_REQUEUE_PI:
 		/* not yet implemented */
-		linux_msg(td,
-			  "linux_sys_futex: "
-			  "op FUTEX_WAIT_REQUEUE_PI not implemented\n");
-		LIN_SDT_PROBE0(futex, linux_sys_futex,
-		    unimplemented_wait_requeue_pi);
+		pem = pem_find(td->td_proc);
+		if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+			linux_msg(td,
+				  "linux_sys_futex: "
+				  "unsupported futex_pi op\n");
+			pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+			LIN_SDT_PROBE0(futex, linux_sys_futex,
+			    unimplemented_wait_requeue_pi);
+		}
 		LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
 		return (ENOSYS);
 
 	case LINUX_FUTEX_CMP_REQUEUE_PI:
 		/* not yet implemented */
-		linux_msg(td,
-			    "linux_sys_futex: "
-			    "op LINUX_FUTEX_CMP_REQUEUE_PI not implemented\n");
-		LIN_SDT_PROBE0(futex, linux_sys_futex,
-		    unimplemented_cmp_requeue_pi);
+		pem = pem_find(td->td_proc);
+		if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+			linux_msg(td,
+				  "linux_sys_futex: "
+				  "unsupported futex_pi op\n");
+			pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+			LIN_SDT_PROBE0(futex, linux_sys_futex,
+			    unimplemented_cmp_requeue_pi);
+		}
 		LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
 		return (ENOSYS);
 
@@ -1023,9 +1133,8 @@
 		return (EINVAL);
 	}
 
-	em = em_find(td->td_proc, EMUL_DOLOCK);
+	em = em_find(td);
 	em->robust_futexes = args->head;
-	EMUL_UNLOCK(&emul_lock);
 
 	LIN_SDT_PROBE1(futex, linux_set_robust_list, return, 0);
 	return (0);
@@ -1037,29 +1146,36 @@
 	struct linux_emuldata *em;
 	struct linux_robust_list_head *head;
 	l_size_t len = sizeof(struct linux_robust_list_head);
+	struct thread *td2;
 	int error = 0;
 
 	LIN_SDT_PROBE2(futex, linux_get_robust_list, entry, td, args);
 
 	if (!args->pid) {
-		em = em_find(td->td_proc, EMUL_DONTLOCK);
+		em = em_find(td);
+		KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n"));
 		head = em->robust_futexes;
 	} else {
-		struct proc *p;
-
-		p = pfind(args->pid);
-		if (p == NULL) {
+		td2 = tdfind(args->pid, -1);
+		if (td2 == NULL) {
 			LIN_SDT_PROBE1(futex, linux_get_robust_list, return,
 			    ESRCH);
 			return (ESRCH);
 		}
+		if (SV_PROC_ABI(td2->td_proc) != SV_ABI_LINUX) {
+			LIN_SDT_PROBE1(futex, linux_get_robust_list, return,
+			    EPERM);
+			PROC_UNLOCK(td2->td_proc);
+			return (EPERM);
+		}
 
-		em = em_find(p, EMUL_DONTLOCK);
+		em = em_find(td2);
+		KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n"));
 		/* XXX: ptrace? */
 		if (priv_check(td, PRIV_CRED_SETUID) ||
 		    priv_check(td, PRIV_CRED_SETEUID) ||
-		    p_candebug(td, p)) {
-			PROC_UNLOCK(p);
+		    p_candebug(td, td2->td_proc)) {
+			PROC_UNLOCK(td2->td_proc);
 
 			LIN_SDT_PROBE1(futex, linux_get_robust_list, return,
 			    EPERM);
@@ -1067,26 +1183,36 @@
 		}
 		head = em->robust_futexes;
 
-		PROC_UNLOCK(p);
+		PROC_UNLOCK(td2->td_proc);
 	}
 
 	error = copyout(&len, args->len, sizeof(l_size_t));
-	if (error)
+	if (error) {
+		LIN_SDT_PROBE1(futex, linux_get_robust_list, copyout_error,
+		    error);
+		LIN_SDT_PROBE1(futex, linux_get_robust_list, return, EFAULT);
 		return (EFAULT);
+	}
 
 	error = copyout(&head, args->head, sizeof(head));
+	if (error) {
+		LIN_SDT_PROBE1(futex, linux_get_robust_list, copyout_error,
+		    error);
+	}
 
+	LIN_SDT_PROBE1(futex, linux_get_robust_list, return, error);
 	return (error);
 }
 
 static int
-handle_futex_death(struct proc *p, uint32_t *uaddr, int pi)
+handle_futex_death(struct linux_emuldata *em, uint32_t *uaddr,
+    unsigned int pi)
 {
 	uint32_t uval, nval, mval;
 	struct futex *f;
 	int error;
 
-	LIN_SDT_PROBE3(futex, handle_futex_death, entry, p, uaddr, pi);
+	LIN_SDT_PROBE3(futex, handle_futex_death, entry, em, uaddr, pi);
 
 retry:
 	error = copyin(uaddr, &uval, 4);
@@ -1095,7 +1221,7 @@
 		LIN_SDT_PROBE1(futex, handle_futex_death, return, EFAULT);
 		return (EFAULT);
 	}
-	if ((uval & FUTEX_TID_MASK) == p->p_pid) {
+	if ((uval & FUTEX_TID_MASK) == em->em_tid) {
 		mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
 		nval = casuword32(uaddr, uval, mval);
 
@@ -1129,7 +1255,7 @@
 
 static int
 fetch_robust_entry(struct linux_robust_list **entry,
-    struct linux_robust_list **head, int *pi)
+    struct linux_robust_list **head, unsigned int *pi)
 {
 	l_ulong uentry;
 	int error;
@@ -1152,18 +1278,16 @@
 
 /* This walks the list of robust futexes releasing them. */
 void
-release_futexes(struct proc *p)
+release_futexes(struct thread *td, struct linux_emuldata *em)
 {
 	struct linux_robust_list_head *head = NULL;
 	struct linux_robust_list *entry, *next_entry, *pending;
 	unsigned int limit = 2048, pi, next_pi, pip;
-	struct linux_emuldata *em;
 	l_long futex_offset;
 	int rc, error;
 
-	LIN_SDT_PROBE1(futex, release_futexes, entry, p);
+	LIN_SDT_PROBE2(futex, release_futexes, entry, td, em);
 
-	em = em_find(p, EMUL_DONTLOCK);
 	head = em->robust_futexes;
 
 	if (head == NULL) {
@@ -1193,7 +1317,7 @@
 		rc = fetch_robust_entry(&next_entry, PTRIN(&entry->next), &next_pi);
 
 		if (entry != pending)
-			if (handle_futex_death(p,
+			if (handle_futex_death(em,
 			    (uint32_t *)((caddr_t)entry + futex_offset), pi)) {
 				LIN_SDT_PROBE0(futex, release_futexes, return);
 				return;
@@ -1213,7 +1337,7 @@
 	}
 
 	if (pending)
-		handle_futex_death(p, (uint32_t *)((caddr_t)pending + futex_offset), pip);
+		handle_futex_death(em, (uint32_t *)((caddr_t)pending + futex_offset), pip);
 
 	LIN_SDT_PROBE0(futex, release_futexes, return);
 }

Modified: trunk/sys/compat/linux/linux_futex.h
===================================================================
--- trunk/sys/compat/linux/linux_futex.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_futex.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: linux_futex.h,v 1.2 2005/12/11 12:20:19 christos Exp $ */
 
 /*-
@@ -30,7 +31,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_futex.h 293493 2016-01-09 15:16:13Z dchagin $
  */
 
 #ifndef _LINUX_FUTEX_H
@@ -76,6 +77,7 @@
 #define	FUTEX_TID_MASK		0x3fffffff
 #define	FUTEX_BITSET_MATCH_ANY	0xffffffff
 
-void	release_futexes(struct proc *);
+void	release_futexes(struct thread *,
+			struct linux_emuldata *);
 
 #endif	/* !_LINUX_FUTEX_H */

Modified: trunk/sys/compat/linux/linux_getcwd.c
===================================================================
--- trunk/sys/compat/linux/linux_getcwd.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_getcwd.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,12 +1,17 @@
+/* $MidnightBSD$ */
 /* $OpenBSD: linux_getcwd.c,v 1.2 2001/05/16 12:50:21 ho Exp $ */
 /* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 2015 The FreeBSD Foundation
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
  * by Bill Sommerfeld.
  *
+ * Portions of this software were developed by Edward Tomasz Napierala
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -30,25 +35,15 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_getcwd.c 321010 2017-07-15 14:57:24Z dchagin $");
 
 #include "opt_compat.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/namei.h>
-#include <sys/filedesc.h>
-#include <sys/kernel.h>
-#include <sys/file.h>
-#include <sys/stat.h>
 #include <sys/syscallsubr.h>
-#include <sys/vnode.h>
-#include <sys/mount.h>
 #include <sys/proc.h>
-#include <sys/uio.h>
 #include <sys/malloc.h>
-#include <sys/dirent.h>
-#include <ufs/ufs/dir.h>	/* XXX only for DIRBLKSIZ */
 
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
@@ -57,364 +52,17 @@
 #include <machine/../linux/linux.h>
 #include <machine/../linux/linux_proto.h>
 #endif
+#include <compat/linux/linux_misc.h>
 #include <compat/linux/linux_util.h>
 
-#include <security/mac/mac_framework.h>
-
-static int
-linux_getcwd_scandir(struct vnode **, struct vnode **,
-    char **, char *, struct thread *);
-static int
-linux_getcwd_common(struct vnode *, struct vnode *,
-		   char **, char *, int, int, struct thread *);
-
-#define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4)
-
 /*
- * Vnode variable naming conventions in this file:
- *
- * rvp: the current root we're aiming towards.
- * lvp, *lvpp: the "lower" vnode
- * uvp, *uvpp: the "upper" vnode.
- *
- * Since all the vnodes we're dealing with are directories, and the
- * lookups are going *up* in the filesystem rather than *down*, the
- * usual "pvp" (parent) or "dvp" (directory) naming conventions are
- * too confusing.
- */
-
-/*
- * XXX Will infinite loop in certain cases if a directory read reliably
- *	returns EINVAL on last block.
- * XXX is EINVAL the right thing to return if a directory is malformed?
- */
-
-/*
- * XXX Untested vs. mount -o union; probably does the wrong thing.
- */
-
-/*
- * Find parent vnode of *lvpp, return in *uvpp
- *
- * If we care about the name, scan it looking for name of directory
- * entry pointing at lvp.
- *
- * Place the name in the buffer which starts at bufp, immediately
- * before *bpp, and move bpp backwards to point at the start of it.
- *
- * On entry, *lvpp is a locked vnode reference; on exit, it is vput and NULL'ed
- * On exit, *uvpp is either NULL or is a locked vnode reference.
- */
-static int
-linux_getcwd_scandir(lvpp, uvpp, bpp, bufp, td)
-	struct vnode **lvpp;
-	struct vnode **uvpp;
-	char **bpp;
-	char *bufp;
-	struct thread *td;
-{
-	int     error = 0;
-	int     eofflag;
-	off_t   off;
-	int     tries;
-	struct uio uio;
-	struct iovec iov;
-	char   *dirbuf = NULL;
-	int	dirbuflen;
-	ino_t   fileno;
-	struct vattr va;
-	struct vnode *uvp = NULL;
-	struct vnode *lvp = *lvpp;	
-	struct componentname cn;
-	int len, reclen;
-	tries = 0;
-
-	/*
-	 * If we want the filename, get some info we need while the
-	 * current directory is still locked.
-	 */
-	if (bufp != NULL) {
-		error = VOP_GETATTR(lvp, &va, td->td_ucred);
-		if (error) {
-			vput(lvp);
-			*lvpp = NULL;
-			*uvpp = NULL;
-			return error;
-		}
-	}
-
-	/*
-	 * Ok, we have to do it the hard way..
-	 * Next, get parent vnode using lookup of ..
-	 */
-	cn.cn_nameiop = LOOKUP;
-	cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY;
-	cn.cn_thread = td;
-	cn.cn_cred = td->td_ucred;
-	cn.cn_pnbuf = NULL;
-	cn.cn_nameptr = "..";
-	cn.cn_namelen = 2;
-	cn.cn_consume = 0;
-	cn.cn_lkflags = LK_SHARED;
-	
-	/*
-	 * At this point, lvp is locked and will be unlocked by the lookup.
-	 * On successful return, *uvpp will be locked
-	 */
-#ifdef MAC
-	error = mac_vnode_check_lookup(td->td_ucred, lvp, &cn);
-	if (error == 0)
-#endif
-		error = VOP_LOOKUP(lvp, uvpp, &cn);
-	if (error) {
-		vput(lvp);
-		*lvpp = NULL;
-		*uvpp = NULL;
-		return error;
-	}
-	uvp = *uvpp;
-
-	/* If we don't care about the pathname, we're done */
-	if (bufp == NULL) {
-		vput(lvp);
-		*lvpp = NULL;
-		return 0;
-	}
-	
-	fileno = va.va_fileid;
-
-	dirbuflen = DIRBLKSIZ;
-	if (dirbuflen < va.va_blocksize)
-		dirbuflen = va.va_blocksize;
-	dirbuf = (char *)malloc(dirbuflen, M_TEMP, M_WAITOK);
-
-#if 0
-unionread:
-#endif
-	off = 0;
-	do {
-		/* call VOP_READDIR of parent */
-		iov.iov_base = dirbuf;
-		iov.iov_len = dirbuflen;
-
-		uio.uio_iov = &iov;
-		uio.uio_iovcnt = 1;
-		uio.uio_offset = off;
-		uio.uio_resid = dirbuflen;
-		uio.uio_segflg = UIO_SYSSPACE;
-		uio.uio_rw = UIO_READ;
-		uio.uio_td = td;
-
-		eofflag = 0;
-
-#ifdef MAC
-		error = mac_vnode_check_readdir(td->td_ucred, uvp);
-		if (error == 0)
-#endif /* MAC */
-			error = VOP_READDIR(uvp, &uio, td->td_ucred, &eofflag,
-			    0, 0);
-
-		off = uio.uio_offset;
-
-		/*
-		 * Try again if NFS tosses its cookies.
-		 * XXX this can still loop forever if the directory is busted
-		 * such that the second or subsequent page of it always
-		 * returns EINVAL
-		 */
-		if ((error == EINVAL) && (tries < 3)) {
-			off = 0;
-			tries++;
-			continue;	/* once more, with feeling */
-		}
-
-		if (!error) {
-			char   *cpos;
-			struct dirent *dp;
-			
-			cpos = dirbuf;
-			tries = 0;
-				
-			/* scan directory page looking for matching vnode */ 
-			for (len = (dirbuflen - uio.uio_resid); len > 0; len -= reclen) {
-				dp = (struct dirent *) cpos;
-				reclen = dp->d_reclen;
-
-				/* check for malformed directory.. */
-				if (reclen < DIRENT_MINSIZE) {
-					error = EINVAL;
-					goto out;
-				}
-				/*
-				 * XXX should perhaps do VOP_LOOKUP to
-				 * check that we got back to the right place,
-				 * but getting the locking games for that
-				 * right would be heinous.
-				 */
-				if ((dp->d_type != DT_WHT) &&
-				    (dp->d_fileno == fileno)) {
-					char *bp = *bpp;
-					bp -= dp->d_namlen;
-					
-					if (bp <= bufp) {
-						error = ERANGE;
-						goto out;
-					}
-					bcopy(dp->d_name, bp, dp->d_namlen);
-					error = 0;
-					*bpp = bp;
-					goto out;
-				}
-				cpos += reclen;
-			}
-		}
-	} while (!eofflag);
-	error = ENOENT;
-		
-out:
-	vput(lvp);
-	*lvpp = NULL;
-	free(dirbuf, M_TEMP);
-	return error;
-}
-
-
-/*
- * common routine shared by sys___getcwd() and linux_vn_isunder()
- */
-
-#define GETCWD_CHECK_ACCESS 0x0001
-
-static int
-linux_getcwd_common (lvp, rvp, bpp, bufp, limit, flags, td)
-	struct vnode *lvp;
-	struct vnode *rvp;
-	char **bpp;
-	char *bufp;
-	int limit;
-	int flags;
-	struct thread *td;
-{
-	struct filedesc *fdp = td->td_proc->p_fd;
-	struct vnode *uvp = NULL;
-	char *bp = NULL;
-	int error;
-	accmode_t accmode = VEXEC;
-
-	if (rvp == NULL) {
-		rvp = fdp->fd_rdir;
-		if (rvp == NULL)
-			rvp = rootvnode;
-	}
-	
-	VREF(rvp);
-	VREF(lvp);
-
-	/*
-	 * Error handling invariant:
-	 * Before a `goto out':
-	 *	lvp is either NULL, or locked and held.
-	 *	uvp is either NULL, or locked and held.
-	 */
-
-	error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY);
-	if (error != 0)
-		panic("vn_lock LK_RETRY returned error %d", error);
-	if (bufp)
-		bp = *bpp;
-	/*
-	 * this loop will terminate when one of the following happens:
-	 *	- we hit the root
-	 *	- getdirentries or lookup fails
-	 *	- we run out of space in the buffer.
-	 */
-	if (lvp == rvp) {
-		if (bp)
-			*(--bp) = '/';
-		goto out;
-	}
-	do {
-		if (lvp->v_type != VDIR) {
-			error = ENOTDIR;
-			goto out;
-		}
-		
-		/*
-		 * access check here is optional, depending on
-		 * whether or not caller cares.
-		 */
-		if (flags & GETCWD_CHECK_ACCESS) {
-			error = VOP_ACCESS(lvp, accmode, td->td_ucred, td);
-			if (error)
-				goto out;
-			accmode = VEXEC|VREAD;
-		}
-		
-		/*
-		 * step up if we're a covered vnode..
-		 */
-		while (lvp->v_vflag & VV_ROOT) {
-			struct vnode *tvp;
-
-			if (lvp == rvp)
-				goto out;
-			
-			tvp = lvp;
-			lvp = lvp->v_mount->mnt_vnodecovered;
-			vput(tvp);
-			/*
-			 * hodie natus est radici frater
-			 */
-			if (lvp == NULL) {
-				error = ENOENT;
-				goto out;
-			}
-			VREF(lvp);
-			error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY);
-			if (error != 0)
-				panic("vn_lock LK_RETRY returned %d", error);
-		}
-		error = linux_getcwd_scandir(&lvp, &uvp, &bp, bufp, td);
-		if (error)
-			goto out;
-#ifdef DIAGNOSTIC		
-		if (lvp != NULL)
-			panic("getcwd: oops, forgot to null lvp");
-		if (bufp && (bp <= bufp)) {
-			panic("getcwd: oops, went back too far");
-		}
-#endif		
-		if (bp) 
-			*(--bp) = '/';
-		lvp = uvp;
-		uvp = NULL;
-		limit--;
-	} while ((lvp != rvp) && (limit > 0)); 
-
-out:
-	if (bpp)
-		*bpp = bp;
-	if (uvp)
-		vput(uvp);
-	if (lvp)
-		vput(lvp);
-	vrele(rvp);
-	return error;
-}
-
-
-/*
  * Find pathname of process's current directory.
- *
- * Use vfs vnode-to-name reverse cache; if that fails, fall back
- * to reading directory contents.
  */
-
 int
 linux_getcwd(struct thread *td, struct linux_getcwd_args *args)
 {
-	caddr_t bp, bend, path;
-	int error, len, lenused;
+	char *path;
+	int error, lenused;
 
 #ifdef DEBUG
 	if (ldebug(getcwd))
@@ -421,49 +69,23 @@
 		printf(ARGS(getcwd, "%p, %ld"), args->buf, (long)args->bufsize);
 #endif
 
-	len = args->bufsize;
+	/*
+	 * Linux returns ERANGE instead of EINVAL.
+	 */
+	if (args->bufsize < 2)
+		return (ERANGE);
 
-	if (len > MAXPATHLEN*4)
-		len = MAXPATHLEN*4;
-	else if (len < 2)
-		return ERANGE;
+	path = malloc(LINUX_PATH_MAX, M_TEMP, M_WAITOK);
 
-	path = (char *)malloc(len, M_TEMP, M_WAITOK);
-
-	error = kern___getcwd(td, path, UIO_SYSSPACE, len);
-	if (!error) {
+	error = kern___getcwd(td, path, UIO_SYSSPACE, args->bufsize,
+	    LINUX_PATH_MAX);
+	if (error == 0) {
 		lenused = strlen(path) + 1;
-		if (lenused <= args->bufsize) {
+		error = copyout(path, args->buf, lenused);
+		if (error == 0)
 			td->td_retval[0] = lenused;
-			error = copyout(path, args->buf, lenused);
-		}
-		else
-			error = ERANGE;
-	} else {
-		bp = &path[len];
-		bend = bp;
-		*(--bp) = '\0';
+	}
 
-		/*
-		 * 5th argument here is "max number of vnodes to traverse".
-		 * Since each entry takes up at least 2 bytes in the output buffer,
-		 * limit it to N/2 vnodes for an N byte buffer.
-		 */
-
-		mtx_lock(&Giant);
-		error = linux_getcwd_common (td->td_proc->p_fd->fd_cdir, NULL,
-		    &bp, path, len/2, GETCWD_CHECK_ACCESS, td);
-		mtx_unlock(&Giant);
-
-		if (error)
-			goto out;
-		lenused = bend - bp;
-		td->td_retval[0] = lenused;
-		/* put the result into user buffer */
-		error = copyout(bp, args->buf, lenused);
-	}
-out:
 	free(path, M_TEMP);
 	return (error);
 }
-

Modified: trunk/sys/compat/linux/linux_ioctl.c
===================================================================
--- trunk/sys/compat/linux/linux_ioctl.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_ioctl.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 1994-1995 S\xF8ren Schmidt
+ * Copyright (c) 1994-1995 Søren Schmidt
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,12 +30,12 @@
 #include "opt_compat.h"
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_ioctl.c 332064 2018-04-05 12:54:10Z emaste $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sysproto.h>
-#include <sys/capability.h>
+#include <sys/capsicum.h>
 #include <sys/cdio.h>
 #include <sys/dvdio.h>
 #include <sys/conf.h>
@@ -68,7 +69,6 @@
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
-#include <net/vnet.h>
 
 #include <dev/usb/usb_ioctl.h>
 
@@ -85,17 +85,16 @@
 #include <compat/linux/linux_socket.h>
 #include <compat/linux/linux_util.h>
 
-#include <compat/linux/linux_videodev.h>
+#include <contrib/v4l/videodev.h>
 #include <compat/linux/linux_videodev_compat.h>
 
-#include <compat/linux/linux_videodev2.h>
+#include <contrib/v4l/videodev2.h>
 #include <compat/linux/linux_videodev2_compat.h>
 
+#include <cam/scsi/scsi_sg.h>
+
 CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
 
-FEATURE(linuxulator_v4l, "V4L ioctl wrapper support in the linuxulator");
-FEATURE(linuxulator_v4l2, "V4L2 ioctl wrapper support in the linuxulator");
-
 static linux_ioctl_function_t linux_ioctl_cdrom;
 static linux_ioctl_function_t linux_ioctl_vfat;
 static linux_ioctl_function_t linux_ioctl_console;
@@ -189,12 +188,14 @@
 static int
 linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
 {
+	cap_rights_t rights;
 	struct file *fp;
 	int error;
 	u_int sectorsize, fwcylinders, fwheads, fwsectors;
 	off_t mediasize, bytespercyl;
 
-	if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+	if (error != 0)
 		return (error);
 	switch (args->cmd & 0xffff) {
 	case LINUX_HDIO_GET_GEO:
@@ -246,6 +247,7 @@
 		} else if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO_BIG) {
 			struct linux_hd_big_geometry hdbg;
 
+			memset(&hdbg, 0, sizeof(hdbg));
 			hdbg.cylinders = fwcylinders;
 			hdbg.heads = fwheads;
 			hdbg.sectors = fwsectors;
@@ -270,12 +272,14 @@
 static int
 linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
 {
+	cap_rights_t rights;
 	struct file *fp;
 	int error;
 	u_int sectorsize;
 	off_t mediasize;
 
-	if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+	if (error != 0)
 		return (error);
 	switch (args->cmd & 0xffff) {
 	case LINUX_BLKGETSIZE:
@@ -294,6 +298,15 @@
 		return (copyout(&sectorsize, (void *)args->arg,
 		    sizeof(sectorsize)));
 		break;
+	case LINUX_BLKSSZGET:
+		error = fo_ioctl(fp, DIOCGSECTORSIZE,
+		    (caddr_t)&sectorsize, td->td_ucred, td);
+		fdrop(fp, td);
+		if (error)
+			return (error);
+		return (copyout(&sectorsize, (void *)args->arg,
+		    sizeof(sectorsize)));
+		break;
 	}
 	fdrop(fp, td);
 	return (ENOIOCTL);
@@ -698,10 +711,12 @@
 	struct termios bios;
 	struct linux_termios lios;
 	struct linux_termio lio;
+	cap_rights_t rights;
 	struct file *fp;
 	int error;
 
-	if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+	if (error != 0)
 		return (error);
 
 	switch (args->cmd & 0xffff) {
@@ -974,7 +989,7 @@
 		error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line,
 		    td->td_ucred, td);
 		if (error)
-			return (error);
+			break;
 		switch (bsd_line) {
 		case TTYDISC:
 			linux_line = LINUX_N_TTY;
@@ -1440,10 +1455,12 @@
 static int
 linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
 {
+	cap_rights_t rights;
 	struct file *fp;
 	int error;
 
-	if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+	if (error != 0)
 		return (error);
 	switch (args->cmd & 0xffff) {
 
@@ -1639,9 +1656,32 @@
 	}
 
 	case LINUX_SCSI_GET_BUS_NUMBER:
+	{
+		struct sg_scsi_id id;
+
+		error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
+		    td->td_ucred, td);
+		if (error)
+			break;
+		error = copyout(&id.channel, (void *)args->arg, sizeof(int));
+		break;
+	}
+
 	case LINUX_SCSI_GET_IDLUN:
-		error = linux_ioctl_sg(td, args);
+	{
+		struct sg_scsi_id id;
+		struct scsi_idlun idl;
+
+		error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
+		    td->td_ucred, td);
+		if (error)
+			break;
+		idl.dev_id = (id.scsi_id & 0xff) + ((id.lun & 0xff) << 8) +
+		    ((id.channel & 0xff) << 16) + ((id.host_no & 0xff) << 24);
+		idl.host_unique_id = id.host_no;
+		error = copyout(&idl, (void *)args->arg, sizeof(idl));
 		break;
+	}
 
 	/* LINUX_CDROM_SEND_PACKET */
 	/* LINUX_CDROM_NEXT_WRITABLE */
@@ -1667,13 +1707,6 @@
  * Sound related ioctls
  */
 
-struct linux_mixer_info {
-	char	id[16];
-	char	name[32];
-	int	modify_counter;
-	int	fillers[10];
-};
-
 struct linux_old_mixer_info {
 	char	id[16];
 	char	name[32];
@@ -1761,12 +1794,8 @@
 		/* Key on encoded length */
 		switch ((args->cmd >> 16) & 0x1fff) {
 		case 0x005c: {	/* SOUND_MIXER_INFO */
-			struct linux_mixer_info info;
-			bzero(&info, sizeof(info));
-			strncpy(info.id, "OSS", sizeof(info.id) - 1);
-			strncpy(info.name, "FreeBSD OSS Mixer", sizeof(info.name) - 1);
-			copyout(&info, (void *)args->arg, sizeof(info));
-			return (0);
+			args->cmd = SOUND_MIXER_INFO;
+			return (sys_ioctl(td, (struct ioctl_args *)args));
 		}
 		case 0x0030: {	/* SOUND_OLD_MIXER_INFO */
 			struct linux_old_mixer_info info;
@@ -1960,15 +1989,15 @@
  * Console related ioctls
  */
 
-#define ISSIGVALID(sig)		((sig) > 0 && (sig) < NSIG)
-
 static int
 linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
 {
+	cap_rights_t rights;
 	struct file *fp;
 	int error;
 
-	if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+	if (error != 0)
 		return (error);
 	switch (args->cmd & 0xffff) {
 
@@ -2042,8 +2071,16 @@
 		struct vt_mode mode;
 		if ((error = copyin((void *)args->arg, &mode, sizeof(mode))))
 			break;
-		if (!ISSIGVALID(mode.frsig) && ISSIGVALID(mode.acqsig))
-			mode.frsig = mode.acqsig;
+		if (LINUX_SIG_VALID(mode.relsig))
+			mode.relsig = linux_to_bsd_signal(mode.relsig);
+		else
+			mode.relsig = 0;
+		if (LINUX_SIG_VALID(mode.acqsig))
+			mode.acqsig = linux_to_bsd_signal(mode.acqsig);
+		else
+			mode.acqsig = 0;
+		/* XXX. Linux ignores frsig and set it to 0. */
+		mode.frsig = 0;
 		if ((error = copyout(&mode, (void *)args->arg, sizeof(mode))))
 			break;
 		args->cmd = VT_SETMODE;
@@ -2086,34 +2123,6 @@
 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
 
 /*
- * Interface function used by linprocfs (at the time of writing). It's not
- * used by the Linuxulator itself.
- */
-int
-linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
-{
-	struct ifnet *ifscan;
-	int ethno;
-
-	IFNET_RLOCK_ASSERT();
-
-	/* Short-circuit non ethernet interfaces */
-	if (!IFP_IS_ETH(ifp))
-		return (strlcpy(buffer, ifp->if_xname, buflen));
-
-	/* Determine the (relative) unit number for ethernet interfaces */
-	ethno = 0;
-	TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
-		if (ifscan == ifp)
-			return (snprintf(buffer, buflen, "eth%d", ethno));
-		if (IFP_IS_ETH(ifscan))
-			ethno++;
-	}
-
-	return (0);
-}
-
-/*
  * Translate a Linux interface name to a FreeBSD interface name,
  * and return the associated ifnet structure
  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
@@ -2353,6 +2362,7 @@
 linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
 {
 	char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
+	cap_rights_t rights;
 	struct ifnet *ifp;
 	struct file *fp;
 	int error, type;
@@ -2360,7 +2370,8 @@
 	ifp = NULL;
 	error = 0;
 
-	if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+	if (error != 0)
 		return (error);
 	type = fp->f_type;
 	fdrop(fp, td);
@@ -2417,6 +2428,7 @@
 		printf("%s(): ioctl %d on %.*s\n", __func__,
 		    args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
 #endif
+		memset(ifname, 0, sizeof(ifname));
 		ifp = ifname_linux_to_bsd(td, lifname, ifname);
 		if (ifp == NULL)
 			return (EINVAL);
@@ -2583,10 +2595,12 @@
 static int
 linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
 {
+	cap_rights_t rights;
 	struct file *fp;
 	int error, type;
 
-	if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+	if (error != 0)
 		return (error);
 	type = fp->f_type;
 	fdrop(fp, td);
@@ -2605,24 +2619,123 @@
 	return sys_ioctl(td, (struct ioctl_args *)args);
 }
 
+#ifdef COMPAT_LINUX32
+#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
+#define PTRIN_CP(src,dst,fld) \
+	do { (dst).fld = PTRIN((src).fld); } while (0)
+#define PTROUT_CP(src,dst,fld) \
+	do { (dst).fld = PTROUT((src).fld); } while (0)
+
 static int
-linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
+linux_ioctl_sg_io(struct thread *td, struct linux_ioctl_args *args)
 {
+	struct sg_io_hdr io;
+	struct sg_io_hdr32 io32;
+	cap_rights_t rights;
 	struct file *fp;
-	u_long cmd;
 	int error;
 
-	if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) {
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+	if (error != 0) {
 		printf("sg_linux_ioctl: fget returned %d\n", error);
 		return (error);
 	}
-	cmd = args->cmd;
 
-	error = (fo_ioctl(fp, cmd, (caddr_t)args->arg, td->td_ucred, td));
+	if ((error = copyin((void *)args->arg, &io32, sizeof(io32))) != 0)
+		goto out;
+
+	CP(io32, io, interface_id);
+	CP(io32, io, dxfer_direction);
+	CP(io32, io, cmd_len);
+	CP(io32, io, mx_sb_len);
+	CP(io32, io, iovec_count);
+	CP(io32, io, dxfer_len);
+	PTRIN_CP(io32, io, dxferp);
+	PTRIN_CP(io32, io, cmdp);
+	PTRIN_CP(io32, io, sbp);
+	CP(io32, io, timeout);
+	CP(io32, io, flags);
+	CP(io32, io, pack_id);
+	PTRIN_CP(io32, io, usr_ptr);
+	CP(io32, io, status);
+	CP(io32, io, masked_status);
+	CP(io32, io, msg_status);
+	CP(io32, io, sb_len_wr);
+	CP(io32, io, host_status);
+	CP(io32, io, driver_status);
+	CP(io32, io, resid);
+	CP(io32, io, duration);
+	CP(io32, io, info);
+
+	if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
+		goto out;
+
+	CP(io, io32, interface_id);
+	CP(io, io32, dxfer_direction);
+	CP(io, io32, cmd_len);
+	CP(io, io32, mx_sb_len);
+	CP(io, io32, iovec_count);
+	CP(io, io32, dxfer_len);
+	PTROUT_CP(io, io32, dxferp);
+	PTROUT_CP(io, io32, cmdp);
+	PTROUT_CP(io, io32, sbp);
+	CP(io, io32, timeout);
+	CP(io, io32, flags);
+	CP(io, io32, pack_id);
+	PTROUT_CP(io, io32, usr_ptr);
+	CP(io, io32, status);
+	CP(io, io32, masked_status);
+	CP(io, io32, msg_status);
+	CP(io, io32, sb_len_wr);
+	CP(io, io32, host_status);
+	CP(io, io32, driver_status);
+	CP(io, io32, resid);
+	CP(io, io32, duration);
+	CP(io, io32, info);
+
+	error = copyout(&io32, (void *)args->arg, sizeof(io32));
+
+out:
 	fdrop(fp, td);
 	return (error);
 }
+#endif
 
+static int
+linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
+{
+
+	switch (args->cmd) {
+	case LINUX_SG_GET_VERSION_NUM:
+		args->cmd = SG_GET_VERSION_NUM;
+		break;
+	case LINUX_SG_SET_TIMEOUT:
+		args->cmd = SG_SET_TIMEOUT;
+		break;
+	case LINUX_SG_GET_TIMEOUT:
+		args->cmd = SG_GET_TIMEOUT;
+		break;
+	case LINUX_SG_IO:
+		args->cmd = SG_IO;
+#ifdef COMPAT_LINUX32
+		return (linux_ioctl_sg_io(td, args));
+#endif
+		break;
+	case LINUX_SG_GET_RESERVED_SIZE:
+		args->cmd = SG_GET_RESERVED_SIZE;
+		break;
+	case LINUX_SG_GET_SCSI_ID:
+		args->cmd = SG_GET_SCSI_ID;
+		break;
+	case LINUX_SG_GET_SG_TABLESIZE:
+		args->cmd = SG_GET_SG_TABLESIZE;
+		break;
+	default:
+		return (ENODEV);
+	}
+	return (sys_ioctl(td, (struct ioctl_args *)args));
+}
+
 /*
  * Video4Linux (V4L) ioctl handler
  */
@@ -2802,7 +2915,7 @@
 		vw->clips = NULL;
 		ppvc = &(vw->clips);
 		while (clipcount-- > 0) {
-			if (plvc == 0) {
+			if (plvc == NULL) {
 				error = EFAULT;
 				break;
 			} else {
@@ -2830,6 +2943,7 @@
 static int
 linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
 {
+	cap_rights_t rights;
 	struct file *fp;
 	int error;
 	struct video_tuner vtun;
@@ -2847,7 +2961,9 @@
 	case LINUX_VIDIOCSCHAN:		args->cmd = VIDIOCSCHAN; break;
 
 	case LINUX_VIDIOCGTUNER:
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error != 0)
 			return (error);
 		error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
 		if (error) {
@@ -2865,7 +2981,9 @@
 		return (error);
 
 	case LINUX_VIDIOCSTUNER:
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error != 0)
 			return (error);
 		error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
 		if (error) {
@@ -2882,7 +3000,9 @@
 	case LINUX_VIDIOCCAPTURE:	args->cmd = VIDIOCCAPTURE; break;
 
 	case LINUX_VIDIOCGWIN:
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error != 0)
 			return (error);
 		error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td);
 		if (!error) {
@@ -2894,7 +3014,9 @@
 		return (error);
 
 	case LINUX_VIDIOCSWIN:
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error != 0)
 			return (error);
 		error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin));
 		if (error) {
@@ -2917,7 +3039,9 @@
 		return (error);
 
 	case LINUX_VIDIOCGFBUF:
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error != 0)
 			return (error);
 		error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td);
 		if (!error) {
@@ -2929,7 +3053,9 @@
 		return (error);
 
 	case LINUX_VIDIOCSFBUF:
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error != 0)
 			return (error);
 		error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf));
 		if (error) {
@@ -2957,7 +3083,9 @@
 	case LINUX_VIDIOCGPLAYINFO:	args->cmd = VIDIOCGPLAYINFO; break;
 
 	case LINUX_VIDIOCSMICROCODE:
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error != 0)
 			return (error);
 		error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode));
 		if (error) {
@@ -3110,6 +3238,7 @@
 static int
 linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
 {
+	cap_rights_t rights;
 	struct file *fp;
 	int error;
 	struct v4l2_format vformat;
@@ -3201,7 +3330,9 @@
 		error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat));
 		if (error)
 			return (error);
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error)
 			return (error);
 		if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0)
 			error = EINVAL;
@@ -3224,7 +3355,9 @@
 		if (error)
 			return (error);
 		linux_to_bsd_v4l2_standard(&l_vstd, &vstd);
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error)
 			return (error);
 		error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd,
 		    td->td_ucred, td);
@@ -3246,7 +3379,9 @@
 				sizeof(struct l_v4l2_input));
 		if (error != 0)
 			return (error);
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error != 0)
 			return (error);
 		error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp,
 		    td->td_ucred, td);
@@ -3265,7 +3400,9 @@
 		error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf));
 		if (error)
 			return (error);
-		if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+		error = fget(td, args->fd,
+		    cap_rights_init(&rights, CAP_IOCTL), &fp);
+		if (error)
 			return (error);
 		linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf);
 		if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF)
@@ -3410,6 +3547,15 @@
 	case FBSD_LUSB_SET_TEMPLATE:
 		args->cmd = USB_SET_TEMPLATE;
 		break;
+	case FBSD_LUSB_FS_OPEN_STREAM:
+		args->cmd = USB_FS_OPEN_STREAM;
+		break;
+	case FBSD_LUSB_GET_DEV_PORT_PATH:
+		args->cmd = USB_GET_DEV_PORT_PATH;
+		break;
+	case FBSD_LUSB_GET_POWER_USAGE:
+		args->cmd = USB_GET_POWER_USAGE;
+		break;
 	default:
 		error = ENOIOCTL;
 	}
@@ -3425,6 +3571,7 @@
 int
 linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
 {
+	cap_rights_t rights;
 	struct file *fp;
 	struct handler_element *he;
 	int error, cmd;
@@ -3435,7 +3582,8 @@
 		    (unsigned long)args->cmd);
 #endif
 
-	if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+	if (error != 0)
 		return (error);
 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
 		fdrop(fp, td);
@@ -3461,10 +3609,17 @@
 	sx_sunlock(&linux_ioctl_sx);
 	fdrop(fp, td);
 
-	linux_msg(td, "ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented",
-	    args->fd, (int)(args->cmd & 0xffff),
-	    (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
+	switch (args->cmd & 0xffff) {
+	case LINUX_BTRFS_IOC_CLONE:
+		return (ENOTSUP);
 
+	default:
+		linux_msg(td, "ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented",
+		    args->fd, (int)(args->cmd & 0xffff),
+		    (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
+		break;
+	}
+
 	return (EINVAL);
 }
 

Modified: trunk/sys/compat/linux/linux_ioctl.h
===================================================================
--- trunk/sys/compat/linux/linux_ioctl.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_ioctl.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1999 Marcel Moolenaar
  * All rights reserved.
@@ -25,7 +26,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_ioctl.h 293596 2016-01-09 18:03:09Z dchagin $
  */
 
 #ifndef _LINUX_IOCTL_H_
@@ -581,13 +582,6 @@
 #define	LINUX_IOCTL_DRM_MAX	0x64ff
 
 /*
- * This doesn't really belong here, but I can't think of a better
- * place to put it.
- */
-struct ifnet;
-int		 linux_ifname(struct ifnet *, char *, size_t);
-
-/*
  * video
  */
 #define LINUX_VIDIOCGCAP		0x7601
@@ -744,8 +738,33 @@
 #define	FBSD_LUSB_SET_IMMED		0xffe2
 #define	FBSD_LUSB_SET_POWER_MODE	0xffe1
 #define	FBSD_LUSB_SET_TEMPLATE		0xffe0
+#define	FBSD_LUSB_FS_OPEN_STREAM	0xffdf
+#define	FBSD_LUSB_GET_DEV_PORT_PATH	0xffde
+#define	FBSD_LUSB_GET_POWER_USAGE	0xffdd
 
 #define	FBSD_LUSB_MAX			0xffff
-#define	FBSD_LUSB_MIN			0xffe0
+#define	FBSD_LUSB_MIN			0xffdd
 
+/*
+ * Linux btrfs clone operation
+ */
+#define LINUX_BTRFS_IOC_CLONE		0x9409 /* 0x40049409 */
+
+
+/*
+ * Pluggable ioctl handlers
+ */
+struct linux_ioctl_args;
+struct thread;
+
+typedef int linux_ioctl_function_t(struct thread *, struct linux_ioctl_args *);
+
+struct linux_ioctl_handler {
+	linux_ioctl_function_t *func;
+	int	low, high;
+};
+
+int	linux_ioctl_register_handler(struct linux_ioctl_handler *h);
+int	linux_ioctl_unregister_handler(struct linux_ioctl_handler *h);
+
 #endif /* !_LINUX_IOCTL_H_ */

Modified: trunk/sys/compat/linux/linux_ipc.c
===================================================================
--- trunk/sys/compat/linux/linux_ipc.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_ipc.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 1994-1995 S\xF8ren Schmidt
+ * Copyright (c) 1994-1995 Søren Schmidt
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_ipc.c 332039 2018-04-04 17:45:05Z emaste $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -117,16 +118,6 @@
 	lpp->swap_successes = bpp->swap_successes ;
 }
 
-struct l_ipc_perm {
-	l_key_t		key;
-	l_uid16_t	uid;
-	l_gid16_t	gid;
-	l_uid16_t	cuid;
-	l_gid16_t	cgid;
-	l_ushort	mode;
-	l_ushort	seq;
-};
-
 static void
 linux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp)
 {
@@ -526,6 +517,9 @@
 	register_t rval;
 	int cmd, error;
 
+	memset(&linux_seminfo, 0, sizeof(linux_seminfo));
+	memset(&linux_semid, 0, sizeof(linux_semid));
+
 	switch (args->cmd & ~LINUX_IPC_64) {
 	case LINUX_IPC_RMID:
 		cmd = IPC_RMID;
@@ -671,6 +665,8 @@
 	struct l_msqid_ds linux_msqid;
 	struct msqid_ds bsd_msqid;
 
+	memset(&linux_msqid, 0, sizeof(linux_msqid));
+
 	bsd_cmd = args->cmd & ~LINUX_IPC_64;
 	switch (bsd_cmd) {
 	case LINUX_IPC_INFO:
@@ -677,6 +673,7 @@
 	case LINUX_MSG_INFO: {
 		struct l_msginfo linux_msginfo;
 
+		memset(&linux_msginfo, 0, sizeof(linux_msginfo));
 		/*
 		 * XXX MSG_INFO uses the same data structure but returns different
 		 * dynamic counters in msgpool, msgmap, and msgtql fields.
@@ -799,6 +796,10 @@
 	struct shmid_ds bsd_shmid;
 	int error;
 
+	memset(&linux_shm_info, 0, sizeof(linux_shm_info));
+	memset(&linux_shmid, 0, sizeof(linux_shmid));
+	memset(&linux_shminfo, 0, sizeof(linux_shminfo));
+
 	switch (args->cmd & ~LINUX_IPC_64) {
 
 	case LINUX_IPC_INFO: {

Modified: trunk/sys/compat/linux/linux_ipc.h
===================================================================
--- trunk/sys/compat/linux/linux_ipc.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_ipc.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2000 Marcel Moolenaar
  * All rights reserved.
@@ -25,7 +26,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_ipc.h 293522 2016-01-09 15:56:01Z dchagin $
  */
 
 #ifndef _LINUX_IPC_H_
@@ -32,6 +33,48 @@
 #define _LINUX_IPC_H_
 
 /*
+ * SystemV IPC defines
+ */
+#define	LINUX_SEMOP		1
+#define	LINUX_SEMGET		2
+#define	LINUX_SEMCTL		3
+#define	LINUX_MSGSND		11
+#define	LINUX_MSGRCV		12
+#define	LINUX_MSGGET		13
+#define	LINUX_MSGCTL		14
+#define	LINUX_SHMAT		21
+#define	LINUX_SHMDT		22
+#define	LINUX_SHMGET		23
+#define	LINUX_SHMCTL		24
+
+#define	LINUX_IPC_RMID		0
+#define	LINUX_IPC_SET		1
+#define	LINUX_IPC_STAT		2
+#define	LINUX_IPC_INFO		3
+
+#define	LINUX_MSG_INFO	12
+
+#define	LINUX_SHM_LOCK		11
+#define	LINUX_SHM_UNLOCK	12
+#define	LINUX_SHM_STAT		13
+#define	LINUX_SHM_INFO		14
+
+#define	LINUX_SHM_RDONLY	0x1000
+#define	LINUX_SHM_RND		0x2000
+#define	LINUX_SHM_REMAP		0x4000
+
+/* semctl commands */
+#define	LINUX_GETPID		11
+#define	LINUX_GETVAL		12
+#define	LINUX_GETALL		13
+#define	LINUX_GETNCNT		14
+#define	LINUX_GETZCNT		15
+#define	LINUX_SETVAL		16
+#define	LINUX_SETALL		17
+#define	LINUX_SEM_STAT		18
+#define	LINUX_SEM_INFO		19
+
+/*
  * Version flags for semctl, msgctl, and shmctl commands
  * These are passed as bitflags or-ed with the actual command
  */
@@ -40,7 +83,7 @@
 #define	LINUX_IPC_64	0x0100	/* New version (support 32-bit UIDs, bigger
 				   message sizes, etc. */
 
-#if defined(__i386__) || defined(__amd64__)
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 
 struct linux_msgctl_args 
 {
@@ -135,8 +178,6 @@
 int linux_shmdt(struct thread *, struct linux_shmdt_args *);
 int linux_shmget(struct thread *, struct linux_shmget_args *);
 
-#define	LINUX_MSG_INFO	12
+#endif	/* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
-#endif	/* __i386__ || __amd64__ */
-
 #endif /* _LINUX_IPC_H_ */

Modified: trunk/sys/compat/linux/linux_mib.c
===================================================================
--- trunk/sys/compat/linux/linux_mib.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_mib.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1999 Marcel Moolenaar
  * All rights reserved.
@@ -27,11 +28,8 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_mib.c 293527 2016-01-09 16:08:22Z dchagin $");
 
-#include "opt_compat.h"
-#include "opt_kdtrace.h"
-
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/sdt.h>
@@ -42,84 +40,11 @@
 #include <sys/mount.h>
 #include <sys/jail.h>
 #include <sys/lock.h>
-#include <sys/mutex.h>
 #include <sys/sx.h>
 
-#ifdef COMPAT_LINUX32
-#include <machine/../linux32/linux.h>
-#else
-#include <machine/../linux/linux.h>
-#endif
-#include <compat/linux/linux_dtrace.h>
 #include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_misc.h>
 
-/* DTrace init */
-LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
-
-/**
- * DTrace probes in this module.
- */
-LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osname, entry);
-LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, sysctl_string_error, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, return, "int");
-
-LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osrelease, entry);
-LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, sysctl_string_error, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, return, "int");
-LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_oss_version, entry);
-LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, sysctl_string_error,
-    "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, return, "int");
-LIN_SDT_PROBE_DEFINE2(mib, linux_map_osrel, entry, "char *", "int *");
-LIN_SDT_PROBE_DEFINE1(mib, linux_map_osrel, return, "int");
-LIN_SDT_PROBE_DEFINE2(mib, linux_get_prison, entry, "struct prison *",
-    "struct prison **");
-LIN_SDT_PROBE_DEFINE1(mib, linux_get_prison, return, "struct linux_prison *");
-LIN_SDT_PROBE_DEFINE2(mib, linux_alloc_prison, entry, "struct prison *",
-    "struct linux_prison **");
-LIN_SDT_PROBE_DEFINE1(mib, linux_alloc_prison, return, "int");
-LIN_SDT_PROBE_DEFINE2(mib, linux_prison_create, entry, "void *", "void *");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, vfs_copyopt_error, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, return, "int");
-LIN_SDT_PROBE_DEFINE2(mib, linux_prison_check, entry, "void *", "void *");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_copyopt_error, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_getopt_error, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, return, "int");
-LIN_SDT_PROBE_DEFINE2(mib, linux_prison_set, entry, "void *", "void *");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_copyopt_error, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_getopt_error, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, return, "int");
-LIN_SDT_PROBE_DEFINE2(mib, linux_prison_get, entry, "void *", "void *");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopt_error, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopts_error, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, return, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_prison_destructor, entry, "void *");
-LIN_SDT_PROBE_DEFINE0(mib, linux_prison_destructor, return);
-LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, entry);
-LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, return);
-LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, entry);
-LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, return);
-LIN_SDT_PROBE_DEFINE2(mib, linux_get_osname, entry, "struct thread *",
-    "char *");
-LIN_SDT_PROBE_DEFINE0(mib, linux_get_osname, return);
-LIN_SDT_PROBE_DEFINE2(mib, linux_set_osname, entry, "struct thread *",
-    "char *");
-LIN_SDT_PROBE_DEFINE1(mib, linux_set_osname, return, "int");
-LIN_SDT_PROBE_DEFINE2(mib, linux_get_osrelease, entry, "struct thread *",
-    "char *");
-LIN_SDT_PROBE_DEFINE0(mib, linux_get_osrelease, return);
-LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, entry, "struct thread *");
-LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, return, "int");
-LIN_SDT_PROBE_DEFINE2(mib, linux_set_osrelease, entry, "struct thread *",
-    "char *");
-LIN_SDT_PROBE_DEFINE1(mib, linux_set_osrelease, return, "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, entry, "struct thread *");
-LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, return, "int");
-
-LIN_SDT_PROBE_DEFINE2(mib, linux_set_oss_version, entry, "struct thread *",
-    "int");
-LIN_SDT_PROBE_DEFINE1(mib, linux_set_oss_version, return, "int");
-
 struct linux_prison {
 	char	pr_osname[LINUX_MAX_UTSNAME];
 	char	pr_osrelease[LINUX_MAX_UTSNAME];
@@ -129,15 +54,14 @@
 
 static struct linux_prison lprison0 = {
 	.pr_osname =		"Linux",
-	.pr_osrelease =		"2.6.18",
+	.pr_osrelease =		LINUX_VERSION_STR,
 	.pr_oss_version =	0x030600,
-	.pr_osrel =		2006018
+	.pr_osrel =		LINUX_VERSION_CODE
 };
 
 static unsigned linux_osd_jail_slot;
 
-static SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0,
-	    "Linux mode");
+SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0, "Linux mode");
 
 static int	linux_set_osname(struct thread *td, char *osname);
 static int	linux_set_osrelease(struct thread *td, char *osrelease);
@@ -149,19 +73,12 @@
 	char osname[LINUX_MAX_UTSNAME];
 	int error;
 
-	LIN_SDT_PROBE0(mib, linux_sysctl_osname, entry);
-
 	linux_get_osname(req->td, osname);
 	error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
-	if (error != 0 || req->newptr == NULL) {
-		LIN_SDT_PROBE1(mib, linux_sysctl_osname, sysctl_string_error,
-		    error);
-		LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error);
+	if (error != 0 || req->newptr == NULL)
 		return (error);
-	}
 	error = linux_set_osname(req->td, osname);
 
-	LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error);
 	return (error);
 }
 
@@ -176,19 +93,12 @@
 	char osrelease[LINUX_MAX_UTSNAME];
 	int error;
 
-	LIN_SDT_PROBE0(mib, linux_sysctl_osrelease, entry);
-
 	linux_get_osrelease(req->td, osrelease);
 	error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
-	if (error != 0 || req->newptr == NULL) {
-		LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, sysctl_string_error,
-		    error);
-		LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error);
+	if (error != 0 || req->newptr == NULL)
 		return (error);
-	}
 	error = linux_set_osrelease(req->td, osrelease);
 
-	LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error);
 	return (error);
 }
 
@@ -203,19 +113,12 @@
 	int oss_version;
 	int error;
 
-	LIN_SDT_PROBE0(mib, linux_sysctl_oss_version, entry);
-
 	oss_version = linux_get_oss_version(req->td);
 	error = sysctl_handle_int(oidp, &oss_version, 0, req);
-	if (error != 0 || req->newptr == NULL) {
-		LIN_SDT_PROBE1(mib, linux_sysctl_oss_version,
-		    sysctl_string_error, error);
-		LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error);
+	if (error != 0 || req->newptr == NULL)
 		return (error);
-	}
 	error = linux_set_oss_version(req->td, oss_version);
 
-	LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error);
 	return (error);
 }
 
@@ -233,37 +136,26 @@
 	char *sep, *eosrelease;
 	int len, v0, v1, v2, v;
 
-	LIN_SDT_PROBE2(mib, linux_map_osrel, entry, osrelease, osrel);
-
 	len = strlen(osrelease);
 	eosrelease = osrelease + len;
 	v0 = strtol(osrelease, &sep, 10);
-	if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') {
-		LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
+	if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.')
 		return (EINVAL);
-	}
 	osrelease = sep + 1;
 	v1 = strtol(osrelease, &sep, 10);
-	if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') {
-		LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
+	if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.')
 		return (EINVAL);
-	}
 	osrelease = sep + 1;
 	v2 = strtol(osrelease, &sep, 10);
-	if (osrelease == sep || sep != eosrelease) {
-		LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
+	if (osrelease == sep || sep != eosrelease)
 		return (EINVAL);
-	}
 
 	v = v0 * 1000000 + v1 * 1000 + v2;
-	if (v < 1000000) {
-		LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
+	if (v < 1000000)
 		return (EINVAL);
-	}
 
 	*osrel = v;
 
-	LIN_SDT_PROBE1(mib, linux_map_osrel, return, 0);
 	return (0);
 }
 
@@ -277,8 +169,6 @@
 	struct prison *pr;
 	struct linux_prison *lpr;
 
-	LIN_SDT_PROBE2(mib, linux_get_prison, entry, spr, prp);
-
 	if (!linux_osd_jail_slot)
 		/* In case osd_register failed. */
 		spr = &prison0;
@@ -293,7 +183,6 @@
 	}
 	*prp = pr;
 
-	LIN_SDT_PROBE1(mib, linux_get_prison, return, lpr);
 	return (lpr);
 }
 
@@ -308,8 +197,6 @@
 	struct linux_prison *lpr, *nlpr;
 	int error;
 
-	LIN_SDT_PROBE2(mib, linux_alloc_prison, entry, pr, lprp);
-
 	/* If this prison already has Linux info, return that. */
 	error = 0;
 	lpr = linux_find_prison(pr, &ppr);
@@ -343,7 +230,6 @@
 	else
 		mtx_unlock(&pr->pr_mtx);
 
-	LIN_SDT_PROBE1(mib, linux_alloc_prison, return, error);
 	return (error);
 }
 
@@ -355,26 +241,16 @@
 {
 	struct prison *pr = obj;
 	struct vfsoptlist *opts = data;
-	int jsys, error;
+	int jsys;
 
-	LIN_SDT_PROBE2(mib, linux_prison_create, entry, obj, data);
-
-	error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
-	if (error != 0) {
-		LIN_SDT_PROBE1(mib, linux_prison_create, vfs_copyopt_error,
-		    error);
-	} else if (jsys == JAIL_SYS_INHERIT) {
-		LIN_SDT_PROBE1(mib, linux_prison_create, return, 0);
+	if (vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)) == 0 &&
+	    jsys == JAIL_SYS_INHERIT)
 		return (0);
-	}
 	/*
 	 * Inherit a prison's initial values from its parent
 	 * (different from JAIL_SYS_INHERIT which also inherits changes).
 	 */
-	error = linux_alloc_prison(pr, NULL);
-
-	LIN_SDT_PROBE1(mib, linux_prison_create, return, error);
-	return (error);
+	return (linux_alloc_prison(pr, NULL));
 }
 
 static int
@@ -384,80 +260,46 @@
 	char *osname, *osrelease;
 	int error, jsys, len, osrel, oss_version;
 
-	LIN_SDT_PROBE2(mib, linux_prison_check, entry, obj, data);
-
 	/* Check that the parameters are correct. */
 	error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
-	if (error != 0) {
-		LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error,
-		    error);
-	}
 	if (error != ENOENT) {
-		if (error != 0) {
-			LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
+		if (error != 0)
 			return (error);
-		}
-		if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) {
-			LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
+		if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT)
 			return (EINVAL);
-		}
 	}
 	error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
-	if (error != 0) {
-		LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error,
-		    error);
-	}
 	if (error != ENOENT) {
-		if (error != 0) {
-			LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
+		if (error != 0)
 			return (error);
-		}
-		if (len == 0 || osname[len - 1] != '\0') {
-			LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
+		if (len == 0 || osname[len - 1] != '\0')
 			return (EINVAL);
-		}
 		if (len > LINUX_MAX_UTSNAME) {
 			vfs_opterror(opts, "linux.osname too long");
-			LIN_SDT_PROBE1(mib, linux_prison_check, return,
-			    ENAMETOOLONG);
 			return (ENAMETOOLONG);
 		}
 	}
 	error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len);
-	if (error != 0) {
-		LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error,
-		    error);
-	}
 	if (error != ENOENT) {
-		if (error != 0) {
-			LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
+		if (error != 0)
 			return (error);
-		}
-		if (len == 0 || osrelease[len - 1] != '\0') {
-			LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
+		if (len == 0 || osrelease[len - 1] != '\0')
 			return (EINVAL);
-		}
 		if (len > LINUX_MAX_UTSNAME) {
 			vfs_opterror(opts, "linux.osrelease too long");
-			LIN_SDT_PROBE1(mib, linux_prison_check, return,
-			    ENAMETOOLONG);
 			return (ENAMETOOLONG);
 		}
 		error = linux_map_osrel(osrelease, &osrel);
 		if (error != 0) {
 			vfs_opterror(opts, "linux.osrelease format error");
-			LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
 			return (error);
 		}
 	}
 	error = vfs_copyopt(opts, "linux.oss_version", &oss_version,
 	    sizeof(oss_version));
-	if (error != 0)
-	    LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error, error);
 
 	if (error == ENOENT)
 		error = 0;
-	LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
 	return (error);
 }
 
@@ -470,24 +312,16 @@
 	char *osname, *osrelease;
 	int error, gotversion, jsys, len, oss_version;
 
-	LIN_SDT_PROBE2(mib, linux_prison_set, entry, obj, data);
-
 	/* Set the parameters, which should be correct. */
 	error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
-	if (error != 0)
-		LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error);
 	if (error == ENOENT)
 		jsys = -1;
 	error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
-	if (error != 0)
-		LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error);
 	if (error == ENOENT)
 		osname = NULL;
 	else
 		jsys = JAIL_SYS_NEW;
 	error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len);
-	if (error != 0)
-		LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error);
 	if (error == ENOENT)
 		osrelease = NULL;
 	else
@@ -494,8 +328,6 @@
 		jsys = JAIL_SYS_NEW;
 	error = vfs_copyopt(opts, "linux.oss_version", &oss_version,
 	    sizeof(oss_version));
-	if (error != 0)
-		LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error);
 	if (error == ENOENT)
 		gotversion = 0;
 	else {
@@ -517,7 +349,6 @@
 		error = linux_alloc_prison(pr, &lpr);
 		if (error) {
 			mtx_unlock(&pr->pr_mtx);
-			LIN_SDT_PROBE1(mib, linux_prison_set, return, error);
 			return (error);
 		}
 		if (osrelease) {
@@ -524,8 +355,6 @@
 			error = linux_map_osrel(osrelease, &lpr->pr_osrel);
 			if (error) {
 				mtx_unlock(&pr->pr_mtx);
-				LIN_SDT_PROBE1(mib, linux_prison_set, return,
-				    error);
 				return (error);
 			}
 			strlcpy(lpr->pr_osrelease, osrelease,
@@ -538,7 +367,6 @@
 		mtx_unlock(&pr->pr_mtx);
 	}
 
-	LIN_SDT_PROBE1(mib, linux_prison_set, return, 0);
 	return (0);
 }
 
@@ -561,40 +389,23 @@
 
 	static int version0;
 
-	LIN_SDT_PROBE2(mib, linux_prison_get, entry, obj, data);
-
 	/* See if this prison is the one with the Linux info. */
 	lpr = linux_find_prison(pr, &ppr);
 	i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
 	error = vfs_setopt(opts, "linux", &i, sizeof(i));
-	if (error != 0) {
-		LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, error);
-		if (error != ENOENT)
-			goto done;
-	}
+	if (error != 0 && error != ENOENT)
+		goto done;
 	if (i) {
 		error = vfs_setopts(opts, "linux.osname", lpr->pr_osname);
-		if (error != 0) {
-			LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
-			    error);
-			if (error != ENOENT)
-				goto done;
-		}
+		if (error != 0 && error != ENOENT)
+			goto done;
 		error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease);
-		if (error != 0) {
-			LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
-			    error);
-			if (error != ENOENT)
-				goto done;
-		}
+		if (error != 0 && error != ENOENT)
+			goto done;
 		error = vfs_setopt(opts, "linux.oss_version",
 		    &lpr->pr_oss_version, sizeof(lpr->pr_oss_version));
-		if (error != 0) {
-			LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error,
-			    error);
-			if(error != ENOENT)
-				goto done;
-		}
+		if (error != 0 && error != ENOENT)
+			goto done;
 	} else {
 		/*
 		 * If this prison is inheriting its Linux info, report
@@ -601,27 +412,15 @@
 		 * empty/zero parameters.
 		 */
 		error = vfs_setopts(opts, "linux.osname", "");
-		if (error != 0) {
-			LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
-			    error);
-			if(error != ENOENT)
-				goto done;
-		}
+		if (error != 0 && error != ENOENT)
+			goto done;
 		error = vfs_setopts(opts, "linux.osrelease", "");
-		if (error != 0) {
-			LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
-			    error);
-			if(error != ENOENT)
-				goto done;
-		}
+		if (error != 0 && error != ENOENT)
+			goto done;
 		error = vfs_setopt(opts, "linux.oss_version", &version0,
 		    sizeof(lpr->pr_oss_version));
-		if (error != 0) {
-			LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error,
-			    error);
-			if(error != ENOENT)
-				goto done;
-		}
+		if (error != 0 && error != ENOENT)
+			goto done;
 	}
 	error = 0;
 
@@ -628,7 +427,6 @@
  done:
 	mtx_unlock(&ppr->pr_mtx);
 
-	LIN_SDT_PROBE1(mib, linux_prison_get, return, error);
 	return (error);
 }
 
@@ -636,9 +434,7 @@
 linux_prison_destructor(void *data)
 {
 
-	LIN_SDT_PROBE1(mib, linux_prison_destructor, entry, data);
 	free(data, M_PRISON);
-	LIN_SDT_PROBE0(mib, linux_prison_destructor, return);
 }
 
 void
@@ -652,8 +448,6 @@
 	    [PR_METHOD_CHECK] =		linux_prison_check
 	};
 
-	LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry);
-
 	linux_osd_jail_slot =
 	    osd_jail_register(linux_prison_destructor, methods);
 	if (linux_osd_jail_slot > 0) {
@@ -663,8 +457,6 @@
 			(void)linux_alloc_prison(pr, NULL);
 		sx_xunlock(&allprison_lock);
 	}
-
-	LIN_SDT_PROBE0(mib, linux_osd_jail_register, return);
 }
 
 void
@@ -671,12 +463,8 @@
 linux_osd_jail_deregister(void)
 {
 
-	LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry);
-
 	if (linux_osd_jail_slot)
 		osd_jail_deregister(linux_osd_jail_slot);
-
-	LIN_SDT_PROBE0(mib, linux_osd_jail_register, return);
 }
 
 void
@@ -685,13 +473,9 @@
 	struct prison *pr;
 	struct linux_prison *lpr;
 
-	LIN_SDT_PROBE2(mib, linux_get_osname, entry, td, dst);
-
 	lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
 	bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME);
 	mtx_unlock(&pr->pr_mtx);
-
-	LIN_SDT_PROBE0(mib, linux_get_osname, return);
 }
 
 static int
@@ -700,13 +484,10 @@
 	struct prison *pr;
 	struct linux_prison *lpr;
 
-	LIN_SDT_PROBE2(mib, linux_set_osname, entry, td, osname);
-
 	lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
 	strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME);
 	mtx_unlock(&pr->pr_mtx);
 
-	LIN_SDT_PROBE1(mib, linux_set_osname, return, 0);
 	return (0);
 }
 
@@ -716,13 +497,9 @@
 	struct prison *pr;
 	struct linux_prison *lpr;
 
-	LIN_SDT_PROBE2(mib, linux_get_osrelease, entry, td, dst);
-
 	lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
 	bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME);
 	mtx_unlock(&pr->pr_mtx);
-
-	LIN_SDT_PROBE0(mib, linux_get_osrelease, return);
 }
 
 int
@@ -732,13 +509,10 @@
 	struct linux_prison *lpr;
 	int osrel;
 
-	LIN_SDT_PROBE1(mib, linux_kernver, entry, td);
-
 	lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
 	osrel = lpr->pr_osrel;
 	mtx_unlock(&pr->pr_mtx);
 
-	LIN_SDT_PROBE1(mib, linux_kernver, return, osrel);
 	return (osrel);
 }
 
@@ -749,8 +523,6 @@
 	struct linux_prison *lpr;
 	int error;
 
-	LIN_SDT_PROBE2(mib, linux_set_osrelease, entry, td, osrelease);
-
 	lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
 	error = linux_map_osrel(osrelease, &lpr->pr_osrel);
 	if (error == 0)
@@ -757,7 +529,6 @@
 		strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME);
 	mtx_unlock(&pr->pr_mtx);
 
-	LIN_SDT_PROBE1(mib, linux_set_osrelease, return, error);
 	return (error);
 }
 
@@ -768,13 +539,10 @@
 	struct linux_prison *lpr;
 	int version;
 
-	LIN_SDT_PROBE1(mib, linux_get_oss_version, entry, td);
-
 	lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
 	version = lpr->pr_oss_version;
 	mtx_unlock(&pr->pr_mtx);
 
-	LIN_SDT_PROBE1(mib, linux_get_oss_version, return, version);
 	return (version);
 }
 
@@ -784,74 +552,9 @@
 	struct prison *pr;
 	struct linux_prison *lpr;
 
-	LIN_SDT_PROBE2(mib, linux_set_oss_version, entry, td, oss_version);
-
 	lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
 	lpr->pr_oss_version = oss_version;
 	mtx_unlock(&pr->pr_mtx);
 
-	LIN_SDT_PROBE1(mib, linux_set_oss_version, return, 0);
 	return (0);
 }
-
-#if defined(DEBUG) || defined(KTR)
-/* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */
-
-u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))];
-
-static int
-linux_debug(int syscall, int toggle, int global)
-{
-
-	if (global) {
-		char c = toggle ? 0 : 0xff;
-
-		memset(linux_debug_map, c, sizeof(linux_debug_map));
-		return (0);
-	}
-	if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL)
-		return (EINVAL);
-	if (toggle)
-		clrbit(linux_debug_map, syscall);
-	else
-		setbit(linux_debug_map, syscall);
-	return (0);
-}
-
-/*
- * Usage: sysctl linux.debug=<syscall_nr>.<0/1>
- *
- *    E.g.: sysctl linux.debug=21.0
- *
- * As a special case, syscall "all" will apply to all syscalls globally.
- */
-#define LINUX_MAX_DEBUGSTR	16
-static int
-linux_sysctl_debug(SYSCTL_HANDLER_ARGS)
-{
-	char value[LINUX_MAX_DEBUGSTR], *p;
-	int error, sysc, toggle;
-	int global = 0;
-
-	value[0] = '\0';
-	error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req);
-	if (error || req->newptr == NULL)
-		return (error);
-	for (p = value; *p != '\0' && *p != '.'; p++);
-	if (*p == '\0')
-		return (EINVAL);
-	*p++ = '\0';
-	sysc = strtol(value, NULL, 0);
-	toggle = strtol(p, NULL, 0);
-	if (strcmp(value, "all") == 0)
-		global = 1;
-	error = linux_debug(sysc, toggle, global);
-	return (error);
-}
-
-SYSCTL_PROC(_compat_linux, OID_AUTO, debug,
-            CTLTYPE_STRING | CTLFLAG_RW,
-            0, 0, linux_sysctl_debug, "A",
-            "Linux debugging control");
-
-#endif /* DEBUG || KTR */

Modified: trunk/sys/compat/linux/linux_mib.h
===================================================================
--- trunk/sys/compat/linux/linux_mib.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_mib.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1999 Marcel Moolenaar
  * All rights reserved.
@@ -25,12 +26,16 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_mib.h 293553 2016-01-09 16:57:03Z dchagin $
  */
 
 #ifndef _LINUX_MIB_H_
 #define _LINUX_MIB_H_
 
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_compat_linux);
+#endif
+
 void	linux_osd_jail_register(void);
 void	linux_osd_jail_deregister(void);
 
@@ -42,9 +47,20 @@
 
 int	linux_kernver(struct thread *td);
 
-#define	LINUX_KERNVER_2004000		2004000
-#define	LINUX_KERNVER_2006000		2006000
+#define	LINUX_KVERSION		2
+#define	LINUX_KPATCHLEVEL	6
+#define	LINUX_KSUBLEVEL		32
 
+#define	LINUX_KERNVER(a,b,c)	(((a) << 16) + ((b) << 8) + (c))
+#define	LINUX_VERSION_CODE	LINUX_KERNVER(LINUX_KVERSION,		\
+				    LINUX_KPATCHLEVEL, LINUX_KSUBLEVEL)
+#define	LINUX_KERNVERSTR(x)	#x
+#define	LINUX_XKERNVERSTR(x)	LINUX_KERNVERSTR(x)
+#define	LINUX_VERSION_STR	LINUX_XKERNVERSTR(LINUX_KVERSION.LINUX_KPATCHLEVEL.LINUX_KSUBLEVEL)
+
+#define	LINUX_KERNVER_2004000	LINUX_KERNVER(2,4,0)
+#define	LINUX_KERNVER_2006000	LINUX_KERNVER(2,6,0)
+
 #define	linux_use26(t)		(linux_kernver(t) >= LINUX_KERNVER_2006000)
 
 #endif /* _LINUX_MIB_H_ */

Modified: trunk/sys/compat/linux/linux_misc.c
===================================================================
--- trunk/sys/compat/linux/linux_misc.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_misc.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,6 +1,7 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2002 Doug Rabson
- * Copyright (c) 1994-1995 S\xF8ren Schmidt
+ * Copyright (c) 1994-1995 Søren Schmidt
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -28,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_misc.c 302962 2016-07-17 15:07:33Z dchagin $");
 
 #include "opt_compat.h"
 #include "opt_kdtrace.h"
@@ -89,22 +90,25 @@
 #include <compat/linux/linux_file.h>
 #include <compat/linux/linux_mib.h>
 #include <compat/linux/linux_signal.h>
+#include <compat/linux/linux_timer.h>
 #include <compat/linux/linux_util.h>
 #include <compat/linux/linux_sysproto.h>
 #include <compat/linux/linux_emul.h>
 #include <compat/linux/linux_misc.h>
 
-/* DTrace init */
-LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
+/**
+ * Special DTrace provider for the linuxulator.
+ *
+ * In this file we define the provider for the entire linuxulator. All
+ * modules (= files of the linuxulator) use it.
+ *
+ * We define a different name depending on the emulated bitsize, see
+ * ../../<ARCH>/linux{,32}/linux.h, e.g.:
+ *      native bitsize          = linuxulator
+ *      amd64, 32bit emulation  = linuxulator32
+ */
+LIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE);
 
-/* Linuxulator-global DTrace probes */
-LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked);
-LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock);
-LIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, locked);
-LIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, unlock);
-LIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, locked);
-LIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, unlock);
-
 int stclohz;				/* Statistics clock frequency */
 
 static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
@@ -130,6 +134,15 @@
 	l_uint		mem_unit;
 	char		_f[20-2*sizeof(l_long)-sizeof(l_int)];	/* padding */
 };
+
+struct l_pselect6arg {
+	l_uintptr_t	ss;
+	l_size_t	ss_len;
+};
+
+static int	linux_utimensat_nsec_valid(l_long);
+
+
 int
 linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
 {
@@ -187,24 +200,27 @@
 	if (ldebug(alarm))
 		printf(ARGS(alarm, "%u"), args->secs);
 #endif
-	
 	secs = args->secs;
+	/*
+	 * Linux alarm() is always successful. Limit secs to INT32_MAX / 2
+	 * to match kern_setitimer()'s limit to avoid error from it.
+	 *
+	 * XXX. Linux limit secs to INT_MAX on 32 and does not limit on 64-bit
+	 * platforms.
+	 */
+	if (secs > INT32_MAX / 2)
+		secs = INT32_MAX / 2;
 
-	if (secs > INT_MAX)
-		secs = INT_MAX;
-
-	it.it_value.tv_sec = (long) secs;
+	it.it_value.tv_sec = secs;
 	it.it_value.tv_usec = 0;
-	it.it_interval.tv_sec = 0;
-	it.it_interval.tv_usec = 0;
+	timevalclear(&it.it_interval);
 	error = kern_setitimer(td, ITIMER_REAL, &it, &old_it);
-	if (error)
-		return (error);
-	if (timevalisset(&old_it.it_value)) {
-		if (old_it.it_value.tv_usec != 0)
-			old_it.it_value.tv_sec++;
-		td->td_retval[0] = old_it.it_value.tv_sec;
-	}
+	KASSERT(error == 0, ("kern_setitimer returns %d", error));
+
+	if ((old_it.it_value.tv_sec == 0 && old_it.it_value.tv_usec > 0) ||
+	    old_it.it_value.tv_usec >= 500000)
+		old_it.it_value.tv_sec++;
+	td->td_retval[0] = old_it.it_value.tv_sec;
 	return (0);
 }
 
@@ -247,7 +263,7 @@
 	unsigned long bss_size;
 	char *library;
 	ssize_t aresid;
-	int error, locked, vfslocked, writecount;
+	int error, locked, writecount;
 
 	LCONVPATHEXIST(td, args->library, &library);
 
@@ -257,11 +273,10 @@
 #endif
 
 	a_out = NULL;
-	vfslocked = 0;
 	locked = 0;
 	vp = NULL;
 
-	NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
+	NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | AUDITVNODE1,
 	    UIO_SYSSPACE, library, td);
 	error = namei(&ni);
 	LFREEPATH(library);
@@ -269,7 +284,6 @@
 		goto cleanup;
 
 	vp = ni.ni_vp;
-	vfslocked = NDHASGIANT(&ni);
 	NDFREE(&ni, NDF_ONLY_PNBUF);
 
 	/*
@@ -396,7 +410,6 @@
 	 */
 	locked = 0;
 	VOP_UNLOCK(vp, 0);
-	VFS_UNLOCK_GIANT(vfslocked);
 
 	/*
 	 * Check if file_offset page aligned. Currently we cannot handle
@@ -414,8 +427,8 @@
 
 		/* get anon user mapping, read+write+execute */
 		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
-		    &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
-		    VM_PROT_ALL, 0);
+		    &vmaddr, a_out->a_text + a_out->a_data, 0, VMFS_NO_SPACE,
+		    VM_PROT_ALL, VM_PROT_ALL, 0);
 		if (error)
 			goto cleanup;
 
@@ -459,7 +472,8 @@
 
 		/* allocate some 'anon' space */
 		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
-		    &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
+		    &vmaddr, bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL,
+		    VM_PROT_ALL, 0);
 		if (error)
 			goto cleanup;
 	}
@@ -466,14 +480,12 @@
 
 cleanup:
 	/* Unlock vnode if needed */
-	if (locked) {
+	if (locked)
 		VOP_UNLOCK(vp, 0);
-		VFS_UNLOCK_GIANT(vfslocked);
-	}
 
 	/* Release the temporary mapping. */
 	if (a_out)
-		kmem_free_wakeup(exec_map, (vm_offset_t)a_out, PAGE_SIZE);
+		kmap_free_wakeup(exec_map, (vm_offset_t)a_out, PAGE_SIZE);
 
 	return (error);
 }
@@ -529,7 +541,7 @@
 		tvp = NULL;
 
 	error = kern_select(td, args->nfds, args->readfds, args->writefds,
-	    args->exceptfds, tvp, sizeof(l_int) * 8);
+	    args->exceptfds, tvp, LINUX_NFDBITS);
 
 #ifdef DEBUG
 	if (ldebug(select))
@@ -696,9 +708,9 @@
 	if (args->buf != NULL) {
 		p = td->td_proc;
 		PROC_LOCK(p);
-		PROC_SLOCK(p);
+		PROC_STATLOCK(p);
 		calcru(p, &utime, &stime);
-		PROC_SUNLOCK(p);
+		PROC_STATUNLOCK(p);
 		calccru(p, &cutime, &cstime);
 		PROC_UNLOCK(p);
 
@@ -744,12 +756,11 @@
 			*p = '\0';
 			break;
 		}
-	strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME);
+	strlcpy(utsname.machine, linux_kplatform, LINUX_MAX_UTSNAME);
 
 	return (copyout(&utsname, args->buf, sizeof(utsname)));
 }
 
-#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 struct l_utimbuf {
 	l_time_t l_actime;
 	l_time_t l_modtime;
@@ -820,6 +831,99 @@
 	return (error);
 }
 
+static int
+linux_utimensat_nsec_valid(l_long nsec)
+{
+
+	if (nsec == LINUX_UTIME_OMIT || nsec == LINUX_UTIME_NOW)
+		return (0);
+	if (nsec >= 0 && nsec <= 999999999)
+		return (0);
+	return (1);
+}
+
+int 
+linux_utimensat(struct thread *td, struct linux_utimensat_args *args)
+{
+	struct l_timespec l_times[2];
+	struct timespec times[2], *timesp = NULL;
+	char *path = NULL;
+	int error, dfd, flags = 0;
+
+	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+
+#ifdef DEBUG
+	if (ldebug(utimensat))
+		printf(ARGS(utimensat, "%d, *"), dfd);
+#endif
+
+	if (args->flags & ~LINUX_AT_SYMLINK_NOFOLLOW)
+		return (EINVAL);
+
+	if (args->times != NULL) {
+		error = copyin(args->times, l_times, sizeof(l_times));
+		if (error != 0)
+			return (error);
+
+		if (linux_utimensat_nsec_valid(l_times[0].tv_nsec) != 0 ||
+		    linux_utimensat_nsec_valid(l_times[1].tv_nsec) != 0)
+			return (EINVAL);
+
+		times[0].tv_sec = l_times[0].tv_sec;
+		switch (l_times[0].tv_nsec)
+		{
+		case LINUX_UTIME_OMIT:
+			times[0].tv_nsec = UTIME_OMIT;
+			break;
+		case LINUX_UTIME_NOW:
+			times[0].tv_nsec = UTIME_NOW;
+			break;
+		default:
+			times[0].tv_nsec = l_times[0].tv_nsec;
+		}
+
+		times[1].tv_sec = l_times[1].tv_sec;
+		switch (l_times[1].tv_nsec)
+		{
+		case LINUX_UTIME_OMIT:
+			times[1].tv_nsec = UTIME_OMIT;
+			break;
+		case LINUX_UTIME_NOW:
+			times[1].tv_nsec = UTIME_NOW;
+			break;
+		default:
+			times[1].tv_nsec = l_times[1].tv_nsec;
+			break;
+		}
+		timesp = times;
+
+		/* This breaks POSIX, but is what the Linux kernel does
+		 * _on purpose_ (documented in the man page for utimensat(2)),
+		 * so we must follow that behaviour. */
+		if (times[0].tv_nsec == UTIME_OMIT &&
+		    times[1].tv_nsec == UTIME_OMIT)
+			return (0);
+	}
+
+	if (args->pathname != NULL)
+		LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+	else if (args->flags != 0)
+		return (EINVAL);
+
+	if (args->flags & LINUX_AT_SYMLINK_NOFOLLOW)
+		flags |= AT_SYMLINK_NOFOLLOW;
+
+	if (path == NULL)
+		error = kern_futimens(td, dfd, timesp, UIO_SYSSPACE);
+	else {
+		error = kern_utimensat(td, dfd, path, UIO_SYSSPACE, timesp,
+	    		UIO_SYSSPACE, flags);
+		LFREEPATH(path);
+	}
+
+	return (error);
+}
+
 int
 linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
 {
@@ -852,7 +956,6 @@
 	LFREEPATH(fname);
 	return (error);
 }
-#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 int
 linux_common_wait(struct thread *td, int pid, int *status,
@@ -868,10 +971,12 @@
 		tmpstat &= 0xffff;
 		if (WIFSIGNALED(tmpstat))
 			tmpstat = (tmpstat & 0xffffff80) |
-			    BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
+			    bsd_to_linux_signal(WTERMSIG(tmpstat));
 		else if (WIFSTOPPED(tmpstat))
 			tmpstat = (tmpstat & 0xffff00ff) |
-			    (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
+			    (bsd_to_linux_signal(WSTOPSIG(tmpstat)) << 8);
+		else if (WIFCONTINUED(tmpstat))
+			tmpstat = 0xffff;
 		error = copyout(&tmpstat, status, sizeof(int));
 	}
 
@@ -878,32 +983,120 @@
 	return (error);
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
 {
-	int options;
- 
+	struct linux_wait4_args wait4_args;
+
 #ifdef DEBUG
 	if (ldebug(waitpid))
 		printf(ARGS(waitpid, "%d, %p, %d"),
 		    args->pid, (void *)args->status, args->options);
 #endif
-	/*
-	 * this is necessary because the test in kern_wait doesn't work
-	 * because we mess with the options here
-	 */
-	if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE))
+
+	wait4_args.pid = args->pid;
+	wait4_args.status = args->status;
+	wait4_args.options = args->options;
+	wait4_args.rusage = NULL;
+
+	return (linux_wait4(td, &wait4_args));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_wait4(struct thread *td, struct linux_wait4_args *args)
+{
+	int error, options;
+	struct rusage ru, *rup;
+
+#ifdef DEBUG
+	if (ldebug(wait4))
+		printf(ARGS(wait4, "%d, %p, %d, %p"),
+		    args->pid, (void *)args->status, args->options,
+		    (void *)args->rusage);
+#endif
+	if (args->options & ~(LINUX_WUNTRACED | LINUX_WNOHANG |
+	    LINUX_WCONTINUED | __WCLONE | __WNOTHREAD | __WALL))
 		return (EINVAL);
-   
-	options = (args->options & (WNOHANG | WUNTRACED));
-	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
-	if (args->options & __WCLONE)
-		options |= WLINUXCLONE;
 
-	return (linux_common_wait(td, args->pid, args->status, options, NULL));
+	options = WEXITED;
+	linux_to_bsd_waitopts(args->options, &options);
+
+	if (args->rusage != NULL)
+		rup = &ru;
+	else
+		rup = NULL;
+	error = linux_common_wait(td, args->pid, args->status, options, rup);
+	if (error != 0)
+		return (error);
+	if (args->rusage != NULL)
+		error = linux_copyout_rusage(&ru, args->rusage);
+	return (error);
 }
 
+int
+linux_waitid(struct thread *td, struct linux_waitid_args *args)
+{
+	int status, options, sig;
+	struct __wrusage wru;
+	siginfo_t siginfo;
+	l_siginfo_t lsi;
+	idtype_t idtype;
+	struct proc *p;
+	int error;
 
+	options = 0;
+	linux_to_bsd_waitopts(args->options, &options);
+
+	if (options & ~(WNOHANG | WNOWAIT | WEXITED | WUNTRACED | WCONTINUED))
+		return (EINVAL);
+	if (!(options & (WEXITED | WUNTRACED | WCONTINUED)))
+		return (EINVAL);
+
+	switch (args->idtype) {
+	case LINUX_P_ALL:
+		idtype = P_ALL;
+		break;
+	case LINUX_P_PID:
+		if (args->id <= 0)
+			return (EINVAL);
+		idtype = P_PID;
+		break;
+	case LINUX_P_PGID:
+		if (args->id <= 0)
+			return (EINVAL);
+		idtype = P_PGID;
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	error = kern_wait6(td, idtype, args->id, &status, options,
+	    &wru, &siginfo);
+	if (error != 0)
+		return (error);
+	if (args->rusage != NULL) {
+		error = linux_copyout_rusage(&wru.wru_children,
+		    args->rusage);
+		if (error != 0)
+			return (error);
+	}
+	if (args->info != NULL) {
+		p = td->td_proc;
+		if (td->td_retval[0] == 0)
+			bzero(&lsi, sizeof(lsi));
+		else {
+			sig = bsd_to_linux_signal(siginfo.si_signo);
+			siginfo_to_lsiginfo(&siginfo, &lsi, sig);
+		}
+		error = copyout(&lsi, args->info, sizeof(lsi));
+	}
+	td->td_retval[0] = 0;
+
+	return (error);
+}
+
 int
 linux_mknod(struct thread *td, struct linux_mknod_args *args)
 {
@@ -914,7 +1107,8 @@
 
 #ifdef DEBUG
 	if (ldebug(mknod))
-		printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev);
+		printf(ARGS(mknod, "%s, %d, %ju"), path, args->mode,
+		    (uintmax_t)args->dev);
 #endif
 
 	switch (args->mode & S_IFMT) {
@@ -1005,15 +1199,23 @@
 int
 linux_personality(struct thread *td, struct linux_personality_args *args)
 {
+	struct linux_pemuldata *pem;
+	struct proc *p = td->td_proc;
+	uint32_t old;
+
 #ifdef DEBUG
 	if (ldebug(personality))
-		printf(ARGS(personality, "%lu"), (unsigned long)args->per);
+		printf(ARGS(personality, "%u"), args->per);
 #endif
-	if (args->per != 0)
-		return (EINVAL);
 
-	/* Yes Jim, it's still a Linux... */
-	td->td_retval[0] = 0;
+	PROC_LOCK(p);
+	pem = pem_find(p);
+	old = pem->persona;
+	if (args->per != 0xffffffff)
+		pem->persona = args->per;
+	PROC_UNLOCK(p);
+
+	td->td_retval[0] = old;
 	return (0);
 }
 
@@ -1084,6 +1286,7 @@
 	return (copyout(&ls, uap->itv, sizeof(ls)));
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_nice(struct thread *td, struct linux_nice_args *args)
 {
@@ -1094,6 +1297,7 @@
 	bsd_args.prio = args->inc;
 	return (sys_setpriority(td, &bsd_args));
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 int
 linux_setgroups(struct thread *td, struct linux_setgroups_args *args)
@@ -1107,7 +1311,7 @@
 	ngrp = args->gidsetsize;
 	if (ngrp < 0 || ngrp >= ngroups_max + 1)
 		return (EINVAL);
-	linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK);
+	linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK);
 	error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t));
 	if (error)
 		goto out;
@@ -1143,12 +1347,12 @@
 		newcred->cr_ngroups = 1;
 
 	setsugid(p);
-	p->p_ucred = newcred;
+	proc_set_cred(p, newcred);
 	PROC_UNLOCK(p);
 	crfree(oldcred);
 	error = 0;
 out:
-	free(linux_gidset, M_TEMP);
+	free(linux_gidset, M_LINUX);
 	return (error);
 }
 
@@ -1180,7 +1384,7 @@
 
 	ngrp = 0;
 	linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset),
-	    M_TEMP, M_WAITOK);
+	    M_LINUX, M_WAITOK);
 	while (ngrp < bsd_gidsetsz) {
 		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
 		ngrp++;
@@ -1187,7 +1391,7 @@
 	}
 
 	error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t));
-	free(linux_gidset, M_TEMP);
+	free(linux_gidset, M_LINUX);
 	if (error)
 		return (error);
 
@@ -1225,6 +1429,7 @@
 	return (kern_setrlimit(td, which, &bsd_rlim));
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
 {
@@ -1267,6 +1472,7 @@
 #endif
 	return (copyout(&rlim, args->rlim, sizeof(rlim)));
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 int
 linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
@@ -1302,7 +1508,9 @@
 linux_sched_setscheduler(struct thread *td,
     struct linux_sched_setscheduler_args *args)
 {
-	struct sched_setscheduler_args bsd;
+	struct sched_param sched_param;
+	struct thread *tdt;
+	int error, policy;
 
 #ifdef DEBUG
 	if (ldebug(sched_setscheduler))
@@ -1312,21 +1520,29 @@
 
 	switch (args->policy) {
 	case LINUX_SCHED_OTHER:
-		bsd.policy = SCHED_OTHER;
+		policy = SCHED_OTHER;
 		break;
 	case LINUX_SCHED_FIFO:
-		bsd.policy = SCHED_FIFO;
+		policy = SCHED_FIFO;
 		break;
 	case LINUX_SCHED_RR:
-		bsd.policy = SCHED_RR;
+		policy = SCHED_RR;
 		break;
 	default:
 		return (EINVAL);
 	}
 
-	bsd.pid = args->pid;
-	bsd.param = (struct sched_param *)args->param;
-	return (sys_sched_setscheduler(td, &bsd));
+	error = copyin(args->param, &sched_param, sizeof(sched_param));
+	if (error)
+		return (error);
+
+	tdt = linux_tdfind(td, args->pid, -1);
+	if (tdt == NULL)
+		return (ESRCH);
+
+	error = kern_sched_setscheduler(td, tdt, policy, &sched_param);
+	PROC_UNLOCK(tdt->td_proc);
+	return (error);
 }
 
 int
@@ -1333,8 +1549,8 @@
 linux_sched_getscheduler(struct thread *td,
     struct linux_sched_getscheduler_args *args)
 {
-	struct sched_getscheduler_args bsd;
-	int error;
+	struct thread *tdt;
+	int error, policy;
 
 #ifdef DEBUG
 	if (ldebug(sched_getscheduler))
@@ -1341,10 +1557,14 @@
 		printf(ARGS(sched_getscheduler, "%d"), args->pid);
 #endif
 
-	bsd.pid = args->pid;
-	error = sys_sched_getscheduler(td, &bsd);
+	tdt = linux_tdfind(td, args->pid, -1);
+	if (tdt == NULL)
+		return (ESRCH);
 
-	switch (td->td_retval[0]) {
+	error = kern_sched_getscheduler(td, tdt, &policy);
+	PROC_UNLOCK(tdt->td_proc);
+
+	switch (policy) {
 	case SCHED_OTHER:
 		td->td_retval[0] = LINUX_SCHED_OTHER;
 		break;
@@ -1355,7 +1575,6 @@
 		td->td_retval[0] = LINUX_SCHED_RR;
 		break;
 	}
-
 	return (error);
 }
 
@@ -1481,21 +1700,13 @@
 int
 linux_getpid(struct thread *td, struct linux_getpid_args *args)
 {
-	struct linux_emuldata *em;
 
 #ifdef DEBUG
 	if (ldebug(getpid))
 		printf(ARGS(getpid, ""));
 #endif
+	td->td_retval[0] = td->td_proc->p_pid;
 
-	if (linux_use26(td)) {
-		em = em_find(td->td_proc, EMUL_DONTLOCK);
-		KASSERT(em != NULL, ("getpid: emuldata not found.\n"));
-		td->td_retval[0] = em->shared->group_pid;
-	} else {
-		td->td_retval[0] = td->td_proc->p_pid;
-	}
-
 	return (0);
 }
 
@@ -1502,6 +1713,7 @@
 int
 linux_gettid(struct thread *td, struct linux_gettid_args *args)
 {
+	struct linux_emuldata *em;
 
 #ifdef DEBUG
 	if (ldebug(gettid))
@@ -1508,7 +1720,11 @@
 		printf(ARGS(gettid, ""));
 #endif
 
-	td->td_retval[0] = td->td_proc->p_pid;
+	em = em_find(td);
+	KASSERT(em != NULL, ("gettid: emuldata not found.\n"));
+
+	td->td_retval[0] = em->em_tid;
+
 	return (0);
 }
 
@@ -1516,8 +1732,6 @@
 int
 linux_getppid(struct thread *td, struct linux_getppid_args *args)
 {
-	struct linux_emuldata *em;
-	struct proc *p, *pp;
 
 #ifdef DEBUG
 	if (ldebug(getppid))
@@ -1524,42 +1738,9 @@
 		printf(ARGS(getppid, ""));
 #endif
 
-	if (!linux_use26(td)) {
-		PROC_LOCK(td->td_proc);
-		td->td_retval[0] = td->td_proc->p_pptr->p_pid;
-		PROC_UNLOCK(td->td_proc);
-		return (0);
-	}
-
-	em = em_find(td->td_proc, EMUL_DONTLOCK);
-
-	KASSERT(em != NULL, ("getppid: process emuldata not found.\n"));
-
-	/* find the group leader */
-	p = pfind(em->shared->group_pid);
-
-	if (p == NULL) {
-#ifdef DEBUG
-	   	printf(LMSG("parent process not found.\n"));
-#endif
-		return (0);
-	}
-
-	pp = p->p_pptr;		/* switch to parent */
-	PROC_LOCK(pp);
-	PROC_UNLOCK(p);
-
-	/* if its also linux process */
-	if (pp->p_sysent == &elf_linux_sysvec) {
-		em = em_find(pp, EMUL_DONTLOCK);
-		KASSERT(em != NULL, ("getppid: parent emuldata not found.\n"));
-
-		td->td_retval[0] = em->shared->group_pid;
-	} else
-		td->td_retval[0] = pp->p_pid;
-
-	PROC_UNLOCK(pp);
-
+	PROC_LOCK(td->td_proc);
+	td->td_retval[0] = td->td_proc->p_pptr->p_pid;
+	PROC_UNLOCK(td->td_proc);
 	return (0);
 }
 
@@ -1664,7 +1845,6 @@
 int
 linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
 {
-	struct linux_emuldata *em;
 
 #ifdef DEBUG
 	if (ldebug(exit_group))
@@ -1671,15 +1851,8 @@
 		printf(ARGS(exit_group, "%i"), args->error_code);
 #endif
 
-	em = em_find(td->td_proc, EMUL_DONTLOCK);
-	if (em->shared->refs > 1) {
-		EMUL_SHARED_WLOCK(&emul_shared_lock);
-		em->shared->flags |= EMUL_SHARED_HASXSTAT;
-		em->shared->xstat = W_EXITCODE(args->error_code, 0);
-		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
-		if (linux_use26(td))
-			linux_kill_threads(td, SIGKILL);
-	}
+	LINUX_CTR2(exit_group, "thread(%d) (%d)", td->td_tid,
+	    args->error_code);
 
 	/*
 	 * XXX: we should send a signal to the parent if
@@ -1687,8 +1860,7 @@
 	 * as it doesnt occur often.
 	 */
 	exit1(td, W_EXITCODE(args->error_code, 0));
-
-	return (0);
+		/* NOTREACHED */
 }
 
 #define _LINUX_CAPABILITY_VERSION  0x19980330
@@ -1796,8 +1968,9 @@
 
 #ifdef DEBUG
 	if (ldebug(prctl))
-		printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option,
-		    args->arg2, args->arg3, args->arg4, args->arg5);
+		printf(ARGS(prctl, "%d, %ju, %ju, %ju, %ju"), args->option,
+		    (uintmax_t)args->arg2, (uintmax_t)args->arg3,
+		    (uintmax_t)args->arg4, (uintmax_t)args->arg5);
 #endif
 
 	switch (args->option) {
@@ -1804,16 +1977,14 @@
 	case LINUX_PR_SET_PDEATHSIG:
 		if (!LINUX_SIG_VALID(args->arg2))
 			return (EINVAL);
-		em = em_find(p, EMUL_DOLOCK);
+		em = em_find(td);
 		KASSERT(em != NULL, ("prctl: emuldata not found.\n"));
 		em->pdeath_signal = args->arg2;
-		EMUL_UNLOCK(&emul_lock);
 		break;
 	case LINUX_PR_GET_PDEATHSIG:
-		em = em_find(p, EMUL_DOLOCK);
+		em = em_find(td);
 		KASSERT(em != NULL, ("prctl: emuldata not found.\n"));
 		pdeath_signal = em->pdeath_signal;
-		EMUL_UNLOCK(&emul_lock);
 		error = copyout(&pdeath_signal,
 		    (void *)(register_t)args->arg2,
 		    sizeof(pdeath_signal));
@@ -1878,6 +2049,57 @@
 	return (error);
 }
 
+int
+linux_sched_setparam(struct thread *td,
+    struct linux_sched_setparam_args *uap)
+{
+	struct sched_param sched_param;
+	struct thread *tdt;
+	int error;
+
+#ifdef DEBUG
+	if (ldebug(sched_setparam))
+		printf(ARGS(sched_setparam, "%d, *"), uap->pid);
+#endif
+
+	error = copyin(uap->param, &sched_param, sizeof(sched_param));
+	if (error)
+		return (error);
+
+	tdt = linux_tdfind(td, uap->pid, -1);
+	if (tdt == NULL)
+		return (ESRCH);
+
+	error = kern_sched_setparam(td, tdt, &sched_param);
+	PROC_UNLOCK(tdt->td_proc);
+	return (error);
+}
+
+int
+linux_sched_getparam(struct thread *td,
+    struct linux_sched_getparam_args *uap)
+{
+	struct sched_param sched_param;
+	struct thread *tdt;
+	int error;
+
+#ifdef DEBUG
+	if (ldebug(sched_getparam))
+		printf(ARGS(sched_getparam, "%d, *"), uap->pid);
+#endif
+
+	tdt = linux_tdfind(td, uap->pid, -1);
+	if (tdt == NULL)
+		return (ESRCH);
+
+	error = kern_sched_getparam(td, tdt, &sched_param);
+	PROC_UNLOCK(tdt->td_proc);
+	if (error == 0)
+		error = copyout(&sched_param, uap->param,
+		    sizeof(sched_param));
+	return (error);
+}
+
 /*
  * Get affinity of a process.
  */
@@ -1886,6 +2108,7 @@
     struct linux_sched_getaffinity_args *args)
 {
 	int error;
+	struct thread *tdt;
 	struct cpuset_getaffinity_args cga;
 
 #ifdef DEBUG
@@ -1896,9 +2119,14 @@
 	if (args->len < sizeof(cpuset_t))
 		return (EINVAL);
 
+	tdt = linux_tdfind(td, args->pid, -1);
+	if (tdt == NULL)
+		return (ESRCH);
+
+	PROC_UNLOCK(tdt->td_proc);
 	cga.level = CPU_LEVEL_WHICH;
-	cga.which = CPU_WHICH_PID;
-	cga.id = args->pid;
+	cga.which = CPU_WHICH_TID;
+	cga.id = tdt->td_tid;
 	cga.cpusetsize = sizeof(cpuset_t);
 	cga.mask = (cpuset_t *) args->user_mask_ptr;
 
@@ -1916,6 +2144,7 @@
     struct linux_sched_setaffinity_args *args)
 {
 	struct cpuset_setaffinity_args csa;
+	struct thread *tdt;
 
 #ifdef DEBUG
 	if (ldebug(sched_setaffinity))
@@ -1925,11 +2154,376 @@
 	if (args->len < sizeof(cpuset_t))
 		return (EINVAL);
 
+	tdt = linux_tdfind(td, args->pid, -1);
+	if (tdt == NULL)
+		return (ESRCH);
+
+	PROC_UNLOCK(tdt->td_proc);
 	csa.level = CPU_LEVEL_WHICH;
-	csa.which = CPU_WHICH_PID;
-	csa.id = args->pid;
+	csa.which = CPU_WHICH_TID;
+	csa.id = tdt->td_tid;
 	csa.cpusetsize = sizeof(cpuset_t);
 	csa.mask = (cpuset_t *) args->user_mask_ptr;
 
 	return (sys_cpuset_setaffinity(td, &csa));
 }
+
+struct linux_rlimit64 {
+	uint64_t	rlim_cur;
+	uint64_t	rlim_max;
+};
+
+int
+linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args)
+{
+	struct rlimit rlim, nrlim;
+	struct linux_rlimit64 lrlim;
+	struct proc *p;
+	u_int which;
+	int flags;
+	int error;
+
+#ifdef DEBUG
+	if (ldebug(prlimit64))
+		printf(ARGS(prlimit64, "%d, %d, %p, %p"), args->pid,
+		    args->resource, (void *)args->new, (void *)args->old);
+#endif
+
+	if (args->resource >= LINUX_RLIM_NLIMITS)
+		return (EINVAL);
+
+	which = linux_to_bsd_resource[args->resource];
+	if (which == -1)
+		return (EINVAL);
+
+	if (args->new != NULL) {
+		/*
+		 * Note. Unlike FreeBSD where rlim is signed 64-bit Linux
+		 * rlim is unsigned 64-bit. FreeBSD treats negative limits
+		 * as INFINITY so we do not need a conversion even.
+		 */
+		error = copyin(args->new, &nrlim, sizeof(nrlim));
+		if (error != 0)
+			return (error);
+	}
+
+	flags = PGET_HOLD | PGET_NOTWEXIT;
+	if (args->new != NULL)
+		flags |= PGET_CANDEBUG;
+	else
+		flags |= PGET_CANSEE;
+	error = pget(args->pid, flags, &p);
+	if (error != 0)
+		return (error);
+
+	if (args->old != NULL) {
+		PROC_LOCK(p);
+		lim_rlimit(p, which, &rlim);
+		PROC_UNLOCK(p);
+		if (rlim.rlim_cur == RLIM_INFINITY)
+			lrlim.rlim_cur = LINUX_RLIM_INFINITY;
+		else
+			lrlim.rlim_cur = rlim.rlim_cur;
+		if (rlim.rlim_max == RLIM_INFINITY)
+			lrlim.rlim_max = LINUX_RLIM_INFINITY;
+		else
+			lrlim.rlim_max = rlim.rlim_max;
+		error = copyout(&lrlim, args->old, sizeof(lrlim));
+		if (error != 0)
+			goto out;
+	}
+
+	if (args->new != NULL)
+		error = kern_proc_setrlimit(td, p, which, &nrlim);
+
+ out:
+	PRELE(p);
+	return (error);
+}
+
+int
+linux_pselect6(struct thread *td, struct linux_pselect6_args *args)
+{
+	struct timeval utv, tv0, tv1, *tvp;
+	struct l_pselect6arg lpse6;
+	struct l_timespec lts;
+	struct timespec uts;
+	l_sigset_t l_ss;
+	sigset_t *ssp;
+	sigset_t ss;
+	int error;
+
+	ssp = NULL;
+	if (args->sig != NULL) {
+		error = copyin(args->sig, &lpse6, sizeof(lpse6));
+		if (error != 0)
+			return (error);
+		if (lpse6.ss_len != sizeof(l_ss))
+			return (EINVAL);
+		if (lpse6.ss != 0) {
+			error = copyin(PTRIN(lpse6.ss), &l_ss,
+			    sizeof(l_ss));
+			if (error != 0)
+				return (error);
+			linux_to_bsd_sigset(&l_ss, &ss);
+			ssp = &ss;
+		}
+	}
+
+	/*
+	 * Currently glibc changes nanosecond number to microsecond.
+	 * This mean losing precision but for now it is hardly seen.
+	 */
+	if (args->tsp != NULL) {
+		error = copyin(args->tsp, &lts, sizeof(lts));
+		if (error != 0)
+			return (error);
+		error = linux_to_native_timespec(&uts, &lts);
+		if (error != 0)
+			return (error);
+
+		TIMESPEC_TO_TIMEVAL(&utv, &uts);
+		if (itimerfix(&utv))
+			return (EINVAL);
+
+		microtime(&tv0);
+		tvp = &utv;
+	} else
+		tvp = NULL;
+
+	error = kern_pselect(td, args->nfds, args->readfds, args->writefds,
+	    args->exceptfds, tvp, ssp, LINUX_NFDBITS);
+
+	if (error == 0 && args->tsp != NULL) {
+		if (td->td_retval[0] != 0) {
+			/*
+			 * Compute how much time was left of the timeout,
+			 * by subtracting the current time and the time
+			 * before we started the call, and subtracting
+			 * that result from the user-supplied value.
+			 */
+
+			microtime(&tv1);
+			timevalsub(&tv1, &tv0);
+			timevalsub(&utv, &tv1);
+			if (utv.tv_sec < 0)
+				timevalclear(&utv);
+		} else
+			timevalclear(&utv);
+
+		TIMEVAL_TO_TIMESPEC(&utv, &uts);
+
+		native_to_linux_timespec(&lts, &uts);
+		error = copyout(&lts, args->tsp, sizeof(lts));
+	}
+
+	return (error);
+}
+
+int
+linux_ppoll(struct thread *td, struct linux_ppoll_args *args)
+{
+	struct timespec ts0, ts1;
+	struct l_timespec lts;
+	struct timespec uts, *tsp;
+	l_sigset_t l_ss;
+	sigset_t *ssp;
+	sigset_t ss;
+	int error;
+
+	if (args->sset != NULL) {
+		if (args->ssize != sizeof(l_ss))
+			return (EINVAL);
+		error = copyin(args->sset, &l_ss, sizeof(l_ss));
+		if (error)
+			return (error);
+		linux_to_bsd_sigset(&l_ss, &ss);
+		ssp = &ss;
+	} else
+		ssp = NULL;
+	if (args->tsp != NULL) {
+		error = copyin(args->tsp, &lts, sizeof(lts));
+		if (error)
+			return (error);
+		error = linux_to_native_timespec(&uts, &lts);
+		if (error != 0)
+			return (error);
+
+		nanotime(&ts0);
+		tsp = &uts;
+	} else
+		tsp = NULL;
+
+	error = kern_poll(td, args->fds, args->nfds, tsp, ssp);
+
+	if (error == 0 && args->tsp != NULL) {
+		if (td->td_retval[0]) {
+			nanotime(&ts1);
+			timespecsub(&ts1, &ts0);
+			timespecsub(&uts, &ts1);
+			if (uts.tv_sec < 0)
+				timespecclear(&uts);
+		} else
+			timespecclear(&uts);
+
+		native_to_linux_timespec(&lts, &uts);
+		error = copyout(&lts, args->tsp, sizeof(lts));
+	}
+
+	return (error);
+}
+
+#if defined(DEBUG) || defined(KTR)
+/* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */
+
+#ifdef COMPAT_LINUX32
+#define	L_MAXSYSCALL	LINUX32_SYS_MAXSYSCALL
+#else
+#define	L_MAXSYSCALL	LINUX_SYS_MAXSYSCALL
+#endif
+
+u_char linux_debug_map[howmany(L_MAXSYSCALL, sizeof(u_char))];
+
+static int
+linux_debug(int syscall, int toggle, int global)
+{
+
+	if (global) {
+		char c = toggle ? 0 : 0xff;
+
+		memset(linux_debug_map, c, sizeof(linux_debug_map));
+		return (0);
+	}
+	if (syscall < 0 || syscall >= L_MAXSYSCALL)
+		return (EINVAL);
+	if (toggle)
+		clrbit(linux_debug_map, syscall);
+	else
+		setbit(linux_debug_map, syscall);
+	return (0);
+}
+#undef L_MAXSYSCALL
+
+/*
+ * Usage: sysctl linux.debug=<syscall_nr>.<0/1>
+ *
+ *    E.g.: sysctl linux.debug=21.0
+ *
+ * As a special case, syscall "all" will apply to all syscalls globally.
+ */
+#define LINUX_MAX_DEBUGSTR	16
+int
+linux_sysctl_debug(SYSCTL_HANDLER_ARGS)
+{
+	char value[LINUX_MAX_DEBUGSTR], *p;
+	int error, sysc, toggle;
+	int global = 0;
+
+	value[0] = '\0';
+	error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req);
+	if (error || req->newptr == NULL)
+		return (error);
+	for (p = value; *p != '\0' && *p != '.'; p++);
+	if (*p == '\0')
+		return (EINVAL);
+	*p++ = '\0';
+	sysc = strtol(value, NULL, 0);
+	toggle = strtol(p, NULL, 0);
+	if (strcmp(value, "all") == 0)
+		global = 1;
+	error = linux_debug(sysc, toggle, global);
+	return (error);
+}
+
+#endif /* DEBUG || KTR */
+
+int
+linux_sched_rr_get_interval(struct thread *td,
+    struct linux_sched_rr_get_interval_args *uap)
+{
+	struct timespec ts;
+	struct l_timespec lts;
+	struct thread *tdt;
+	int error;
+
+	/*
+	 * According to man in case the invalid pid specified
+	 * EINVAL should be returned.
+	 */
+	if (uap->pid < 0)
+		return (EINVAL);
+
+	tdt = linux_tdfind(td, uap->pid, -1);
+	if (tdt == NULL)
+		return (ESRCH);
+
+	error = kern_sched_rr_get_interval_td(td, tdt, &ts);
+	PROC_UNLOCK(tdt->td_proc);
+	if (error != 0)
+		return (error);
+	native_to_linux_timespec(&lts, &ts);
+	return (copyout(&lts, uap->interval, sizeof(lts)));
+}
+
+/*
+ * In case when the Linux thread is the initial thread in
+ * the thread group thread id is equal to the process id.
+ * Glibc depends on this magic (assert in pthread_getattr_np.c).
+ */
+struct thread *
+linux_tdfind(struct thread *td, lwpid_t tid, pid_t pid)
+{
+	struct linux_emuldata *em;
+	struct thread *tdt;
+	struct proc *p;
+
+	tdt = NULL;
+	if (tid == 0 || tid == td->td_tid) {
+		tdt = td;
+		PROC_LOCK(tdt->td_proc);
+	} else if (tid > PID_MAX)
+		tdt = tdfind(tid, pid);
+	else {
+		/*
+		 * Initial thread where the tid equal to the pid.
+		 */
+		p = pfind(tid);
+		if (p != NULL) {
+			if (SV_PROC_ABI(p) != SV_ABI_LINUX) {
+				/*
+				 * p is not a Linuxulator process.
+				 */
+				PROC_UNLOCK(p);
+				return (NULL);
+			}
+			FOREACH_THREAD_IN_PROC(p, tdt) {
+				em = em_find(tdt);
+				if (tid == em->em_tid)
+					return (tdt);
+			}
+			PROC_UNLOCK(p);
+		}
+		return (NULL);
+	}
+
+	return (tdt);
+}
+
+void
+linux_to_bsd_waitopts(int options, int *bsdopts)
+{
+
+	if (options & LINUX_WNOHANG)
+		*bsdopts |= WNOHANG;
+	if (options & LINUX_WUNTRACED)
+		*bsdopts |= WUNTRACED;
+	if (options & LINUX_WEXITED)
+		*bsdopts |= WEXITED;
+	if (options & LINUX_WCONTINUED)
+		*bsdopts |= WCONTINUED;
+	if (options & LINUX_WNOWAIT)
+		*bsdopts |= WNOWAIT;
+
+	if (options & __WCLONE)
+		*bsdopts |= WLINUXCLONE;
+}

Modified: trunk/sys/compat/linux/linux_misc.h
===================================================================
--- trunk/sys/compat/linux/linux_misc.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_misc.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2006 Roman Divacky
  * All rights reserved.
@@ -25,12 +26,25 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_misc.h 321009 2017-07-15 14:48:31Z dchagin $
  */
 
 #ifndef _LINUX_MISC_H_
 #define	_LINUX_MISC_H_
 
+#include <sys/sysctl.h>
+
+				/* bits per mask */
+#define	LINUX_NFDBITS		sizeof(l_fd_mask) * 8
+
+/*
+ * Miscellaneous
+ */
+#define	LINUX_NAME_MAX		255
+#define	LINUX_MAX_UTSNAME	65
+
+#define	LINUX_CTL_MAXNAME	10
+
 /* defines for prctl */
 #define	LINUX_PR_SET_PDEATHSIG  1	/* Second arg is a signal. */
 #define	LINUX_PR_GET_PDEATHSIG  2	/*
@@ -47,8 +61,10 @@
 #define	LINUX_MREMAP_MAYMOVE	1
 #define	LINUX_MREMAP_FIXED	2
 
-extern const char *linux_platform;
+#define	LINUX_PATH_MAX		4096
 
+extern const char *linux_kplatform;
+
 /*
  * Non-standard aux entry types used in Linux ELF binaries.
  */
@@ -60,18 +76,90 @@
 #define	LINUX_AT_BASE_PLATFORM	24	/* string identifying real platform, may
 					 * differ from AT_PLATFORM.
 					 */
+#define	LINUX_AT_RANDOM		25	/* address of random bytes */
 #define	LINUX_AT_EXECFN		31	/* filename of program */
+#define	LINUX_AT_SYSINFO	32	/* vsyscall */
+#define	LINUX_AT_SYSINFO_EHDR	33	/* vdso header */
 
+#define	LINUX_AT_RANDOM_LEN	16	/* size of random bytes */
+
 /* Linux sets the i387 to extended precision. */
 #if defined(__i386__) || defined(__amd64__)
 #define	__LINUX_NPXCW__		0x37f
 #endif
 
+#define	LINUX_CLONE_VM			0x00000100
+#define	LINUX_CLONE_FS			0x00000200
+#define	LINUX_CLONE_FILES		0x00000400
+#define	LINUX_CLONE_SIGHAND		0x00000800
+#define	LINUX_CLONE_PID			0x00001000	/* No longer exist in Linux */
+#define	LINUX_CLONE_VFORK		0x00004000
+#define	LINUX_CLONE_PARENT		0x00008000
+#define	LINUX_CLONE_THREAD		0x00010000
+#define	LINUX_CLONE_SETTLS		0x00080000
+#define	LINUX_CLONE_PARENT_SETTID	0x00100000
+#define	LINUX_CLONE_CHILD_CLEARTID	0x00200000
+#define	LINUX_CLONE_CHILD_SETTID	0x01000000
+
+/* Scheduling policies */
+#define	LINUX_SCHED_OTHER	0
+#define	LINUX_SCHED_FIFO	1
+#define	LINUX_SCHED_RR		2
+
+struct l_new_utsname {
+	char	sysname[LINUX_MAX_UTSNAME];
+	char	nodename[LINUX_MAX_UTSNAME];
+	char	release[LINUX_MAX_UTSNAME];
+	char	version[LINUX_MAX_UTSNAME];
+	char	machine[LINUX_MAX_UTSNAME];
+	char	domainname[LINUX_MAX_UTSNAME];
+};
+
+#define	LINUX_CLOCK_REALTIME		0
+#define	LINUX_CLOCK_MONOTONIC		1
+#define	LINUX_CLOCK_PROCESS_CPUTIME_ID	2
+#define	LINUX_CLOCK_THREAD_CPUTIME_ID	3
+#define	LINUX_CLOCK_REALTIME_HR		4
+#define	LINUX_CLOCK_MONOTONIC_HR	5
+
+#define LINUX_UTIME_NOW			0x3FFFFFFF
+#define LINUX_UTIME_OMIT		0x3FFFFFFE
+
 extern int stclohz;
 
-#define __WCLONE 0x80000000
+#define	LINUX_WNOHANG		0x00000001
+#define	LINUX_WUNTRACED		0x00000002
+#define	LINUX_WSTOPPED		LINUX_WUNTRACED
+#define	LINUX_WEXITED		0x00000004
+#define	LINUX_WCONTINUED	0x00000008
+#define	LINUX_WNOWAIT		0x01000000
 
+
+#define	__WNOTHREAD		0x20000000
+#define	__WALL			0x40000000
+#define	__WCLONE		0x80000000
+
+/* Linux waitid idtype  */
+#define	LINUX_P_ALL		0
+#define	LINUX_P_PID		1
+#define	LINUX_P_PGID		2
+
+#define	LINUX_RLIMIT_LOCKS	RLIM_NLIMITS + 1
+#define	LINUX_RLIMIT_SIGPENDING	RLIM_NLIMITS + 2
+#define	LINUX_RLIMIT_MSGQUEUE	RLIM_NLIMITS + 3
+#define	LINUX_RLIMIT_NICE	RLIM_NLIMITS + 4
+#define	LINUX_RLIMIT_RTPRIO	RLIM_NLIMITS + 5
+#define	LINUX_RLIMIT_RTTIME	RLIM_NLIMITS + 6
+
+#define	LINUX_RLIM_INFINITY	(~0UL)
+
 int linux_common_wait(struct thread *td, int pid, int *status,
 			int options, struct rusage *ru);
+void linux_to_bsd_waitopts(int options, int *bsdopts);
+int linux_set_upcall_kse(struct thread *td, register_t stack);
+int linux_set_cloned_tls(struct thread *td, void *desc);
+struct thread	*linux_tdfind(struct thread *, lwpid_t, pid_t);
 
+int linux_sysctl_debug(SYSCTL_HANDLER_ARGS);
+
 #endif	/* _LINUX_MISC_H_ */

Added: trunk/sys/compat/linux/linux_mmap.c
===================================================================
--- trunk/sys/compat/linux/linux_mmap.c	                        (rev 0)
+++ trunk/sys/compat/linux/linux_mmap.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,258 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2004 Tim J. Robbins
+ * Copyright (c) 2002 Doug Rabson
+ * Copyright (c) 2000 Marcel Moolenaar
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * 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
+ *    in this position and unchanged.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/10/sys/compat/linux/linux_mmap.c 302964 2016-07-17 15:23:32Z dchagin $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_mmap.c 302964 2016-07-17 15:23:32Z dchagin $");
+
+#include <sys/capsicum.h>
+#include <sys/file.h>
+#include <sys/imgact.h>
+#include <sys/ktr.h>
+#include <sys/mman.h>
+#include <sys/proc.h>
+#include <sys/resourcevar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_mmap.h>
+#include <compat/linux/linux_persona.h>
+#include <compat/linux/linux_util.h>
+
+
+#define STACK_SIZE  (2 * 1024 * 1024)
+#define GUARD_SIZE  (4 * PAGE_SIZE)
+
+#if defined(__amd64__)
+static void linux_fixup_prot(struct thread *td, int *prot);
+#endif
+
+
+int
+linux_mmap_common(struct thread *td, uintptr_t addr, size_t len, int prot,
+    int flags, int fd, off_t pos)
+{
+	struct proc *p = td->td_proc;
+	struct vmspace *vms = td->td_proc->p_vmspace;
+	struct mmap_args /* {
+		caddr_t addr;
+		size_t len;
+		int prot;
+		int flags;
+		int fd;
+		off_t pos;
+	} */ bsd_args;
+	int error;
+	struct file *fp;
+
+	cap_rights_t rights;
+	LINUX_CTR6(mmap2, "0x%lx, %ld, %ld, 0x%08lx, %ld, 0x%lx",
+	    addr, len, prot, flags, fd, pos);
+
+	error = 0;
+	bsd_args.flags = 0;
+	fp = NULL;
+
+	/*
+	 * Linux mmap(2):
+	 * You must specify exactly one of MAP_SHARED and MAP_PRIVATE
+	 */
+	if (!((flags & LINUX_MAP_SHARED) ^ (flags & LINUX_MAP_PRIVATE)))
+		return (EINVAL);
+
+	if (flags & LINUX_MAP_SHARED)
+		bsd_args.flags |= MAP_SHARED;
+	if (flags & LINUX_MAP_PRIVATE)
+		bsd_args.flags |= MAP_PRIVATE;
+	if (flags & LINUX_MAP_FIXED)
+		bsd_args.flags |= MAP_FIXED;
+	if (flags & LINUX_MAP_ANON) {
+		/* Enforce pos to be on page boundary, then ignore. */
+		if ((pos & PAGE_MASK) != 0)
+			return (EINVAL);
+		pos = 0;
+		bsd_args.flags |= MAP_ANON;
+	} else
+		bsd_args.flags |= MAP_NOSYNC;
+	if (flags & LINUX_MAP_GROWSDOWN)
+		bsd_args.flags |= MAP_STACK;
+
+	/*
+	 * PROT_READ, PROT_WRITE, or PROT_EXEC implies PROT_READ and PROT_EXEC
+	 * on Linux/i386 if the binary requires executable stack.
+	 * We do this only for IA32 emulation as on native i386 this is does not
+	 * make sense without PAE.
+	 *
+	 * XXX. Linux checks that the file system is not mounted with noexec.
+	 */
+	bsd_args.prot = prot;
+#if defined(__amd64__)
+	linux_fixup_prot(td, &bsd_args.prot);
+#endif
+
+	/* Linux does not check file descriptor when MAP_ANONYMOUS is set. */
+	bsd_args.fd = (bsd_args.flags & MAP_ANON) ? -1 : fd;
+	if (bsd_args.fd != -1) {
+		/*
+		 * Linux follows Solaris mmap(2) description:
+		 * The file descriptor fildes is opened with
+		 * read permission, regardless of the
+		 * protection options specified.
+		 */
+
+		error = fget(td, bsd_args.fd,
+		    cap_rights_init(&rights, CAP_MMAP), &fp);
+		if (error != 0)
+			return (error);
+		if (fp->f_type != DTYPE_VNODE) {
+			fdrop(fp, td);
+			return (EINVAL);
+		}
+
+		/* Linux mmap() just fails for O_WRONLY files */
+		if (!(fp->f_flag & FREAD)) {
+			fdrop(fp, td);
+			return (EACCES);
+		}
+
+		fdrop(fp, td);
+	}
+
+	if (flags & LINUX_MAP_GROWSDOWN) {
+		/*
+		 * The Linux MAP_GROWSDOWN option does not limit auto
+		 * growth of the region.  Linux mmap with this option
+		 * takes as addr the initial BOS, and as len, the initial
+		 * region size.  It can then grow down from addr without
+		 * limit.  However, Linux threads has an implicit internal
+		 * limit to stack size of STACK_SIZE.  Its just not
+		 * enforced explicitly in Linux.  But, here we impose
+		 * a limit of (STACK_SIZE - GUARD_SIZE) on the stack
+		 * region, since we can do this with our mmap.
+		 *
+		 * Our mmap with MAP_STACK takes addr as the maximum
+		 * downsize limit on BOS, and as len the max size of
+		 * the region.  It then maps the top SGROWSIZ bytes,
+		 * and auto grows the region down, up to the limit
+		 * in addr.
+		 *
+		 * If we don't use the MAP_STACK option, the effect
+		 * of this code is to allocate a stack region of a
+		 * fixed size of (STACK_SIZE - GUARD_SIZE).
+		 */
+
+		if ((caddr_t)addr + len > vms->vm_maxsaddr) {
+			/*
+			 * Some Linux apps will attempt to mmap
+			 * thread stacks near the top of their
+			 * address space.  If their TOS is greater
+			 * than vm_maxsaddr, vm_map_growstack()
+			 * will confuse the thread stack with the
+			 * process stack and deliver a SEGV if they
+			 * attempt to grow the thread stack past their
+			 * current stacksize rlimit.  To avoid this,
+			 * adjust vm_maxsaddr upwards to reflect
+			 * the current stacksize rlimit rather
+			 * than the maximum possible stacksize.
+			 * It would be better to adjust the
+			 * mmap'ed region, but some apps do not check
+			 * mmap's return value.
+			 */
+			PROC_LOCK(p);
+			vms->vm_maxsaddr = (char *)p->p_sysent->sv_usrstack -
+			    lim_cur(p, RLIMIT_STACK);
+			PROC_UNLOCK(p);
+		}
+
+		/*
+		 * This gives us our maximum stack size and a new BOS.
+		 * If we're using VM_STACK, then mmap will just map
+		 * the top SGROWSIZ bytes, and let the stack grow down
+		 * to the limit at BOS.  If we're not using VM_STACK
+		 * we map the full stack, since we don't have a way
+		 * to autogrow it.
+		 */
+		if (len > STACK_SIZE - GUARD_SIZE) {
+			bsd_args.addr = (caddr_t)addr;
+			bsd_args.len = len;
+		} else {
+			bsd_args.addr = (caddr_t)addr -
+			    (STACK_SIZE - GUARD_SIZE - len);
+			bsd_args.len = STACK_SIZE - GUARD_SIZE;
+		}
+	} else {
+		bsd_args.addr = (caddr_t)addr;
+		bsd_args.len  = len;
+	}
+	bsd_args.pos = pos;
+
+	error = sys_mmap(td, &bsd_args);
+
+	LINUX_CTR2(mmap2, "return: %d (%p)", error, td->td_retval[0]);
+
+	return (error);
+}
+
+int
+linux_mprotect_common(struct thread *td, uintptr_t addr, size_t len, int prot)
+{
+	struct mprotect_args bsd_args;
+
+	bsd_args.addr = (void *)addr;
+	bsd_args.len = len;
+	bsd_args.prot = prot;
+
+#if defined(__amd64__)
+	linux_fixup_prot(td, &bsd_args.prot);
+#endif
+	return (sys_mprotect(td, &bsd_args));
+}
+
+#if defined(__amd64__)
+static void
+linux_fixup_prot(struct thread *td, int *prot)
+{
+	struct linux_pemuldata *pem;
+
+	if (SV_PROC_FLAG(td->td_proc, SV_ILP32) && *prot & PROT_READ) {
+		pem = pem_find(td->td_proc);
+		if (pem->persona & LINUX_READ_IMPLIES_EXEC)
+			*prot |= PROT_EXEC;
+	}
+
+}
+#endif


Property changes on: trunk/sys/compat/linux/linux_mmap.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/compat/linux/linux_mmap.h
===================================================================
--- trunk/sys/compat/linux/linux_mmap.h	                        (rev 0)
+++ trunk/sys/compat/linux/linux_mmap.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,50 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2004 Tim J. Robbins
+ * Copyright (c) 2002 Doug Rabson
+ * Copyright (c) 2000 Marcel Moolenaar
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * 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
+ *    in this position and unchanged.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/10/sys/compat/linux/linux_mmap.h 302964 2016-07-17 15:23:32Z dchagin $
+ */
+
+#ifndef _LINUX_MMAP_H_
+#define	_LINUX_MMAP_H_
+
+/* mmap options */
+#define	LINUX_MAP_SHARED	0x0001
+#define	LINUX_MAP_PRIVATE	0x0002
+#define	LINUX_MAP_FIXED		0x0010
+#define	LINUX_MAP_ANON		0x0020
+#define	LINUX_MAP_GROWSDOWN	0x0100
+
+
+int linux_mmap_common(struct thread *, uintptr_t, size_t, int, int,
+			int, off_t);
+int linux_mprotect_common(struct thread *, uintptr_t, size_t, int);
+
+#endif	/* _LINUX_MMAP_H_ */


Property changes on: trunk/sys/compat/linux/linux_mmap.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/compat/linux/linux_persona.h
===================================================================
--- trunk/sys/compat/linux/linux_persona.h	                        (rev 0)
+++ trunk/sys/compat/linux/linux_persona.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,57 @@
+/* $MidnightBSD$ */
+/*
+ * $FreeBSD: stable/10/sys/compat/linux/linux_persona.h 302962 2016-07-17 15:07:33Z dchagin $
+ */
+
+#ifndef LINUX_PERSONALITY_H
+#define LINUX_PERSONALITY_H
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+	LINUX_UNAME26 =			0x0020000,
+	LINUX_ADDR_NO_RANDOMIZE = 	0x0040000,	/* disable randomization
+							 * of VA space
+							 */
+	LINUX_FDPIC_FUNCPTRS =		0x0080000,	/* userspace function
+							 * ptrs point to descriptors
+							 * (signal handling)
+							 */
+	LINUX_MMAP_PAGE_ZERO =		0x0100000,
+	LINUX_ADDR_COMPAT_LAYOUT =	0x0200000,
+	LINUX_READ_IMPLIES_EXEC =	0x0400000,
+	LINUX_ADDR_LIMIT_32BIT =	0x0800000,
+	LINUX_SHORT_INODE =		0x1000000,
+	LINUX_WHOLE_SECONDS =		0x2000000,
+	LINUX_STICKY_TIMEOUTS =		0x4000000,
+	LINUX_ADDR_LIMIT_3GB =		0x8000000,
+};
+
+/*
+ * Security-relevant compatibility flags that must be
+ * cleared upon setuid or setgid exec:
+ */
+#define LINUX_PER_CLEAR_ON_SETID	(LINUX_READ_IMPLIES_EXEC  | \
+					LINUX_ADDR_NO_RANDOMIZE  | \
+					LINUX_ADDR_COMPAT_LAYOUT | \
+					LINUX_MMAP_PAGE_ZERO)
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte.  Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+	LINUX_PER_LINUX =	0x0000,
+	LINUX_PER_LINUX_32BIT =	0x0000 | LINUX_ADDR_LIMIT_32BIT,
+	LINUX_PER_LINUX_FDPIC =	0x0000 | LINUX_FDPIC_FUNCPTRS,
+	LINUX_PER_LINUX32 =	0x0008,
+	LINUX_PER_LINUX32_3GB =	0x0008 | LINUX_ADDR_LIMIT_3GB,
+	LINUX_PER_MASK =	0x00ff,
+};
+
+#endif /* LINUX_PERSONALITY_H */


Property changes on: trunk/sys/compat/linux/linux_persona.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/compat/linux/linux_signal.c
===================================================================
--- trunk/sys/compat/linux/linux_signal.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_signal.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 1994-1995 S\xF8ren Schmidt
+ * Copyright (c) 1994-1995 Søren Schmidt
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_signal.c 293575 2016-01-09 17:29:08Z dchagin $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -53,41 +54,13 @@
 #include <compat/linux/linux_signal.h>
 #include <compat/linux/linux_util.h>
 #include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_misc.h>
 
-void
-linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
-{
-	int b, l;
+static int	linux_do_tkill(struct thread *td, struct thread *tdt,
+		    ksiginfo_t *ksi);
+static void	sicode_to_lsicode(int si_code, int *lsi_code);
 
-	SIGEMPTYSET(*bss);
-	bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
-	bss->__bits[1] = lss->__bits[1];
-	for (l = 1; l <= LINUX_SIGTBLSZ; l++) {
-		if (LINUX_SIGISMEMBER(*lss, l)) {
-			b = linux_to_bsd_signal[_SIG_IDX(l)];
-			if (b)
-				SIGADDSET(*bss, b);
-		}
-	}
-}
 
-void
-bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
-{
-	int b, l;
-
-	LINUX_SIGEMPTYSET(*lss);
-	lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
-	lss->__bits[1] = bss->__bits[1];
-	for (b = 1; b <= LINUX_SIGTBLSZ; b++) {
-		if (SIGISMEMBER(*bss, b)) {
-			l = bsd_to_linux_signal[_SIG_IDX(b)];
-			if (l)
-				LINUX_SIGADDSET(*lss, l);
-		}
-	}
-}
-
 static void
 linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa)
 {
@@ -155,12 +128,8 @@
 		linux_to_bsd_sigaction(linux_nsa, nsa);
 	} else
 		nsa = NULL;
+	sig = linux_to_bsd_signal(linux_sig);
 
-	if (linux_sig <= LINUX_SIGTBLSZ)
-		sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)];
-	else
-		sig = linux_sig;
-
 	error = kern_sigaction(td, sig, nsa, osa, 0);
 	if (error)
 		return (error);
@@ -171,7 +140,7 @@
 	return (0);
 }
 
-
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_signal(struct thread *td, struct linux_signal_args *args)
 {
@@ -193,6 +162,7 @@
 
 	return (error);
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 int
 linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args)
@@ -262,6 +232,7 @@
 	return (error);
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args)
 {
@@ -279,7 +250,7 @@
 		if (error)
 			return (error);
 		LINUX_SIGEMPTYSET(set);
-		set.__bits[0] = mask;
+		set.__mask = mask;
 	}
 
 	error = linux_do_sigprocmask(td, args->how,
@@ -287,12 +258,13 @@
 				     args->omask ? &oset : NULL);
 
 	if (args->omask != NULL && !error) {
-		mask = oset.__bits[0];
+		mask = oset.__mask;
 		error = copyout(&mask, args->omask, sizeof(l_osigset_t));
 	}
 
 	return (error);
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 int
 linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args)
@@ -327,6 +299,7 @@
 	return (error);
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args)
 {
@@ -341,7 +314,7 @@
 	PROC_LOCK(p);
 	bsd_to_linux_sigset(&td->td_sigmask, &mask);
 	PROC_UNLOCK(p);
-	td->td_retval[0] = mask.__bits[0];
+	td->td_retval[0] = mask.__mask;
 	return (0);
 }
 
@@ -359,9 +332,9 @@
 
 	PROC_LOCK(p);
 	bsd_to_linux_sigset(&td->td_sigmask, &lset);
-	td->td_retval[0] = lset.__bits[0];
+	td->td_retval[0] = lset.__mask;
 	LINUX_SIGEMPTYSET(lset);
-	lset.__bits[0] = args->mask;
+	lset.__mask = args->mask;
 	linux_to_bsd_sigset(&lset, &bset);
 	td->td_sigmask = bset;
 	SIG_CANTMASK(td->td_sigmask);
@@ -370,9 +343,6 @@
 	return (0);
 }
 
-/*
- * MPSAFE
- */
 int
 linux_sigpending(struct thread *td, struct linux_sigpending_args *args)
 {
@@ -392,9 +362,10 @@
 	SIGSETAND(bset, td->td_sigmask);
 	PROC_UNLOCK(p);
 	bsd_to_linux_sigset(&bset, &lset);
-	mask = lset.__bits[0];
+	mask = lset.__mask;
 	return (copyout(&mask, args->mask, sizeof(mask)));
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 /*
  * MPSAFE
@@ -458,8 +429,8 @@
 #ifdef DEBUG
 		if (ldebug(rt_sigtimedwait))
 			printf(LMSG("linux_rt_sigtimedwait: "
-			    "incoming timeout (%d/%d)\n"),
-			    ltv.tv_sec, ltv.tv_usec);
+			    "incoming timeout (%jd/%jd)\n"),
+			    (intmax_t)ltv.tv_sec, (intmax_t)ltv.tv_usec);
 #endif
 		tv.tv_sec = (long)ltv.tv_sec;
 		tv.tv_usec = (suseconds_t)ltv.tv_usec;
@@ -495,7 +466,7 @@
 	if (error)
 		return (error);
 
-	sig = BSD_TO_LINUX_SIGNAL(info.ksi_signo);
+	sig = bsd_to_linux_signal(info.ksi_signo);
 
 	if (args->ptr) {
 		memset(&linfo, 0, sizeof(linfo));
@@ -527,10 +498,10 @@
 	if (!LINUX_SIG_VALID(args->signum) && args->signum != 0)
 		return (EINVAL);
 
-	if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ)
-		tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)];
+	if (args->signum > 0)
+		tmp.signum = linux_to_bsd_signal(args->signum);
 	else
-		tmp.signum = args->signum;
+		tmp.signum = 0;
 
 	tmp.pid = args->pid;
 	return (sys_kill(td, &tmp));
@@ -537,57 +508,22 @@
 }
 
 static int
-linux_do_tkill(struct thread *td, l_int tgid, l_int pid, l_int signum)
+linux_do_tkill(struct thread *td, struct thread *tdt, ksiginfo_t *ksi)
 {
-	struct proc *proc = td->td_proc;
-	struct linux_emuldata *em;
 	struct proc *p;
-	ksiginfo_t ksi;
 	int error;
 
-	AUDIT_ARG_SIGNUM(signum);
-	AUDIT_ARG_PID(pid);
-
-	/*
-	 * Allow signal 0 as a means to check for privileges
-	 */
-	if (!LINUX_SIG_VALID(signum) && signum != 0)
-		return (EINVAL);
-
-	if (signum > 0 && signum <= LINUX_SIGTBLSZ)
-		signum = linux_to_bsd_signal[_SIG_IDX(signum)];
-
-	if ((p = pfind(pid)) == NULL) {
-		if ((p = zpfind(pid)) == NULL)
-			return (ESRCH);
-	}
-
+	p = tdt->td_proc;
+	AUDIT_ARG_SIGNUM(ksi->ksi_signo);
+	AUDIT_ARG_PID(p->p_pid);
 	AUDIT_ARG_PROCESS(p);
-	error = p_cansignal(td, p, signum);
-	if (error != 0 || signum == 0)
-		goto out;
 
-	error = ESRCH;
-	em = em_find(p, EMUL_DONTLOCK);
-
-	if (em == NULL) {
-#ifdef DEBUG
-		printf("emuldata not found in do_tkill.\n");
-#endif
+	error = p_cansignal(td, p, ksi->ksi_signo);
+	if (error != 0 || ksi->ksi_signo == 0)
 		goto out;
-	}
-	if (tgid > 0 && em->shared->group_pid != tgid)
-		goto out;
 
-	ksiginfo_init(&ksi);
-	ksi.ksi_signo = signum;
-	ksi.ksi_code = LINUX_SI_TKILL;
-	ksi.ksi_errno = 0;
-	ksi.ksi_pid = proc->p_pid;
-	ksi.ksi_uid = proc->p_ucred->cr_ruid;
+	tdksignal(tdt, ksi->ksi_signo, ksi);
 
-	error = pksignal(p, ksi.ksi_signo, &ksi);
-
 out:
 	PROC_UNLOCK(p);
 	return (error);
@@ -596,20 +532,53 @@
 int
 linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
 {
+	struct thread *tdt;
+	ksiginfo_t ksi;
+	int sig;
 
 #ifdef DEBUG
 	if (ldebug(tgkill))
-		printf(ARGS(tgkill, "%d, %d, %d"), args->tgid, args->pid, args->sig);
+		printf(ARGS(tgkill, "%d, %d, %d"),
+		    args->tgid, args->pid, args->sig);
 #endif
+
 	if (args->pid <= 0 || args->tgid <=0)
 		return (EINVAL);
 
-	return (linux_do_tkill(td, args->tgid, args->pid, args->sig));
+	/*
+	 * Allow signal 0 as a means to check for privileges
+	 */
+	if (!LINUX_SIG_VALID(args->sig) && args->sig != 0)
+		return (EINVAL);
+
+	if (args->sig > 0)
+		sig = linux_to_bsd_signal(args->sig);
+	else
+		sig = 0;
+
+	tdt = linux_tdfind(td, args->pid, args->tgid);
+	if (tdt == NULL)
+		return (ESRCH);
+
+	ksiginfo_init(&ksi);
+	ksi.ksi_signo = sig;
+	ksi.ksi_code = SI_LWP;
+	ksi.ksi_errno = 0;
+	ksi.ksi_pid = td->td_proc->p_pid;
+	ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
+	return (linux_do_tkill(td, tdt, &ksi));
 }
 
+/*
+ * Deprecated since 2.5.75. Replaced by tgkill().
+ */
 int
 linux_tkill(struct thread *td, struct linux_tkill_args *args)
 {
+	struct thread *tdt;
+	ksiginfo_t ksi;
+	int sig;
+
 #ifdef DEBUG
 	if (ldebug(tkill))
 		printf(ARGS(tkill, "%i, %i"), args->tid, args->sig);
@@ -617,40 +586,182 @@
 	if (args->tid <= 0)
 		return (EINVAL);
 
-	return (linux_do_tkill(td, 0, args->tid, args->sig));
+	if (!LINUX_SIG_VALID(args->sig))
+		return (EINVAL);
+
+	sig = linux_to_bsd_signal(args->sig);
+
+	tdt = linux_tdfind(td, args->tid, -1);
+	if (tdt == NULL)
+		return (ESRCH);
+
+	ksiginfo_init(&ksi);
+	ksi.ksi_signo = sig;
+	ksi.ksi_code = SI_LWP;
+	ksi.ksi_errno = 0;
+	ksi.ksi_pid = td->td_proc->p_pid;
+	ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
+	return (linux_do_tkill(td, tdt, &ksi));
 }
 
 void
-ksiginfo_to_lsiginfo(ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig)
+ksiginfo_to_lsiginfo(const ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig)
 {
 
+	siginfo_to_lsiginfo(&ksi->ksi_info, lsi, sig);
+}
+
+static void
+sicode_to_lsicode(int si_code, int *lsi_code)
+{
+
+	switch (si_code) {
+	case SI_USER:
+		*lsi_code = LINUX_SI_USER;
+		break;
+	case SI_KERNEL:
+		*lsi_code = LINUX_SI_KERNEL;
+		break;
+	case SI_QUEUE:
+		*lsi_code = LINUX_SI_QUEUE;
+		break;
+	case SI_TIMER:
+		*lsi_code = LINUX_SI_TIMER;
+		break;
+	case SI_MESGQ:
+		*lsi_code = LINUX_SI_MESGQ;
+		break;
+	case SI_ASYNCIO:
+		*lsi_code = LINUX_SI_ASYNCIO;
+		break;
+	case SI_LWP:
+		*lsi_code = LINUX_SI_TKILL;
+		break;
+	default:
+		*lsi_code = si_code;
+		break;
+	}
+}
+
+void
+siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig)
+{
+
+	/* sig alredy converted */
 	lsi->lsi_signo = sig;
-	lsi->lsi_code = ksi->ksi_code;
+	sicode_to_lsicode(si->si_code, &lsi->lsi_code);
 
-	switch (sig) {
-	case LINUX_SIGPOLL:
-		/* XXX si_fd? */
-		lsi->lsi_band = ksi->ksi_band;
+	switch (si->si_code) {
+	case SI_LWP:
+		lsi->lsi_pid = si->si_pid;
+		lsi->lsi_uid = si->si_uid;
 		break;
-	case LINUX_SIGCHLD:
-		lsi->lsi_pid = ksi->ksi_pid;
-		lsi->lsi_uid = ksi->ksi_uid;
-		lsi->lsi_status = ksi->ksi_status;
+
+	case SI_TIMER:
+		lsi->lsi_int = si->si_value.sival_int;
+		lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
+		lsi->lsi_tid = si->si_timerid;
 		break;
-	case LINUX_SIGBUS:
-	case LINUX_SIGILL:
-	case LINUX_SIGFPE:
-	case LINUX_SIGSEGV:
-		lsi->lsi_addr = PTROUT(ksi->ksi_addr);
+
+	case SI_QUEUE:
+		lsi->lsi_pid = si->si_pid;
+		lsi->lsi_uid = si->si_uid;
+		lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
 		break;
+
+	case SI_ASYNCIO:
+		lsi->lsi_int = si->si_value.sival_int;
+		lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
+		break;
+
 	default:
-		/* XXX SI_TIMER etc... */
-		lsi->lsi_pid = ksi->ksi_pid;
-		lsi->lsi_uid = ksi->ksi_uid;
+		switch (sig) {
+		case LINUX_SIGPOLL:
+			/* XXX si_fd? */
+			lsi->lsi_band = si->si_band;
+			break;
+
+		case LINUX_SIGCHLD:
+			lsi->lsi_errno = 0;
+			lsi->lsi_pid = si->si_pid;
+			lsi->lsi_uid = si->si_uid;
+
+			if (si->si_code == CLD_STOPPED)
+				lsi->lsi_status = bsd_to_linux_signal(si->si_status);
+			else if (si->si_code == CLD_CONTINUED)
+				lsi->lsi_status = bsd_to_linux_signal(SIGCONT);
+			else
+				lsi->lsi_status = si->si_status;
+			break;
+
+		case LINUX_SIGBUS:
+		case LINUX_SIGILL:
+		case LINUX_SIGFPE:
+		case LINUX_SIGSEGV:
+			lsi->lsi_addr = PTROUT(si->si_addr);
+			break;
+
+		default:
+			lsi->lsi_pid = si->si_pid;
+			lsi->lsi_uid = si->si_uid;
+			if (sig >= LINUX_SIGRTMIN) {
+				lsi->lsi_int = si->si_value.sival_int;
+				lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
+			}
+			break;
+		}
 		break;
 	}
-	if (sig >= LINUX_SIGRTMIN) {
-		lsi->lsi_int = ksi->ksi_info.si_value.sival_int;
-		lsi->lsi_ptr = PTROUT(ksi->ksi_info.si_value.sival_ptr);
+}
+
+void
+lsiginfo_to_ksiginfo(const l_siginfo_t *lsi, ksiginfo_t *ksi, int sig)
+{
+
+	ksi->ksi_signo = sig;
+	ksi->ksi_code = lsi->lsi_code;	/* XXX. Convert. */
+	ksi->ksi_pid = lsi->lsi_pid;
+	ksi->ksi_uid = lsi->lsi_uid;
+	ksi->ksi_status = lsi->lsi_status;
+	ksi->ksi_addr = PTRIN(lsi->lsi_addr);
+	ksi->ksi_info.si_value.sival_int = lsi->lsi_int;
+}
+
+int
+linux_rt_sigqueueinfo(struct thread *td, struct linux_rt_sigqueueinfo_args *args)
+{
+	l_siginfo_t linfo;
+	struct proc *p;
+	ksiginfo_t ksi;
+	int error;
+	int sig;
+
+	if (!LINUX_SIG_VALID(args->sig))
+		return (EINVAL);
+
+	error = copyin(args->info, &linfo, sizeof(linfo));
+	if (error != 0)
+		return (error);
+
+	if (linfo.lsi_code >= 0)
+		return (EPERM);
+
+	sig = linux_to_bsd_signal(args->sig);
+
+	error = ESRCH;
+	if ((p = pfind(args->pid)) != NULL ||
+	    (p = zpfind(args->pid)) != NULL) {
+		error = p_cansignal(td, p, sig);
+		if (error != 0) {
+			PROC_UNLOCK(p);
+			return (error);
+		}
+
+		ksiginfo_init(&ksi);
+		lsiginfo_to_ksiginfo(&linfo, &ksi, sig);
+		error = tdsendsignal(p, NULL, sig, &ksi);
+		PROC_UNLOCK(p);
 	}
+
+	return (error);
 }

Modified: trunk/sys/compat/linux/linux_signal.h
===================================================================
--- trunk/sys/compat/linux/linux_signal.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_signal.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2000 Marcel Moolenaar
  * All rights reserved.
@@ -25,22 +26,27 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_signal.h 293575 2016-01-09 17:29:08Z dchagin $
  */
 
 #ifndef _LINUX_SIGNAL_H_
 #define _LINUX_SIGNAL_H_
 
-#define	LINUX_SI_TKILL		-6;
+/*
+ * si_code values
+ */
+#define	LINUX_SI_USER		0	/* sent by kill, sigsend, raise */
+#define	LINUX_SI_KERNEL		0x80	/* sent by the kernel from somewhere */
+#define	LINUX_SI_QUEUE		-1	/* sent by sigqueue */
+#define	LINUX_SI_TIMER		-2	/* sent by timer expiration */
+#define	LINUX_SI_MESGQ		-3	/* sent by real time mesq state change */
+#define	LINUX_SI_ASYNCIO	-4	/* sent by AIO completion */
+#define	LINUX_SI_SIGIO		-5	/* sent by queued SIGIO */
+#define	LINUX_SI_TKILL		-6	/* sent by tkill system call */
 
-void linux_to_bsd_sigset(l_sigset_t *, sigset_t *);
-void bsd_to_linux_sigset(sigset_t *, l_sigset_t *);
 int linux_do_sigaction(struct thread *, int, l_sigaction_t *, l_sigaction_t *);
-void ksiginfo_to_lsiginfo(ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig);
+void ksiginfo_to_lsiginfo(const ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig);
+void siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig);
+void lsiginfo_to_ksiginfo(const l_siginfo_t *lsi, ksiginfo_t *ksi, int sig);
 
-#define LINUX_SIG_VALID(sig)	((sig) <= LINUX_NSIG && (sig) > 0)
-
-#define BSD_TO_LINUX_SIGNAL(sig)				\
-	(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
-
 #endif /* _LINUX_SIGNAL_H_ */

Modified: trunk/sys/compat/linux/linux_socket.c
===================================================================
--- trunk/sys/compat/linux/linux_socket.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_socket.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 1995 S\xF8ren Schmidt
+ * Copyright (c) 1995 Søren Schmidt
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_socket.c 321022 2017-07-15 17:44:29Z dchagin $");
 
 /* XXX we use functions that might not exist. */
 #include "opt_compat.h"
@@ -37,7 +38,7 @@
 #include <sys/proc.h>
 #include <sys/systm.h>
 #include <sys/sysproto.h>
-#include <sys/capability.h>
+#include <sys/capsicum.h>
 #include <sys/fcntl.h>
 #include <sys/file.h>
 #include <sys/limits.h>
@@ -70,10 +71,17 @@
 #include <machine/../linux/linux.h>
 #include <machine/../linux/linux_proto.h>
 #endif
+#include <compat/linux/linux_file.h>
 #include <compat/linux/linux_socket.h>
+#include <compat/linux/linux_timer.h>
 #include <compat/linux/linux_util.h>
 
 static int linux_to_bsd_domain(int);
+static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *,
+					l_uint);
+static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *,
+					l_uint, struct msghdr *);
+static int linux_set_socket_flags(int, int *);
 
 /*
  * Reads a linux sockaddr and does any necessary translation.
@@ -282,6 +290,63 @@
 }
 
 static int
+linux_to_bsd_ip6_sockopt(int opt)
+{
+
+	switch (opt) {
+	case LINUX_IPV6_NEXTHOP:
+		return (IPV6_NEXTHOP);
+	case LINUX_IPV6_UNICAST_HOPS:
+		return (IPV6_UNICAST_HOPS);
+	case LINUX_IPV6_MULTICAST_IF:
+		return (IPV6_MULTICAST_IF);
+	case LINUX_IPV6_MULTICAST_HOPS:
+		return (IPV6_MULTICAST_HOPS);
+	case LINUX_IPV6_MULTICAST_LOOP:
+		return (IPV6_MULTICAST_LOOP);
+	case LINUX_IPV6_ADD_MEMBERSHIP:
+		return (IPV6_JOIN_GROUP);
+	case LINUX_IPV6_DROP_MEMBERSHIP:
+		return (IPV6_LEAVE_GROUP);
+	case LINUX_IPV6_V6ONLY:
+		return (IPV6_V6ONLY);
+	case LINUX_IPV6_DONTFRAG:
+		return (IPV6_DONTFRAG);
+#if 0
+	case LINUX_IPV6_CHECKSUM:
+		return (IPV6_CHECKSUM);
+	case LINUX_IPV6_RECVPKTINFO:
+		return (IPV6_RECVPKTINFO);
+	case LINUX_IPV6_PKTINFO:
+		return (IPV6_PKTINFO);
+	case LINUX_IPV6_RECVHOPLIMIT:
+		return (IPV6_RECVHOPLIMIT);
+	case LINUX_IPV6_HOPLIMIT:
+		return (IPV6_HOPLIMIT);
+	case LINUX_IPV6_RECVHOPOPTS:
+		return (IPV6_RECVHOPOPTS);
+	case LINUX_IPV6_HOPOPTS:
+		return (IPV6_HOPOPTS);
+	case LINUX_IPV6_RTHDRDSTOPTS:
+		return (IPV6_RTHDRDSTOPTS);
+	case LINUX_IPV6_RECVRTHDR:
+		return (IPV6_RECVRTHDR);
+	case LINUX_IPV6_RTHDR:
+		return (IPV6_RTHDR);
+	case LINUX_IPV6_RECVDSTOPTS:
+		return (IPV6_RECVDSTOPTS);
+	case LINUX_IPV6_DSTOPTS:
+		return (IPV6_DSTOPTS);
+	case LINUX_IPV6_RECVPATHMTU:
+		return (IPV6_RECVPATHMTU);
+	case LINUX_IPV6_PATHMTU:
+		return (IPV6_PATHMTU);
+#endif
+	}
+	return (-1);
+}
+
+static int
 linux_to_bsd_so_sockopt(int opt)
 {
 
@@ -384,7 +449,7 @@
 	if (flags & LINUX_MSG_ERRQUEUE)
 		;
 #endif
-	return ret_flags;
+	return (ret_flags);
 }
 
 /*
@@ -398,16 +463,17 @@
 {
 	struct sockaddr sa;
 	size_t sa_len = sizeof(struct sockaddr);
-	int error;
-	
+	int error, bdom;
+
 	if ((error = copyin(arg, &sa, sa_len)))
 		return (error);
-	
-	*(u_short *)&sa = sa.sa_family;
-	
-	error = copyout(&sa, arg, sa_len);
-	
-	return (error);
+
+	bdom = bsd_to_linux_domain(sa.sa_family);
+	if (bdom == -1)
+		return (EAFNOSUPPORT);
+
+	*(u_short *)&sa = bdom;
+	return (copyout(&sa, arg, sa_len));
 }
 
 static int
@@ -415,20 +481,20 @@
 {
 	struct sockaddr sa;
 	size_t sa_len = sizeof(struct sockaddr);
-	int error;
+	int error, bdom;
 
 	if ((error = copyin(arg, &sa, sa_len)))
 		return (error);
 
-	sa.sa_family = *(sa_family_t *)&sa;
+	bdom = linux_to_bsd_domain(*(sa_family_t *)&sa);
+	if (bdom == -1)
+		return (EAFNOSUPPORT);
+
+	sa.sa_family = bdom;
 	sa.sa_len = len;
-
-	error = copyout(&sa, arg, sa_len);
-
-	return (error);
+	return (copyout(&sa, arg, sa_len));
 }
 
-
 static int
 linux_sa_put(struct osockaddr *osa)
 {
@@ -448,11 +514,7 @@
 		return (EINVAL);
 
 	sa.sa_family = bdom;
-	error = copyout(&sa, osa, sizeof(sa.sa_family));
-	if (error)
-		return (error);
-
-	return (0);
+	return (copyout(&sa, osa, sizeof(sa.sa_family)));
 }
 
 static int
@@ -477,6 +539,8 @@
 		return (LINUX_SCM_RIGHTS);
 	case SCM_CREDS:
 		return (LINUX_SCM_CREDENTIALS);
+	case SCM_TIMESTAMP:
+		return (LINUX_SCM_TIMESTAMP);
 	}
 	return (-1);
 }
@@ -529,20 +593,15 @@
 }
 
 static int
-linux_set_socket_flags(struct thread *td, int s, int flags)
+linux_set_socket_flags(int lflags, int *flags)
 {
-	int error;
 
-	if (flags & LINUX_SOCK_NONBLOCK) {
-		error = kern_fcntl(td, s, F_SETFL, O_NONBLOCK);
-		if (error)
-			return (error);
-	}
-	if (flags & LINUX_SOCK_CLOEXEC) {
-		error = kern_fcntl(td, s, F_SETFD, FD_CLOEXEC);
-		if (error)
-			return (error);
-	}
+	if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
+		return (EINVAL);
+	if (lflags & LINUX_SOCK_NONBLOCK)
+		*flags |= SOCK_NONBLOCK;
+	if (lflags & LINUX_SOCK_CLOEXEC)
+		*flags |= SOCK_CLOEXEC;
 	return (0);
 }
 
@@ -573,7 +632,8 @@
 static int
 linux_check_hdrincl(struct thread *td, int s)
 {
-	int error, optval, size_val;
+	int error, optval;
+	socklen_t size_val;
 
 	size_val = sizeof(optval);
 	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
@@ -584,15 +644,6 @@
 	return (optval == 0);
 }
 
-struct linux_sendto_args {
-	int s;
-	l_uintptr_t msg;
-	int len;
-	int flags;
-	l_uintptr_t to;
-	int tolen;
-};
-
 /*
  * Updated sendto() when IP_HDRINCL is set:
  * tweak endian-dependent fields in the IP packet.
@@ -617,7 +668,7 @@
 	    linux_args->len > IP_MAXPACKET)
 		return (EINVAL);
 
-	packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
+	packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK);
 
 	/* Make kernel copy of the packet to be sent */
 	if ((error = copyin(PTRIN(linux_args->msg), packet,
@@ -640,17 +691,11 @@
 	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
 	    NULL, UIO_SYSSPACE);
 goout:
-	free(packet, M_TEMP);
+	free(packet, M_LINUX);
 	return (error);
 }
 
-struct linux_socket_args {
-	int domain;
-	int type;
-	int protocol;
-};
-
-static int
+int
 linux_socket(struct thread *td, struct linux_socket_args *args)
 {
 	struct socket_args /* {
@@ -658,15 +703,16 @@
 		int type;
 		int protocol;
 	} */ bsd_args;
-	int retval_socket, socket_flags;
+	int retval_socket;
 
 	bsd_args.protocol = args->protocol;
-	socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK;
-	if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
-		return (EINVAL);
 	bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
 	if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
 		return (EINVAL);
+	retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
+		&bsd_args.type);
+	if (retval_socket != 0)
+		return (retval_socket);
 	bsd_args.domain = linux_to_bsd_domain(args->domain);
 	if (bsd_args.domain == -1)
 		return (EAFNOSUPPORT);
@@ -675,13 +721,6 @@
 	if (retval_socket)
 		return (retval_socket);
 
-	retval_socket = linux_set_socket_flags(td, td->td_retval[0],
-	    socket_flags);
-	if (retval_socket) {
-		(void)kern_close(td, td->td_retval[0]);
-		goto out;
-	}
-
 	if (bsd_args.type == SOCK_RAW
 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
 	    && bsd_args.domain == PF_INET) {
@@ -710,17 +749,10 @@
 	}
 #endif
 
-out:
 	return (retval_socket);
 }
 
-struct linux_bind_args {
-	int s;
-	l_uintptr_t name;
-	int namelen;
-};
-
-static int
+int
 linux_bind(struct thread *td, struct linux_bind_args *args)
 {
 	struct sockaddr *sa;
@@ -738,16 +770,10 @@
 	return (error);
 }
 
-struct linux_connect_args {
-	int s;
-	l_uintptr_t name;
-	int namelen;
-};
-int linux_connect(struct thread *, struct linux_connect_args *);
-
 int
 linux_connect(struct thread *td, struct linux_connect_args *args)
 {
+	cap_rights_t rights;
 	struct socket *so;
 	struct sockaddr *sa;
 	u_int fflag;
@@ -772,7 +798,8 @@
 	 * socket and use the file descriptor reference instead of
 	 * creating a new one.
 	 */
-	error = fgetsock(td, args->s, CAP_CONNECT, &so, &fflag);
+	error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT),
+	    &so, &fflag);
 	if (error == 0) {
 		error = EISCONN;
 		if (fflag & FNONBLOCK) {
@@ -787,12 +814,7 @@
 	return (error);
 }
 
-struct linux_listen_args {
-	int s;
-	int backlog;
-};
-
-static int
+int
 linux_listen(struct thread *td, struct linux_listen_args *args)
 {
 	struct listen_args /* {
@@ -809,43 +831,46 @@
 linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
     l_uintptr_t namelen, int flags)
 {
-	struct accept_args /* {
+	struct accept4_args /* {
 		int	s;
 		struct sockaddr * __restrict name;
 		socklen_t * __restrict anamelen;
+		int	flags;
 	} */ bsd_args;
-	int error;
+	cap_rights_t rights;
+	struct socket *so;
+	struct file *fp;
+	int error, error1;
 
-	if (flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
-		return (EINVAL);
-
 	bsd_args.s = s;
 	/* XXX: */
 	bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr);
 	bsd_args.anamelen = PTRIN(namelen);/* XXX */
-	error = sys_accept(td, &bsd_args);
+	bsd_args.flags = 0;
+	error = linux_set_socket_flags(flags, &bsd_args.flags);
+	if (error != 0)
+		return (error);
+	error = sys_accept4(td, &bsd_args);
 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
 	if (error) {
 		if (error == EFAULT && namelen != sizeof(struct sockaddr_in))
 			return (EINVAL);
+		if (error == EINVAL) {
+			error1 = getsock_cap(td, s,
+			    cap_rights_init(&rights, CAP_ACCEPT), &fp, NULL);
+			if (error1 != 0)
+				return (error1);
+			so = fp->f_data;
+			if (so->so_type == SOCK_DGRAM) {
+				fdrop(fp, td);
+				return (EOPNOTSUPP);
+			}
+			fdrop(fp, td);
+		}
 		return (error);
 	}
-
-	/*
-	 * linux appears not to copy flags from the parent socket to the
-	 * accepted one, so we must clear the flags in the new descriptor
-	 * and apply the requested flags.
-	 */
-	error = kern_fcntl(td, td->td_retval[0], F_SETFL, 0);
-	if (error)
-		goto out;
-	error = linux_set_socket_flags(td, td->td_retval[0], flags);
-	if (error)
-		goto out;
 	if (addr)
 		error = linux_sa_put(PTRIN(addr));
-
-out:
 	if (error) {
 		(void)kern_close(td, td->td_retval[0]);
 		td->td_retval[0] = 0;
@@ -853,13 +878,7 @@
 	return (error);
 }
 
-struct linux_accept_args {
-	int s;
-	l_uintptr_t addr;
-	l_uintptr_t namelen;
-};
-
-static int
+int
 linux_accept(struct thread *td, struct linux_accept_args *args)
 {
 
@@ -867,14 +886,7 @@
 	    args->namelen, 0));
 }
 
-struct linux_accept4_args {
-	int s;
-	l_uintptr_t addr;
-	l_uintptr_t namelen;
-	int flags;
-};
-
-static int
+int
 linux_accept4(struct thread *td, struct linux_accept4_args *args)
 {
 
@@ -882,13 +894,7 @@
 	    args->namelen, args->flags));
 }
 
-struct linux_getsockname_args {
-	int s;
-	l_uintptr_t addr;
-	l_uintptr_t namelen;
-};
-
-static int
+int
 linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
 {
 	struct getsockname_args /* {
@@ -906,19 +912,10 @@
 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
 	if (error)
 		return (error);
-	error = linux_sa_put(PTRIN(args->addr));
-	if (error)
-		return (error);
-	return (0);
+	return (linux_sa_put(PTRIN(args->addr)));
 }
 
-struct linux_getpeername_args {
-	int s;
-	l_uintptr_t addr;
-	l_uintptr_t namelen;
-};
-
-static int
+int
 linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
 {
 	struct getpeername_args /* {
@@ -930,25 +927,15 @@
 
 	bsd_args.fdes = args->s;
 	bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
-	bsd_args.alen = (int *)PTRIN(args->namelen);
+	bsd_args.alen = (socklen_t *)PTRIN(args->namelen);
 	error = sys_getpeername(td, &bsd_args);
 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
 	if (error)
 		return (error);
-	error = linux_sa_put(PTRIN(args->addr));
-	if (error)
-		return (error);
-	return (0);
+	return (linux_sa_put(PTRIN(args->addr)));
 }
 
-struct linux_socketpair_args {
-	int domain;
-	int type;
-	int protocol;
-	l_uintptr_t rsv;
-};
-
-static int
+int
 linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
 {
 	struct socketpair_args /* {
@@ -957,20 +944,18 @@
 		int protocol;
 		int *rsv;
 	} */ bsd_args;
-	int error, socket_flags;
-	int sv[2];
+	int error;
 
 	bsd_args.domain = linux_to_bsd_domain(args->domain);
 	if (bsd_args.domain != PF_LOCAL)
 		return (EAFNOSUPPORT);
-
-	socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK;
-	if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
-		return (EINVAL);
 	bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
 	if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
 		return (EINVAL);
-
+	error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
+		&bsd_args.type);
+	if (error != 0)
+		return (error);
 	if (args->protocol != 0 && args->protocol != PF_UNIX)
 
 		/*
@@ -983,27 +968,10 @@
 	else
 		bsd_args.protocol = 0;
 	bsd_args.rsv = (int *)PTRIN(args->rsv);
-	error = kern_socketpair(td, bsd_args.domain, bsd_args.type,
-	    bsd_args.protocol, sv);
-	if (error)
-		return (error);
-	error = linux_set_socket_flags(td, sv[0], socket_flags);
-	if (error)
-		goto out;
-	error = linux_set_socket_flags(td, sv[1], socket_flags);
-	if (error)
-		goto out;
-
-	error = copyout(sv, bsd_args.rsv, 2 * sizeof(int));
-
-out:
-	if (error) {
-		(void)kern_close(td, sv[0]);
-		(void)kern_close(td, sv[1]);
-	}
-	return (error);
+	return (sys_socketpair(td, &bsd_args));
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 struct linux_send_args {
 	int s;
 	l_uintptr_t msg;
@@ -1029,7 +997,7 @@
 	bsd_args.flags = args->flags;
 	bsd_args.to = NULL;
 	bsd_args.tolen = 0;
-	return sys_sendto(td, &bsd_args);
+	return (sys_sendto(td, &bsd_args));
 }
 
 struct linux_recv_args {
@@ -1059,13 +1027,13 @@
 	bsd_args.fromlenaddr = 0;
 	return (sys_recvfrom(td, &bsd_args));
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
-static int
+int
 linux_sendto(struct thread *td, struct linux_sendto_args *args)
 {
 	struct msghdr msg;
 	struct iovec aiov;
-	int error;
 
 	if (linux_check_hdrincl(td, args->s) == 0)
 		/* IP_HDRINCL set, tweak the packet before sending */
@@ -1079,68 +1047,60 @@
 	msg.msg_flags = 0;
 	aiov.iov_base = PTRIN(args->msg);
 	aiov.iov_len = args->len;
-	error = linux_sendit(td, args->s, &msg, args->flags, NULL,
-	    UIO_USERSPACE);
-	return (error);
+	return (linux_sendit(td, args->s, &msg, args->flags, NULL,
+	    UIO_USERSPACE));
 }
 
-struct linux_recvfrom_args {
-	int s;
-	l_uintptr_t buf;
-	int len;
-	int flags;
-	l_uintptr_t from;
-	l_uintptr_t fromlen;
-};
-
-static int
+int
 linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
 {
-	struct recvfrom_args /* {
-		int	s;
-		caddr_t	buf;
-		size_t	len;
-		int	flags;
-		struct sockaddr * __restrict from;
-		socklen_t * __restrict fromlenaddr;
-	} */ bsd_args;
-	size_t len;
-	int error;
+	struct msghdr msg;
+	struct iovec aiov;
+	int error, fromlen;
 
-	if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t))))
+	if (PTRIN(args->fromlen) != NULL) {
+		error = copyin(PTRIN(args->fromlen), &fromlen,
+		    sizeof(fromlen));
+		if (error != 0)
+			return (error);
+		if (fromlen < 0)
+			return (EINVAL);
+		msg.msg_namelen = fromlen;
+	} else
+		msg.msg_namelen = 0;
+
+	msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from);
+	msg.msg_iov = &aiov;
+	msg.msg_iovlen = 1;
+	aiov.iov_base = PTRIN(args->buf);
+	aiov.iov_len = args->len;
+	msg.msg_control = 0;
+	msg.msg_flags = linux_to_bsd_msg_flags(args->flags);
+
+	error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL);
+	if (error != 0)
 		return (error);
 
-	bsd_args.s = args->s;
-	bsd_args.buf = PTRIN(args->buf);
-	bsd_args.len = args->len;
-	bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
-	/* XXX: */
-	bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from);
-	bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */
-	
-	linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
-	error = sys_recvfrom(td, &bsd_args);
-	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
-	
-	if (error)
-		return (error);
-	if (args->from) {
+	if (PTRIN(args->from) != NULL) {
+		error = bsd_to_linux_sockaddr((struct sockaddr *)
+		    PTRIN(args->from));
+		if (error != 0)
+			return (error);
+
 		error = linux_sa_put((struct osockaddr *)
 		    PTRIN(args->from));
-		if (error)
-			return (error);
 	}
-	return (0);
+
+	if (PTRIN(args->fromlen) != NULL)
+		error = copyout(&msg.msg_namelen, PTRIN(args->fromlen),
+		    sizeof(msg.msg_namelen));
+
+	return (error);
 }
 
-struct linux_sendmsg_args {
-	int s;
-	l_uintptr_t msg;
-	int flags;
-};
-
 static int
-linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
+linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
+    l_uint flags)
 {
 	struct cmsghdr *cmsg;
 	struct cmsgcred cmcred;
@@ -1156,8 +1116,8 @@
 	void *data;
 	int error;
 
-	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
-	if (error)
+	error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
+	if (error != 0)
 		return (error);
 
 	/*
@@ -1171,7 +1131,7 @@
 		linux_msg.msg_control = PTROUT(NULL);
 
 	error = linux_to_bsd_msghdr(&msg, &linux_msg);
-	if (error)
+	if (error != 0)
 		return (error);
 
 #ifdef COMPAT_LINUX32
@@ -1180,7 +1140,7 @@
 #else
 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
 #endif
-	if (error)
+	if (error != 0)
 		return (error);
 
 	control = NULL;
@@ -1187,22 +1147,20 @@
 	cmsg = NULL;
 
 	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
-		error = kern_getsockname(td, args->s, &sa, &datalen);
-		if (error)
+		error = kern_getsockname(td, s, &sa, &datalen);
+		if (error != 0)
 			goto bad;
 		sa_family = sa->sa_family;
 		free(sa, M_SONAME);
 
 		error = ENOBUFS;
-		cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
-		control = m_get(M_WAIT, MT_CONTROL);
-		if (control == NULL)
-			goto bad;
+		cmsg = malloc(CMSG_HDRSZ, M_LINUX, M_WAITOK|M_ZERO);
+		control = m_get(M_WAITOK, MT_CONTROL);
 
 		do {
 			error = copyin(ptr_cmsg, &linux_cmsg,
 			    sizeof(struct l_cmsghdr));
-			if (error)
+			if (error != 0)
 				goto bad;
 
 			error = EINVAL;
@@ -1266,28 +1224,61 @@
 
 	msg.msg_iov = iov;
 	msg.msg_flags = 0;
-	error = linux_sendit(td, args->s, &msg, args->flags, control,
-	    UIO_USERSPACE);
+	error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE);
+	control = NULL;
 
 bad:
+	m_freem(control);
 	free(iov, M_IOV);
 	if (cmsg)
-		free(cmsg, M_TEMP);
+		free(cmsg, M_LINUX);
 	return (error);
 }
 
-struct linux_recvmsg_args {
-	int s;
-	l_uintptr_t msg;
-	int flags;
-};
+int
+linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
+{
 
+	return (linux_sendmsg_common(td, args->s, PTRIN(args->msg),
+	    args->flags));
+}
+
+int
+linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args)
+{
+	struct l_mmsghdr *msg;
+	l_uint retval;
+	int error, datagrams;
+
+	if (args->vlen > UIO_MAXIOV)
+		args->vlen = UIO_MAXIOV;
+
+	msg = PTRIN(args->msg);
+	datagrams = 0;
+	while (datagrams < args->vlen) {
+		error = linux_sendmsg_common(td, args->s, &msg->msg_hdr,
+		    args->flags);
+		if (error != 0)
+			break;
+
+		retval = td->td_retval[0];
+		error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
+		if (error != 0)
+			break;
+		++msg;
+		++datagrams;
+	}
+	if (error == 0)
+		td->td_retval[0] = datagrams;
+	return (error);
+}
+
 static int
-linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
+linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
+    l_uint flags, struct msghdr *msg)
 {
 	struct cmsghdr *cm;
 	struct cmsgcred *cmcred;
-	struct msghdr msg;
 	struct l_cmsghdr *linux_cmsg = NULL;
 	struct l_ucred linux_ucred;
 	socklen_t datalen, outlen;
@@ -1295,55 +1286,57 @@
 	struct iovec *iov, *uiov;
 	struct mbuf *control = NULL;
 	struct mbuf **controlp;
+	struct timeval *ftmvl;
+	l_timeval ltmvl;
 	caddr_t outbuf;
 	void *data;
 	int error, i, fd, fds, *fdp;
 
-	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
-	if (error)
+	error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
+	if (error != 0)
 		return (error);
 
-	error = linux_to_bsd_msghdr(&msg, &linux_msg);
-	if (error)
+	error = linux_to_bsd_msghdr(msg, &linux_msg);
+	if (error != 0)
 		return (error);
 
 #ifdef COMPAT_LINUX32
-	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
+	error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen,
 	    &iov, EMSGSIZE);
 #else
-	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
+	error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE);
 #endif
-	if (error)
+	if (error != 0)
 		return (error);
 
-	if (msg.msg_name) {
-		error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
-		    msg.msg_namelen);
-		if (error)
+	if (msg->msg_name) {
+		error = linux_to_bsd_sockaddr((struct sockaddr *)msg->msg_name,
+		    msg->msg_namelen);
+		if (error != 0)
 			goto bad;
 	}
 
-	uiov = msg.msg_iov;
-	msg.msg_iov = iov;
-	controlp = (msg.msg_control != NULL) ? &control : NULL;
-	error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp);
-	msg.msg_iov = uiov;
-	if (error)
+	uiov = msg->msg_iov;
+	msg->msg_iov = iov;
+	controlp = (msg->msg_control != NULL) ? &control : NULL;
+	error = kern_recvit(td, s, msg, UIO_USERSPACE, controlp);
+	msg->msg_iov = uiov;
+	if (error != 0)
 		goto bad;
 
-	error = bsd_to_linux_msghdr(&msg, &linux_msg);
-	if (error)
+	error = bsd_to_linux_msghdr(msg, &linux_msg);
+	if (error != 0)
 		goto bad;
 
 	if (linux_msg.msg_name) {
 		error = bsd_to_linux_sockaddr((struct sockaddr *)
 		    PTRIN(linux_msg.msg_name));
-		if (error)
+		if (error != 0)
 			goto bad;
 	}
 	if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
 		error = linux_sa_put(PTRIN(linux_msg.msg_name));
-		if (error)
+		if (error != 0)
 			goto bad;
 	}
 
@@ -1351,12 +1344,12 @@
 	outlen = 0;
 
 	if (control) {
-		linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
+		linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO);
 
-		msg.msg_control = mtod(control, struct cmsghdr *);
-		msg.msg_controllen = control->m_len;
+		msg->msg_control = mtod(control, struct cmsghdr *);
+		msg->msg_controllen = control->m_len;
 
-		cm = CMSG_FIRSTHDR(&msg);
+		cm = CMSG_FIRSTHDR(msg);
 
 		while (cm != NULL) {
 			linux_cmsg->cmsg_type =
@@ -1376,7 +1369,7 @@
 			switch (cm->cmsg_type)
 			{
 			case SCM_RIGHTS:
-				if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
+				if (flags & LINUX_MSG_CMSG_CLOEXEC) {
 					fds = datalen / sizeof(int);
 					fdp = data;
 					for (i = 0; i < fds; i++) {
@@ -1405,6 +1398,18 @@
 				data = &linux_ucred;
 				datalen = sizeof(linux_ucred);
 				break;
+
+			case SCM_TIMESTAMP:
+				if (datalen != sizeof(struct timeval)) {
+					error = EMSGSIZE;
+					goto bad;
+				}
+				ftmvl = (struct timeval *)data;
+				ltmvl.tv_sec = ftmvl->tv_sec;
+				ltmvl.tv_usec = ftmvl->tv_usec;
+				data = <mvl;
+				datalen = sizeof(ltmvl);
+				break;
 			}
 
 			if (outlen + LINUX_CMSG_LEN(datalen) >
@@ -1433,30 +1438,92 @@
 			outbuf += LINUX_CMSG_ALIGN(datalen);
 			outlen += LINUX_CMSG_LEN(datalen);
 
-			cm = CMSG_NXTHDR(&msg, cm);
+			cm = CMSG_NXTHDR(msg, cm);
 		}
 	}
 
 out:
 	linux_msg.msg_controllen = outlen;
-	error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
+	error = copyout(&linux_msg, msghdr, sizeof(linux_msg));
 
 bad:
 	free(iov, M_IOV);
-	if (control != NULL)
-		m_freem(control);
-	if (linux_cmsg != NULL)
-		free(linux_cmsg, M_TEMP);
+	m_freem(control);
+	free(linux_cmsg, M_LINUX);
 
 	return (error);
 }
 
-struct linux_shutdown_args {
-	int s;
-	int how;
-};
+int
+linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
+{
+	struct msghdr bsd_msg;
 
-static int
+	return (linux_recvmsg_common(td, args->s, PTRIN(args->msg),
+	    args->flags, &bsd_msg));
+}
+
+int
+linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args)
+{
+	struct l_mmsghdr *msg;
+	struct msghdr bsd_msg;
+	struct l_timespec lts;
+	struct timespec ts, tts;
+	l_uint retval;
+	int error, datagrams;
+
+	if (args->timeout) {
+		error = copyin(args->timeout, &lts, sizeof(struct l_timespec));
+		if (error != 0)
+			return (error);
+		error = linux_to_native_timespec(&ts, &lts);
+		if (error != 0)
+			return (error);
+		getnanotime(&tts);
+		timespecadd(&tts, &ts);
+	}
+
+	msg = PTRIN(args->msg);
+	datagrams = 0;
+	while (datagrams < args->vlen) {
+		error = linux_recvmsg_common(td, args->s, &msg->msg_hdr,
+		    args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg);
+		if (error != 0)
+			break;
+
+		retval = td->td_retval[0];
+		error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
+		if (error != 0)
+			break;
+		++msg;
+		++datagrams;
+
+		/*
+		 * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet.
+		 */
+		if (args->flags & LINUX_MSG_WAITFORONE)
+			args->flags |= LINUX_MSG_DONTWAIT;
+
+		/*
+		 * See BUGS section of recvmmsg(2).
+		 */
+		if (args->timeout) {
+			getnanotime(&ts);
+			timespecsub(&ts, &tts);
+			if (!timespecisset(&ts) || ts.tv_sec > 0)
+				break;
+		}
+		/* Out of band data, return right away. */
+		if (bsd_msg.msg_flags & MSG_OOB)
+			break;
+	}
+	if (error == 0)
+		td->td_retval[0] = datagrams;
+	return (error);
+}
+
+int
 linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
 {
 	struct shutdown_args /* {
@@ -1469,15 +1536,7 @@
 	return (sys_shutdown(td, &bsd_args));
 }
 
-struct linux_setsockopt_args {
-	int s;
-	int level;
-	int optname;
-	l_uintptr_t optval;
-	int optlen;
-};
-
-static int
+int
 linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
 {
 	struct setsockopt_args /* {
@@ -1517,6 +1576,9 @@
 	case IPPROTO_IP:
 		name = linux_to_bsd_ip_sockopt(args->optname);
 		break;
+	case IPPROTO_IPV6:
+		name = linux_to_bsd_ip6_sockopt(args->optname);
+		break;
 	case IPPROTO_TCP:
 		name = linux_to_bsd_tcp_sockopt(args->optname);
 		break;
@@ -1542,15 +1604,7 @@
 	return (error);
 }
 
-struct linux_getsockopt_args {
-	int s;
-	int level;
-	int optname;
-	l_uintptr_t optval;
-	l_uintptr_t optlen;
-};
-
-static int
+int
 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
 {
 	struct getsockopt_args /* {
@@ -1562,10 +1616,10 @@
 	} */ bsd_args;
 	l_timeval linux_tv;
 	struct timeval tv;
-	socklen_t tv_len, xulen;
+	socklen_t tv_len, xulen, len;
 	struct xucred xu;
 	struct l_ucred lxu;
-	int error, name;
+	int error, name, newval;
 
 	bsd_args.s = args->s;
 	bsd_args.level = linux_to_bsd_sockopt_level(args->level);
@@ -1604,6 +1658,15 @@
 			return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
 			/* NOTREACHED */
 			break;
+		case SO_ERROR:
+			len = sizeof(newval);
+			error = kern_getsockopt(td, args->s, bsd_args.level,
+			    name, &newval, UIO_SYSSPACE, &len);
+			if (error)
+				return (error);
+			newval = -SV_ABI_ERRNO(td->td_proc, newval);
+			return (copyout(&newval, PTRIN(args->optval), len));
+			/* NOTREACHED */
 		default:
 			break;
 		}
@@ -1611,6 +1674,9 @@
 	case IPPROTO_IP:
 		name = linux_to_bsd_ip_sockopt(args->optname);
 		break;
+	case IPPROTO_IPV6:
+		name = linux_to_bsd_ip6_sockopt(args->optname);
+		break;
 	case IPPROTO_TCP:
 		name = linux_to_bsd_tcp_sockopt(args->optname);
 		break;
@@ -1634,6 +1700,8 @@
 	return (error);
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+
 /* Argument list sizes for linux_socketcall */
 
 #define LINUX_AL(x) ((x) * sizeof(l_ulong))
@@ -1648,7 +1716,8 @@
 	LINUX_AL(6) /* recvfrom */,	LINUX_AL(2) /* shutdown */,
 	LINUX_AL(5) /* setsockopt */,	LINUX_AL(5) /* getsockopt */,
 	LINUX_AL(3) /* sendmsg */,	LINUX_AL(3) /* recvmsg */,
-	LINUX_AL(4) /* accept4 */
+	LINUX_AL(4) /* accept4 */,	LINUX_AL(5) /* recvmmsg */,
+	LINUX_AL(4) /* sendmmsg */
 };
 
 #define	LINUX_AL_SIZE	sizeof(lxs_args) / sizeof(lxs_args[0]) - 1
@@ -1704,8 +1773,13 @@
 		return (linux_recvmsg(td, arg));
 	case LINUX_ACCEPT4:
 		return (linux_accept4(td, arg));
+	case LINUX_RECVMMSG:
+		return (linux_recvmmsg(td, arg));
+	case LINUX_SENDMMSG:
+		return (linux_sendmmsg(td, arg));
 	}
 
 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
 	return (ENOSYS);
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */

Modified: trunk/sys/compat/linux/linux_socket.h
===================================================================
--- trunk/sys/compat/linux/linux_socket.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_socket.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2000 Assar Westerlund
  * All rights reserved.
@@ -25,7 +26,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_socket.h 299705 2016-05-14 00:35:49Z pfg $
  */
 
 #ifndef _LINUX_SOCKET_H_
@@ -48,15 +49,39 @@
 #define LINUX_MSG_RST		0x1000
 #define LINUX_MSG_ERRQUEUE	0x2000
 #define LINUX_MSG_NOSIGNAL	0x4000
+#define LINUX_MSG_WAITFORONE	0x10000
 #define LINUX_MSG_CMSG_CLOEXEC	0x40000000
 
 /* Socket-level control message types */
 
 #define LINUX_SCM_RIGHTS	0x01
-#define LINUX_SCM_CREDENTIALS   0x02
+#define LINUX_SCM_CREDENTIALS	0x02
+#define LINUX_SCM_TIMESTAMP	0x1D
 
-/* Ancilliary data object information macros */
+struct l_msghdr {
+	l_uintptr_t	msg_name;
+	l_int		msg_namelen;
+	l_uintptr_t	msg_iov;
+	l_size_t	msg_iovlen;
+	l_uintptr_t	msg_control;
+	l_size_t	msg_controllen;
+	l_uint		msg_flags;
+};
 
+struct l_mmsghdr {
+	struct l_msghdr	msg_hdr;
+	l_uint		msg_len;
+
+};
+
+struct l_cmsghdr {
+	l_size_t	cmsg_len;
+	l_int		cmsg_level;
+	l_int		cmsg_type;
+};
+
+/* Ancillary data object information macros */
+
 #define LINUX_CMSG_ALIGN(len)	roundup2(len, sizeof(l_ulong))
 #define LINUX_CMSG_DATA(cmsg)	((void *)((char *)(cmsg) + \
 				    LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr))))
@@ -116,4 +141,198 @@
 	uint32_t	gid;
 };
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+
+struct linux_sendto_args {
+	int s;
+	l_uintptr_t msg;
+	int len;
+	int flags;
+	l_uintptr_t to;
+	int tolen;
+};
+
+struct linux_socket_args {
+	int domain;
+	int type;
+	int protocol;
+};
+
+struct linux_bind_args {
+	int s;
+	l_uintptr_t name;
+	int namelen;
+};
+
+struct linux_connect_args {
+	int s;
+	l_uintptr_t name;
+	int namelen;
+};
+
+struct linux_listen_args {
+	int s;
+	int backlog;
+};
+
+struct linux_accept_args {
+	int s;
+	l_uintptr_t addr;
+	l_uintptr_t namelen;
+};
+
+struct linux_accept4_args {
+	int s;
+	l_uintptr_t addr;
+	l_uintptr_t namelen;
+	int flags;
+};
+
+struct linux_getsockname_args {
+	int s;
+	l_uintptr_t addr;
+	l_uintptr_t namelen;
+};
+
+struct linux_getpeername_args {
+	int s;
+	l_uintptr_t addr;
+	l_uintptr_t namelen;
+};
+
+struct linux_socketpair_args {
+	int domain;
+	int type;
+	int protocol;
+	l_uintptr_t rsv;
+};
+
+struct linux_recvfrom_args {
+	int s;
+	l_uintptr_t buf;
+	int len;
+	int flags;
+	l_uintptr_t from;
+	l_uintptr_t fromlen;
+};
+
+struct linux_sendmsg_args {
+	int s;
+	l_uintptr_t msg;
+	int flags;
+};
+
+struct linux_recvmsg_args {
+	int s;
+	l_uintptr_t msg;
+	int flags;
+};
+
+struct linux_shutdown_args {
+	int s;
+	int how;
+};
+
+struct linux_setsockopt_args {
+	int s;
+	int level;
+	int optname;
+	l_uintptr_t optval;
+	int optlen;
+};
+
+struct linux_getsockopt_args {
+	int s;
+	int level;
+	int optname;
+	l_uintptr_t optval;
+	l_uintptr_t optlen;
+};
+
+int linux_socket(struct thread *td, struct linux_socket_args *args);
+int linux_bind(struct thread *td, struct linux_bind_args *args);
+int linux_connect(struct thread *, struct linux_connect_args *);
+int linux_listen(struct thread *td, struct linux_listen_args *args);
+int linux_accept(struct thread *td, struct linux_accept_args *args);
+int linux_accept4(struct thread *td, struct linux_accept4_args *args);
+int linux_getsockname(struct thread *td, struct linux_getsockname_args *args);
+int linux_getpeername(struct thread *td, struct linux_getpeername_args *args);
+int linux_socketpair(struct thread *td, struct linux_socketpair_args *args);
+int linux_sendto(struct thread *td, struct linux_sendto_args *args);
+int linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args);
+int linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args);
+int linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args);
+int linux_shutdown(struct thread *td, struct linux_shutdown_args *args);
+int linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args);
+int linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args);
+
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+/* Operations for socketcall */
+
+#define	LINUX_SOCKET 		1
+#define	LINUX_BIND		2
+#define	LINUX_CONNECT 		3
+#define	LINUX_LISTEN 		4
+#define	LINUX_ACCEPT 		5
+#define	LINUX_GETSOCKNAME	6
+#define	LINUX_GETPEERNAME	7
+#define	LINUX_SOCKETPAIR	8
+#define	LINUX_SEND		9
+#define	LINUX_RECV		10
+#define	LINUX_SENDTO 		11
+#define	LINUX_RECVFROM 		12
+#define	LINUX_SHUTDOWN 		13
+#define	LINUX_SETSOCKOPT	14
+#define	LINUX_GETSOCKOPT	15
+#define	LINUX_SENDMSG		16
+#define	LINUX_RECVMSG		17
+#define	LINUX_ACCEPT4		18
+#define	LINUX_RECVMMSG		19
+#define	LINUX_SENDMMSG		20
+
+/* Socket options */
+#define	LINUX_IP_TOS		1
+#define	LINUX_IP_TTL		2
+#define	LINUX_IP_HDRINCL	3
+#define	LINUX_IP_OPTIONS	4
+
+#define	LINUX_IP_MULTICAST_IF		32
+#define	LINUX_IP_MULTICAST_TTL		33
+#define	LINUX_IP_MULTICAST_LOOP		34
+#define	LINUX_IP_ADD_MEMBERSHIP		35
+#define	LINUX_IP_DROP_MEMBERSHIP	36
+
+#define	LINUX_IPV6_CHECKSUM		7
+#define	LINUX_IPV6_NEXTHOP		9
+#define	LINUX_IPV6_UNICAST_HOPS		16
+#define	LINUX_IPV6_MULTICAST_IF		17
+#define	LINUX_IPV6_MULTICAST_HOPS	18
+#define	LINUX_IPV6_MULTICAST_LOOP	19
+#define	LINUX_IPV6_ADD_MEMBERSHIP	20
+#define	LINUX_IPV6_DROP_MEMBERSHIP	21
+#define	LINUX_IPV6_V6ONLY		26
+
+#define	LINUX_IPV6_RECVPKTINFO		49
+#define	LINUX_IPV6_PKTINFO		50
+#define	LINUX_IPV6_RECVHOPLIMIT		51
+#define	LINUX_IPV6_HOPLIMIT		52
+#define	LINUX_IPV6_RECVHOPOPTS		53
+#define	LINUX_IPV6_HOPOPTS		54
+#define	LINUX_IPV6_RTHDRDSTOPTS		55
+#define	LINUX_IPV6_RECVRTHDR		56
+#define	LINUX_IPV6_RTHDR		57
+#define	LINUX_IPV6_RECVDSTOPTS		58
+#define	LINUX_IPV6_DSTOPTS		59
+#define	LINUX_IPV6_RECVPATHMTU		60
+#define	LINUX_IPV6_PATHMTU		61
+#define	LINUX_IPV6_DONTFRAG		62
+
+#define	LINUX_TCP_NODELAY	1
+#define	LINUX_TCP_MAXSEG	2
+#define	LINUX_TCP_KEEPIDLE	4
+#define	LINUX_TCP_KEEPINTVL	5
+#define	LINUX_TCP_KEEPCNT	6
+#define	LINUX_TCP_MD5SIG	14
+
 #endif /* _LINUX_SOCKET_H_ */

Modified: trunk/sys/compat/linux/linux_stats.c
===================================================================
--- trunk/sys/compat/linux/linux_stats.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_stats.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 1994-1995 S\xF8ren Schmidt
+ * Copyright (c) 1994-1995 Søren Schmidt
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,11 +28,12 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_stats.c 323366 2017-09-09 14:30:16Z emaste $");
 
 #include "opt_compat.h"
 
 #include <sys/param.h>
+#include <sys/capsicum.h>
 #include <sys/dirent.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
@@ -58,7 +60,6 @@
 #include <compat/linux/linux_util.h>
 #include <compat/linux/linux_file.h>
 
-#define	LINUX_SHMFS_MAGIC 0x01021994
 
 static void
 translate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
@@ -251,11 +252,12 @@
 	return (error);
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 static int
 stat_copyout(struct stat *buf, void *ubuf)
 {
 	struct l_stat lbuf;
-	
+
 	bzero(&lbuf, sizeof(lbuf));
 	lbuf.st_dev = buf->st_dev;
 	lbuf.st_ino = buf->st_ino;
@@ -301,7 +303,7 @@
 		return (error);
 	}
 	LFREEPATH(path);
-	return(stat_copyout(&buf, args->up));
+	return (stat_copyout(&buf, args->up));
 }
 
 int
@@ -323,21 +325,21 @@
 		return (error);
 	}
 	LFREEPATH(path);
-	return(stat_copyout(&buf, args->up));
+	return (stat_copyout(&buf, args->up));
 }
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
-/* XXX - All fields of type l_int are defined as l_long on i386 */
 struct l_statfs {
-	l_int		f_type;
-	l_int		f_bsize;
-	l_int		f_blocks;
-	l_int		f_bfree;
-	l_int		f_bavail;
-	l_int		f_files;
-	l_int		f_ffree;
+	l_long		f_type;
+	l_long		f_bsize;
+	l_long		f_blocks;
+	l_long		f_bfree;
+	l_long		f_bavail;
+	l_long		f_files;
+	l_long		f_ffree;
 	l_fsid_t	f_fsid;
-	l_int		f_namelen;
-	l_int		f_spare[6];
+	l_long		f_namelen;
+	l_long		f_spare[6];
 };
 
 #define	LINUX_CODA_SUPER_MAGIC	0x73757245L
@@ -350,7 +352,9 @@
 #define	LINUX_NTFS_SUPER_MAGIC	0x5346544EL
 #define	LINUX_PROC_SUPER_MAGIC	0x9fa0L
 #define	LINUX_UFS_SUPER_MAGIC	0x00011954L	/* XXX - UFS_MAGIC in Linux */
+#define	LINUX_ZFS_SUPER_MAGIC	0x2FC12FC1
 #define LINUX_DEVFS_SUPER_MAGIC	0x1373L
+#define	LINUX_SHMFS_MAGIC	0x01021994
 
 static long
 bsd_to_linux_ftype(const char *fstypename)
@@ -358,6 +362,7 @@
 	int i;
 	static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
 		{"ufs",     LINUX_UFS_SUPER_MAGIC},
+		{"zfs",     LINUX_ZFS_SUPER_MAGIC},
 		{"cd9660",  LINUX_ISOFS_SUPER_MAGIC},
 		{"nfs",     LINUX_NFS_SUPER_MAGIC},
 		{"ext2fs",  LINUX_EXT2_SUPER_MAGIC},
@@ -368,6 +373,7 @@
 		{"hpfs",    LINUX_HPFS_SUPER_MAGIC},
 		{"coda",    LINUX_CODA_SUPER_MAGIC},
 		{"devfs",   LINUX_DEVFS_SUPER_MAGIC},
+		{"tmpfs",   LINUX_SHMFS_MAGIC},
 		{NULL,      0L}};
 
 	for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
@@ -377,10 +383,22 @@
 	return (0L);
 }
 
-static void
+static int
 bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
 {
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+	uint64_t tmp;
 
+#define	LINUX_HIBITS	0xffffffff00000000ULL
+
+	tmp = bsd_statfs->f_blocks | bsd_statfs->f_bfree | bsd_statfs->f_files |
+	    bsd_statfs->f_bsize;
+	if ((bsd_statfs->f_bavail != -1 && (bsd_statfs->f_bavail & LINUX_HIBITS)) ||
+	    (bsd_statfs->f_ffree != -1 && (bsd_statfs->f_ffree & LINUX_HIBITS)) ||
+	    (tmp & LINUX_HIBITS))
+		return (EOVERFLOW);
+#undef	LINUX_HIBITS
+#endif
 	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
 	linux_statfs->f_bsize = bsd_statfs->f_bsize;
 	linux_statfs->f_blocks = bsd_statfs->f_blocks;
@@ -391,6 +409,8 @@
 	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
 	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
 	linux_statfs->f_namelen = MAXNAMLEN;
+
+	return (0);
 }
 
 int
@@ -399,7 +419,7 @@
 	struct l_statfs linux_statfs;
 	struct statfs bsd_statfs;
 	char *path;
-	int error, dev_shm;
+	int error;
 
 	LCONVPATHEXIST(td, args->path, &path);
 
@@ -407,20 +427,17 @@
 	if (ldebug(statfs))
 		printf(ARGS(statfs, "%s, *"), path);
 #endif
-	dev_shm = 0;
 	error = kern_statfs(td, path, UIO_SYSSPACE, &bsd_statfs);
-	if (strncmp(path, "/dev/shm", sizeof("/dev/shm") - 1) == 0)
-		dev_shm = (path[8] == '\0'
-		    || (path[8] == '/' && path[9] == '\0'));
 	LFREEPATH(path);
 	if (error)
 		return (error);
-	bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
-	if (dev_shm)
-		linux_statfs.f_type = LINUX_SHMFS_MAGIC;
-	return copyout(&linux_statfs, args->buf, sizeof(linux_statfs));
+	error = bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
+	if (error)
+		return (error);
+	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 static void
 bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
 {
@@ -459,10 +476,32 @@
 	if (error)
 		return (error);
 	bsd_to_linux_statfs64(&bsd_statfs, &linux_statfs);
-	return copyout(&linux_statfs, args->buf, sizeof(linux_statfs));
+	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
 }
 
 int
+linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
+{
+	struct l_statfs64 linux_statfs;
+	struct statfs bsd_statfs;
+	int error;
+
+#ifdef DEBUG
+	if (ldebug(fstatfs64))
+		printf(ARGS(fstatfs64, "%d, *"), args->fd);
+#endif
+	if (args->bufsize != sizeof(struct l_statfs64))
+		return (EINVAL);
+
+	error = kern_fstatfs(td, args->fd, &bsd_statfs);
+	if (error)
+		return error;
+	bsd_to_linux_statfs64(&bsd_statfs, &linux_statfs);
+	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
 linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
 {
 	struct l_statfs linux_statfs;
@@ -475,9 +514,11 @@
 #endif
 	error = kern_fstatfs(td, args->fd, &bsd_statfs);
 	if (error)
-		return error;
-	bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
-	return copyout(&linux_statfs, args->buf, sizeof(linux_statfs));
+		return (error);
+	error = bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
+	if (error)
+		return (error);
+	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
 }
 
 struct l_ustat
@@ -493,7 +534,7 @@
 {
 #ifdef DEBUG
 	if (ldebug(ustat))
-		printf(ARGS(ustat, "%d, *"), args->dev);
+		printf(ARGS(ustat, "%ju, *"), (uintmax_t)args->dev);
 #endif
 
 	return (EOPNOTSUPP);
@@ -624,4 +665,74 @@
 	return (error);
 }
 
+#else /* __amd64__ && !COMPAT_LINUX32 */
+
+int
+linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
+{
+	char *path;
+	int error, dfd, flag;
+	struct stat buf;
+
+	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
+		return (EINVAL);
+	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
+	    AT_SYMLINK_NOFOLLOW : 0;
+
+	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(newfstatat))
+		printf(ARGS(newfstatat, "%i, %s, %i"), args->dfd, path, args->flag);
+#endif
+
+	error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
+	if (error == 0)
+		error = newstat_copyout(&buf, args->statbuf);
+	LFREEPATH(path);
+
+	return (error);
+}
+
 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
+{
+	cap_rights_t rights;
+	struct mount *mp;
+	struct vnode *vp;
+	int error, save;
+
+	error = fgetvp(td, args->fd, cap_rights_init(&rights, CAP_FSYNC), &vp);
+	if (error != 0)
+		/*
+		 * Linux syncfs() returns only EBADF, however fgetvp()
+		 * can return EINVAL in case of file descriptor does
+		 * not represent a vnode. XXX.
+		 */
+		return (error);
+
+	mp = vp->v_mount;
+	mtx_lock(&mountlist_mtx);
+	error = vfs_busy(mp, MBF_MNTLSTLOCK);
+	if (error != 0) {
+		/* See comment above. */
+		mtx_unlock(&mountlist_mtx);
+		goto out;
+	}
+	if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
+	    vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
+		save = curthread_pflags_set(TDP_SYNCIO);
+		vfs_msync(mp, MNT_NOWAIT);
+		VFS_SYNC(mp, MNT_NOWAIT);
+		curthread_pflags_restore(save);
+		vn_finished_write(mp);
+	}
+	vfs_unbusy(mp);
+
+ out:
+	vrele(vp);
+	return (error);
+}

Modified: trunk/sys/compat/linux/linux_sysctl.c
===================================================================
--- trunk/sys/compat/linux/linux_sysctl.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_sysctl.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2001 Marcel Moolenaar
  * All rights reserved.
@@ -27,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_sysctl.c 293532 2016-01-09 16:20:29Z dchagin $");
 
 #include "opt_compat.h"
 #include "opt_kdtrace.h"
@@ -52,6 +53,7 @@
 #endif
 
 #include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_misc.h>
 #include <compat/linux/linux_util.h>
 
 #define	LINUX_CTL_KERN		1
@@ -140,12 +142,12 @@
 		return (ENOTDIR);
 	}
 
-	mib = malloc(la.nlen * sizeof(l_int), M_TEMP, M_WAITOK);
+	mib = malloc(la.nlen * sizeof(l_int), M_LINUX, M_WAITOK);
 	error = copyin(PTRIN(la.name), mib, la.nlen * sizeof(l_int));
 	if (error) {
 		LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error);
 		LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
-		free(mib, M_TEMP);
+		free(mib, M_LINUX);
 		return (error);
 	}
 
@@ -157,7 +159,7 @@
 		switch (mib[1]) {
 		case LINUX_KERN_VERSION:
 			error = handle_string(&la, version);
-			free(mib, M_TEMP);
+			free(mib, M_LINUX);
 			LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
 			return (error);
 		default:
@@ -186,7 +188,7 @@
 		sbuf_delete(sb);
 	}
 
-	free(mib, M_TEMP);
+	free(mib, M_LINUX);
 
 	LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR);
 	return (ENOTDIR);

Modified: trunk/sys/compat/linux/linux_sysproto.h
===================================================================
--- trunk/sys/compat/linux/linux_sysproto.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_sysproto.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005 Travis Poppe
  * All rights reserved.
@@ -25,7 +26,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_sysproto.h 143197 2005-03-07 00:18:06Z sobomax $
  */
 
 #ifndef LINUX_SYSPROTO

Modified: trunk/sys/compat/linux/linux_time.c
===================================================================
--- trunk/sys/compat/linux/linux_time.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_time.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */
 
 /*-
@@ -30,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_time.c 315658 2017-03-21 01:24:56Z vangyzen $");
 #if 0
 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $");
 #endif
@@ -40,8 +41,11 @@
 
 #include <sys/param.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/ucred.h>
 #include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/resourcevar.h>
 #include <sys/sdt.h>
 #include <sys/signal.h>
 #include <sys/stdint.h>
@@ -60,6 +64,7 @@
 #endif
 
 #include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_timer.h>
 
 /* DTrace init */
 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
@@ -102,7 +107,6 @@
 LIN_SDT_PROBE_DEFINE2(time, linux_nanosleep, entry, "const struct l_timespec *",
     "struct l_timespec *");
 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int");
-LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, nanosleep_error, "int");
 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int");
 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int");
 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, return, "int");
@@ -109,7 +113,6 @@
 LIN_SDT_PROBE_DEFINE4(time, linux_clock_nanosleep, entry, "clockid_t", "int",
     "struct l_timespec *", "struct l_timespec *");
 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int");
-LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, nanosleep_error, "int");
 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int");
 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int");
 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int");
@@ -116,13 +119,8 @@
 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int");
 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, return, "int");
 
-static void native_to_linux_timespec(struct l_timespec *,
-				     struct timespec *);
-static int linux_to_native_timespec(struct timespec *,
-				     struct l_timespec *);
-static int linux_to_native_clockid(clockid_t *, clockid_t);
 
-static void
+void
 native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
 {
 
@@ -134,7 +132,7 @@
 	LIN_SDT_PROBE0(time, native_to_linux_timespec, return);
 }
 
-static int
+int
 linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
 {
 
@@ -151,12 +149,26 @@
 	return (0);
 }
 
-static int
+int
 linux_to_native_clockid(clockid_t *n, clockid_t l)
 {
 
 	LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l);
 
+	if (l < 0) {
+		/* cpu-clock */
+		if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD)
+			return (EINVAL);
+		if (LINUX_CPUCLOCK_WHICH(l) >= LINUX_CPUCLOCK_MAX)
+			return (EINVAL);
+
+		if (LINUX_CPUCLOCK_PERTHREAD(l))
+			*n = CLOCK_THREAD_CPUTIME_ID;
+		else
+			*n = CLOCK_PROCESS_CPUTIME_ID;
+		return (0);
+	}
+
 	switch (l) {
 	case LINUX_CLOCK_REALTIME:
 		*n = CLOCK_REALTIME;
@@ -164,21 +176,27 @@
 	case LINUX_CLOCK_MONOTONIC:
 		*n = CLOCK_MONOTONIC;
 		break;
-	case LINUX_CLOCK_PROCESS_CPUTIME_ID:
-	case LINUX_CLOCK_THREAD_CPUTIME_ID:
-	case LINUX_CLOCK_REALTIME_HR:
-	case LINUX_CLOCK_MONOTONIC_HR:
+	case LINUX_CLOCK_REALTIME_COARSE:
+		*n = CLOCK_REALTIME_FAST;
+		break;
+	case LINUX_CLOCK_MONOTONIC_COARSE:
+		*n = CLOCK_MONOTONIC_FAST;
+		break;
+	case LINUX_CLOCK_MONOTONIC_RAW:
+	case LINUX_CLOCK_BOOTTIME:
+	case LINUX_CLOCK_REALTIME_ALARM:
+	case LINUX_CLOCK_BOOTTIME_ALARM:
+	case LINUX_CLOCK_SGI_CYCLE:
+	case LINUX_CLOCK_TAI:
 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
 		    unsupported_clockid, l);
 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
 		return (EINVAL);
-		break;
 	default:
 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
 		    unknown_clockid, l);
 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
 		return (EINVAL);
-		break;
 	}
 
 	LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0);
@@ -189,9 +207,14 @@
 linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
 {
 	struct l_timespec lts;
-	int error;
+	struct timespec tp;
+	struct rusage ru;
+	struct thread *targettd;
+	struct proc *p;
+	int error, clockwhich;
 	clockid_t nwhich = 0;	/* XXX: GCC */
-	struct timespec tp;
+	pid_t pid;
+	lwpid_t tid;
 
 	LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp);
 
@@ -202,7 +225,100 @@
 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
 		return (error);
 	}
-	error = kern_clock_gettime(td, nwhich, &tp);
+
+	switch (nwhich) {
+	case CLOCK_PROCESS_CPUTIME_ID:
+		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+		pid = LINUX_CPUCLOCK_ID(args->which);
+		if (pid == 0) {
+			p = td->td_proc;
+			PROC_LOCK(p);
+		} else {
+			error = pget(pid, PGET_CANSEE, &p);
+			if (error != 0)
+				return (EINVAL);
+		}
+		switch (clockwhich) {
+		case LINUX_CPUCLOCK_PROF:
+			PROC_STATLOCK(p);
+			calcru(p, &ru.ru_utime, &ru.ru_stime);
+			PROC_STATUNLOCK(p);
+			PROC_UNLOCK(p);
+			timevaladd(&ru.ru_utime, &ru.ru_stime);
+			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+			break;
+		case LINUX_CPUCLOCK_VIRT:
+			PROC_STATLOCK(p);
+			calcru(p, &ru.ru_utime, &ru.ru_stime);
+			PROC_STATUNLOCK(p);
+			PROC_UNLOCK(p);
+			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+			break;
+		case LINUX_CPUCLOCK_SCHED:
+			PROC_UNLOCK(p);
+			error = kern_clock_getcpuclockid2(td, pid,
+			    CPUCLOCK_WHICH_PID, &nwhich);
+			if (error != 0)
+				return (EINVAL);
+			error = kern_clock_gettime(td, nwhich, &tp);
+			break;
+		default:
+			PROC_UNLOCK(p);
+			return (EINVAL);
+		}
+
+		break;
+
+	case CLOCK_THREAD_CPUTIME_ID:
+		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+		p = td->td_proc;
+		tid = LINUX_CPUCLOCK_ID(args->which);
+		if (tid == 0) {
+			targettd = td;
+			PROC_LOCK(p);
+		} else {
+			targettd = tdfind(tid, p->p_pid);
+			if (targettd == NULL)
+				return (EINVAL);
+		}
+		switch (clockwhich) {
+		case LINUX_CPUCLOCK_PROF:
+			PROC_STATLOCK(p);
+			thread_lock(targettd);
+			rufetchtd(targettd, &ru);
+			thread_unlock(targettd);
+			PROC_STATUNLOCK(p);
+			PROC_UNLOCK(p);
+			timevaladd(&ru.ru_utime, &ru.ru_stime);
+			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+			break;
+		case LINUX_CPUCLOCK_VIRT:
+			PROC_STATLOCK(p);
+			thread_lock(targettd);
+			rufetchtd(targettd, &ru);
+			thread_unlock(targettd);
+			PROC_STATUNLOCK(p);
+			PROC_UNLOCK(p);
+			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+			break;
+		case LINUX_CPUCLOCK_SCHED:
+			error = kern_clock_getcpuclockid2(td, tid,
+			    CPUCLOCK_WHICH_TID, &nwhich);
+			PROC_UNLOCK(p);
+			if (error != 0)
+				return (EINVAL);
+			error = kern_clock_gettime(td, nwhich, &tp);
+			break;
+		default:
+			PROC_UNLOCK(p);
+			return (EINVAL);
+		}
+		break;
+
+	default:
+		error = kern_clock_gettime(td, nwhich, &tp);
+		break;
+	}
 	if (error != 0) {
 		LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
@@ -260,19 +376,16 @@
 int
 linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
 {
+	struct proc *p;
 	struct timespec ts;
 	struct l_timespec lts;
-	int error;
+	int error, clockwhich;
 	clockid_t nwhich = 0;	/* XXX: GCC */
+	pid_t pid;
+	lwpid_t tid;
 
 	LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp);
 
-	if (args->tp == NULL) {
-		LIN_SDT_PROBE0(time, linux_clock_getres, nullcall);
-		LIN_SDT_PROBE1(time, linux_clock_getres, return, 0);
-	  	return (0);
-	}
-
 	error = linux_to_native_clockid(&nwhich, args->which);
 	if (error != 0) {
 		LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error,
@@ -280,6 +393,59 @@
 		LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
 		return (error);
 	}
+
+	/*
+	 * Check user supplied clock id in case of per-process 
+	 * or thread-specific cpu-time clock.
+	 */
+	switch (nwhich) {
+	case CLOCK_THREAD_CPUTIME_ID:
+		tid = LINUX_CPUCLOCK_ID(args->which);
+		if (tid != 0) {
+			p = td->td_proc;
+			if (tdfind(tid, p->p_pid) == NULL)
+				return (ESRCH);
+			PROC_UNLOCK(p);
+		}
+		break;
+	case CLOCK_PROCESS_CPUTIME_ID:
+		pid = LINUX_CPUCLOCK_ID(args->which);
+		if (pid != 0) {
+			error = pget(pid, PGET_CANSEE, &p);
+			if (error != 0)
+				return (EINVAL);
+			PROC_UNLOCK(p);
+		}
+		break;
+	}
+
+	if (args->tp == NULL) {
+		LIN_SDT_PROBE0(time, linux_clock_getres, nullcall);
+		LIN_SDT_PROBE1(time, linux_clock_getres, return, 0);
+	  	return (0);
+	}
+
+	switch (nwhich) {
+	case CLOCK_THREAD_CPUTIME_ID:
+	case CLOCK_PROCESS_CPUTIME_ID:
+		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+		switch (clockwhich) {
+		case LINUX_CPUCLOCK_PROF:
+			nwhich = CLOCK_PROF;
+			break;
+		case LINUX_CPUCLOCK_VIRT:
+			nwhich = CLOCK_VIRTUAL;
+			break;
+		case LINUX_CPUCLOCK_SCHED:
+			break;
+		default:
+			return (EINVAL);
+		}
+		break;
+
+	default:
+		break;
+	}
 	error = kern_clock_getres(td, nwhich, &ts);
 	if (error != 0) {
 		LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error);
@@ -302,7 +468,7 @@
 	struct timespec *rmtp;
 	struct l_timespec lrqts, lrmts;
 	struct timespec rqts, rmts;
-	int error;
+	int error, error2;
 
 	LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp);
 
@@ -314,9 +480,9 @@
 	}
 
 	if (args->rmtp != NULL)
-	   	rmtp = &rmts;
+		rmtp = &rmts;
 	else
-	   	rmtp = NULL;
+		rmtp = NULL;
 
 	error = linux_to_native_timespec(&rqts, &lrqts);
 	if (error != 0) {
@@ -325,25 +491,19 @@
 		return (error);
 	}
 	error = kern_nanosleep(td, &rqts, rmtp);
-	if (error != 0) {
-		LIN_SDT_PROBE1(time, linux_nanosleep, nanosleep_error, error);
-		LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
-		return (error);
-	}
-
-	if (args->rmtp != NULL) {
-	   	native_to_linux_timespec(&lrmts, rmtp);
-	   	error = copyout(&lrmts, args->rmtp, sizeof(lrmts));
-		if (error != 0) {
+	if (error == EINTR && args->rmtp != NULL) {
+		native_to_linux_timespec(&lrmts, rmtp);
+		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
+		if (error2 != 0) {
 			LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error,
-			    error);
-			LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
-		   	return (error);
+			    error2);
+			LIN_SDT_PROBE1(time, linux_nanosleep, return, error2);
+			return (error2);
 		}
 	}
 
-	LIN_SDT_PROBE1(time, linux_nanosleep, return, 0);
-	return (0);
+	LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
+	return (error);
 }
 
 int
@@ -352,7 +512,7 @@
 	struct timespec *rmtp;
 	struct l_timespec lrqts, lrmts;
 	struct timespec rqts, rmts;
-	int error;
+	int error, error2;
 
 	LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which,
 	    args->flags, args->rqtp, args->rmtp);
@@ -372,7 +532,7 @@
 		return (EINVAL);
 	}
 
-	error = copyin(args->rqtp, &lrqts, sizeof lrqts);
+	error = copyin(args->rqtp, &lrqts, sizeof(lrqts));
 	if (error != 0) {
 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error,
 		    error);
@@ -381,9 +541,9 @@
 	}
 
 	if (args->rmtp != NULL)
-	   	rmtp = &rmts;
+		rmtp = &rmts;
 	else
-	   	rmtp = NULL;
+		rmtp = NULL;
 
 	error = linux_to_native_timespec(&rqts, &lrqts);
 	if (error != 0) {
@@ -393,24 +553,19 @@
 		return (error);
 	}
 	error = kern_nanosleep(td, &rqts, rmtp);
-	if (error != 0) {
-		LIN_SDT_PROBE1(time, linux_clock_nanosleep, nanosleep_error,
-		    error);
-		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
-		return (error);
-	}
-
-	if (args->rmtp != NULL) {
+	if (error == EINTR && args->rmtp != NULL) {
+		/* XXX. Not for TIMER_ABSTIME */
 	   	native_to_linux_timespec(&lrmts, rmtp);
-	   	error = copyout(&lrmts, args->rmtp, sizeof lrmts );
-		if (error != 0) {
+		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
+		if (error2 != 0) {
 			LIN_SDT_PROBE1(time, linux_clock_nanosleep,
-			    copyout_error, error);
-			LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
-		   	return (error);
+			    copyout_error, error2);
+			LIN_SDT_PROBE1(time, linux_clock_nanosleep,
+			    return, error2);
+			return (error2);
 		}
 	}
 
-	LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, 0);
-	return (0);
+	LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
+	return (error);
 }

Added: trunk/sys/compat/linux/linux_timer.c
===================================================================
--- trunk/sys/compat/linux/linux_timer.c	                        (rev 0)
+++ trunk/sys/compat/linux/linux_timer.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,170 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 Bjoern A. Zeeb
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
+ * ("MRC2"), as part of the DARPA MRC research programme.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_timer.c 321012 2017-07-15 15:08:18Z dchagin $");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/signal.h>
+#include <sys/syscallsubr.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_timer.h>
+
+
+static int
+linux_convert_l_sigevent(struct l_sigevent *l_sig, struct sigevent *sig)
+{
+
+	CP(*l_sig, *sig, sigev_notify);
+	switch (l_sig->sigev_notify) {
+	case L_SIGEV_SIGNAL:
+		if (!LINUX_SIG_VALID(l_sig->sigev_signo))
+			return (EINVAL);
+		sig->sigev_notify = SIGEV_SIGNAL;
+		sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo);
+		PTRIN_CP(*l_sig, *sig, sigev_value.sival_ptr);
+		break;
+	case L_SIGEV_NONE:
+		sig->sigev_notify = SIGEV_NONE;
+		break;
+	case L_SIGEV_THREAD:
+#if 0
+		/* Seems to not be used anywhere (anymore)? */
+		sig->sigev_notify = SIGEV_THREAD;
+		return (ENOSYS);
+#else
+		return (EINVAL);
+#endif
+	case L_SIGEV_THREAD_ID:
+		if (!LINUX_SIG_VALID(l_sig->sigev_signo))
+			return (EINVAL);
+		sig->sigev_notify = SIGEV_THREAD_ID;
+		CP2(*l_sig, *sig, _l_sigev_un._tid, sigev_notify_thread_id);
+		sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo);
+		PTRIN_CP(*l_sig, *sig, sigev_value.sival_ptr);
+		break;
+	default:
+		return (EINVAL);
+	}
+	return (0);
+}
+
+int
+linux_timer_create(struct thread *td, struct linux_timer_create_args *uap)
+{
+	struct l_sigevent l_ev;
+	struct sigevent ev, *evp;
+	clockid_t nwhich;
+	int error, id;
+
+	if (uap->evp == NULL) {
+		evp = NULL;
+	} else {
+		error = copyin(uap->evp, &l_ev, sizeof(l_ev));
+		if (error != 0)
+			return (error);
+		error = linux_convert_l_sigevent(&l_ev, &ev);
+		if (error != 0)
+			return (error);
+		evp = &ev;
+	}
+	error = linux_to_native_clockid(&nwhich, uap->clock_id);
+	if (error != 0)
+		return (error);
+	error = kern_ktimer_create(td, nwhich, evp, &id, -1);
+	if (error == 0) {
+		error = copyout(&id, uap->timerid, sizeof(int));
+		if (error != 0)
+			kern_ktimer_delete(td, id);
+	}
+	return (error);
+}
+
+int
+linux_timer_settime(struct thread *td, struct linux_timer_settime_args *uap)
+{
+	struct l_itimerspec l_val, l_oval;
+	struct itimerspec val, oval, *ovalp;
+	int error;
+
+	error = copyin(uap->new, &l_val, sizeof(l_val));
+	if (error != 0)
+		return (error);
+	ITS_CP(l_val, val);
+	ovalp = uap->old != NULL ? &oval : NULL;
+	error = kern_ktimer_settime(td, uap->timerid, uap->flags, &val, ovalp);
+	if (error == 0 && uap->old != NULL) {
+		ITS_CP(oval, l_oval);
+		error = copyout(&l_oval, uap->old, sizeof(l_oval));
+	}
+	return (error);
+}
+
+int
+linux_timer_gettime(struct thread *td, struct linux_timer_gettime_args *uap)
+{
+	struct l_itimerspec l_val;
+	struct itimerspec val;
+	int error;
+
+	error = kern_ktimer_gettime(td, uap->timerid, &val);
+	if (error == 0) {
+		ITS_CP(val, l_val);
+		error = copyout(&l_val, uap->setting, sizeof(l_val));
+	}
+	return (error);
+}
+
+int
+linux_timer_getoverrun(struct thread *td, struct linux_timer_getoverrun_args *uap)
+{
+
+	return (kern_ktimer_getoverrun(td, uap->timerid));
+}
+
+int
+linux_timer_delete(struct thread *td, struct linux_timer_delete_args *uap)
+{
+
+	return (kern_ktimer_delete(td, uap->timerid));
+}


Property changes on: trunk/sys/compat/linux/linux_timer.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/compat/linux/linux_timer.h
===================================================================
--- trunk/sys/compat/linux/linux_timer.h	                        (rev 0)
+++ trunk/sys/compat/linux/linux_timer.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,121 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 Bjoern A. Zeeb
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
+ * ("MRC2"), as part of the DARPA MRC research programme.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/10/sys/compat/linux/linux_timer.h 293566 2016-01-09 17:12:45Z dchagin $
+ */
+
+#ifndef	_LINUX_TIMER_H
+#define	_LINUX_TIMER_H
+
+#ifndef	__LINUX_ARCH_SIGEV_PREAMBLE_SIZE
+#define	__LINUX_ARCH_SIGEV_PREAMBLE_SIZE	\
+	(sizeof(l_int) * 2 + sizeof(l_sigval_t))
+#endif
+
+#define	LINUX_SIGEV_MAX_SIZE			64
+#define	LINUX_SIGEV_PAD_SIZE			\
+	((LINUX_SIGEV_MAX_SIZE - __LINUX_ARCH_SIGEV_PREAMBLE_SIZE) / \
+	sizeof(l_int))
+
+#define	LINUX_CLOCK_REALTIME			0
+#define	LINUX_CLOCK_MONOTONIC			1
+#define	LINUX_CLOCK_PROCESS_CPUTIME_ID		2
+#define	LINUX_CLOCK_THREAD_CPUTIME_ID		3
+#define	LINUX_CLOCK_MONOTONIC_RAW		4
+#define	LINUX_CLOCK_REALTIME_COARSE		5
+#define	LINUX_CLOCK_MONOTONIC_COARSE		6
+#define	LINUX_CLOCK_BOOTTIME			7
+#define	LINUX_CLOCK_REALTIME_ALARM		8
+#define	LINUX_CLOCK_BOOTTIME_ALARM		9
+#define	LINUX_CLOCK_SGI_CYCLE			10
+#define	LINUX_CLOCK_TAI				11
+
+#define	LINUX_CPUCLOCK_PERTHREAD_MASK		4
+#define	LINUX_CPUCLOCK_MASK			3
+#define	LINUX_CPUCLOCK_WHICH(clock)		\
+	((clock) & (clockid_t) LINUX_CPUCLOCK_MASK)
+#define	LINUX_CPUCLOCK_PROF			0
+#define	LINUX_CPUCLOCK_VIRT			1
+#define	LINUX_CPUCLOCK_SCHED			2
+#define	LINUX_CPUCLOCK_MAX			3
+#define	LINUX_CLOCKFD				LINUX_CPUCLOCK_MAX
+#define	LINUX_CLOCKFD_MASK			\
+	(LINUX_CPUCLOCK_PERTHREAD_MASK|LINUX_CPUCLOCK_MASK)
+
+#define	LINUX_CPUCLOCK_ID(clock)		((pid_t) ~((clock) >> 3))
+#define	LINUX_CPUCLOCK_PERTHREAD(clock)		\
+	(((clock) & (clockid_t) LINUX_CPUCLOCK_PERTHREAD_MASK) != 0)
+
+
+#define	L_SIGEV_SIGNAL				0
+#define	L_SIGEV_NONE				1
+#define	L_SIGEV_THREAD				2
+#define	L_SIGEV_THREAD_ID			4
+
+#define	TS_CP(src,dst,fld) do {			\
+	CP((src).fld,(dst).fld,tv_sec);		\
+	CP((src).fld,(dst).fld,tv_nsec);	\
+} while (0)
+
+#define	ITS_CP(src, dst) do {			\
+	TS_CP((src), (dst), it_interval);	\
+	TS_CP((src), (dst), it_value);		\
+} while (0)
+
+struct l_sigevent {
+	l_sigval_t sigev_value;
+	l_int sigev_signo;
+	l_int sigev_notify;
+	union {
+		l_int _pad[LINUX_SIGEV_PAD_SIZE];
+		l_int _tid;
+		struct {
+			l_uintptr_t _function;
+			l_uintptr_t _attribute;
+		} _l_sigev_thread;
+	} _l_sigev_un;
+}
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+__packed
+#endif
+;
+
+struct l_itimerspec {
+	struct l_timespec it_interval;
+	struct l_timespec it_value;
+};
+
+void native_to_linux_timespec(struct l_timespec *,
+				     struct timespec *);
+int linux_to_native_timespec(struct timespec *,
+				     struct l_timespec *);
+int linux_to_native_clockid(clockid_t *, clockid_t);
+
+#endif	/* _LINUX_TIMER_H */


Property changes on: trunk/sys/compat/linux/linux_timer.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/compat/linux/linux_uid16.c
===================================================================
--- trunk/sys/compat/linux/linux_uid16.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_uid16.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2001  The FreeBSD Project
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_uid16.c 302229 2016-06-27 21:25:01Z bdrewery $");
 
 #include "opt_compat.h"
 #include "opt_kdtrace.h"
@@ -87,7 +88,7 @@
 LIN_SDT_PROBE_DEFINE1(uid16, linux_setgid16, return, "int");
 LIN_SDT_PROBE_DEFINE1(uid16, linux_setuid16, entry, "l_uid16_t");
 LIN_SDT_PROBE_DEFINE1(uid16, linux_setuid16, return, "int");
-LIN_SDT_PROBE_DEFINE2(uid16, linux_setregid16, entry, "l_git16_t", "l_git16_t");
+LIN_SDT_PROBE_DEFINE2(uid16, linux_setregid16, entry, "l_gid16_t", "l_gid16_t");
 LIN_SDT_PROBE_DEFINE1(uid16, linux_setregid16, return, "int");
 LIN_SDT_PROBE_DEFINE2(uid16, linux_setreuid16, entry, "l_uid16_t", "l_uid16_t");
 LIN_SDT_PROBE_DEFINE1(uid16, linux_setreuid16, return, "int");
@@ -172,12 +173,12 @@
 		LIN_SDT_PROBE1(uid16, linux_setgroups16, return, EINVAL);
 		return (EINVAL);
 	}
-	linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK);
+	linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK);
 	error = copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t));
 	if (error) {
 		LIN_SDT_PROBE1(uid16, linux_setgroups16, copyin_error, error);
 		LIN_SDT_PROBE1(uid16, linux_setgroups16, return, error);
-		free(linux_gidset, M_TEMP);
+		free(linux_gidset, M_LINUX);
 		return (error);
 	}
 	newcred = crget();
@@ -214,12 +215,12 @@
 		newcred->cr_ngroups = 1;
 
 	setsugid(td->td_proc);
-	p->p_ucred = newcred;
+	proc_set_cred(p, newcred);
 	PROC_UNLOCK(p);
 	crfree(oldcred);
 	error = 0;
 out:
-	free(linux_gidset, M_TEMP);
+	free(linux_gidset, M_LINUX);
 
 	LIN_SDT_PROBE1(uid16, linux_setgroups16, return, error);
 	return (error);
@@ -260,7 +261,7 @@
 
 	ngrp = 0;
 	linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset),
-	    M_TEMP, M_WAITOK);
+	    M_LINUX, M_WAITOK);
 	while (ngrp < bsd_gidsetsz) {
 		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
 		ngrp++;
@@ -267,7 +268,7 @@
 	}
 
 	error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t));
-	free(linux_gidset, M_TEMP);
+	free(linux_gidset, M_LINUX);
 	if (error) {
 		LIN_SDT_PROBE1(uid16, linux_getgroups16, copyout_error, error);
 		LIN_SDT_PROBE1(uid16, linux_getgroups16, return, error);

Modified: trunk/sys/compat/linux/linux_util.c
===================================================================
--- trunk/sys/compat/linux/linux_util.c	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_util.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994 Christos Zoulas
  * Copyright (c) 1995 Frank van der Linden
@@ -30,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_util.c 293546 2016-01-09 16:44:17Z dchagin $");
 
 #include "opt_compat.h"
 #include "opt_kdtrace.h"
@@ -53,48 +54,14 @@
 #include <machine/stdarg.h>
 
 #include <compat/linux/linux_util.h>
-#ifdef COMPAT_LINUX32
-#include <machine/../linux32/linux.h>
-#else
-#include <machine/../linux/linux.h>
-#endif
 
-#include <compat/linux/linux_dtrace.h>
+MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
+MALLOC_DEFINE(M_EPOLL, "lepoll", "Linux events structures");
+MALLOC_DEFINE(M_FUTEX, "futex", "Linux futexes");
+MALLOC_DEFINE(M_FUTEX_WP, "futex wp", "Linux futex waiting proc");
 
 const char      linux_emul_path[] = "/compat/linux";
 
-/* DTrace init */
-LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
-
-/**
- * DTrace probes in this module.
- */
-LIN_SDT_PROBE_DEFINE5(util, linux_emul_convpath, entry, "const char *",
-    "enum uio_seg", "char **", "int", "int");
-LIN_SDT_PROBE_DEFINE1(util, linux_emul_convpath, return, "int");
-LIN_SDT_PROBE_DEFINE1(util, linux_msg, entry, "const char *");
-LIN_SDT_PROBE_DEFINE0(util, linux_msg, return);
-LIN_SDT_PROBE_DEFINE2(util, linux_driver_get_name_dev, entry, "device_t",
-    "const char *");
-LIN_SDT_PROBE_DEFINE0(util, linux_driver_get_name_dev, nullcall);
-LIN_SDT_PROBE_DEFINE1(util, linux_driver_get_name_dev, return, "char *");
-LIN_SDT_PROBE_DEFINE3(util, linux_driver_get_major_minor, entry, "char *",
-    "int *", "int *");
-LIN_SDT_PROBE_DEFINE0(util, linux_driver_get_major_minor, nullcall);
-LIN_SDT_PROBE_DEFINE1(util, linux_driver_get_major_minor, notfound, "char *");
-LIN_SDT_PROBE_DEFINE3(util, linux_driver_get_major_minor, return, "int",
-    "int", "int");
-LIN_SDT_PROBE_DEFINE0(util, linux_get_char_devices, entry);
-LIN_SDT_PROBE_DEFINE1(util, linux_get_char_devices, return, "char *");
-LIN_SDT_PROBE_DEFINE1(util, linux_free_get_char_devices, entry, "char *");
-LIN_SDT_PROBE_DEFINE0(util, linux_free_get_char_devices, return);
-LIN_SDT_PROBE_DEFINE1(util, linux_device_register_handler, entry,
-    "struct linux_device_handler *");
-LIN_SDT_PROBE_DEFINE1(util, linux_device_register_handler, return, "int");
-LIN_SDT_PROBE_DEFINE1(util, linux_device_unregister_handler, entry,
-    "struct linux_device_handler *");
-LIN_SDT_PROBE_DEFINE1(util, linux_device_unregister_handler, return, "int");
-
 /*
  * Search an alternate path before passing pathname arguments on to
  * system calls. Useful for keeping a separate 'emulation tree'.
@@ -108,13 +75,9 @@
 {
 	int retval;
 
-	LIN_SDT_PROBE5(util, linux_emul_convpath, entry, path, pathseg, pbuf,
-	    cflag, dfd);
-
 	retval = kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
 	    cflag, dfd);
 
-	LIN_SDT_PROBE1(util, linux_emul_convpath, return, retval);
 	return (retval);
 }
 
@@ -124,8 +87,6 @@
 	va_list ap;
 	struct proc *p;
 
-	LIN_SDT_PROBE1(util, linux_msg, entry, fmt);
-
 	p = td->td_proc;
 	printf("linux: pid %d (%s): ", (int)p->p_pid, p->p_comm);
 	va_start(ap, fmt);
@@ -132,8 +93,6 @@
 	vprintf(fmt, ap);
 	va_end(ap);
 	printf("\n");
-
-	LIN_SDT_PROBE0(util, linux_msg, return);
 }
 
 struct device_element
@@ -156,24 +115,14 @@
 	struct device_element *de;
 	const char *device_name = device_get_name(dev);
 
-	LIN_SDT_PROBE2(util, linux_driver_get_name_dev, entry, dev,
-	    device_name);
-
-	if (device_name == NULL) {
-		LIN_SDT_PROBE0(util, linux_driver_get_name_dev, nullcall);
-		LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return, NULL);
+	if (device_name == NULL)
 		return NULL;
-	}
 	TAILQ_FOREACH(de, &devices, list) {
-		if (strcmp(device_name, de->entry.bsd_driver_name) == 0) {
-			LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return,
-			    de->entry.linux_driver_name);
+		if (strcmp(device_name, de->entry.bsd_driver_name) == 0)
 			return (de->entry.linux_driver_name);
-		}
 	}
 
-	LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return, NULL);
-	return NULL;
+	return (NULL);
 }
 
 int
@@ -181,15 +130,8 @@
 {
 	struct device_element *de;
 
-	LIN_SDT_PROBE3(util, linux_driver_get_major_minor, entry, node, major,
-	    minor);
-
-	if (node == NULL || major == NULL || minor == NULL) {
-		LIN_SDT_PROBE0(util, linux_driver_get_major_minor, nullcall);
-		LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 1,
-		   0, 0);
+	if (node == NULL || major == NULL || minor == NULL)
 		return 1;
-	}
 
 	if (strlen(node) > strlen("pts/") &&
 	    strncmp(node, "pts/", strlen("pts/")) == 0) {
@@ -204,9 +146,7 @@
 		*major = 136 + (devno / 256);
 		*minor = devno % 256;
 
-		LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 0,
-		    *major, *minor);
-		return 0;
+		return (0);
 	}
 
 	TAILQ_FOREACH(de, &devices, list) {
@@ -213,16 +153,11 @@
 		if (strcmp(node, de->entry.bsd_device_name) == 0) {
 			*major = de->entry.linux_major;
 			*minor = de->entry.linux_minor;
-
-			LIN_SDT_PROBE3(util, linux_driver_get_major_minor,
-			    return, 0, *major, *minor);
-			return 0;
+			return (0);
 		}
 	}
 
-	LIN_SDT_PROBE1(util, linux_driver_get_major_minor, notfound, node);
-	LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 1, 0, 0);
-	return 1;
+	return (1);
 }
 
 char *
@@ -233,8 +168,6 @@
 	char formated[256];
 	int current_size = 0, string_size = 1024;
 
-	LIN_SDT_PROBE0(util, linux_get_char_devices, entry);
-
 	string = malloc(string_size, M_LINUX, M_WAITOK);
 	string[0] = '\000';
 	last = "";
@@ -261,8 +194,7 @@
 		}
 	}
 
-	LIN_SDT_PROBE1(util, linux_get_char_devices, return, string);
-	return string;
+	return (string);
 }
 
 void
@@ -269,11 +201,7 @@
 linux_free_get_char_devices(char *string)
 {
 
-	LIN_SDT_PROBE1(util, linux_get_char_devices, entry, string);
-
 	free(string, M_LINUX);
-
-	LIN_SDT_PROBE0(util, linux_get_char_devices, return);
 }
 
 static int linux_major_starting = 200;
@@ -283,13 +211,8 @@
 {
 	struct device_element *de;
 
-	LIN_SDT_PROBE1(util, linux_device_register_handler, entry, d);
-
-	if (d == NULL) {
-		LIN_SDT_PROBE1(util, linux_device_register_handler, return,
-		    EINVAL);
+	if (d == NULL)
 		return (EINVAL);
-	}
 
 	de = malloc(sizeof(*de), M_LINUX, M_WAITOK);
 	if (d->linux_major < 0) {
@@ -300,7 +223,6 @@
 	/* Add the element to the list, sorted on span. */
 	TAILQ_INSERT_TAIL(&devices, de, list);
 
-	LIN_SDT_PROBE1(util, linux_device_register_handler, return, 0);
 	return (0);
 }
 
@@ -309,13 +231,8 @@
 {
 	struct device_element *de;
 
-	LIN_SDT_PROBE1(util, linux_device_unregister_handler, entry, d);
-
-	if (d == NULL) {
-		LIN_SDT_PROBE1(util, linux_device_unregister_handler, return,
-		    EINVAL);
+	if (d == NULL)
 		return (EINVAL);
-	}
 
 	TAILQ_FOREACH(de, &devices, list) {
 		if (bcmp(d, &de->entry, sizeof(*d)) == 0) {
@@ -322,12 +239,9 @@
 			TAILQ_REMOVE(&devices, de, list);
 			free(de, M_LINUX);
 
-			LIN_SDT_PROBE1(util, linux_device_unregister_handler,
-			    return, 0);
 			return (0);
 		}
 	}
 
-	LIN_SDT_PROBE1(util, linux_device_unregister_handler, return, EINVAL);
 	return (EINVAL);
 }

Modified: trunk/sys/compat/linux/linux_util.h
===================================================================
--- trunk/sys/compat/linux/linux_util.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_util.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994 Christos Zoulas
  * Copyright (c) 1995 Frank van der Linden
@@ -28,7 +29,7 @@
  *
  * from: svr4_util.h,v 1.5 1994/11/18 02:54:31 christos Exp
  * from: linux_util.h,v 1.2 1995/03/05 23:23:50 fvdl Exp
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_util.h 293546 2016-01-09 16:44:17Z dchagin $
  */
 
 #ifndef	_LINUX_UTIL_H_
@@ -44,6 +45,11 @@
 #include <sys/cdefs.h>
 #include <sys/uio.h>
 
+MALLOC_DECLARE(M_LINUX);
+MALLOC_DECLARE(M_EPOLL);
+MALLOC_DECLARE(M_FUTEX);
+MALLOC_DECLARE(M_FUTEX_WP);
+
 extern const char linux_emul_path[];
 
 int linux_emul_convpath(struct thread *, const char *, enum uio_seg, char **, int, int);
@@ -115,7 +121,6 @@
 #define	LINUX_CTRFMT(nm, fmt)	#nm"("fmt")"
 
 #define	LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6) do {			\
-	if (ldebug(f))							\
 		CTR6(KTR_LINUX, LINUX_CTRFMT(f, m),			\
 		    p1, p2, p3, p4, p5, p6);				\
 } while (0)

Added: trunk/sys/compat/linux/linux_vdso.c
===================================================================
--- trunk/sys/compat/linux/linux_vdso.c	                        (rev 0)
+++ trunk/sys/compat/linux/linux_vdso.c	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,245 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Dmitry Chagin
+ * All rights reserved.
+ *
+ * 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
+ *    in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_vdso.c 293523 2016-01-09 15:57:28Z dchagin $");
+
+#include "opt_compat.h"
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+#define	__ELF_WORD_SIZE	32
+#else
+#define	__ELF_WORD_SIZE	64
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/elf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/rwlock.h>
+#include <sys/queue.h>
+#include <sys/sysent.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <compat/linux/linux_vdso.h>
+
+SLIST_HEAD(, linux_vdso_sym) __elfN(linux_vdso_syms) =
+    SLIST_HEAD_INITIALIZER(__elfN(linux_vdso_syms));
+
+static int __elfN(symtabindex);
+static int __elfN(symstrindex);
+
+static void
+__elfN(linux_vdso_lookup)(Elf_Ehdr *, struct linux_vdso_sym *);
+
+
+void
+__elfN(linux_vdso_sym_init)(struct linux_vdso_sym *s)
+{
+
+	SLIST_INSERT_HEAD(&__elfN(linux_vdso_syms), s, sym);
+}
+
+vm_object_t
+__elfN(linux_shared_page_init)(char **mapping)
+{
+	vm_page_t m;
+	vm_object_t obj;
+	vm_offset_t addr;
+
+	obj = vm_pager_allocate(OBJT_PHYS, 0, PAGE_SIZE,
+	    VM_PROT_DEFAULT, 0, NULL);
+	VM_OBJECT_WLOCK(obj);
+	m = vm_page_grab(obj, 0, VM_ALLOC_NOBUSY | VM_ALLOC_ZERO);
+	m->valid = VM_PAGE_BITS_ALL;
+	VM_OBJECT_WUNLOCK(obj);
+	addr = kva_alloc(PAGE_SIZE);
+	pmap_qenter(addr, &m, 1);
+	*mapping = (char *)addr;
+	return (obj);
+}
+
+void
+__elfN(linux_shared_page_fini)(vm_object_t obj)
+{
+
+	vm_object_deallocate(obj);
+}
+
+void
+__elfN(linux_vdso_fixup)(struct sysentvec *sv)
+{
+	Elf_Ehdr *ehdr;
+	Elf_Shdr *shdr;
+	int i;
+
+	ehdr = (Elf_Ehdr *) sv->sv_sigcode;
+
+	if (!IS_ELF(*ehdr) ||
+	    ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
+	    ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
+	    ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
+	    ehdr->e_shoff == 0 ||
+	    ehdr->e_shentsize != sizeof(Elf_Shdr))
+		panic("Linux invalid vdso header.\n");
+
+	if (ehdr->e_type != ET_DYN)
+		panic("Linux invalid vdso header.\n");
+
+	shdr = (Elf_Shdr *) ((caddr_t)ehdr + ehdr->e_shoff);
+
+	__elfN(symtabindex) = -1;
+	__elfN(symstrindex) = -1;
+	for (i = 0; i < ehdr->e_shnum; i++) {
+		if (shdr[i].sh_size == 0)
+			continue;
+		if (shdr[i].sh_type == SHT_DYNSYM) {
+			__elfN(symtabindex) = i;
+			__elfN(symstrindex) = shdr[i].sh_link;
+		}
+	}
+
+	if (__elfN(symtabindex) == -1 || __elfN(symstrindex) == -1)
+		panic("Linux invalid vdso header.\n");
+
+	ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX;
+}
+
+void
+__elfN(linux_vdso_reloc)(struct sysentvec *sv, long vdso_adjust)
+{
+	struct linux_vdso_sym *lsym;
+	Elf_Ehdr *ehdr;
+	Elf_Phdr *phdr;
+	Elf_Shdr *shdr;
+	Elf_Dyn *dyn;
+	Elf_Sym *sym;
+	int i, symcnt;
+
+	ehdr = (Elf_Ehdr *) sv->sv_sigcode;
+
+	/* Adjust our so relative to the sigcode_base */
+	if (vdso_adjust != 0) {
+		ehdr->e_entry += vdso_adjust;
+		phdr = (Elf_Phdr *)((caddr_t)ehdr + ehdr->e_phoff);
+
+		/* phdrs */
+		for (i = 0; i < ehdr->e_phnum; i++) {
+			phdr[i].p_vaddr += vdso_adjust;
+			if (phdr[i].p_type != PT_DYNAMIC)
+				continue;
+			dyn = (Elf_Dyn *)((caddr_t)ehdr + phdr[i].p_offset);
+			for(; dyn->d_tag != DT_NULL; dyn++) {
+				switch (dyn->d_tag) {
+				case DT_PLTGOT:
+				case DT_HASH:
+				case DT_STRTAB:
+				case DT_SYMTAB:
+				case DT_RELA:
+				case DT_INIT:
+				case DT_FINI:
+				case DT_REL:
+				case DT_DEBUG:
+				case DT_JMPREL:
+				case DT_VERSYM:
+				case DT_VERDEF:
+				case DT_VERNEED:
+				case DT_ADDRRNGLO ... DT_ADDRRNGHI:
+					dyn->d_un.d_ptr += vdso_adjust;
+					break;
+				case DT_ENCODING ... DT_LOOS-1:
+				case DT_LOOS ... DT_HIOS:
+					if (dyn->d_tag >= DT_ENCODING &&
+					    (dyn->d_tag & 1) == 0)
+						dyn->d_un.d_ptr += vdso_adjust;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+
+		/* sections */
+		shdr = (Elf_Shdr *)((caddr_t)ehdr + ehdr->e_shoff);
+		for(i = 0; i < ehdr->e_shnum; i++) {
+			if (!(shdr[i].sh_flags & SHF_ALLOC))
+				continue;
+			shdr[i].sh_addr += vdso_adjust;
+			if (shdr[i].sh_type != SHT_SYMTAB &&
+			    shdr[i].sh_type != SHT_DYNSYM)
+				continue;
+
+			sym = (Elf_Sym *)((caddr_t)ehdr + shdr[i].sh_offset);
+			symcnt = shdr[i].sh_size / sizeof(*sym);
+
+			for(i = 0; i < symcnt; i++, sym++) {
+				if (sym->st_shndx == SHN_UNDEF ||
+				    sym->st_shndx == SHN_ABS)
+					continue;
+				sym->st_value += vdso_adjust;
+			}
+		}
+	}
+
+	SLIST_FOREACH(lsym, &__elfN(linux_vdso_syms), sym)
+		__elfN(linux_vdso_lookup)(ehdr, lsym);
+}
+
+static void
+__elfN(linux_vdso_lookup)(Elf_Ehdr *ehdr, struct linux_vdso_sym *vsym)
+{
+	vm_offset_t strtab, symname;
+	uint32_t symcnt;
+	Elf_Shdr *shdr;
+	int i;
+
+	shdr = (Elf_Shdr *) ((caddr_t)ehdr + ehdr->e_shoff);
+
+	strtab = (vm_offset_t)((caddr_t)ehdr +
+	    shdr[__elfN(symstrindex)].sh_offset);
+	Elf_Sym *sym = (Elf_Sym *)((caddr_t)ehdr +
+	    shdr[__elfN(symtabindex)].sh_offset);
+	symcnt = shdr[__elfN(symtabindex)].sh_size / sizeof(*sym);
+
+	for (i = 0; i < symcnt; ++i, ++sym) {
+		symname = strtab + sym->st_name;
+		if (strncmp(vsym->symname, (char *)symname, vsym->size) == 0) {
+			*vsym->ptr = (uintptr_t)sym->st_value;
+			break;
+		}
+	}
+}


Property changes on: trunk/sys/compat/linux/linux_vdso.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/compat/linux/linux_vdso.h
===================================================================
--- trunk/sys/compat/linux/linux_vdso.h	                        (rev 0)
+++ trunk/sys/compat/linux/linux_vdso.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -0,0 +1,66 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Dmitry Chagin
+ * All rights reserved.
+ *
+ * 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
+ *    in this position and unchanged.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/10/sys/compat/linux/linux_vdso.h 293523 2016-01-09 15:57:28Z dchagin $
+ */
+
+#ifndef _LINUX_VDSO_H_
+#define	_LINUX_VDSO_H_
+
+#include <sys/types.h>
+
+struct linux_vdso_sym {
+	SLIST_ENTRY(linux_vdso_sym) sym;
+	uint32_t	size;
+	uintptr_t *	ptr;
+	char		symname[];
+};
+
+vm_object_t __elfN(linux_shared_page_init)(char **);
+void	__elfN(linux_shared_page_fini)(vm_object_t);
+void	__elfN(linux_vdso_fixup)(struct sysentvec *);
+void	__elfN(linux_vdso_reloc)(struct sysentvec *, long);
+void	__elfN(linux_vdso_sym_init)(struct linux_vdso_sym *);
+
+#define	LINUX_VDSO_SYM_INTPTR(name)				\
+uintptr_t name;							\
+LINUX_VDSO_SYM_DEFINE(name)
+
+#define	LINUX_VDSO_SYM_CHAR(name)				\
+const char * name;						\
+LINUX_VDSO_SYM_DEFINE(name)
+
+#define	LINUX_VDSO_SYM_DEFINE(name)				\
+static struct linux_vdso_sym name ## sym = {			\
+	.symname	= #name,				\
+	.size		= sizeof(#name),			\
+	.ptr		= (uintptr_t *)&name			\
+};								\
+SYSINIT(__elfN(name ## _sym_init), SI_SUB_EXEC,			\
+    SI_ORDER_FIRST, __elfN(linux_vdso_sym_init), &name ## sym);	\
+struct __hack
+
+#endif	/* _LINUX_VDSO_H_ */


Property changes on: trunk/sys/compat/linux/linux_vdso.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/compat/linux/linux_videodev2_compat.h
===================================================================
--- trunk/sys/compat/linux/linux_videodev2_compat.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_videodev2_compat.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_videodev2_compat.h 221434 2011-05-04 13:09:20Z netchild $
  */
 
 /*

Modified: trunk/sys/compat/linux/linux_videodev_compat.h
===================================================================
--- trunk/sys/compat/linux/linux_videodev_compat.h	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/linux_videodev_compat.h	2018-05-30 20:41:36 UTC (rev 10147)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/linux_videodev_compat.h 200110 2009-12-04 21:06:54Z netchild $
  */
 
 /*

Modified: trunk/sys/compat/linux/stats_timing.d
===================================================================
--- trunk/sys/compat/linux/stats_timing.d	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/stats_timing.d	2018-05-30 20:41:36 UTC (rev 10147)
@@ -25,7 +25,8 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/stats_timing.d 293493 2016-01-09 15:16:13Z dchagin $
  */
 
 /**
@@ -39,7 +40,6 @@
  *      possible for a given application
  *  - graph of longest running (CPU-time!) function in total
  *    - may help finding problem cases in the kernel code
- * - timing statistics for the emul_lock
  * - graph of longest held (CPU-time!) locks
  */
 

Modified: trunk/sys/compat/linux/trace_futexes.d
===================================================================
--- trunk/sys/compat/linux/trace_futexes.d	2018-05-30 20:39:37 UTC (rev 10146)
+++ trunk/sys/compat/linux/trace_futexes.d	2018-05-30 20:41:36 UTC (rev 10147)
@@ -25,7 +25,8 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/compat/linux/trace_futexes.d 299705 2016-05-14 00:35:49Z pfg $
  */
 
 /**
@@ -120,7 +121,7 @@
 linuxulator*:locks:futex_mtx:unlock
 /check[probefunc, arg0] == 0/
 {
-	printf("ERROR: unlock attemt of unlocked %s (%p),", probefunc, arg0);
+	printf("ERROR: unlock attempt of unlocked %s (%p),", probefunc, arg0);
 	printf("       missing SDT probe in kernel, or dtrace program started");
 	printf("       while the %s was already held (race condition).", probefunc);
 	printf("       Stack trace follows:");



More information about the Midnightbsd-cvs mailing list