[DTrace-devel] [PATCH v3] Allow arbitrary tracefs mount points

Kris Van Hees kris.van.hees at oracle.com
Fri Nov 15 20:42:49 UTC 2024


On Tue, Nov 12, 2024 at 01:42:56PM +0000, Nick Alcock wrote:
> So as of kernel 6.3 (upstream commit 2455f0e124d317dd08d337a75), the
> canonical tracefs location has moved to /sys/kernel/tracing.  Unfortunately
> this requires an explicit mount, and a great many installations have not
> done this and perhaps never will.  So if the debugfs is mounted on
> /sys/kernel/debug, it automatically makes /sys/kernel/debug/tracing appear
> as it used to, as another tracefs mount.  And of course there's nothing
> special about the "canonical location": it's up to the admin, who might
> choose to remount the thing anywhere at all.
> 
> To make this even more fun, it's quite possible to end up with the tracefs
> on /sys/kernel/debug/tracing, but an empty directory at /sys/kernel/tracing
> (I got that during testing with no effort at all).
> 
> All this means that the existing DTrace hardwiring for tracefs/eventsfs
> locations isn't good enough.  Instead, hunt for a suitable tracefs mount with
> getmntent(), and add a function to open files under that directory, allowing
> the path to be created using a printf-style format string (mimicking the
> things we used to do with EVENTSFS defines and the like).  This is actually
> all we need; there is no need to ever return these paths at all, so there
> is no clogging up the code with free()s -- and actually there's a
> noticeable simplification in most cases.
> 
> Tested with both in-practice-observed locations of debugfs, and the
> obviously crazy and bad-in-a-format-string path of "/%s/%s/%n" to make sure
> that is properly rejected.

I think it is useful to put the testing (and results) in the commit msg for
this, especially since you do not have a testcase for this (and I can
understand why - though if we were to use chroot or something a test could
be constructed, right).  And the case of tracefs *not* being in standard
location is worth pointing out to clearly show that this does work in the
most generic case.

Or if output of testing is too much to include (I assume it shouldn't be),
at least make sure you test standard and non-standard locations, and then
confidently report here that it works for all locations that do not have
% in the path name.

> Bug: https://github.com/oracle/dtrace-utils/issues/111
> Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
> ---
>  include/tracefs.h                             | 14 ----
>  libdtrace/dt_error.c                          |  3 +-
>  libdtrace/dt_impl.h                           |  3 +
>  libdtrace/dt_open.c                           |  1 +
>  libdtrace/dt_prov_dtrace.c                    | 27 +++----
>  libdtrace/dt_prov_fbt.c                       | 37 ++++-----
>  libdtrace/dt_prov_rawtp.c                     |  9 ++-
>  libdtrace/dt_prov_sdt.c                       | 30 ++++---
>  libdtrace/dt_prov_syscall.c                   | 27 ++++---
>  libdtrace/dt_prov_uprobe.c                    | 41 +++++-----
>  libdtrace/dt_provider.h                       |  1 -
>  libdtrace/dt_subr.c                           | 80 +++++++++++++++++++
>  runtest.sh                                    |  8 ++
>  test/unittest/funcs/tst.rw_.x                 |  7 +-
>  test/unittest/providers/tst.dtrace_cleanup.sh |  9 ++-
>  test/utils/clean_probes.sh                    | 12 ++-
>  16 files changed, 203 insertions(+), 106 deletions(-)
>  delete mode 100644 include/tracefs.h
> 
> diff --git a/include/tracefs.h b/include/tracefs.h
> deleted file mode 100644
> index d671f51adefc..000000000000
> --- a/include/tracefs.h
> +++ /dev/null
> @@ -1,14 +0,0 @@
> -/*
> - * Oracle Linux DTrace; simple uprobe helper functions
> - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
> - * Licensed under the Universal Permissive License v 1.0 as shown at
> - * http://oss.oracle.com/licenses/upl.
> - */
> -
> -#ifndef	_TRACEFS_H
> -#define	_TRACEFS_H
> -
> -#define TRACEFS		"/sys/kernel/debug/tracing/"
> -#define EVENTSFS	TRACEFS "events/"
> -
> -#endif /* _TRACEFS_H */
> diff --git a/libdtrace/dt_error.c b/libdtrace/dt_error.c
> index 213f0d9e1385..9c4a2b32888e 100644
> --- a/libdtrace/dt_error.c
> +++ b/libdtrace/dt_error.c
> @@ -98,7 +98,8 @@ static const struct {
>  	{ EDT_READMAXSTACK, "Cannot read kernel param perf_event_max_stack" },
>  	{ EDT_TRACEMEM, "Missing or corrupt tracemem() record" },
>  	{ EDT_PCAP, "Missing or corrupt pcap() record" },
> -	{ EDT_PRINT, "Missing or corrupt print() record" }
> +	{ EDT_PRINT, "Missing or corrupt print() record" },
> +	{ EDT_TRACEFS, "Cannot find tracefs" }
>  };
>  
>  static const int _dt_nerr = sizeof(_dt_errlist) / sizeof(_dt_errlist[0]);
> diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
> index 68fb8ec53c06..950cb34819aa 100644
> --- a/libdtrace/dt_impl.h
> +++ b/libdtrace/dt_impl.h
> @@ -354,6 +354,7 @@ struct dtrace_hdl {
>  	char *dt_module_path;	/* pathname of kernel module root */
>  	dt_version_t dt_kernver;/* kernel version, used in the libpath */
>  	char *dt_dofstash_path;	/* Path to the DOF stash.  */
> +	char *dt_tracefs_path;	/* Path to tracefs.  */
>  	uid_t dt_useruid;	/* lowest non-system uid: set via -xuseruid */
>  	char *dt_sysslice;	/* the systemd system slice: set via -xsysslice */
>  	uint_t dt_lazyload;	/* boolean:  set via -xlazyload */
> @@ -643,6 +644,7 @@ enum {
>  	EDT_TRACEMEM,		/* missing or corrupt tracemem() record */
>  	EDT_PCAP,		/* missing or corrupt pcap() record */
>  	EDT_PRINT,		/* missing or corrupt print() record */
> +	EDT_TRACEFS,		/* cannot find tracefs */
>  };
>  
>  /*
> @@ -713,6 +715,7 @@ extern void dt_conf_init(dtrace_hdl_t *);
>  
>  extern int dt_gmatch(const char *, const char *);
>  extern char *dt_basename(char *);
> +extern int dt_tracefs_open(dtrace_hdl_t *, const char *fn, int flags, ...);
>  
>  extern ulong_t dt_popc(ulong_t);
>  extern ulong_t dt_popcb(const ulong_t *, ulong_t);
> diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
> index e1972aa821e7..775830f64492 100644
> --- a/libdtrace/dt_open.c
> +++ b/libdtrace/dt_open.c
> @@ -1317,6 +1317,7 @@ dtrace_close(dtrace_hdl_t *dtp)
>  	free(dtp->dt_cpp_argv);
>  	free(dtp->dt_cpp_path);
>  	free(dtp->dt_ld_path);
> +	free(dtp->dt_tracefs_path);
>  	free(dtp->dt_sysslice);
>  	free(dtp->dt_dofstash_path);
>  
> diff --git a/libdtrace/dt_prov_dtrace.c b/libdtrace/dt_prov_dtrace.c
> index 34b5d8e2467f..670954beb4c9 100644
> --- a/libdtrace/dt_prov_dtrace.c
> +++ b/libdtrace/dt_prov_dtrace.c
> @@ -23,8 +23,6 @@ static const char		funname[] = "";
>  
>  #define PROBE_FUNC_SUFFIX	"_probe"
>  
> -#define UPROBE_EVENTS		TRACEFS "uprobe_events"

Since you keep KPROBE_EVENTS etc in other providers, why not here?

> -
>  static const dtrace_pattr_t	pattr = {
>  { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
>  { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
> @@ -229,11 +227,9 @@ out:
>  static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
>  {
>  	if (!dt_tp_probe_has_info(prp)) {
> -		char	*spec;
> -		char	*fn;
> -		FILE	*f;
> -		size_t	len;
> -		int	fd, rc = -1;
> +		char		*spec;
> +		FILE		*f;
> +		int		fd = -1, rc = -1;
>  
>  		/* get a uprobe specification for this probe */
>  		spec = uprobe_spec(getpid(), prp->desc->prb);
> @@ -241,7 +237,8 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
>  			return -ENOENT;
>  
>  		/* add a uprobe */
> -		fd = open(UPROBE_EVENTS, O_WRONLY | O_APPEND);
> +		fd = dt_tracefs_open(dtp, "uprobe_events", O_WRONLY | O_APPEND);
> +
>  		if (fd != -1) {
>  			rc = dprintf(fd, "p:" GROUP_FMT "/%s %s\n",
>  				     GROUP_DATA, prp->desc->prb, spec);
> @@ -252,16 +249,12 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
>  			return -ENOENT;
>  
>  		/* open format file */
> -		len = snprintf(NULL, 0, "%s" GROUP_FMT "/%s/format",
> -			       EVENTSFS, GROUP_DATA, prp->desc->prb) + 1;
> -		fn = dt_alloc(dtp, len);
> -		if (fn == NULL)
> +		fd = dt_tracefs_open(dtp, "events/" GROUP_FMT "/%s/format",
> +				     O_RDONLY, GROUP_DATA, prp->desc->prb);
> +		if (fd < 0)
>  			return -ENOENT;
>  
> -		snprintf(fn, len, "%s" GROUP_FMT "/%s/format",
> -			 EVENTSFS, GROUP_DATA, prp->desc->prb);
> -		f = fopen(fn, "r");
> -		dt_free(dtp, fn);
> +		f = fdopen(fd, "r");
>  		if (f == NULL)
>  			return -ENOENT;
>  
> @@ -296,7 +289,7 @@ static void detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
>  
>  	dt_tp_probe_detach(dtp, prp);
>  
> -	fd = open(UPROBE_EVENTS, O_WRONLY | O_APPEND);
> +	fd = dt_tracefs_open(dtp, "uprobe_events", O_WRONLY | O_APPEND);
>  	if (fd == -1)
>  		return;
>  
> diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
> index 21f63ddffc73..b5c1f5d22a06 100644
> --- a/libdtrace/dt_prov_fbt.c
> +++ b/libdtrace/dt_prov_fbt.c
> @@ -43,8 +43,8 @@
>  static const char		prvname[] = "fbt";
>  static const char		modname[] = "vmlinux";
>  
> -#define KPROBE_EVENTS		TRACEFS "kprobe_events"
> -#define PROBE_LIST		TRACEFS "available_filter_functions"
> +#define KPROBE_EVENTS		"kprobe_events"
> +#define PROBE_LIST		"available_filter_functions"
>  
>  #define FBT_GROUP_FMT		GROUP_FMT "_%s"
>  #define FBT_GROUP_DATA		GROUP_DATA, prp->desc->prb
> @@ -65,6 +65,7 @@ static int populate(dtrace_hdl_t *dtp)
>  {
>  	dt_provider_t		*prv;
>  	dt_provimpl_t		*impl;
> +	int			fd;
>  	FILE			*f;
>  	char			*buf = NULL;
>  	char			*p;
> @@ -79,7 +80,11 @@ static int populate(dtrace_hdl_t *dtp)
>  	if (prv == NULL)
>  		return -1;			/* errno already set */
>  
> -	f = fopen(PROBE_LIST, "r");
> +	fd = dt_tracefs_open(dtp, PROBE_LIST, O_RDONLY);
> +	if (fd < 0)
> +		return 0;
> +
> +	f = fdopen(fd, "r");
>  	if (f == NULL)
>  		return 0;
>  
> @@ -363,16 +368,14 @@ static int kprobe_trampoline(dt_pcb_t *pcb, uint_t exitlbl)
>  static int kprobe_attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
>  {
>  	if (!dt_tp_probe_has_info(prp)) {
> -		char	*fn;
> -		FILE	*f;
> -		size_t	len;
> -		int	fd, rc = -1;
> +		FILE		*f;
> +		int		fd, rc = -1;
>  
>  		/*
>  		 * Register the kprobe with the tracing subsystem.  This will
>  		 * create a tracepoint event.
>  		 */
> -		fd = open(KPROBE_EVENTS, O_WRONLY | O_APPEND);
> +		fd = dt_tracefs_open(dtp, KPROBE_EVENTS, O_WRONLY | O_APPEND);
>  		if (fd == -1)
>  			return -ENOENT;
>  
> @@ -383,19 +386,13 @@ static int kprobe_attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
>  		if (rc == -1)
>  			return -ENOENT;
>  
> -		/* create format file name */
> -		len = snprintf(NULL, 0, "%s" FBT_GROUP_FMT "/%s/format",
> -			       EVENTSFS, FBT_GROUP_DATA, prp->desc->fun) + 1;
> -		fn = dt_alloc(dtp, len);
> -		if (fn == NULL)
> +		/* open format file */
> +		fd = dt_tracefs_open(dtp, "events/" FBT_GROUP_FMT "/%s/format",
> +				     O_RDONLY, FBT_GROUP_DATA, prp->desc->fun);
> +		if (fd < 0)
>  			return -ENOENT;
>  
> -		snprintf(fn, len, "%s" FBT_GROUP_FMT "/%s/format", EVENTSFS,
> -			 FBT_GROUP_DATA, prp->desc->fun);
> -
> -		/* open format file */
> -		f = fopen(fn, "r");
> -		dt_free(dtp, fn);
> +		f = fdopen(fd, "r");
>  		if (f == NULL)
>  			return -ENOENT;
>  
> @@ -431,7 +428,7 @@ static void kprobe_detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
>  
>  	dt_tp_probe_detach(dtp, prp);
>  
> -	fd = open(KPROBE_EVENTS, O_WRONLY | O_APPEND);
> +	fd = dt_tracefs_open(dtp, KPROBE_EVENTS, O_WRONLY | O_APPEND);
>  	if (fd == -1)
>  		return;
>  
> diff --git a/libdtrace/dt_prov_rawtp.c b/libdtrace/dt_prov_rawtp.c
> index 778a6f9cde90..6940edce6a6d 100644
> --- a/libdtrace/dt_prov_rawtp.c
> +++ b/libdtrace/dt_prov_rawtp.c
> @@ -38,7 +38,7 @@
>  static const char		prvname[] = "rawtp";
>  static const char		modname[] = "vmlinux";
>  
> -#define PROBE_LIST		TRACEFS "available_events"
> +#define PROBE_LIST		"available_events"
>  
>  #define KPROBES			"kprobes"
>  #define SYSCALLS		"syscalls"
> @@ -64,6 +64,7 @@ static const dtrace_pattr_t	pattr = {
>  static int populate(dtrace_hdl_t *dtp)
>  {
>  	dt_provider_t	*prv;
> +	int		fd;
>  	FILE		*f;
>  	char		*buf = NULL;
>  	char		*p;
> @@ -73,7 +74,11 @@ static int populate(dtrace_hdl_t *dtp)
>  	if (prv == NULL)
>  		return -1;			/* errno already set */
>  
> -	f = fopen(PROBE_LIST, "r");
> +	fd = dt_tracefs_open(dtp, PROBE_LIST, O_RDONLY);
> +	if (fd < 0)
> +		return 0;
> +
> +	f = fdopen(fd, "r");
>  	if (f == NULL)
>  		return 0;
>  
> diff --git a/libdtrace/dt_prov_sdt.c b/libdtrace/dt_prov_sdt.c
> index 675e0458ca4c..7ebe010efa79 100644
> --- a/libdtrace/dt_prov_sdt.c
> +++ b/libdtrace/dt_prov_sdt.c
> @@ -36,7 +36,7 @@
>  static const char		prvname[] = "sdt";
>  static const char		modname[] = "vmlinux";
>  
> -#define PROBE_LIST		TRACEFS "available_events"
> +#define PROBE_LIST		"available_events"
>  
>  #define KPROBES			"kprobes"
>  #define SYSCALLS		"syscalls"
> @@ -62,6 +62,7 @@ static const dtrace_pattr_t	pattr = {
>  static int populate(dtrace_hdl_t *dtp)
>  {
>  	dt_provider_t	*prv;
> +	int		fd;
>  	FILE		*f;
>  	char		*buf = NULL;
>  	char		*p;
> @@ -71,7 +72,11 @@ static int populate(dtrace_hdl_t *dtp)
>  	if (prv == NULL)
>  		return -1;			/* errno already set */
>  
> -	f = fopen(PROBE_LIST, "r");
> +	fd = dt_tracefs_open(dtp, PROBE_LIST, O_RDONLY);
> +	if (fd < 0)
> +		return 0;
> +
> +	f = fdopen(fd, "r");
>  	if (f == NULL)
>  		return 0;
>  
> @@ -192,16 +197,16 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
>  static int probe_info_tracefs(dtrace_hdl_t *dtp, const dt_probe_t *prp,
>  			      int *argcp, dt_argdesc_t **argvp)
>  {
> +	int				fd;
>  	FILE				*f;
> -	char				*fn;
>  	int				rc;
>  	const dtrace_probedesc_t	*pdp = prp->desc;
>  
> -	if (asprintf(&fn, EVENTSFS "%s/%s/format", pdp->mod, pdp->prb) == -1)
> -		return dt_set_errno(dtp, EDT_NOMEM);
> +	fd = dt_tracefs_open(dtp, "events/%s/%s/format", O_RDONLY, pdp->mod, pdp->prb);
> +	if (fd < 0)
> +		return -ENOENT;
>  
> -	f = fopen(fn, "r");
> -	free(fn);
> +	f = fdopen(fd, "r");
>  	if (!f)
>  		return -ENOENT;
>  
> @@ -223,15 +228,18 @@ static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
>  	int			argc = 0;
>  	dt_argdesc_t		*argv = NULL;
>  	dtrace_typeinfo_t	sym;
> +	int			fd;
>  	FILE			*f;
>  	uint32_t		id;
>  
>  	/* Retrieve the event id. */
> -	if (asprintf(&str, EVENTSFS "%s/%s/id", prp->desc->mod, prp->desc->prb) == -1)
> -		return dt_set_errno(dtp, EDT_NOMEM);
>  
> -	f = fopen(str, "r");
> -	free(str);
> +	fd = dt_tracefs_open(dtp, "events/%s/%s/id", O_RDONLY,
> +			     prp->desc->mod, prp->desc->prb);
> +	if (fd < 0)
> +		return dt_set_errno(dtp, EDT_ENABLING_ERR);
> +
> +	f = fdopen(fd, "r");
>  	if (!f)
>  		return dt_set_errno(dtp, EDT_ENABLING_ERR);
>  
> diff --git a/libdtrace/dt_prov_syscall.c b/libdtrace/dt_prov_syscall.c
> index 20843c6f538e..63ce3bc43ae1 100644
> --- a/libdtrace/dt_prov_syscall.c
> +++ b/libdtrace/dt_prov_syscall.c
> @@ -38,7 +38,7 @@
>  static const char		prvname[] = "syscall";
>  static const char		modname[] = "vmlinux";
>  
> -#define SYSCALLSFS		EVENTSFS "syscalls/"
> +#define SYSCALLSFS		"events/syscalls/"
>  
>  /*
>   * We need to skip over an extra field: __syscall_nr.
> @@ -61,7 +61,7 @@ struct syscall_data {
>  
>  #define SCD_ARG(n)	offsetof(struct syscall_data, arg[n])
>  
> -#define PROBE_LIST	TRACEFS "available_events"
> +#define PROBE_LIST	"available_events"
>  
>  #define PROV_PREFIX	"syscalls:"
>  #define ENTRY_PREFIX	"sys_enter_"
> @@ -71,6 +71,7 @@ struct syscall_data {
>  static int populate(dtrace_hdl_t *dtp)
>  {
>  	dt_provider_t	*prv;
> +	int		fd;
>  	FILE		*f;
>  	char		*buf = NULL;
>  	size_t		n;
> @@ -79,7 +80,11 @@ static int populate(dtrace_hdl_t *dtp)
>  	if (prv == NULL)
>  		return -1;			/* errno already set */
>  
> -	f = fopen(PROBE_LIST, "r");
> +	fd = dt_tracefs_open(dtp, PROBE_LIST, O_RDONLY);
> +	if (fd < 0)
> +		return 0;
> +
> +	f = fdopen(fd, "r");
>  	if (f == NULL)
>  		return 0;
>  
> @@ -195,23 +200,21 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
>  static int probe_info(dtrace_hdl_t *dtp, const dt_probe_t *prp,
>  		      int *argcp, dt_argdesc_t **argvp)
>  {
> +	int		fd;
>  	FILE		*f;
> -	char		fn[256];
>  	int		rc;
>  
>  	/*
>  	 * We know that the probe name is either "entry" or "return", so we can
>  	 * just check the first character.
>  	 */
> -	strcpy(fn, SYSCALLSFS);
> -	if (prp->desc->prb[0] == 'e')
> -		strcat(fn, "sys_enter_");
> -	else
> -		strcat(fn, "sys_exit_");
> -	strcat(fn, prp->desc->fun);
> -	strcat(fn, "/format");
> +	fd = dt_tracefs_open(dtp, SYSCALLSFS "/sys_%s_%s/format", O_RDONLY,
> +			     (prp->desc->prb[0] == 'e') ? "enter" : "exit",
> +			     prp->desc->fun);
> +	if (fd < 0)
> +		return -ENOENT;
>  
> -	f = fopen(fn, "r");
> +	f = fdopen(fd, "r");
>  	if (!f)
>  		return -ENOENT;
>  
> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
> index 205014617586..6a02243ff572 100644
> --- a/libdtrace/dt_prov_uprobe.c
> +++ b/libdtrace/dt_prov_uprobe.c
> @@ -1116,13 +1116,13 @@ static char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int flags)
>   * uprobe may be a uretprobe.  Return the probe's name as
>   * a new dynamically-allocated string, or NULL on error.
>   */
> -static char *uprobe_create(dev_t dev, ino_t ino, const char *mapping_fn,
> -			   uint64_t addr, int flags)
> +static char *uprobe_create(dtrace_hdl_t *dtp, dev_t dev, ino_t ino,
> +			   const char *mapping_fn, uint64_t addr, int flags)
>  {
> -	int	fd = -1;
> -	int	rc = -1;
> -	char	*name;
> -	char	*spec;
> +	int		fd = -1;
> +	int		rc = -1;
> +	char		*name;
> +	char		*spec;
>  
>  	if (asprintf(&spec, "%s:0x%lx", mapping_fn, addr) < 0)
>  		return NULL;
> @@ -1132,8 +1132,8 @@ static char *uprobe_create(dev_t dev, ino_t ino, const char *mapping_fn,
>  		goto out;
>  
>  	/* Add the uprobe. */
> -	fd = open(TRACEFS "uprobe_events", O_WRONLY | O_APPEND);
> -	if (fd == -1)
> +	fd = dt_tracefs_open(dtp, "uprobe_events", O_WRONLY | O_APPEND);
> +	if (fd < 0)
>  		goto out;
>  
>  	rc = dprintf(fd, "%c:%s %s\n", flags & PP_IS_RETURN ? 'r' : 'p', name, spec);
> @@ -1153,8 +1153,8 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *uprp, int bpf_fd)
>  {
>  	dt_uprobe_t	*upp = uprp->prv_data;
>  	tp_probe_t	*tpp = upp->tp;
> +	int		fd;
>  	FILE		*f;
> -	char		*fn;
>  	char		*prb = NULL;
>  	int		rc = -1;
>  
> @@ -1163,7 +1163,7 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *uprp, int bpf_fd)
>  
>  	assert(upp->fn != NULL);
>  
> -	prb = uprobe_create(upp->dev, upp->inum, upp->fn, upp->off,
> +	prb = uprobe_create(dtp, upp->dev, upp->inum, upp->fn, upp->off,
>  			    upp->flags);
>  
>  	/*
> @@ -1177,12 +1177,12 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *uprp, int bpf_fd)
>  				  upp->flags);
>  
>  	/* open format file */
> -	rc = asprintf(&fn, "%s%s/format", EVENTSFS, prb);
> +	fd = dt_tracefs_open(dtp, "events/%s/format", O_RDONLY, prb);
>  	free(prb);
> -	if (rc < 0)
> +	if (fd < 0)
>  		return -ENOENT;
> -	f = fopen(fn, "r");
> -	free(fn);
> +
> +	f = fdopen(fd, "r");
>  	if (f == NULL)
>  		return -ENOENT;
>  
> @@ -1251,21 +1251,20 @@ done:
>   * Destroy a uprobe for a given device and address.
>   */
>  static int
> -uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int flags)
> +uprobe_delete(dtrace_hdl_t *dtp, dev_t dev, ino_t ino, uint64_t addr, int flags)
>  {
> -	int	fd = -1;
> -	int	rc = -1;
> -	char	*name;
> +	int		fd = -1;
> +	int		rc = -1;
> +	char		*name;
>  
>  	name = uprobe_name(dev, ino, addr, flags);
>  	if (!name)
>  		goto out;
>  
> -	fd = open(TRACEFS "uprobe_events", O_WRONLY | O_APPEND);
> +	fd = dt_tracefs_open(dtp, "uprobe_events", O_WRONLY | O_APPEND);
>  	if (fd == -1)
>  		goto out;
>  
> -
>  	rc = dprintf(fd, "-:%s\n", name);
>  
>  out:
> @@ -1297,7 +1296,7 @@ static void detach(dtrace_hdl_t *dtp, const dt_probe_t *uprp)
>  
>  	dt_tp_detach(dtp, tpp);
>  
> -	uprobe_delete(upp->dev, upp->inum, upp->off, upp->flags);
> +	uprobe_delete(dtp, upp->dev, upp->inum, upp->off, upp->flags);
>  }
>  
>  /*
> diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h
> index 8f143dceaed7..4598a380b950 100644
> --- a/libdtrace/dt_provider.h
> +++ b/libdtrace/dt_provider.h
> @@ -12,7 +12,6 @@
>  #include <dt_impl.h>
>  #include <dt_ident.h>
>  #include <dt_list.h>
> -#include <tracefs.h>
>  
>  #ifdef	__cplusplus
>  extern "C" {
> diff --git a/libdtrace/dt_subr.c b/libdtrace/dt_subr.c
> index d5dca164861e..f129e5591465 100644
> --- a/libdtrace/dt_subr.c
> +++ b/libdtrace/dt_subr.c
> @@ -20,6 +20,7 @@
>  #include <assert.h>
>  #include <limits.h>
>  #include <sys/ioctl.h>
> +#include <mntent.h>
>  #include <port.h>
>  
>  #include <dt_impl.h>
> @@ -998,3 +999,82 @@ uint32_t dt_gen_hval(const char *p, uint32_t hval, size_t len)
>  
>  	return hval;
>  }
> +
> +/*
> + * Find the tracefs and store it away in dtp.
> + */
> +static int
> +find_tracefs_path(dtrace_hdl_t *dtp)
> +{
> +	FILE *mounts;
> +	struct mntent *mnt;
> +
> +	if ((mounts = setmntent("/proc/mounts", "r")) == NULL) {
> +		dt_dprintf("Cannot open /proc/mounts: %s\n", strerror(errno));
> +		return dt_set_errno(dtp, EDT_TRACEFS);
> +	}
> +
> +	while ((mnt = getmntent(mounts)) != NULL) {
> +		/*
> +		 * Only accept tracefs paths that do not contain percent
> +		 * characters in their mounted paths, since we use this
> +		 * to augment a format string in dt_tracefs_vfn().
> +		 */
> +		if ((strcmp(mnt->mnt_type, "tracefs") == 0) &&
> +		    (strchr(mnt->mnt_dir, '%') == NULL)) {
> +			dtp->dt_tracefs_path = strdup(mnt->mnt_dir);
> +			break;
> +		}
> +	}
> +	endmntent(mounts);
> +
> +	if (!dtp->dt_tracefs_path) {
> +		dt_dprintf("Cannot find a suitable tracefs path.\n");
> +		return dt_set_errno(dtp, EDT_TRACEFS);
> +	}
> +
> +	dt_dprintf("Found tracefs at %s\n", dtp->dt_tracefs_path);
> +
> +	return 0;
> +}
> +
> +static char *
> +dt_tracefs_vfn(dtrace_hdl_t *dtp, const char *fn, va_list ap)
> +{
> +	char *full_fn;
> +	char *str;
> +
> +	if (!dtp->dt_tracefs_path)
> +		if (find_tracefs_path(dtp) < 0)
> +			return NULL;		/* errno is set for us. */
> +
> +	if (asprintf(&full_fn, "%s/%s", dtp->dt_tracefs_path, fn) < 0) {
> +		dt_set_errno(dtp, EDT_NOMEM);
> +		return NULL;
> +	}
> +
> +	if (vasprintf(&str, full_fn, ap) < 0) {
> +		str = NULL;
> +		dt_set_errno(dtp, EDT_NOMEM);
> +	}
> +	free(full_fn);
> +	return str;
> +}
> +
> +int
> +dt_tracefs_open(dtrace_hdl_t *dtp, const char *fn, int flags, ...)
> +{
> +	va_list ap;
> +	char *str;
> +	int fd;
> +
> +	va_start(ap, flags);
> +	if ((str = dt_tracefs_vfn(dtp, fn, ap)) == NULL) {
> +		va_end(ap);
> +		return -1; 			/* errno is set for us. */
> +	}
> +
> +	fd = open(str, flags, 0666);
> +	free(str);
> +	return fd;				/* errno is set for us. */
> +}
> diff --git a/runtest.sh b/runtest.sh
> index 46b532d7e161..fbf4e60c82a9 100755
> --- a/runtest.sh
> +++ b/runtest.sh
> @@ -607,6 +607,14 @@ elif ! /usr/bin/cpp -x c -fno-show-column - /dev/null < /dev/null 2>&1 | \
>      export DTRACE_OPT_CPPARGS="-fno-show-column"
>  fi
>  
> +# Find the tracefs.
> +tracefs="$(awk '$3 == "tracefs" { print $2; exit; }' /proc/mounts)"
> +if [[ -z $tracefs ]]; then
> +    echo "Cannot find any tracefs mounts in /proc/mounts.  Some tests will fail." >&2
> +fi
> +
> +export tracefs
> +
>  # More than one dtrace tree -> run tests for all dtraces, and verify identical
>  # intermediate code is produced by each dtrace.
>  
> diff --git a/test/unittest/funcs/tst.rw_.x b/test/unittest/funcs/tst.rw_.x
> index 29c581116154..5737c7575a26 100755
> --- a/test/unittest/funcs/tst.rw_.x
> +++ b/test/unittest/funcs/tst.rw_.x
> @@ -1,6 +1,11 @@
>  #!/bin/sh
>  
> -FUNCS=/sys/kernel/debug/tracing/available_filter_functions
> +FUNCS=${tracefs}/available_filter_functions
> +
> +if [[ ! -e $FUNCS ]]; then
> +	echo no tracefs found
> +	exit 1
> +fi
>  
>  if ! grep -qw  _raw_read_lock $FUNCS; then
>          echo no _raw_read_lock FBT probe due to kernel config
> diff --git a/test/unittest/providers/tst.dtrace_cleanup.sh b/test/unittest/providers/tst.dtrace_cleanup.sh
> index 4ac59ccb4315..f3e434ae76fc 100755
> --- a/test/unittest/providers/tst.dtrace_cleanup.sh
> +++ b/test/unittest/providers/tst.dtrace_cleanup.sh
> @@ -1,7 +1,7 @@
>  #!/bin/bash
>  #
>  # Oracle Linux DTrace.
> -# Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
> +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
>  # Licensed under the Universal Permissive License v 1.0 as shown at
>  # http://oss.oracle.com/licenses/upl.
>  
> @@ -14,7 +14,12 @@
>  ##
>  
>  dtrace=$1
> -UPROBE_EVENTS=/sys/kernel/debug/tracing/uprobe_events
> +UPROBE_EVENTS=${tracefs}/uprobe_events
> +
> +if [[ ! -e $UPROBE_EVENTS ]]; then
> +	echo "no tracefs/uprobe_events" >&2
> +	exit 67
> +fi
>  
>  out=/tmp/output.$$
>  $dtrace $dt_flags -n BEGIN,END &>> $out &
> diff --git a/test/utils/clean_probes.sh b/test/utils/clean_probes.sh
> index 8292b3096424..cfd100088eb7 100755
> --- a/test/utils/clean_probes.sh
> +++ b/test/utils/clean_probes.sh
> @@ -1,9 +1,13 @@
>  #!/usr/bin/bash
>  
> -TRACEFS=/sys/kernel/debug/tracing
> -EVENTS=${TRACEFS}/available_events
> -KPROBES=${TRACEFS}/kprobe_events
> -UPROBES=${TRACEFS}/uprobe_events
> +EVENTS=${tracefs}/available_events
> +KPROBES=${tracefs}/kprobe_events
> +UPROBES=${tracefs}/uprobe_events
> +
> +# We can't work without the tracefs: just give up quietly.
> +if [[ ! -e $EVENTS ]]; then
> +    exit 0
> +fi
>  
>  # Check permissions
>  if [[ ! -r ${EVENTS} ]]; then
> -- 
> 2.46.0.278.g36e3a12567
> 



More information about the DTrace-devel mailing list