- >500 static DTrace probes for the linuxulator

- DTrace scripts to check for errors, performance, ...
  they serve mostly as examples of what you can do with the static probe;s
  with moderate load the scripts may be overwhelmed, excessive lock-tracing
  may influence program behavior (see the last design decission)

Design decissions:
 - use "linuxulator" as the provider for the native bitsize; add the
   bitsize for the non-native emulation (e.g. "linuxuator32" on amd64)
 - Add probes only for locks which are acquired in one function and released
   in another function. Locks which are aquired and released in the same
   function should be easy to pair in the code, inter-function
   locking is more easy to verify in DTrace.
 - Probes for locks should be fired after locking and before releasing to
   prevent races (to provide data/function stability in DTrace, see the
   man-page of "dtrace -v ..." and the corresponding DTrace docs).
This commit is contained in:
Alexander Leidinger 2012-05-05 19:42:38 +00:00
parent 15efbb17a8
commit 19e252baeb
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=235063
20 changed files with 2082 additions and 216 deletions

View File

@ -42,6 +42,7 @@ extern u_char linux_debug_map[];
#define ldebug(name) isclr(linux_debug_map, LINUX_SYS_linux_ ## name)
#define ARGS(nm, fmt) "linux(%ld): "#nm"("fmt")\n", (long)td->td_proc->p_pid
#define LMSG(fmt) "linux(%ld): "fmt"\n", (long)td->td_proc->p_pid
#define LINUX_DTRACE linuxulator32
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_LINUX);

View File

@ -29,14 +29,23 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/sdt.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <amd64/linux32/linux.h>
#include <amd64/linux32/linux32_proto.h>
#include <compat/linux/linux_dtrace.h>
#include <compat/linux/linux_util.h>
/* DTrace init */
LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
DUMMY(stime);
DUMMY(olduname);
DUMMY(syslog);

View File

@ -0,0 +1,144 @@
#!/usr/sbin/dtrace -qs
/*-
* Copyright (c) 2008-2012 Alexander Leidinger <netchild@FreeBSD.org>
* 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$
*/
/*
* Report error conditions:
* - emulation errors (unsupportet stuff, unknown stuff, ...)
* - kernel errors (resource shortage, ...)
* - programming errors (errors which can happen, but should not happen)
*/
linuxulator*:dummy::not_implemented,
linuxulator*:emul:proc_exit:child_clear_tid_error,
linuxulator*:emul:proc_exit:futex_failed,
linuxulator*:emul:linux_schedtail:copyout_error,
linuxulator*:futex:futex_get:error,
linuxulator*:futex:futex_sleep:requeue_error,
linuxulator*:futex:futex_sleep:sleep_error,
linuxulator*:futex:futex_wait:copyin_error,
linuxulator*:futex:futex_wait:itimerfix_error,
linuxulator*:futex:futex_wait:sleep_error,
linuxulator*:futex:futex_atomic_op:missing_access_check,
linuxulator*:futex:futex_atomic_op:unimplemented_op,
linuxulator*:futex:futex_atomic_op:unimplemented_cmp,
linuxulator*:futex:linux_sys_futex:unimplemented_clockswitch,
linuxulator*:futex:linux_sys_futex:copyin_error,
linuxulator*:futex:linux_sys_futex:unhandled_efault,
linuxulator*:futex:linux_sys_futex:unimplemented_lock_pi,
linuxulator*:futex:linux_sys_futex:unimplemented_unlock_pi,
linuxulator*:futex:linux_sys_futex:unimplemented_trylock_pi,
linuxulator*:futex:linux_sys_futex:unimplemented_wait_requeue_pi,
linuxulator*:futex:linux_sys_futex:unimplemented_cmp_requeue_pi,
linuxulator*:futex:linux_sys_futex:unknown_operation,
linuxulator*:futex:linux_get_robust_list:copyout_error,
linuxulator*:futex:handle_futex_death:copyin_error,
linuxulator*:futex:fetch_robust_entry:copyin_error,
linuxulator*:futex:release_futexes:copyin_error,
linuxulator*:time:linux_clock_gettime:conversion_error,
linuxulator*:time:linux_clock_gettime:gettime_error,
linuxulator*:time:linux_clock_gettime:copyout_error,
linuxulator*:time:linux_clock_settime:conversion_error,
linuxulator*:time:linux_clock_settime:settime_error,
linuxulator*:time:linux_clock_settime:copyin_error,
linuxulator*:time:linux_clock_getres:conversion_error,
linuxulator*:time:linux_clock_getres:getres_error,
linuxulator*:time:linux_clock_getres:copyout_error,
linuxulator*:time:linux_nanosleep:conversion_error,
linuxulator*:time:linux_nanosleep:nanosleep_error,
linuxulator*:time:linux_nanosleep:copyout_error,
linuxulator*:time:linux_nanosleep:copyin_error,
linuxulator*:time:linux_clock_nanosleep:copyin_error,
linuxulator*:time:linux_clock_nanosleep:conversion_error,
linuxulator*:time:linux_clock_nanosleep:copyout_error,
linuxulator*:time:linux_clock_nanosleep:nanosleep_error,
linuxulator*:sysctl:handle_string:copyout_error,
linuxulator*:sysctl:linux_sysctl:copyin_error,
linuxulator*:mib:linux_sysctl_osname:sysctl_string_error,
linuxulator*:mib:linux_sysctl_osrelease:sysctl_string_error,
linuxulator*:mib:linux_sysctl_oss_version:sysctl_string_error,
linuxulator*:mib:linux_prison_create:vfs_copyopt_error,
linuxulator*:mib:linux_prison_check:vfs_copyopt_error,
linuxulator*:mib:linux_prison_check:vfs_getopt_error,
linuxulator*:mib:linux_prison_set:vfs_copyopt_error,
linuxulator*:mib:linux_prison_set:vfs_getopt_error,
linuxulator*:mib:linux_prison_get:vfs_setopt_error,
linuxulator*:mib:linux_prison_get:vfs_setopts_error
{
printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod, probefunc);
stack();
ustack();
}
linuxulator*:util:linux_driver_get_name_dev:nullcall,
linuxulator*:util:linux_driver_get_major_minor:nullcall,
linuxulator*:futex:linux_sys_futex:invalid_cmp_requeue_use,
linuxulator*:futex:linux_sys_futex:deprecated_requeue,
linuxulator*:futex:linux_set_robust_list:size_error,
linuxulator*:time:linux_clock_getres:nullcall
{
printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n", probename, probeprov, probemod, probefunc, execname);
stack();
ustack();
}
linuxulator*:util:linux_driver_get_major_minor:notfound
{
printf("WARNING: Application %s failed to find %s in %s:%s:%s, this may or may not be a problem.\n", execname, stringof(args[0]), probename, probeprov, probemod);
stack();
ustack();
}
linuxulator*:time:linux_to_native_clockid:unknown_clockid
{
printf("INFO: Application %s tried to use unknown clockid %d. Please report this to freebsd-emulation@FreeBSD.org.\n", execname, arg0);
}
linuxulator*:time:linux_to_native_clockid:unsupported_clockid,
linuxulator*:time:linux_clock_nanosleep:unsupported_clockid
{
printf("WARNING: Application %s tried to use unsupported clockid (%d), this may or may not be a problem for the application.\nPatches to support this clockid are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0);
}
linuxulator*:time:linux_clock_nanosleep:unsupported_flags
{
printf("WARNING: Application %s tried to use unsupported flags (%d), this may or may not be a problem for the application.\nPatches to support those flags are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0);
}
linuxulator*:sysctl:linux_sysctl:wrong_length
{
printf("ERROR: Application %s issued a sysctl which failed the length restrictions.\nThe length passed is %d, the min length supported is 1 and the max length supported is %d.\n", execname, arg0, arg1);
stack();
ustack();
}
linuxulator*:sysctl:linux_sysctl:unsupported_sysctl
{
printf("ERROR: Application %s issued an unsupported sysctl (%s).\nPatches to support this sysctl are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, stringof(args[0]));
}

View File

@ -0,0 +1,132 @@
#!/usr/sbin/dtrace -qs
/*-
* Copyright (c) 2008-2012 Alexander Leidinger <netchild@FreeBSD.org>
* 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$
*/
/**
* Check if the internal locks are correctly acquired/released:
* - no recursive locking (mtx locks, write locks)
* - no unlocking of already unlocked one
*
* Print stacktrace if a lock is longer locked than about 10sec or more.
*/
#pragma D option dynvarsize=32m
#pragma D option specsize=32m
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/
{
printf("ERROR: recursive lock of %s (%p),", probefunc, arg0);
printf(" or missing SDT probe in kernel. Stack trace follows:");
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];
@stats[probefunc] = count();
ts[probefunc] = timestamp;
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(" missing SDT probe in kernel, or dtrace program started");
printf(" while the %s was already held (race condition).", probefunc);
printf(" Stack trace follows:");
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]);
spec[probefunc] = 0;
--check[probefunc];
}
/* 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"]);
spec["futex_mtx"] = 0;
}
/* Statistics */
END
{
printf("Number of locks per type:");
printa(@stats);
}

View File

@ -0,0 +1,95 @@
/*-
* Copyright (c) 2008-2012 Alexander Leidinger <netchild@FreeBSD.org>
* 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$
*/
#ifndef _LINUX_DTRACE_H_
#define _LINUX_DTRACE_H_
/**
* DTrace support macros for the linuxulator.
*
* Some wrapper macros to make it more easy to handle the linuxulator
* providers and to allow to make the name depend upon the bitsize.
*
* Basically this is the same as the normal SDT macros in sys/sdt.h. The
* difference is that the provider name is automatically inserted, and
* we do not use a different name for the probe-description.
*/
#define LIN_SDT_PROVIDER_DEFINE(x) SDT_PROVIDER_DEFINE(x)
#define LIN_SDT_PROVIDER_DECLARE(x) SDT_PROVIDER_DECLARE(x)
#define _LIN_SDT_PROBE_DECLARE(a, b, c, d) SDT_PROBE_DECLARE(a, b, c, d)
#define LIN_SDT_PROBE_DECLARE(a, b, c) _LIN_SDT_PROBE_DECLARE( \
LINUX_DTRACE, a, b, c)
#define _LIN_SDT_PROBE_DEFINE0(a, b, c, d) SDT_PROBE_DEFINE(a, \
b, c, d, 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)
#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)
#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)
#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)
#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)
#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_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, \
c, d, e)
#define LIN_SDT_PROBE3(a, b, c, d, e, f) SDT_PROBE3(LINUX_DTRACE, a, b, \
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, \
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)
#endif /* _LINUX_DTRACE_H_ */

View File

@ -30,6 +30,7 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -38,6 +39,7 @@ __FBSDID("$FreeBSD$");
#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>
@ -53,9 +55,64 @@ __FBSDID("$FreeBSD$");
#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>
/**
* 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);
/**
* 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;
@ -65,6 +122,8 @@ em_find(struct proc *p, int locked)
{
struct linux_emuldata *em;
LIN_SDT_PROBE2(emul, em_find, entry, p, locked);
if (locked == EMUL_DOLOCK)
EMUL_LOCK(&emul_lock);
@ -73,6 +132,7 @@ em_find(struct proc *p, int locked)
if (em == NULL && locked == EMUL_DOLOCK)
EMUL_UNLOCK(&emul_lock);
LIN_SDT_PROBE1(emul, em_find, return, em);
return (em);
}
@ -82,8 +142,10 @@ linux_proc_init(struct thread *td, pid_t child, int flags)
struct linux_emuldata *em, *p_em;
struct proc *p;
LIN_SDT_PROBE3(emul, proc_init, entry, td, child, flags);
if (child != 0) {
/* non-exec call */
/* fork or create a thread */
em = malloc(sizeof *em, M_LINUX, M_WAITOK | M_ZERO);
em->pid = child;
em->pdeath_signal = 0;
@ -91,9 +153,12 @@ linux_proc_init(struct thread *td, pid_t child, int flags)
em->robust_futexes = NULL;
if (flags & LINUX_CLONE_THREAD) {
/* handled later in the code */
LIN_SDT_PROBE0(emul, proc_init, create_thread);
} else {
struct linux_emuldata_shared *s;
LIN_SDT_PROBE0(emul, proc_init, fork);
s = malloc(sizeof *s, M_LINUX, M_WAITOK | M_ZERO);
s->refs = 1;
s->group_pid = child;
@ -102,6 +167,9 @@ linux_proc_init(struct thread *td, pid_t child, int flags)
em->shared = s;
}
} else {
/* exec */
LIN_SDT_PROBE0(emul, proc_init, exec);
/* lookup the old one */
em = em_find(td->td_proc, EMUL_DOLOCK);
KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
@ -136,8 +204,7 @@ linux_proc_init(struct thread *td, pid_t child, int flags)
* rwlock held
*/
}
}
if (child != 0) {
EMUL_SHARED_WLOCK(&emul_shared_lock);
LIST_INSERT_HEAD(&em->shared->threads, em, threads);
EMUL_SHARED_WUNLOCK(&emul_shared_lock);
@ -149,6 +216,7 @@ linux_proc_init(struct thread *td, pid_t child, int flags)
} else
EMUL_UNLOCK(&emul_lock);
LIN_SDT_PROBE0(emul, proc_init, return);
return (0);
}
@ -164,6 +232,8 @@ linux_proc_exit(void *arg __unused, struct proc *p)
if (__predict_true(p->p_sysent != &elf_linux_sysvec))
return;
LIN_SDT_PROBE1(emul, proc_exit, entry, p);
release_futexes(p);
/* find the emuldata */
@ -173,6 +243,9 @@ linux_proc_exit(void *arg __unused, struct proc *p)
/* 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);
@ -208,7 +281,12 @@ linux_proc_exit(void *arg __unused, struct proc *p)
error = copyout(&null, child_clear_tid, sizeof(null));
if (error) {
LIN_SDT_PROBE1(emul, proc_exit,
child_clear_tid_error, error);
free(em, M_LINUX);
LIN_SDT_PROBE0(emul, proc_exit, return);
return;
}
@ -224,8 +302,10 @@ linux_proc_exit(void *arg __unused, struct proc *p)
* this cannot happen at the moment and if this happens it
* probably means there is a user space bug
*/
if (error)
if (error) {
LIN_SDT_PROBE0(emul, proc_exit, futex_failed);
printf(LMSG("futex stuff in proc_exit failed.\n"));
}
}
/* clean the stuff up */
@ -250,6 +330,8 @@ linux_proc_exit(void *arg __unused, struct proc *p)
EMUL_UNLOCK(&emul_lock);
}
sx_xunlock(&proctree_lock);
LIN_SDT_PROBE0(emul, proc_exit, return);
}
/*
@ -260,6 +342,9 @@ linux_proc_exit(void *arg __unused, struct proc *p)
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);
}
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);
@ -297,6 +382,10 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
free(em, M_LINUX);
}
if (__predict_false(imgp->sysent == &elf_linux_sysvec)) {
LIN_SDT_PROBE0(emul, proc_exec, return);
}
}
void
@ -309,6 +398,8 @@ linux_schedtail(struct thread *td)
p = td->td_proc;
LIN_SDT_PROBE1(emul, linux_schedtail, entry, p);
/* find the emuldata */
em = em_find(p, EMUL_DOLOCK);
@ -316,10 +407,18 @@ linux_schedtail(struct thread *td)
child_set_tid = em->child_set_tid;
EMUL_UNLOCK(&emul_lock);
if (child_set_tid != NULL)
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;
}
@ -328,10 +427,7 @@ linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args
{
struct linux_emuldata *em;
#ifdef DEBUG
if (ldebug(set_tid_address))
printf(ARGS(set_tid_address, "%p"), args->tidptr);
#endif
LIN_SDT_PROBE1(emul, linux_set_tid_address, entry, args->tidptr);
/* find the emuldata */
em = em_find(td->td_proc, EMUL_DOLOCK);
@ -342,6 +438,8 @@ linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args
td->td_retval[0] = td->td_proc->p_pid;
EMUL_UNLOCK(&emul_lock);
LIN_SDT_PROBE0(emul, linux_set_tid_address, return);
return 0;
}
@ -351,6 +449,8 @@ 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"));
@ -364,9 +464,10 @@ linux_kill_threads(struct thread *td, int sig)
if ((sp->p_flag & P_WEXIT) == 0)
kern_psignal(sp, sig);
PROC_UNLOCK(sp);
#ifdef DEBUG
printf(LMSG("linux_kill_threads: kill PID %d\n"), em->pid);
#endif
LIN_SDT_PROBE1(emul, linux_kill_threads, kill, em->pid);
}
EMUL_SHARED_RUNLOCK(&emul_shared_lock);
LIN_SDT_PROBE0(emul, linux_kill_threads, return);
}

View File

@ -64,13 +64,42 @@ struct linux_emuldata {
struct linux_emuldata *em_find(struct proc *, int locked);
#define EMUL_LOCK(l) mtx_lock(l)
#define EMUL_UNLOCK(l) mtx_unlock(l)
/*
* 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)
#define EMUL_SHARED_RLOCK(l) sx_slock(l)
#define EMUL_SHARED_RUNLOCK(l) sx_sunlock(l)
#define EMUL_SHARED_WLOCK(l) sx_xlock(l)
#define EMUL_SHARED_WUNLOCK(l) sx_xunlock(l)
#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

View File

@ -30,6 +30,7 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -38,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/sdt.h>
#include <sys/sx.h>
#include <sys/unistd.h>
@ -48,9 +50,17 @@ __FBSDID("$FreeBSD$");
#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>
/* 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)

File diff suppressed because it is too large Load Diff

View File

@ -29,8 +29,12 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/sdt.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/proc.h>
@ -41,15 +45,81 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/sx.h>
#include "opt_compat.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>
/* 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];
@ -79,11 +149,19 @@ linux_sysctl_osname(SYSCTL_HANDLER_ARGS)
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 || req->newptr == NULL)
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);
return (error);
}
error = linux_set_osname(req->td, osname);
LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error);
return (error);
}
@ -98,11 +176,19 @@ linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS)
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 || req->newptr == NULL)
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);
return (error);
}
error = linux_set_osrelease(req->td, osrelease);
LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error);
return (error);
}
@ -117,11 +203,19 @@ linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS)
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 || req->newptr == NULL)
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);
return (error);
}
error = linux_set_oss_version(req->td, oss_version);
LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error);
return (error);
}
@ -139,25 +233,37 @@ linux_map_osrel(char *osrelease, int *osrel)
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 != '.')
if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') {
LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
return (EINVAL);
}
osrelease = sep + 1;
v1 = strtol(osrelease, &sep, 10);
if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.')
if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') {
LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
return (EINVAL);
}
osrelease = sep + 1;
v2 = strtol(osrelease, &sep, 10);
if (osrelease == sep || sep != eosrelease)
if (osrelease == sep || sep != eosrelease) {
LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
return (EINVAL);
}
v = v0 * 1000000 + v1 * 1000 + v2;
if (v < 1000000)
if (v < 1000000) {
LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
return (EINVAL);
}
*osrel = v;
LIN_SDT_PROBE1(mib, linux_map_osrel, return, 0);
return (0);
}
@ -171,6 +277,8 @@ linux_find_prison(struct prison *spr, struct prison **prp)
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;
@ -184,6 +292,8 @@ linux_find_prison(struct prison *spr, struct prison **prp)
mtx_unlock(&pr->pr_mtx);
}
*prp = pr;
LIN_SDT_PROBE1(mib, linux_get_prison, return, lpr);
return (lpr);
}
@ -198,6 +308,8 @@ linux_alloc_prison(struct prison *pr, struct linux_prison **lprp)
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);
@ -230,6 +342,8 @@ linux_alloc_prison(struct prison *pr, struct linux_prison **lprp)
*lprp = lpr;
else
mtx_unlock(&pr->pr_mtx);
LIN_SDT_PROBE1(mib, linux_alloc_prison, return, error);
return (error);
}
@ -241,16 +355,26 @@ linux_prison_create(void *obj, void *data)
{
struct prison *pr = obj;
struct vfsoptlist *opts = data;
int jsys;
int jsys, error;
if (vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)) == 0 &&
jsys == JAIL_SYS_INHERIT)
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);
return (0);
}
/*
* Inherit a prison's initial values from its parent
* (different from JAIL_SYS_INHERIT which also inherits changes).
*/
return linux_alloc_prison(pr, NULL);
error = linux_alloc_prison(pr, NULL);
LIN_SDT_PROBE1(mib, linux_prison_create, return, error);
return (error);
}
static int
@ -260,44 +384,81 @@ linux_prison_check(void *obj __unused, void *data)
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)
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
return (error);
if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT)
}
if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) {
LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
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)
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
return (error);
if (len == 0 || osname[len - 1] != '\0')
}
if (len == 0 || osname[len - 1] != '\0') {
LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
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)
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
return (error);
if (len == 0 || osrelease[len - 1] != '\0')
}
if (len == 0 || osrelease[len - 1] != '\0') {
LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
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));
return (error == ENOENT ? 0 : error);
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);
}
static int
@ -309,22 +470,32 @@ linux_prison_set(void *obj, void *data)
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
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 {
@ -346,12 +517,15 @@ linux_prison_set(void *obj, void *data)
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) {
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,
@ -363,6 +537,8 @@ linux_prison_set(void *obj, void *data)
lpr->pr_oss_version = oss_version;
mtx_unlock(&pr->pr_mtx);
}
LIN_SDT_PROBE1(mib, linux_prison_set, return, 0);
return (0);
}
@ -385,43 +561,74 @@ linux_prison_get(void *obj, void *data)
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 && error != ENOENT)
goto done;
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, error);
if (error != ENOENT)
goto done;
}
if (i) {
error = vfs_setopts(opts, "linux.osname", lpr->pr_osname);
if (error != 0 && error != ENOENT)
goto done;
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
error);
if (error != ENOENT)
goto done;
}
error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease);
if (error != 0 && error != ENOENT)
goto done;
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
error);
if (error != ENOENT)
goto done;
}
error = vfs_setopt(opts, "linux.oss_version",
&lpr->pr_oss_version, sizeof(lpr->pr_oss_version));
if (error != 0 && error != ENOENT)
goto done;
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error,
error);
if(error != ENOENT)
goto done;
}
} else {
/*
* If this prison is inheriting its Linux info, report
* empty/zero parameters.
*/
error = vfs_setopts(opts, "linux.osname", "");
if (error != 0 && error != ENOENT)
goto done;
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
error);
if(error != ENOENT)
goto done;
}
error = vfs_setopts(opts, "linux.osrelease", "");
if (error != 0 && error != ENOENT)
goto done;
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
error);
if(error != ENOENT)
goto done;
}
error = vfs_setopt(opts, "linux.oss_version", &version0,
sizeof(lpr->pr_oss_version));
if (error != 0 && error != ENOENT)
goto done;
if (error != 0) {
LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error,
error);
if(error != ENOENT)
goto done;
}
}
error = 0;
done:
mtx_unlock(&ppr->pr_mtx);
LIN_SDT_PROBE1(mib, linux_prison_get, return, error);
return (error);
}
@ -429,7 +636,9 @@ static void
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
@ -443,6 +652,8 @@ linux_osd_jail_register(void)
[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) {
@ -452,14 +663,20 @@ linux_osd_jail_register(void)
(void)linux_alloc_prison(pr, NULL);
sx_xunlock(&allprison_lock);
}
LIN_SDT_PROBE0(mib, linux_osd_jail_register, return);
}
void
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
@ -468,9 +685,13 @@ linux_get_osname(struct thread *td, char *dst)
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
@ -479,9 +700,13 @@ linux_set_osname(struct thread *td, char *osname)
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);
}
@ -491,9 +716,13 @@ linux_get_osrelease(struct thread *td, char *dst)
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
@ -503,9 +732,13 @@ linux_kernver(struct thread *td)
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);
}
@ -516,11 +749,15 @@ linux_set_osrelease(struct thread *td, char *osrelease)
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)
strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME);
mtx_unlock(&pr->pr_mtx);
LIN_SDT_PROBE1(mib, linux_set_osrelease, return, error);
return (error);
}
@ -531,9 +768,13 @@ linux_get_oss_version(struct thread *td)
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);
}
@ -543,13 +784,18 @@ linux_set_oss_version(struct thread *td, int oss_version)
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))];

View File

@ -31,6 +31,7 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/blist.h>
@ -53,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <sys/racct.h>
#include <sys/resourcevar.h>
#include <sys/sched.h>
#include <sys/sdt.h>
#include <sys/signalvar.h>
#include <sys/stat.h>
#include <sys/syscallsubr.h>
@ -83,6 +85,7 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux_proto.h>
#endif
#include <compat/linux/linux_dtrace.h>
#include <compat/linux/linux_file.h>
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_signal.h>
@ -91,6 +94,17 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_misc.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);
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] = {

View File

@ -30,12 +30,15 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/sdt.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/sbuf.h>
@ -48,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux_proto.h>
#endif
#include <compat/linux/linux_dtrace.h>
#include <compat/linux/linux_util.h>
#define LINUX_CTL_KERN 1
@ -65,23 +69,49 @@ __FBSDID("$FreeBSD$");
#define LINUX_KERN_OSREV 3
#define LINUX_KERN_VERSION 4
/* DTrace init */
LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
/**
* DTrace probes in this module.
*/
LIN_SDT_PROBE_DEFINE2(sysctl, handle_string, entry, "struct l___sysctl_args *",
"char *");
LIN_SDT_PROBE_DEFINE1(sysctl, handle_string, copyout_error, "int");
LIN_SDT_PROBE_DEFINE1(sysctl, handle_string, return, "int");
LIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, entry, "struct l___sysctl_args *",
"struct thread *");
LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, copyin_error, "int");
LIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, wrong_length, "int", "int");
LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, unsupported_sysctl, "char *");
LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, return, "int");
static int
handle_string(struct l___sysctl_args *la, char *value)
{
int error;
LIN_SDT_PROBE2(sysctl, handle_string, entry, la, value);
if (la->oldval != 0) {
l_int len = strlen(value);
error = copyout(value, PTRIN(la->oldval), len + 1);
if (!error && la->oldlenp != 0)
error = copyout(&len, PTRIN(la->oldlenp), sizeof(len));
if (error)
if (error) {
LIN_SDT_PROBE1(sysctl, handle_string, copyout_error,
error);
LIN_SDT_PROBE1(sysctl, handle_string, return, error);
return (error);
}
}
if (la->newval != 0)
if (la->newval != 0) {
LIN_SDT_PROBE1(sysctl, handle_string, return, ENOTDIR);
return (ENOTDIR);
}
LIN_SDT_PROBE1(sysctl, handle_string, return, 0);
return (0);
}
@ -91,18 +121,30 @@ linux_sysctl(struct thread *td, struct linux_sysctl_args *args)
struct l___sysctl_args la;
struct sbuf *sb;
l_int *mib;
char *sysctl_string;
int error, i;
error = copyin(args->args, &la, sizeof(la));
if (error)
return (error);
LIN_SDT_PROBE2(sysctl, linux_sysctl, entry, td, args->args);
if (la.nlen <= 0 || la.nlen > LINUX_CTL_MAXNAME)
error = copyin(args->args, &la, sizeof(la));
if (error) {
LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error);
LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
return (error);
}
if (la.nlen <= 0 || la.nlen > LINUX_CTL_MAXNAME) {
LIN_SDT_PROBE2(sysctl, linux_sysctl, wrong_length, la.nlen,
LINUX_CTL_MAXNAME);
LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR);
return (ENOTDIR);
}
mib = malloc(la.nlen * sizeof(l_int), M_TEMP, 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);
return (error);
}
@ -116,6 +158,7 @@ linux_sysctl(struct thread *td, struct linux_sysctl_args *args)
case LINUX_KERN_VERSION:
error = handle_string(&la, version);
free(mib, M_TEMP);
LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
return (error);
default:
break;
@ -128,16 +171,23 @@ linux_sysctl(struct thread *td, struct linux_sysctl_args *args)
sb = sbuf_new(NULL, NULL, 20 + la.nlen * 5, SBUF_AUTOEXTEND);
if (sb == NULL) {
linux_msg(td, "sysctl is not implemented");
LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl,
"unknown sysctl, ENOMEM during lookup");
} else {
sbuf_printf(sb, "sysctl ");
for (i = 0; i < la.nlen; i++)
sbuf_printf(sb, "%c%d", (i) ? ',' : '{', mib[i]);
sbuf_printf(sb, "} is not implemented");
sbuf_finish(sb);
sysctl_string = sbuf_data(sb);
linux_msg(td, "%s", sbuf_data(sb));
LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl,
sysctl_string);
sbuf_delete(sb);
}
free(mib, M_TEMP);
LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR);
return (ENOTDIR);
}

View File

@ -36,10 +36,13 @@ __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp
#endif
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <sys/sdt.h>
#include <sys/signal.h>
#include <sys/stdint.h>
#include <sys/syscallsubr.h>
@ -56,6 +59,63 @@ __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp
#include <machine/../linux/linux_proto.h>
#endif
#include <compat/linux/linux_dtrace.h>
/* DTrace init */
LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
/**
* DTrace probes in this module.
*/
LIN_SDT_PROBE_DEFINE2(time, native_to_linux_timespec, entry,
"struct l_timespec *", "struct timespec *");
LIN_SDT_PROBE_DEFINE0(time, native_to_linux_timespec, return);
LIN_SDT_PROBE_DEFINE2(time, linux_to_native_timespec, entry,
"struct timespec *", "struct l_timespec *");
LIN_SDT_PROBE_DEFINE1(time, linux_to_native_timespec, return, "int");
LIN_SDT_PROBE_DEFINE2(time, linux_to_native_clockid, entry, "clockid_t *",
"clockid_t");
LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid,
"clockid_t");
LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid,
"clockid_t");
LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, return, "int");
LIN_SDT_PROBE_DEFINE2(time, linux_clock_gettime, entry, "clockid_t",
"struct l_timespec *");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, conversion_error, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, return, "int");
LIN_SDT_PROBE_DEFINE2(time, linux_clock_settime, entry, "clockid_t",
"struct l_timespec *");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, settime_error, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, return, "int");
LIN_SDT_PROBE_DEFINE2(time, linux_clock_getres, entry, "clockid_t",
"struct l_timespec *");
LIN_SDT_PROBE_DEFINE0(time, linux_clock_getres, nullcall);
LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, conversion_error, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, getres_error, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, return, "int");
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");
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");
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 *,
@ -65,24 +125,38 @@ static int linux_to_native_clockid(clockid_t *, clockid_t);
static void
native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
{
LIN_SDT_PROBE2(time, native_to_linux_timespec, entry, ltp, ntp);
ltp->tv_sec = ntp->tv_sec;
ltp->tv_nsec = ntp->tv_nsec;
LIN_SDT_PROBE0(time, native_to_linux_timespec, return);
}
static int
linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
{
if (ltp->tv_sec < 0 || ltp->tv_nsec > (l_long)999999999L)
LIN_SDT_PROBE2(time, linux_to_native_timespec, entry, ntp, ltp);
if (ltp->tv_sec < 0 || ltp->tv_nsec > (l_long)999999999L) {
LIN_SDT_PROBE1(time, linux_to_native_timespec, return, EINVAL);
return (EINVAL);
}
ntp->tv_sec = ltp->tv_sec;
ntp->tv_nsec = ltp->tv_nsec;
LIN_SDT_PROBE1(time, linux_to_native_timespec, return, 0);
return (0);
}
static int
linux_to_native_clockid(clockid_t *n, clockid_t l)
{
LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l);
switch (l) {
case LINUX_CLOCK_REALTIME:
*n = CLOCK_REALTIME;
@ -94,11 +168,20 @@ linux_to_native_clockid(clockid_t *n, clockid_t l)
case LINUX_CLOCK_THREAD_CPUTIME_ID:
case LINUX_CLOCK_REALTIME_HR:
case LINUX_CLOCK_MONOTONIC_HR:
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);
return (0);
}
@ -110,15 +193,29 @@ linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
clockid_t nwhich = 0; /* XXX: GCC */
struct timespec tp;
LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp);
error = linux_to_native_clockid(&nwhich, args->which);
if (error != 0)
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error,
error);
LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
return (error);
}
error = kern_clock_gettime(td, nwhich, &tp);
if (error != 0)
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
return (error);
}
native_to_linux_timespec(&lts, &tp);
return (copyout(&lts, args->tp, sizeof lts));
error = copyout(&lts, args->tp, sizeof lts);
if (error != 0)
LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error);
LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
return (error);
}
int
@ -129,17 +226,35 @@ linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
int error;
clockid_t nwhich = 0; /* XXX: GCC */
error = linux_to_native_clockid(&nwhich, args->which);
if (error != 0)
return (error);
error = copyin(args->tp, &lts, sizeof lts);
if (error != 0)
return (error);
error = linux_to_native_timespec(&ts, &lts);
if (error != 0)
return (error);
LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp);
return (kern_clock_settime(td, nwhich, &ts));
error = linux_to_native_clockid(&nwhich, args->which);
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
error);
LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
return (error);
}
error = copyin(args->tp, &lts, sizeof lts);
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error);
LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
return (error);
}
error = linux_to_native_timespec(&ts, &lts);
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
error);
LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
return (error);
}
error = kern_clock_settime(td, nwhich, &ts);
if (error != 0)
LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error);
LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
return (error);
}
int
@ -150,18 +265,35 @@ linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
int error;
clockid_t nwhich = 0; /* XXX: GCC */
if (args->tp == NULL)
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)
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error,
error);
LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
return (error);
}
error = kern_clock_getres(td, nwhich, &ts);
if (error != 0)
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error);
LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
return (error);
}
native_to_linux_timespec(&lts, &ts);
return (copyout(&lts, args->tp, sizeof lts));
error = copyout(&lts, args->tp, sizeof lts);
if (error != 0)
LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error);
LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
return (error);
}
int
@ -172,9 +304,14 @@ linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
struct timespec rqts, rmts;
int error;
LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp);
error = copyin(args->rqtp, &lrqts, sizeof lrqts);
if (error != 0)
if (error != 0) {
LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error);
LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
return (error);
}
if (args->rmtp != NULL)
rmtp = &rmts;
@ -182,19 +319,30 @@ linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
rmtp = NULL;
error = linux_to_native_timespec(&rqts, &lrqts);
if (error != 0)
if (error != 0) {
LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error);
LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
return (error);
}
error = kern_nanosleep(td, &rqts, rmtp);
if (error != 0)
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 != 0) {
LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error,
error);
LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
return (error);
}
}
LIN_SDT_PROBE1(time, linux_nanosleep, return, 0);
return (0);
}
@ -206,15 +354,31 @@ linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args
struct timespec rqts, rmts;
int error;
if (args->flags != 0)
return (EINVAL); /* XXX deal with TIMER_ABSTIME */
LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which,
args->flags, args->rqtp, args->rmtp);
if (args->which != LINUX_CLOCK_REALTIME)
if (args->flags != 0) {
/* XXX deal with TIMER_ABSTIME */
LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags,
args->flags);
LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL);
return (EINVAL); /* XXX deal with TIMER_ABSTIME */
}
if (args->which != LINUX_CLOCK_REALTIME) {
LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid,
args->which);
LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL);
return (EINVAL);
}
error = copyin(args->rqtp, &lrqts, sizeof lrqts);
if (error != 0)
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error,
error);
LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
return (error);
}
if (args->rmtp != NULL)
rmtp = &rmts;
@ -222,18 +386,31 @@ linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args
rmtp = NULL;
error = linux_to_native_timespec(&rqts, &lrqts);
if (error != 0)
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error,
error);
LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
return (error);
}
error = kern_nanosleep(td, &rqts, rmtp);
if (error != 0)
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) {
native_to_linux_timespec(&lrmts, rmtp);
error = copyout(&lrmts, args->rmtp, sizeof lrmts );
if (error != 0)
if (error != 0) {
LIN_SDT_PROBE1(time, linux_clock_nanosleep,
copyout_error, error);
LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
return (error);
}
}
LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, 0);
return (0);
}

View File

@ -28,14 +28,17 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/fcntl.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/sdt.h>
#include <sys/syscallsubr.h>
#include <sys/sysproto.h>
#include <sys/systm.h>
@ -48,8 +51,53 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux_proto.h>
#endif
#include <compat/linux/linux_dtrace.h>
#include <compat/linux/linux_util.h>
/* DTrace init */
LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
/**
* DTrace probes in this module.
*/
LIN_SDT_PROBE_DEFINE3(uid16, linux_chown16, entry, "char *", "l_uid16_t",
"l_gid16_t");
LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, conv_path, "char *");
LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, return, "int");
LIN_SDT_PROBE_DEFINE3(uid16, linux_lchown16, entry, "char *", "l_uid16_t",
"l_gid16_t");
LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, conv_path, "char *");
LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, return, "int");
LIN_SDT_PROBE_DEFINE2(uid16, linux_setgroups16, entry, "l_uint", "l_gid16_t *");
LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, copyin_error, "int");
LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, priv_check_cred_error, "int");
LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, return, "int");
LIN_SDT_PROBE_DEFINE2(uid16, linux_getgroups16, entry, "l_uint", "l_gid16_t *");
LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, copyout_error, "int");
LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, return, "int");
LIN_SDT_PROBE_DEFINE0(uid16, linux_getgid16, entry);
LIN_SDT_PROBE_DEFINE1(uid16, linux_getgid16, return, "int");
LIN_SDT_PROBE_DEFINE0(uid16, linux_getuid16, entry);
LIN_SDT_PROBE_DEFINE1(uid16, linux_getuid16, return, "int");
LIN_SDT_PROBE_DEFINE0(uid16, linux_getegid16, entry);
LIN_SDT_PROBE_DEFINE1(uid16, linux_getegid16, return, "int");
LIN_SDT_PROBE_DEFINE0(uid16, linux_geteuid16, entry);
LIN_SDT_PROBE_DEFINE1(uid16, linux_geteuid16, return, "int");
LIN_SDT_PROBE_DEFINE1(uid16, linux_setgid16, entry, "l_gid16_t");
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_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");
LIN_SDT_PROBE_DEFINE3(uid16, linux_setresgid16, entry, "l_gid16_t", "l_gid16_t",
"l_gid16_t");
LIN_SDT_PROBE_DEFINE1(uid16, linux_setresgid16, return, "int");
LIN_SDT_PROBE_DEFINE3(uid16, linux_setresuid16, entry, "l_uid16_t", "l_uid16_t",
"l_uid16_t");
LIN_SDT_PROBE_DEFINE1(uid16, linux_setresuid16, return, "int");
DUMMY(setfsuid16);
DUMMY(setfsgid16);
DUMMY(getresuid16);
@ -65,13 +113,20 @@ linux_chown16(struct thread *td, struct linux_chown16_args *args)
LCONVPATHEXIST(td, args->path, &path);
#ifdef DEBUG
if (ldebug(chown16))
printf(ARGS(chown16, "%s, %d, %d"), path, args->uid, args->gid);
#endif
/*
* The DTrace probes have to be after the LCONVPATHEXIST, as
* LCONVPATHEXIST may return on its own and we do not want to
* have a stray entry without the corresponding return.
*/
LIN_SDT_PROBE3(uid16, linux_chown16, entry, args->path, args->uid,
args->gid);
LIN_SDT_PROBE1(uid16, linux_chown16, conv_path, path);
error = kern_chown(td, path, UIO_SYSSPACE, CAST_NOCHG(args->uid),
CAST_NOCHG(args->gid));
LFREEPATH(path);
LIN_SDT_PROBE1(uid16, linux_chown16, return, error);
return (error);
}
@ -83,14 +138,20 @@ linux_lchown16(struct thread *td, struct linux_lchown16_args *args)
LCONVPATHEXIST(td, args->path, &path);
#ifdef DEBUG
if (ldebug(lchown16))
printf(ARGS(lchown16, "%s, %d, %d"), path, args->uid,
args->gid);
#endif
/*
* The DTrace probes have to be after the LCONVPATHEXIST, as
* LCONVPATHEXIST may return on its own and we do not want to
* have a stray entry without the corresponding return.
*/
LIN_SDT_PROBE3(uid16, linux_lchown16, entry, args->path, args->uid,
args->gid);
LIN_SDT_PROBE1(uid16, linux_lchown16, conv_path, path);
error = kern_lchown(td, path, UIO_SYSSPACE, CAST_NOCHG(args->uid),
CAST_NOCHG(args->gid));
LFREEPATH(path);
LIN_SDT_PROBE1(uid16, linux_lchown16, return, error);
return (error);
}
@ -103,17 +164,19 @@ linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args)
int ngrp, error;
struct proc *p;
#ifdef DEBUG
if (ldebug(setgroups16))
printf(ARGS(setgroups16, "%d, *"), args->gidsetsize);
#endif
LIN_SDT_PROBE2(uid16, linux_setgroups16, entry, args->gidsetsize,
args->gidset);
ngrp = args->gidsetsize;
if (ngrp < 0 || ngrp >= ngroups_max + 1)
if (ngrp < 0 || ngrp >= ngroups_max + 1) {
LIN_SDT_PROBE1(uid16, linux_setgroups16, return, EINVAL);
return (EINVAL);
}
linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, 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);
return (error);
}
@ -131,6 +194,9 @@ linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args)
if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0) {
PROC_UNLOCK(p);
crfree(newcred);
LIN_SDT_PROBE1(uid16, linux_setgroups16, priv_check_cred_error,
error);
goto out;
}
@ -154,6 +220,8 @@ linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args)
error = 0;
out:
free(linux_gidset, M_TEMP);
LIN_SDT_PROBE1(uid16, linux_setgroups16, return, error);
return (error);
}
@ -165,10 +233,8 @@ linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args)
gid_t *bsd_gidset;
int bsd_gidsetsz, ngrp, error;
#ifdef DEBUG
if (ldebug(getgroups16))
printf(ARGS(getgroups16, "%d, *"), args->gidsetsize);
#endif
LIN_SDT_PROBE2(uid16, linux_getgroups16, entry, args->gidsetsize,
args->gidset);
cred = td->td_ucred;
bsd_gidset = cred->cr_groups;
@ -182,11 +248,15 @@ linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args)
if ((ngrp = args->gidsetsize) == 0) {
td->td_retval[0] = bsd_gidsetsz;
LIN_SDT_PROBE1(uid16, linux_getgroups16, return, 0);
return (0);
}
if (ngrp < bsd_gidsetsz)
if (ngrp < bsd_gidsetsz) {
LIN_SDT_PROBE1(uid16, linux_getgroups16, return, EINVAL);
return (EINVAL);
}
ngrp = 0;
linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset),
@ -198,10 +268,15 @@ linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args)
error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t));
free(linux_gidset, M_TEMP);
if (error)
if (error) {
LIN_SDT_PROBE1(uid16, linux_getgroups16, copyout_error, error);
LIN_SDT_PROBE1(uid16, linux_getgroups16, return, error);
return (error);
}
td->td_retval[0] = ngrp;
LIN_SDT_PROBE1(uid16, linux_getgroups16, return, 0);
return (0);
}
@ -219,7 +294,11 @@ int
linux_getgid16(struct thread *td, struct linux_getgid16_args *args)
{
LIN_SDT_PROBE0(uid16, linux_getgid16, entry);
td->td_retval[0] = td->td_ucred->cr_rgid;
LIN_SDT_PROBE1(uid16, linux_getgid16, return, 0);
return (0);
}
@ -227,7 +306,11 @@ int
linux_getuid16(struct thread *td, struct linux_getuid16_args *args)
{
LIN_SDT_PROBE0(uid16, linux_getuid16, entry);
td->td_retval[0] = td->td_ucred->cr_ruid;
LIN_SDT_PROBE1(uid16, linux_getuid16, return, 0);
return (0);
}
@ -235,74 +318,124 @@ int
linux_getegid16(struct thread *td, struct linux_getegid16_args *args)
{
struct getegid_args bsd;
int error;
return (sys_getegid(td, &bsd));
LIN_SDT_PROBE0(uid16, linux_getegid16, entry);
error = sys_getegid(td, &bsd);
LIN_SDT_PROBE1(uid16, linux_getegid16, return, error);
return (error);
}
int
linux_geteuid16(struct thread *td, struct linux_geteuid16_args *args)
{
struct geteuid_args bsd;
int error;
return (sys_geteuid(td, &bsd));
LIN_SDT_PROBE0(uid16, linux_geteuid16, entry);
error = sys_geteuid(td, &bsd);
LIN_SDT_PROBE1(uid16, linux_geteuid16, return, error);
return (error);
}
int
linux_setgid16(struct thread *td, struct linux_setgid16_args *args)
{
struct setgid_args bsd;
int error;
LIN_SDT_PROBE1(uid16, linux_setgid16, entry, args->gid);
bsd.gid = args->gid;
return (sys_setgid(td, &bsd));
error = sys_setgid(td, &bsd);
LIN_SDT_PROBE1(uid16, linux_setgid16, return, error);
return (error);
}
int
linux_setuid16(struct thread *td, struct linux_setuid16_args *args)
{
struct setuid_args bsd;
int error;
LIN_SDT_PROBE1(uid16, linux_setuid16, entry, args->uid);
bsd.uid = args->uid;
return (sys_setuid(td, &bsd));
error = sys_setuid(td, &bsd);
LIN_SDT_PROBE1(uid16, linux_setuid16, return, error);
return (error);
}
int
linux_setregid16(struct thread *td, struct linux_setregid16_args *args)
{
struct setregid_args bsd;
int error;
LIN_SDT_PROBE2(uid16, linux_setregid16, entry, args->rgid, args->egid);
bsd.rgid = CAST_NOCHG(args->rgid);
bsd.egid = CAST_NOCHG(args->egid);
return (sys_setregid(td, &bsd));
error = sys_setregid(td, &bsd);
LIN_SDT_PROBE1(uid16, linux_setregid16, return, error);
return (error);
}
int
linux_setreuid16(struct thread *td, struct linux_setreuid16_args *args)
{
struct setreuid_args bsd;
int error;
LIN_SDT_PROBE2(uid16, linux_setreuid16, entry, args->ruid, args->euid);
bsd.ruid = CAST_NOCHG(args->ruid);
bsd.euid = CAST_NOCHG(args->euid);
return (sys_setreuid(td, &bsd));
error = sys_setreuid(td, &bsd);
LIN_SDT_PROBE1(uid16, linux_setreuid16, return, error);
return (error);
}
int
linux_setresgid16(struct thread *td, struct linux_setresgid16_args *args)
{
struct setresgid_args bsd;
int error;
LIN_SDT_PROBE3(uid16, linux_setresgid16, entry, args->rgid, args->egid,
args->sgid);
bsd.rgid = CAST_NOCHG(args->rgid);
bsd.egid = CAST_NOCHG(args->egid);
bsd.sgid = CAST_NOCHG(args->sgid);
return (sys_setresgid(td, &bsd));
error = sys_setresgid(td, &bsd);
LIN_SDT_PROBE1(uid16, linux_setresgid16, return, error);
return (error);
}
int
linux_setresuid16(struct thread *td, struct linux_setresuid16_args *args)
{
struct setresuid_args bsd;
int error;
LIN_SDT_PROBE3(uid16, linux_setresuid16, entry, args->ruid, args->euid,
args->suid);
bsd.ruid = CAST_NOCHG(args->ruid);
bsd.euid = CAST_NOCHG(args->euid);
bsd.suid = CAST_NOCHG(args->suid);
return (sys_setresuid(td, &bsd));
error = sys_setresuid(td, &bsd);
LIN_SDT_PROBE1(uid16, linux_setresuid16, return, error);
return (error);
}

View File

@ -33,16 +33,19 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/fcntl.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/linker_set.h>
#include <sys/mutex.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/sdt.h>
#include <sys/syscallsubr.h>
#include <sys/systm.h>
#include <sys/vnode.h>
@ -56,8 +59,42 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux.h>
#endif
#include <compat/linux/linux_dtrace.h>
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'.
@ -66,17 +103,19 @@ const char linux_emul_path[] = "/compat/linux";
* named file, i.e. we check if the directory it should be in exists.
*/
int
linux_emul_convpath(td, path, pathseg, pbuf, cflag, dfd)
struct thread *td;
const char *path;
enum uio_seg pathseg;
char **pbuf;
int cflag;
int dfd;
linux_emul_convpath(struct thread *td, const char *path, enum uio_seg pathseg,
char **pbuf, int cflag, int dfd)
{
int retval;
return (kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
cflag, dfd));
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);
}
void
@ -85,12 +124,16 @@ linux_msg(const struct thread *td, const char *fmt, ...)
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);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
LIN_SDT_PROBE0(util, linux_msg, return);
}
struct device_element
@ -113,13 +156,23 @@ linux_driver_get_name_dev(device_t dev)
struct device_element *de;
const char *device_name = device_get_name(dev);
if (device_name == NULL)
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);
return NULL;
}
TAILQ_FOREACH(de, &devices, list) {
if (strcmp(device_name, de->entry.bsd_driver_name) == 0)
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);
return (de->entry.linux_driver_name);
}
}
LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return, NULL);
return NULL;
}
@ -128,8 +181,15 @@ linux_driver_get_major_minor(const char *node, int *major, int *minor)
{
struct device_element *de;
if (node == NULL || major == NULL || minor == NULL)
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);
return 1;
}
if (strlen(node) > strlen("pts/") &&
strncmp(node, "pts/", strlen("pts/")) == 0) {
@ -143,6 +203,9 @@ linux_driver_get_major_minor(const char *node, int *major, int *minor)
devno = strtoul(node + strlen("pts/"), NULL, 10);
*major = 136 + (devno / 256);
*minor = devno % 256;
LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 0,
*major, *minor);
return 0;
}
@ -150,10 +213,15 @@ linux_driver_get_major_minor(const char *node, int *major, int *minor)
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;
}
}
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;
}
@ -165,6 +233,8 @@ linux_get_char_devices()
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 = "";
@ -191,13 +261,19 @@ linux_get_char_devices()
}
}
LIN_SDT_PROBE1(util, linux_get_char_devices, return, string);
return string;
}
void
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;
@ -207,11 +283,15 @@ linux_device_register_handler(struct linux_device_handler *d)
{
struct device_element *de;
if (d == NULL)
return (EINVAL);
LIN_SDT_PROBE1(util, linux_device_register_handler, entry, d);
de = malloc(sizeof(*de),
M_LINUX, M_WAITOK);
if (d == NULL) {
LIN_SDT_PROBE1(util, linux_device_register_handler, return,
EINVAL);
return (EINVAL);
}
de = malloc(sizeof(*de), M_LINUX, M_WAITOK);
if (d->linux_major < 0) {
d->linux_major = linux_major_starting++;
}
@ -220,6 +300,7 @@ linux_device_register_handler(struct linux_device_handler *d)
/* 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);
}
@ -228,16 +309,25 @@ linux_device_unregister_handler(struct linux_device_handler *d)
{
struct device_element *de;
if (d == NULL)
LIN_SDT_PROBE1(util, linux_device_unregister_handler, entry, d);
if (d == NULL) {
LIN_SDT_PROBE1(util, linux_device_unregister_handler, return,
EINVAL);
return (EINVAL);
}
TAILQ_FOREACH(de, &devices, list) {
if (bcmp(d, &de->entry, sizeof(*d)) == 0) {
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);
}

View File

@ -68,15 +68,23 @@ int linux_emul_convpath(struct thread *, const char *, enum uio_seg, char **, in
#define LFREEPATH(path) free(path, M_TEMP)
#define DUMMY(s) \
LIN_SDT_PROBE_DEFINE0(dummy, s, entry); \
LIN_SDT_PROBE_DEFINE0(dummy, s, not_implemented); \
LIN_SDT_PROBE_DEFINE1(dummy, s, return, "int"); \
int \
linux_ ## s(struct thread *td, struct linux_ ## s ## _args *args) \
{ \
static pid_t pid; \
\
LIN_SDT_PROBE0(dummy, s, entry); \
\
if (pid != td->td_proc->p_pid) { \
linux_msg(td, "syscall %s not implemented", #s); \
LIN_SDT_PROBE0(dummy, s, not_implemented); \
pid = td->td_proc->p_pid; \
}; \
\
LIN_SDT_PROBE1(dummy, s, return, ENOSYS); \
return (ENOSYS); \
} \
struct __hack

View File

@ -0,0 +1,94 @@
#!/usr/sbin/dtrace -qs
/*-
* Copyright (c) 2008-2012 Alexander Leidinger <netchild@FreeBSD.org>
* 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$
*/
/**
* Some statistics (all per provider):
* - number of calls to a function per executable binary (not per PID!)
* - allows to see where an optimization would be beneficial for a given
* application
* - graph of CPU time spend in functions per executable binary
* - together with the number of calls to this function this allows
* to determine if a kernel optimization would be beneficial / is
* 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
*/
#pragma D option dynvarsize=32m
linuxulator*:::entry
{
self->time[probefunc] = vtimestamp;
@calls[probeprov, execname, probefunc] = count();
}
linuxulator*:::return
/self->time[probefunc] != 0/
{
this->timediff = self->time[probefunc] - vtimestamp;
@stats[probeprov, execname, probefunc] = quantize(this->timediff);
@longest[probeprov, probefunc] = max(this->timediff);
self->time[probefunc] = 0;
}
linuxulator*:::locked
{
self->lock[arg0] = vtimestamp;
}
linuxulator*:::unlock
/self->lock[arg0] != 0/
{
this->timediff = self->lock[arg0] - vtimestamp;
@lockstats[probefunc] = quantize(this->timediff);
@longlock[probefunc] = max(this->timediff);
self->lock[arg0] = 0;
}
END
{
printf("Number of calls per provider/application/kernel function:");
printa(@calls);
printf("CPU-timing statistics per provider/application/kernel function (in ns):");
printa(@stats);
printf("Longest running (CPU-time!) functions per provider (in ns):");
printa(@longest);
printf("Lock CPU-timing statistics:");
printa(@lockstats);
printf("Longest running (CPU-time!) locks:");
printa(@longlock);
}

View File

@ -0,0 +1,182 @@
#!/usr/sbin/dtrace -qs
/*-
* Copyright (c) 2011-2012 Alexander Leidinger <netchild@FreeBSD.org>
* 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$
*/
/**
* Trace futex operations:
* - internal locks
* - size of the futex list
* - report error conditions (emulation errors, kernel errors,
* programming errors)
* - execution time (wallclock) of futex related functions
*/
#pragma D option specsize=32m
/* Error conditions */
linuxulator*:futex:futex_get:error,
linuxulator*:futex:futex_sleep:requeue_error,
linuxulator*:futex:futex_sleep:sleep_error,
linuxulator*:futex:futex_wait:copyin_error,
linuxulator*:futex:futex_wait:itimerfix_error,
linuxulator*:futex:futex_wait:sleep_error,
linuxulator*:futex:futex_atomic_op:missing_access_check,
linuxulator*:futex:futex_atomic_op:unimplemented_op,
linuxulator*:futex:futex_atomic_op:unimplemented_cmp,
linuxulator*:futex:linux_sys_futex:unimplemented_clockswitch,
linuxulator*:futex:linux_sys_futex:copyin_error,
linuxulator*:futex:linux_sys_futex:unhandled_efault,
linuxulator*:futex:linux_sys_futex:unimplemented_lock_pi,
linuxulator*:futex:linux_sys_futex:unimplemented_unlock_pi,
linuxulator*:futex:linux_sys_futex:unimplemented_trylock_pi,
linuxulator*:futex:linux_sys_futex:unimplemented_wait_requeue_pi,
linuxulator*:futex:linux_sys_futex:unimplemented_cmp_requeue_pi,
linuxulator*:futex:linux_sys_futex:unknown_operation,
linuxulator*:futex:linux_get_robust_list:copyout_error,
linuxulator*:futex:handle_futex_death:copyin_error,
linuxulator*:futex:fetch_robust_entry:copyin_error,
linuxulator*:futex:release_futexes:copyin_error
{
printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod,
probefunc);
stack();
ustack();
}
linuxulator*:futex:linux_sys_futex:invalid_cmp_requeue_use,
linuxulator*:futex:linux_sys_futex:deprecated_requeue,
linuxulator*:futex:linux_set_robust_list:size_error
{
printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n",
probename, probeprov, probemod, probefunc, execname);
stack();
ustack();
}
/* Per futex checks/statistics */
linuxulator*:futex:futex:create
{
++futex_count;
@max_futexes = max(futex_count);
}
linuxulator*:futex:futex:destroy
/futex_count == 0/
{
printf("ERROR: Request to destroy a futex which was not created,\n");
printf(" or this script was started after some futexes where\n");
printf(" created. Stack trace:\n");
stack();
ustack();
}
linuxulator*:futex:futex:destroy
{
--futex_count;
}
/* Internal locks */
linuxulator*:locks:futex_mtx:locked
{
++check[probefunc, arg0];
@stats[probefunc] = count();
ts[probefunc] = timestamp;
spec[probefunc] = speculation();
printf("Stacktrace of last lock operation of the %s:\n", probefunc);
stack();
}
linuxulator*:locks:futex_mtx:unlock
/check[probefunc, arg0] == 0/
{
printf("ERROR: unlock attemt 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:");
stack();
}
linuxulator*:locks:futex_mtx:unlock
{
discard(spec[probefunc]);
spec[probefunc] = 0;
--check[probefunc, arg0];
}
/* Timeout handling for internal locks */
tick-10s
/spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/
{
commit(spec["futex_mtx"]);
spec["futex_mtx"] = 0;
}
/* Timing statistings */
linuxulator*:futex::entry
{
self->time[probefunc] = timestamp;
@calls[probeprov, execname, probefunc] = count();
}
linuxulator*:futex::return
/self->time[probefunc] != 0/
{
this->timediff = self->time[probefunc] - timestamp;
@timestats[probeprov, execname, probefunc] = quantize(this->timediff);
@longest[probeprov, probefunc] = max(this->timediff);
self->time[probefunc] = 0;
}
/* Statistics */
END
{
printf("Number of locks per type:");
printa(@stats);
printf("Number of maximum number of futexes in the futex list:");
printa(@max_futexes);
printf("Number of futexes still existing: %d", futex_count);
printf("Number of calls per provider/application/kernel function:");
printa(@calls);
printf("Wallclock-timing statistics per provider/application/kernel function (in ns):");
printa(@timestats);
printf("Longest running (wallclock!) functions per provider (in ns):");
printa(@longest);
}

View File

@ -42,6 +42,7 @@ extern u_char linux_debug_map[];
#define ldebug(name) isclr(linux_debug_map, LINUX_SYS_linux_ ## name)
#define ARGS(nm, fmt) "linux(%ld): "#nm"("fmt")\n", (long)td->td_proc->p_pid
#define LMSG(fmt) "linux(%ld): "fmt"\n", (long)td->td_proc->p_pid
#define LINUX_DTRACE linuxulator
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_LINUX);

View File

@ -29,14 +29,23 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/sdt.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <i386/linux/linux.h>
#include <i386/linux/linux_proto.h>
#include <compat/linux/linux_dtrace.h>
#include <compat/linux/linux_util.h>
/* DTrace init */
LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
DUMMY(stime);
DUMMY(fstat);
DUMMY(olduname);