From: Luca Boccassi Date: Thu, 26 Jan 2023 12:51:55 +0000 (+0000) Subject: manager: add GetMallocInfo() hidden/debug method X-Git-Tag: v254-rc1~1164^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fb22861da1866f7fd47c5d9c3744d527a44e2e06;p=thirdparty%2Fsystemd.git manager: add GetMallocInfo() hidden/debug method Return the output of malloc_info() via a file descriptor (in case it gets large on a busy system). Useful to get live data about memory usage when it is not possible to run under a profiler from the get-go. Do not formally register the method, but add a 'hidden' interface so that it cannot be seen by introspection or by looking at the object. --- diff --git a/src/core/dbus.c b/src/core/dbus.c index c295e1fbd41..9ce9ddc8f2a 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -737,6 +737,10 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void return 0; } + r = bus_register_malloc_status(bus, "org.freedesktop.systemd1"); + if (r < 0) + log_warning_errno(r, "Failed to register MemoryAllocation1, ignoring: %m"); + r = set_ensure_put(&m->private_buses, NULL, bus); if (r == -ENOMEM) { log_oom(); @@ -798,6 +802,10 @@ static int bus_setup_api(Manager *m, sd_bus *bus) { if (r < 0) return log_error_errno(r, "Failed to request name: %m"); + r = bus_register_malloc_status(bus, "org.freedesktop.systemd1"); + if (r < 0) + log_warning_errno(r, "Failed to register MemoryAllocation1, ignoring: %m"); + log_debug("Successfully connected to API bus."); return 0; diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index d09ec5148df..61ec6661e0b 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -18,6 +18,8 @@ #include "bus-internal.h" #include "bus-label.h" #include "bus-util.h" +#include "data-fd-util.h" +#include "fd-util.h" #include "path-util.h" #include "socket-util.h" #include "stdio-util.h" @@ -578,6 +580,62 @@ int bus_reply_pair_array(sd_bus_message *m, char **l) { return sd_bus_send(NULL, reply, NULL); } +static int method_dump_memory_state_by_fd(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { + _cleanup_free_ char *dump = NULL; /* keep this above dump_file, so that it's freed after */ + _cleanup_fclose_ FILE *dump_file = NULL; + _cleanup_close_ int fd = -EBADF; + size_t dump_size; + int r; + + assert(message); + + dump_file = open_memstream(&dump, &dump_size); + if (!dump_file) + return -ENOMEM; + + r = RET_NERRNO(malloc_info(/* options= */ 0, dump_file)); + if (r < 0) + return r; + + dump_file = safe_fclose(dump_file); + + fd = acquire_data_fd(dump, dump_size, 0); + if (fd < 0) + return fd; + + r = sd_bus_reply_method_return(message, "h", fd); + if (r < 0) + return r; + + return 1; /* Stop further processing */ +} + +/* The default install callback will fail and disconnect the bus if it cannot register the match, but this + * is only a debug method, we definitely don't want to fail in case there's some permission issue. */ +static int dummy_install_callback(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { + return 1; +} + +int bus_register_malloc_status(sd_bus *bus, const char *destination) { + const char *match; + int r; + + assert(bus); + assert(!isempty(destination)); + + match = strjoina("type='method_call'," + "interface='org.freedesktop.MemoryAllocation1'," + "path='/org/freedesktop/MemoryAllocation1'," + "destination='", destination, "',", + "member='GetMallocInfo'"); + + r = sd_bus_add_match_async(bus, NULL, match, method_dump_memory_state_by_fd, dummy_install_callback, NULL); + if (r < 0) + return log_debug_errno(r, "Failed to subscribe to GetMallocInfo() calls on MemoryAllocation1 interface: %m"); + + return 0; +} + static void bus_message_unref_wrapper(void *m) { sd_bus_message_unref(m); } diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index ab553c866ca..6489bfc756d 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -63,4 +63,7 @@ static inline int bus_open_system_watch_bind(sd_bus **ret) { int bus_reply_pair_array(sd_bus_message *m, char **l); +/* Listen to GetMallocInfo() calls to 'destination' and return malloc_info() via FD */ +int bus_register_malloc_status(sd_bus *bus, const char *destination); + extern const struct hash_ops bus_message_hash_ops;