Skip to content

Commit

Permalink
daemon: support libfuse 2
Browse files Browse the repository at this point in the history
So it turns out that some people want to use libfuse 2 still, even
though it's been obsoleted by libfuse 3 for nearly a decade.  This turns
out to be not terribly difficult!

There are two major changess that impact us (ignoring the options-
parsing thing fixed in the last commit):

 - libfuse 2 has a 'channel' abstraction in which the fd to the kernel
   is nested.  libfuse 3 dropped it because it turned out there was only
   ever one of them so the abstraction was redundant, but that makes it
   easy for us to pick the fd out: we can grab the fuse_session_next_chan()
   without ever worrying that we might have to call that function more
   than once or deal with more than one channel.

   This changes the main read loop() enough that we can just implement
   it twice.

 - that's good because of another annoying difference: OL carries a
   NUMA-aware API which actually changes the public API of libfuse's
   fuse_session_receive_buf function.  This is hard to check for because
   the extra functions you need to call to actually turn this behaviour
   on were never added to the symbol version file, so you can't link
   with them.  So we detect these functions using the macros just added
   to do straight compilation checking, with no linking, and use their
   presence as a clue that fuse_session_receive_buf has the NUMA-aware
   API change.  (We don't use the NUMA stuff: it's only useful if you're
   using a multithreaded event loop, which we're not.)

We currently handle systems with both libfuse 2 and 3 by checking that
libfuse 3 is available, and if not, falling back to libfuse 2 (and if
that isn't present either you get a link failure).  Thus libfuse 3 is
preferred if both are present.  There is an additional libfuse2=yes
build option if you want to force the use of the old libfuse even when
the newer one is present.

One extra bit of complexity: we call pkg-config on whatever libfuse we
hope is present, and this emits very noisy multi-line error messages if
it isn't present: so suppress execution of all the dtprobed build rules
until the tree is configured and we have some idea of which libfuse is
there.

Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees@oracle.com>
  • Loading branch information
nickalcock authored and kvanhees committed Nov 8, 2022
1 parent c47002c commit 7ff38c7
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 8 deletions.
4 changes: 4 additions & 0 deletions Makeconfig
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,9 @@ $(eval $(call check-symbol-rule,LIBCTF,ctf_open,ctf))
$(eval $(call check-symbol-rule,STRRSTR,strrstr,c))
$(eval $(call check-symbol-rule,WAITFD,waitfd,c))
$(eval $(call check-symbol-rule,LIBSYSTEMD,sd_notify,systemd))
ifndef WANTS_LIBFUSE2
$(eval $(call check-symbol-rule,FUSE_LOG,fuse_set_log_func,fuse3))
$(eval $(call check-symbol-rule,LIBFUSE3,fuse_session_receive_buf,fuse3))
endif
$(eval $(call check-header-rule,FUSE_NUMA,fuse_set_numa,fuse/fuse_lowlevel))
$(eval $(call check-header-symbol-rule,CLOSE_RANGE,close_range(3,~0U,0),c,unistd))
9 changes: 8 additions & 1 deletion Makeoptions
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ debugging ?= no
dof_dbg ?= no
coverage ?= no
verbose ?= no
libfuse2 ?= no

help::
@printf "Options:\n\n" >&2
@printf "make debugging=yes [targets] Disable optimization to make debugger use easier\n" >&2
@printf "make coverage=yes [targets] Turn on coverage support in the testsuite\n" >&2
@printf "make verbose=yes [target] Enable verbose building\n" >&2
@printf "make dof_dbg=yes [targets] Turn on especially noisy DOF parser debugging\n" >&2
@printf "make dof_dbg=yes [targets] Turn on especially noisy DOF parser debugging\n\n" >&2
@printf "Dependencies:\n\n" >&2
@printf "make libfuse2=yes [targets] Build against libfuse 2 even if libfuse 3 is found\n" >&2
@printf "\n" >&2

ifneq ($(debugging),no)
Expand All @@ -34,3 +37,7 @@ endif
ifeq ($(verbose),no)
override MAKEFLAGS += --silent
endif

ifneq ($(libfuse2),no)
override WANTS_LIBFUSE2 = yes
endif
20 changes: 18 additions & 2 deletions dtprobed/Build
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,28 @@
# Licensed under the Universal Permissive License v 1.0 as shown at
# http://oss.oracle.com/licenses/upl.

# Temporarily suppress dtprobed builds before configury is done: we don't know
# which fuse is safe to even look up with pkg-config without ugly messages.
ifdef CONFIGURED
CMDS += dtprobed

# Support FUSE 2 as well as FUSE 3: use if explicitly requested or if
# FUSE 3 is not found.
ifdef WANTS_LIBFUSE2
LIBFUSE := fuse
else
ifndef HAVE_LIBFUSE3
LIBFUSE := fuse
else
LIBFUSE := fuse3
endif
endif

dtprobed_DIR := $(current-dir)
dtprobed_TARGET = dtprobed
dtprobed_CPPFLAGS := -I. -Idtprobed -Ilibproc -Ilibcommon -Ilibport
dtprobed_CFLAGS := $(shell pkg-config --cflags fuse3)
dtprobed_LIBS := -lcommon -lproc -lcommon -lport -lelf $(shell pkg-config --libs fuse3)
dtprobed_CFLAGS := $(shell pkg-config --cflags $(LIBFUSE))
dtprobed_LIBS := -lcommon -lproc -lcommon -lport -lelf $(shell pkg-config --libs $(LIBFUSE))
dtprobed_DEPS := libproc.a libcommon.a libport.a
dtprobed_SOURCES := dtprobed.c
dtprobed_LIBSOURCES := libproc libcommon
Expand All @@ -24,6 +39,7 @@ dtprobed_SOURCES += rpl_fuse_log.c
endif

dtprobed.c_CFLAGS := -Wno-pedantic
endif

install::
mkdir -p $(INSTSBINDIR)
Expand Down
88 changes: 87 additions & 1 deletion dtprobed/dtprobed.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,18 @@
#include <linux/seccomp.h>
#include <sys/syscall.h>

/*
* Compatibility. With libfuse 3, we use a few newer features that need at
* least version 31 (3.2.0): with libfuse 2, the default will suffice. We also
* use the logging infrastructure added in libfuse 3.7, but provide an alternate
* implementation if not available.
*/

#if HAVE_LIBFUSE3
#define FUSE_USE_VERSION 31
#else /* libfuse 2 */
/* Use the default (21). */
#endif

#include <cuse_lowlevel.h>
#include <fuse_lowlevel.h>
Expand Down Expand Up @@ -93,6 +104,28 @@ dt_debug_printf(const char *subsys, const char *fmt, va_list ap)
}
}

#if HAVE_LIBFUSE3
static int
session_fd(struct fuse_session *cuse_session)
{
return fuse_session_fd(cuse_session);
}
#else /* libfuse 2 */
static struct fuse_chan *cuse_chan;

static void
init_cuse_chan(struct fuse_session *cuse_session)
{
cuse_chan = fuse_session_next_chan(cuse_session, NULL);
}

static int
session_fd(struct fuse_session *cuse_session)
{
return fuse_chan_fd(cuse_chan);
}
#endif

/*
* States for the ioctl processing loop, which gets repeatedly called due to the
* request/reply nature of unrestricted FUSE ioctls.
Expand Down Expand Up @@ -141,6 +174,10 @@ setup_helper_device(int argc, char **argv, char *devname, dtprobed_userdata_t *u
return NULL;
}

#ifndef HAVE_LIBFUSE3 /* libfuse 2 */
init_cuse_chan(cs);
#endif

if (multithreaded) {
fprintf(stderr, "CUSE thinks dtprobed is multithreaded!\n");
fprintf(stderr, "This should never happen.\n");
Expand Down Expand Up @@ -202,7 +239,7 @@ dof_parser_start(int sync_fd)
* Sandboxed parser child. Close unwanted fds and nail into
* seccomp jail.
*/
close(fuse_session_fd(cuse_session));
close(session_fd(cuse_session));
close(parser_in_pipe[1]);
close(parser_out_pipe[0]);
if (!foreground)
Expand Down Expand Up @@ -507,6 +544,7 @@ process_dof(fuse_req_t req, int out, int in, pid_t pid,
return -1;
}

#if HAVE_LIBFUSE3
static int
loop(void)
{
Expand Down Expand Up @@ -538,6 +576,54 @@ loop(void)
fuse_session_reset(cuse_session);
return ret < 0 ? -1 : 0;
}
#else /* libfuse 2 */
static int
loop(void)
{
struct pollfd fds[1];
void *buf;
size_t bufsize;
int ret = 0;

bufsize = fuse_chan_bufsize(cuse_chan);
buf = malloc(bufsize);
if (!buf) {
fprintf(stderr, "Cannot allocate memory for FUSE buffer\n");
return -1;
}

fds[0].fd = fuse_chan_fd(cuse_chan);
fds[0].events = POLLIN;

while (!fuse_session_exited(cuse_session)) {
struct fuse_buf fbuf = { .mem = buf, .size = bufsize };
struct fuse_chan *tmpch = cuse_chan;

if ((ret = poll(fds, 1, -1)) < 0)
break;

if (fds[0].revents != 0) {
if ((ret = fuse_session_receive_buf(cuse_session,
&fbuf, &tmpch)) <= 0) {
if (ret == -EINTR)
continue;

break;
}

#ifdef HAVE_FUSE_NUMA
fuse_session_process_buf(cuse_session, &fbuf, tmpch, 0);
#else
fuse_session_process_buf(cuse_session, &fbuf, tmpch);
#endif
}
}

free(buf);
fuse_session_reset(cuse_session);
return ret < 0 ? -1 : 0;
}
#endif

static void
usage(void)
Expand Down
20 changes: 16 additions & 4 deletions dtrace.spec
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,18 @@ BuildRequires: rpm
Name: dtrace
License: Universal Permissive License (UPL), Version 1.0
Group: Development/Tools
Requires: cpp elfutils-libelf zlib libpcap fuse3 >= 3.2.0
BuildRequires: glibc-headers bison flex zlib-devel elfutils-libelf-devel fuse3-devel >= 3.2.0 systemd systemd-devel
Requires: cpp elfutils-libelf zlib libpcap
BuildRequires: glibc-headers bison flex zlib-devel elfutils-libelf-devel systemd systemd-devel
BuildRequires: glibc-static %{glibc32} wireshark libpcap-devel valgrind-devel
%if "%{?dist}" == ".el7"
Requires: fuse
BuildRequires: fuse-devel
%define maybe_use_fuse2 libfuse2=yes
%else
Requires: fuse3 >= 3.2.0
BuildRequires: fuse3-devel >= 3.2.0
%define maybe_use_fuse2 %{nil}
%endif
%{?systemd_requires}
BuildRequires: kernel%{variant}-devel = %{build_kernel}
%if "%{?dist}" == ".el8"
Expand All @@ -76,7 +85,7 @@ Conflicts: systemtap-sdt-devel
Provides: systemtap-sdt-devel
Summary: DTrace user interface.
Version: 2.0.0
Release: 1.11%{?dist}
Release: 1.11.1%{?dist}
Source: dtrace-%{version}.tar.bz2
BuildRoot: %{_tmppath}/%{name}-%{version}-build
ExclusiveArch: x86_64 aarch64
Expand Down Expand Up @@ -156,7 +165,7 @@ it always tests the installed DTrace.
%build
make -j $(getconf _NPROCESSORS_ONLN) VERSION=%{version} \
KERNELDIRPREFIX=/usr/src/kernels KERNELDIRSUFFIX= \
KERNELS="%{kerneldirs}"
KERNELS="%{kerneldirs}" %{maybe_use_fuse2}

# Force off debuginfo splitting. We have no debuginfo in dtrace proper,
# and the testsuite requires debuginfo for proper operation.
Expand Down Expand Up @@ -252,6 +261,9 @@ fi
%{_libdir}/dtrace/testsuite

%changelog
* Tue Nov 08 2022 Kris Van Hees <kris.vna.hees@oracle.com> - 2.0.0-1.11.1
- Support both libfuse 2 and libfuse 3.

* Fri Oct 28 2022 Kris Van Hees <kris.van.hees@oracle.com> - 2.0.0-1.11
- Add initial support for USDT. (Nick Alcock, Kris Van Hees)
- Add support for aggregation keys. (Eugene Loh, Kris Van Hees)
Expand Down

0 comments on commit 7ff38c7

Please sign in to comment.