Introduce a DBus server thread that runs alongside the other virtiofsd threads. It processes changes to the /org/qemu/virtiofsd object which can be accessed at the org.qemu.virtiofsd location on the bus.
This code does not use locking because we are the only writer to the int current_log_level variable. More advanced management commands would require locking to prevent race conditions with the other threads. Signed-off-by: Stefan Hajnoczi <stefa...@redhat.com> --- contrib/virtiofsd/Makefile.objs | 3 +- contrib/virtiofsd/dbus.h | 9 ++ contrib/virtiofsd/dbus.c | 162 +++++++++++++++++++++++++++++ contrib/virtiofsd/passthrough_ll.c | 8 +- 4 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 contrib/virtiofsd/dbus.h create mode 100644 contrib/virtiofsd/dbus.c diff --git a/contrib/virtiofsd/Makefile.objs b/contrib/virtiofsd/Makefile.objs index 9b2af1bc23..d59ab60f3d 100644 --- a/contrib/virtiofsd/Makefile.objs +++ b/contrib/virtiofsd/Makefile.objs @@ -8,7 +8,8 @@ virtiofsd-obj-y = buffer.o \ helper.o \ passthrough_ll.o \ seccomp.o \ - gdbus_generated.o + gdbus_generated.o \ + dbus.o seccomp.o-cflags := $(SECCOMP_CFLAGS) seccomp.o-libs := $(SECCOMP_LIBS) diff --git a/contrib/virtiofsd/dbus.h b/contrib/virtiofsd/dbus.h new file mode 100644 index 0000000000..aa18e47408 --- /dev/null +++ b/contrib/virtiofsd/dbus.h @@ -0,0 +1,9 @@ +#ifndef DBUS_H +#define DBUS_H + +#include <stdbool.h> + +bool setup_dbus(void); +void cleanup_dbus(void); + +#endif /* DBUS_H */ diff --git a/contrib/virtiofsd/dbus.c b/contrib/virtiofsd/dbus.c new file mode 100644 index 0000000000..bc2308e34b --- /dev/null +++ b/contrib/virtiofsd/dbus.c @@ -0,0 +1,162 @@ +#include <assert.h> +#include <stdio.h> +#include <glib.h> +#include "fuse_log.h" +#include "dbus.h" +#include "gdbus_generated.h" + +static GThread *the_dbus_thread; +static GMainContext *the_dbus_context; +static GMainLoop *the_dbus_loop; + +/* Set the string property based on the current log level */ +static void refresh_log_level(Virtiofsd *virtiofsd) +{ + switch (current_log_level) { + case LOG_ERR: + virtiofsd_set_log_level(virtiofsd, "err"); + break; + case LOG_WARNING: + virtiofsd_set_log_level(virtiofsd, "warning"); + break; + case LOG_INFO: + virtiofsd_set_log_level(virtiofsd, "info"); + break; + case LOG_DEBUG: + virtiofsd_set_log_level(virtiofsd, "debug"); + break; + } +} + +/* Handle changes to Virtiofsd object properties */ +static void notify(GObject *object, GParamSpec *pspec) +{ + Virtiofsd *virtiofsd = VIRTIOFSD(object); + + fprintf(stderr, "%s %s\n", __func__, pspec->name); + + if (strcmp(pspec->name, "log-level") == 0) { + const char *s = virtiofsd_get_log_level(virtiofsd); + + if (strcmp(s, "err") == 0) { + current_log_level = LOG_ERR; + } else if (strcmp(s, "warning") == 0) { + current_log_level = LOG_WARNING; + } else if (strcmp(s, "info") == 0) { + current_log_level = LOG_INFO; + } else if (strcmp(s, "debug") == 0) { + current_log_level = LOG_DEBUG; + } else { + /* Invalid, reset the log level property */ + refresh_log_level(virtiofsd); + } + } +} + +typedef struct { + Virtiofsd *virtiofsd; + pthread_barrier_t *started; +} GBusOwnNameData; + +static void bus_acquired(GDBusConnection *connection, const gchar *name, + gpointer user_data) +{ + GBusOwnNameData *data = user_data; + GError *error = NULL; + + if (!g_dbus_interface_skeleton_export( + G_DBUS_INTERFACE_SKELETON(data->virtiofsd), + connection, "/org/qemu/virtiofsd", &error)) { + fuse_err("g_dbus_interface_skeleton_export: %s\n", error->message); + g_error_free(error); + exit(EXIT_FAILURE); + } +} + +static void name_acquired(GDBusConnection *connection, const gchar *name, + gpointer user_data) +{ + GBusOwnNameData *data = user_data; + + pthread_barrier_wait(data->started); +} + +static void name_lost(GDBusConnection *connection, const gchar *name, + gpointer user_data) +{ + if (connection) { + fuse_err("unable to own dbus name\n"); + } else { + fuse_err("unable to connect to dbus\n"); + } + exit(EXIT_FAILURE); +} + +static gpointer dbus_thread(gpointer opaque) +{ + GBusOwnNameData data; + Virtiofsd *virtiofsd; + guint owner_id; + + g_main_context_push_thread_default(the_dbus_context); + + virtiofsd = virtiofsd_skeleton_new(); + refresh_log_level(virtiofsd); + g_signal_connect(virtiofsd, "notify", G_CALLBACK(notify), NULL); + + data.virtiofsd = virtiofsd; + data.started = opaque; + + owner_id = g_bus_own_name(G_BUS_TYPE_SESSION, "org.qemu.virtiofsd", + G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE, bus_acquired, name_acquired, + name_lost, &data, NULL); + + g_main_loop_run(the_dbus_loop); + g_bus_unown_name(owner_id); + g_object_unref(virtiofsd); + + g_main_context_pop_thread_default(the_dbus_context); + return NULL; +} + +/** + * Start DBus server thread. + * + * Returns: true on success, false on failure + */ +bool setup_dbus(void) +{ + pthread_barrier_t started; + + assert(!the_dbus_thread); + + fuse_info("Using dbus address %s\n", + getenv("DBUS_SESSION_BUS_ADDRESS") ?: "(null)"); + + pthread_barrier_init(&started, NULL, 2); + + the_dbus_context = g_main_context_new(); + the_dbus_loop = g_main_loop_new(the_dbus_context, FALSE); + the_dbus_thread = g_thread_new("dbus-thread", dbus_thread, &started); + + pthread_barrier_wait(&started); + pthread_barrier_destroy(&started); + + return true; +} + +/** + * Stop DBus server thread. + */ +void cleanup_dbus(void) +{ + g_main_loop_quit(the_dbus_loop); + g_thread_join(the_dbus_thread); + the_dbus_thread = NULL; + + g_main_loop_unref(the_dbus_loop); + the_dbus_loop = NULL; + + g_main_context_unref(the_dbus_context); + the_dbus_context = NULL; +} diff --git a/contrib/virtiofsd/passthrough_ll.c b/contrib/virtiofsd/passthrough_ll.c index 0ef01b7e3f..0ddd7d280a 100644 --- a/contrib/virtiofsd/passthrough_ll.c +++ b/contrib/virtiofsd/passthrough_ll.c @@ -66,6 +66,7 @@ #include <gmodule.h> #include "fuse_log.h" #include "seccomp.h" +#include "dbus.h" /* Keep track of inode posix locks for each owner. */ struct lo_inode_plock { @@ -2989,6 +2990,9 @@ int main(int argc, char *argv[]) if (fuse_session_mount(se) != 0) goto err_out3; + if (!setup_dbus()) + goto err_out4; + fuse_daemonize(opts.foreground); if (lo.ireg_sock != -1) { @@ -2998,7 +3002,7 @@ int main(int argc, char *argv[]) if (ret) { warnx("pthread_create: %s", strerror(ret)); ret = 1; - goto err_out4; + goto err_out5; } get_shared(&lo, &lo.root); @@ -3014,6 +3018,8 @@ int main(int argc, char *argv[]) /* Block until ctrl+c or fusermount -u */ ret = virtio_loop(se); +err_out5: + cleanup_dbus(); err_out4: fuse_session_unmount(se); err_out3: -- 2.21.0