]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
manager: add GetMallocInfo() hidden/debug method
authorLuca Boccassi <bluca@debian.org>
Thu, 26 Jan 2023 12:51:55 +0000 (12:51 +0000)
committerLuca Boccassi <bluca@debian.org>
Thu, 23 Feb 2023 13:26:52 +0000 (13:26 +0000)
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.

src/core/dbus.c
src/shared/bus-util.c
src/shared/bus-util.h

index c295e1fbd415247c7ee9aeb69741b8860402911e..9ce9ddc8f2a9056391adf1ca65a4291f5a2b1d23 100644 (file)
@@ -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;
index d09ec5148df4bf0b3843cf7c6eac217a61ec0a5f..61ec6661e0b32952773e10deb2d9c916a71339dc 100644 (file)
@@ -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);
 }
index ab553c866ca886d140617a0917f5a681b70d6ca6..6489bfc756db37e1b9aced9d8b16e0e1497469f4 100644 (file)
@@ -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;