Message ID | 20190905152136.30637-3-stefanha@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | virtiofsd: get/set log level via DBus | expand |
* Stefan Hajnoczi (stefanha@redhat.com) wrote: > 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 <stefanha@redhat.com> OK, that is less complex than I'd feared. I guess there's something probably nice to do with name/integer mapping for warning levels that we could use from one of the libraries. Dave > --- > 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 > -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
On Thu, Sep 05, 2019 at 06:27:32PM +0100, Dr. David Alan Gilbert wrote: > * Stefan Hajnoczi (stefanha@redhat.com) wrote: > > 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 <stefanha@redhat.com> > > OK, that is less complex than I'd feared. > I guess there's something probably nice to do with name/integer mapping > for warning levels that we could use from one of the libraries. I used a free-form string because it's what systemd's LogLevel property also does. But I can investigate the cleanest approach for limiting it to a set of string constants. Stefan
On Fri, Sep 06, 2019 at 11:23:28AM +0100, Stefan Hajnoczi wrote: > On Thu, Sep 05, 2019 at 06:27:32PM +0100, Dr. David Alan Gilbert wrote: > > * Stefan Hajnoczi (stefanha@redhat.com) wrote: > > > 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 <stefanha@redhat.com> > > > > OK, that is less complex than I'd feared. > > I guess there's something probably nice to do with name/integer mapping > > for warning levels that we could use from one of the libraries. > > I used a free-form string because it's what systemd's LogLevel property > also does. But I can investigate the cleanest approach for limiting it > to a set of string constants. There's no concept of "enums" at the DBus protocol level. Sending enums in string form is the normal practice - avoiding integer values means you are not vulnerable to enum values changing if someone inserts a new constant in the middlle of the enum. This same reason is why QAPI uses strings for enums instead of ints. Regards, Daniel
* Daniel P. Berrangé (berrange@redhat.com) wrote: > On Fri, Sep 06, 2019 at 11:23:28AM +0100, Stefan Hajnoczi wrote: > > On Thu, Sep 05, 2019 at 06:27:32PM +0100, Dr. David Alan Gilbert wrote: > > > * Stefan Hajnoczi (stefanha@redhat.com) wrote: > > > > 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 <stefanha@redhat.com> > > > > > > OK, that is less complex than I'd feared. > > > I guess there's something probably nice to do with name/integer mapping > > > for warning levels that we could use from one of the libraries. > > > > I used a free-form string because it's what systemd's LogLevel property > > also does. But I can investigate the cleanest approach for limiting it > > to a set of string constants. > > There's no concept of "enums" at the DBus protocol level. Sending enums > in string form is the normal practice - avoiding integer values means > you are not vulnerable to enum values changing if someone inserts a new > constant in the middlle of the enum. This same reason is why QAPI uses > strings for enums instead of ints. Oh, I wasn't talking aobut changing protocol; I just meant there was probably a neater way of doing the string look up than the opencoded way it was done. Dave > Regards, > Daniel > -- > |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| > |: https://libvirt.org -o- https://fstop138.berrange.com :| > |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :| -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
On Fri, Sep 06, 2019 at 12:12:23PM +0100, Dr. David Alan Gilbert wrote: > * Daniel P. Berrangé (berrange@redhat.com) wrote: > > On Fri, Sep 06, 2019 at 11:23:28AM +0100, Stefan Hajnoczi wrote: > > > On Thu, Sep 05, 2019 at 06:27:32PM +0100, Dr. David Alan Gilbert wrote: > > > > * Stefan Hajnoczi (stefanha@redhat.com) wrote: > > > > > 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 <stefanha@redhat.com> > > > > > > > > OK, that is less complex than I'd feared. > > > > I guess there's something probably nice to do with name/integer mapping > > > > for warning levels that we could use from one of the libraries. > > > > > > I used a free-form string because it's what systemd's LogLevel property > > > also does. But I can investigate the cleanest approach for limiting it > > > to a set of string constants. > > > > There's no concept of "enums" at the DBus protocol level. Sending enums > > in string form is the normal practice - avoiding integer values means > > you are not vulnerable to enum values changing if someone inserts a new > > constant in the middlle of the enum. This same reason is why QAPI uses > > strings for enums instead of ints. > > Oh, I wasn't talking aobut changing protocol; I just meant there was > probably a neater way of doing the string look up than the opencoded way > it was done. Oh sure, you can declare the enum in a header, and then run glib-mkenums with that header file and it will spit out the code neccessary to register a GEnum class. This gives you ability to do int/string conversions with a simple api https://developer.gnome.org/gobject/stable/gobject-Enumeration-and-Flag-Types.html https://developer.gnome.org/gobject/stable/glib-mkenums.html It makes sense to use this, since virtiofsd is already using GObject via GDbus. Regards, Daniel
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:
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 <stefanha@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