[systemd-commits] 5 commits - Makefile.am src/bus-proxyd src/core src/hostname src/libsystemd src/locale src/login src/machine src/network src/shared src/systemctl src/systemd src/timedate

Lennart Poettering lennart at kemper.freedesktop.org
Wed May 14 16:24:01 PDT 2014


 Makefile.am                                   |    2 
 src/bus-proxyd/bus-proxyd.c                   |   16 -
 src/core/dbus-job.c                           |    2 
 src/core/dbus-manager.c                       |   64 ++--
 src/core/dbus-snapshot.c                      |    2 
 src/core/dbus-unit.c                          |    8 
 src/core/dbus.c                               |   33 +-
 src/core/selinux-access.c                     |    2 
 src/core/selinux-access.h                     |   18 -
 src/hostname/hostnamed.c                      |    2 
 src/libsystemd/libsystemd.sym.m4              |   20 -
 src/libsystemd/sd-bus/bus-control.h           |    1 
 src/libsystemd/sd-bus/bus-internal.h          |   64 +++-
 src/libsystemd/sd-bus/bus-match.c             |  110 ++++---
 src/libsystemd/sd-bus/bus-match.h             |   11 
 src/libsystemd/sd-bus/bus-objects.c           |  392 ++++++++------------------
 src/libsystemd/sd-bus/bus-objects.h           |    1 
 src/libsystemd/sd-bus/bus-slot.c              |  244 ++++++++++++++++
 src/libsystemd/sd-bus/bus-slot.h              |   29 +
 src/libsystemd/sd-bus/bus-track.c             |   76 +++--
 src/libsystemd/sd-bus/bus-util.c              |   22 -
 src/libsystemd/sd-bus/bus-util.h              |    4 
 src/libsystemd/sd-bus/busctl.c                |    6 
 src/libsystemd/sd-bus/sd-bus.c                |  330 +++++++++++----------
 src/libsystemd/sd-bus/test-bus-chat.c         |    8 
 src/libsystemd/sd-bus/test-bus-kernel-bloom.c |    2 
 src/libsystemd/sd-bus/test-bus-kernel.c       |    2 
 src/libsystemd/sd-bus/test-bus-match.c        |   59 +--
 src/libsystemd/sd-bus/test-bus-objects.c      |   12 
 src/locale/localed.c                          |    2 
 src/login/logind-seat-dbus.c                  |    2 
 src/login/logind-session-dbus.c               |    2 
 src/login/logind-user-dbus.c                  |    2 
 src/login/logind.c                            |   19 -
 src/machine/machine-dbus.c                    |    2 
 src/machine/machined.c                        |   10 
 src/network/networkd-link.c                   |    2 
 src/shared/hashmap.c                          |   28 +
 src/shared/hashmap.h                          |    1 
 src/systemctl/systemctl.c                     |    8 
 src/systemd/sd-bus.h                          |   43 +-
 src/systemd/sd-event.h                        |    7 
 src/timedate/timedated.c                      |    2 
 43 files changed, 971 insertions(+), 701 deletions(-)

New commits:
commit 19befb2d5fc087f96e40ddc432b2cc9385666209
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu May 15 01:15:30 2014 +0200

    sd-bus: introduce sd_bus_slot objects encapsulating callbacks or vtables attached to a bus connection
    
    This makes callback behaviour more like sd-event or sd-resolve, and
    creates proper object for unregistering callbacks.
    
    Taking the refernce to the slot is optional. If not taken life time of
    the slot will be bound to the underlying bus object (or in the case of
    an async call until the reply has been recieved).

diff --git a/Makefile.am b/Makefile.am
index 653fcfc..89b1d4e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2119,6 +2119,8 @@ libsystemd_internal_la_SOURCES = \
 	src/libsystemd/sd-bus/bus-track.h \
 	src/libsystemd/sd-bus/bus-util.c \
 	src/libsystemd/sd-bus/bus-util.h \
+	src/libsystemd/sd-bus/bus-slot.c \
+	src/libsystemd/sd-bus/bus-slot.h \
 	src/libsystemd/sd-bus/bus-protocol.h \
 	src/libsystemd/sd-bus/kdbus.h \
 	src/libsystemd/sd-bus/sd-memfd.c \
diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index c5f9f00..e095d61 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -40,6 +40,7 @@
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-util.h"
+#include "bus-internal.h"
 #include "build.h"
 #include "strv.h"
 #include "def.h"
@@ -551,7 +552,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
                 if (r < 0)
                         return synthetic_reply_method_errno(m, r, NULL);
 
-                r = sd_bus_add_match(a, match, NULL, NULL);
+                r = sd_bus_add_match(a, NULL, match, NULL, NULL);
                 if (r < 0)
                         return synthetic_reply_method_errno(m, r, NULL);
 
@@ -564,7 +565,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
                 if (r < 0)
                         return synthetic_reply_method_errno(m, r, NULL);
 
-                r = sd_bus_remove_match(a, match, NULL, NULL);
+                r = bus_remove_match_by_string(a, match, NULL, NULL);
+                if (r == 0)
+                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
                 if (r < 0)
                         return synthetic_reply_method_errno(m, r, NULL);
 
@@ -739,9 +742,10 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
                 r = sd_bus_release_name(a, name);
                 if (r < 0) {
                         if (r == -ESRCH)
-                                synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
+                                return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
                         if (r == -EADDRINUSE)
-                                synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
+                                return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
+
                         return synthetic_reply_method_errno(m, r, NULL);
                 }
 
@@ -1177,7 +1181,7 @@ int main(int argc, char *argv[]) {
                         goto finish;
                 }
 
-                r = sd_bus_add_match(a, match, NULL, NULL);
+                r = sd_bus_add_match(a, NULL, match, NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match for NameLost: %s", strerror(-r));
                         goto finish;
@@ -1198,7 +1202,7 @@ int main(int argc, char *argv[]) {
                         goto finish;
                 }
 
-                r = sd_bus_add_match(a, match, NULL, NULL);
+                r = sd_bus_add_match(a, NULL, match, NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match for NameAcquired: %s", strerror(-r));
                         goto finish;
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 189d925..fb8e496 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -310,7 +310,7 @@ static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_
                 sd_bus_message *message;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
@@ -536,58 +536,58 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
         assert(bus);
 
 #ifdef HAVE_SELINUX
-        r = sd_bus_add_filter(bus, selinux_filter, m);
+        r = sd_bus_add_filter(bus, NULL, selinux_filter, m);
         if (r < 0) {
                 log_error("Failed to add SELinux access filter: %s", strerror(-r));
                 return r;
         }
 #endif
 
-        r = sd_bus_add_object_vtable(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
+        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
         if (r < 0) {
                 log_error("Failed to register Manager vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
+        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
         if (r < 0) {
                 log_error("Failed to register Job vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
+        r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
         if (r < 0) {
                 log_error("Failed to add job enumerator: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
+        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
         if (r < 0) {
                 log_error("Failed to register Unit vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
+        r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
         if (r < 0) {
                 log_error("Failed to add job enumerator: %s", strerror(-r));
                 return r;
         }
 
         for (t = 0; t < _UNIT_TYPE_MAX; t++) {
-                r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
+                r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
                 if (r < 0)  {
                         log_error("Failed to register type specific vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                         return r;
                 }
 
                 if (unit_vtable[t]->cgroup_context_offset > 0) {
-                        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
+                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
                         if (r < 0) {
                                 log_error("Failed to register control group unit vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                                 return r;
                         }
 
-                        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
+                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
                         if (r < 0) {
                                 log_error("Failed to register control group vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                                 return r;
@@ -595,7 +595,7 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
                 }
 
                 if (unit_vtable[t]->exec_context_offset > 0) {
-                        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
+                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
                         if (r < 0) {
                                 log_error("Failed to register execute vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                                 return r;
@@ -603,7 +603,7 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
                 }
 
                 if (unit_vtable[t]->kill_context_offset > 0) {
-                        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
+                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
                         if (r < 0) {
                                 log_error("Failed to register kill vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                                 return r;
@@ -622,6 +622,7 @@ static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
 
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "sender='org.freedesktop.DBus.Local',"
                         "type='signal',"
                         "path='/org/freedesktop/DBus/Local',"
@@ -710,6 +711,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
 
                 r = sd_bus_add_match(
                                 bus,
+                                NULL,
                                 "type='signal',"
                                 "interface='org.freedesktop.systemd1.Agent',"
                                 "member='Released',"
@@ -780,6 +782,7 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
 
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "type='signal',"
                         "sender='org.freedesktop.DBus',"
                         "path='/org/freedesktop/DBus',"
@@ -791,6 +794,7 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
 
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "type='signal',"
                         "sender='org.freedesktop.DBus',"
                         "path='/org/freedesktop/DBus',"
@@ -874,6 +878,7 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
          * the system bus */
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "type='signal',"
                         "interface='org.freedesktop.systemd1.Agent',"
                         "member='Released',"
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index 2be6dcd..48cbbdb 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -591,7 +591,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
+        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
         if (r < 0) {
                 log_error("Failed to register object: %s", strerror(-r));
                 return r;
diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4
index 14d9dcf..7545ae4 100644
--- a/src/libsystemd/libsystemd.sym.m4
+++ b/src/libsystemd/libsystemd.sym.m4
@@ -173,7 +173,6 @@ m4_ifdef(`ENABLE_KDBUS',
         sd_bus_send_to;
         sd_bus_call;
         sd_bus_call_async;
-        sd_bus_call_async_cancel;
         sd_bus_get_fd;
         sd_bus_get_events;
         sd_bus_get_timeout;
@@ -181,27 +180,26 @@ m4_ifdef(`ENABLE_KDBUS',
         sd_bus_process_priority;
         sd_bus_wait;
         sd_bus_flush;
-        sd_bus_get_current;
+        sd_bus_get_current_message;
+        sd_bus_get_current_slot;
         sd_bus_get_tid;
         sd_bus_attach_event;
         sd_bus_detach_event;
         sd_bus_get_event;
         sd_bus_add_filter;
-        sd_bus_remove_filter;
         sd_bus_add_match;
-        sd_bus_remove_match;
         sd_bus_add_object;
-        sd_bus_remove_object;
         sd_bus_add_fallback;
-        sd_bus_remove_fallback;
         sd_bus_add_object_vtable;
-        sd_bus_remove_object_vtable;
         sd_bus_add_fallback_vtable;
-        sd_bus_remove_fallback_vtable;
         sd_bus_add_node_enumerator;
-        sd_bus_remove_node_enumerator;
         sd_bus_add_object_manager;
-        sd_bus_remove_object_manager;
+        sd_bus_slot_ref;
+        sd_bus_slot_unref;
+        sd_bus_slot_get_bus;
+        sd_bus_slot_get_userdata;
+        sd_bus_slot_set_userdata;
+        sd_bus_slot_get_current_message;
         sd_bus_message_new_signal;
         sd_bus_message_new_method_call;
         sd_bus_message_new_method_return;
diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h
index 420e091..aa290ed 100644
--- a/src/libsystemd/sd-bus/bus-control.h
+++ b/src/libsystemd/sd-bus/bus-control.h
@@ -22,6 +22,7 @@
 ***/
 
 #include "sd-bus.h"
+#include "bus-match.h"
 
 int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
 int bus_remove_match_internal(sd_bus *bus, const char *match, uint64_t cookie);
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 3dceb8a..042d352 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -40,7 +40,6 @@
 
 struct reply_callback {
         sd_bus_message_handler_t callback;
-        void *userdata;
         usec_t timeout;
         uint64_t cookie;
         unsigned prioq_idx;
@@ -48,13 +47,23 @@ struct reply_callback {
 
 struct filter_callback {
         sd_bus_message_handler_t callback;
-        void *userdata;
 
         unsigned last_iteration;
 
         LIST_FIELDS(struct filter_callback, callbacks);
 };
 
+struct match_callback {
+        sd_bus_message_handler_t callback;
+
+        uint64_t cookie;
+        unsigned last_iteration;
+
+        char *match_string;
+
+        struct bus_match_node *match_node;
+};
+
 struct node {
         char *path;
         struct node *parent;
@@ -64,8 +73,7 @@ struct node {
         LIST_HEAD(struct node_callback, callbacks);
         LIST_HEAD(struct node_vtable, vtables);
         LIST_HEAD(struct node_enumerator, enumerators);
-
-        bool object_manager;
+        LIST_HEAD(struct node_object_manager, object_managers);
 };
 
 struct node_callback {
@@ -73,7 +81,6 @@ struct node_callback {
 
         bool is_fallback;
         sd_bus_message_handler_t callback;
-        void *userdata;
 
         unsigned last_iteration;
 
@@ -84,20 +91,24 @@ struct node_enumerator {
         struct node *node;
 
         sd_bus_node_enumerator_t callback;
-        void *userdata;
 
         unsigned last_iteration;
 
         LIST_FIELDS(struct node_enumerator, enumerators);
 };
 
+struct node_object_manager {
+        struct node *node;
+
+        LIST_FIELDS(struct node_object_manager, object_managers);
+};
+
 struct node_vtable {
         struct node *node;
 
         char *interface;
         bool is_fallback;
         const sd_bus_vtable *vtable;
-        void *userdata;
         sd_bus_object_find_t find;
 
         unsigned last_iteration;
@@ -114,6 +125,37 @@ struct vtable_member {
         const sd_bus_vtable *vtable;
 };
 
+typedef enum BusSlotType {
+        _BUS_SLOT_DISCONNECTED,
+        BUS_REPLY_CALLBACK,
+        BUS_FILTER_CALLBACK,
+        BUS_MATCH_CALLBACK,
+        BUS_NODE_CALLBACK,
+        BUS_NODE_ENUMERATOR,
+        BUS_NODE_VTABLE,
+        BUS_NODE_OBJECT_MANAGER,
+} BusSlotType;
+
+struct sd_bus_slot {
+        unsigned n_ref;
+        sd_bus *bus;
+        void *userdata;
+        BusSlotType type;
+        bool floating;
+
+        LIST_FIELDS(sd_bus_slot, slots);
+
+        union {
+                struct reply_callback reply_callback;
+                struct filter_callback filter_callback;
+                struct match_callback match_callback;
+                struct node_callback node_callback;
+                struct node_enumerator node_enumerator;
+                struct node_object_manager node_object_manager;
+                struct node_vtable node_vtable;
+        };
+};
+
 enum bus_state {
         BUS_UNSET,
         BUS_OPENING,
@@ -231,7 +273,6 @@ struct sd_bus {
         char *exec_path;
         char **exec_argv;
 
-        uint64_t hello_cookie;
         unsigned iteration_counter;
 
         void *kdbus_buffer;
@@ -260,7 +301,8 @@ struct sd_bus {
         sd_event *event;
         int event_priority;
 
-        sd_bus_message *current;
+        sd_bus_message *current_message;
+        sd_bus_slot *current_slot;
 
         sd_bus **default_bus_ptr;
         pid_t tid;
@@ -276,6 +318,8 @@ struct sd_bus {
         unsigned bloom_n_hash;
 
         sd_bus_track *track_queue;
+
+        LIST_HEAD(sd_bus_slot, slots);
 };
 
 #define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
@@ -340,3 +384,5 @@ int bus_set_address_system(sd_bus *bus);
 int bus_set_address_user(sd_bus *bus);
 int bus_set_address_system_remote(sd_bus *b, const char *host);
 int bus_set_address_system_container(sd_bus *b, const char *machine);
+
+int bus_remove_match_by_string(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c
index c54ca8d..b868159 100644
--- a/src/libsystemd/sd-bus/bus-match.c
+++ b/src/libsystemd/sd-bus/bus-match.c
@@ -116,6 +116,9 @@ static void bus_match_node_free(struct bus_match_node *node) {
 static bool bus_match_node_maybe_free(struct bus_match_node *node) {
         assert(node);
 
+        if (node->type == BUS_MATCH_ROOT)
+                return false;
+
         if (node->child)
                 return false;
 
@@ -275,10 +278,10 @@ int bus_match_run(
         case BUS_MATCH_LEAF:
 
                 if (bus) {
-                        if (node->leaf.last_iteration == bus->iteration_counter)
+                        if (node->leaf.callback->last_iteration == bus->iteration_counter)
                                 return 0;
 
-                        node->leaf.last_iteration = bus->iteration_counter;
+                        node->leaf.callback->last_iteration = bus->iteration_counter;
                 }
 
                 r = sd_bus_message_rewind(m, true);
@@ -287,9 +290,17 @@ int bus_match_run(
 
                 /* Run the callback. And then invoke siblings. */
                 if (node->leaf.callback) {
+                        sd_bus_slot *slot;
+
                         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
 
-                        r = node->leaf.callback(bus, m, node->leaf.userdata, &error_buffer);
+                        slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
+                        if (bus)
+                                bus->current_slot = slot;
+                        r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
+                        if (bus)
+                                bus->current_slot = NULL;
+
                         r = bus_maybe_reply_error(m, r, &error_buffer);
                         if (r != 0)
                                 return r;
@@ -535,16 +546,13 @@ static int bus_match_find_compare_value(
 
 static int bus_match_add_leaf(
                 struct bus_match_node *where,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                uint64_t cookie,
-                struct bus_match_node **ret) {
+                struct match_callback *callback) {
 
         struct bus_match_node *n;
 
         assert(where);
         assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
-        assert(ret);
+        assert(callback);
 
         n = new0(struct bus_match_node, 1);
         if (!n)
@@ -555,13 +563,12 @@ static int bus_match_add_leaf(
         n->next = where->child;
         if (n->next)
                 n->next->prev = n;
+
         n->leaf.callback = callback;
-        n->leaf.userdata = userdata;
-        n->leaf.cookie = cookie;
+        callback->match_node = n;
 
         where->child = n;
 
-        *ret = n;
         return 1;
 }
 
@@ -578,9 +585,13 @@ static int bus_match_find_leaf(
         assert(ret);
 
         for (c = where->child; c; c = c->next) {
+                sd_bus_slot *s;
+
+                s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
+
                 if (c->type == BUS_MATCH_LEAF &&
-                    c->leaf.callback == callback &&
-                    c->leaf.userdata == userdata) {
+                    c->leaf.callback->callback == callback &&
+                    s->userdata == userdata) {
                         *ret = c;
                         return 1;
                 }
@@ -892,16 +903,14 @@ int bus_match_add(
                 struct bus_match_node *root,
                 struct bus_match_component *components,
                 unsigned n_components,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                uint64_t cookie,
-                struct bus_match_node **ret) {
+                struct match_callback *callback) {
 
         unsigned i;
         struct bus_match_node *n;
         int r;
 
         assert(root);
+        assert(callback);
 
         n = root;
         for (i = 0; i < n_components; i++) {
@@ -912,29 +921,56 @@ int bus_match_add(
                         return r;
         }
 
-        r = bus_match_add_leaf(n, callback, userdata, cookie, &n);
-        if (r < 0)
-                return r;
+        return bus_match_add_leaf(n, callback);
+}
 
-        if (ret)
-                *ret = n;
+int bus_match_remove(
+                struct bus_match_node *root,
+                struct match_callback *callback) {
 
-        return 0;
+        struct bus_match_node *node, *pp;
+
+        assert(root);
+        assert(callback);
+
+        node = callback->match_node;
+        if (!node)
+                return 0;
+
+        assert(node->type == BUS_MATCH_LEAF);
+
+        callback->match_node = NULL;
+
+        /* Free the leaf */
+        pp = node->parent;
+        bus_match_node_free(node);
+
+        /* Prune the tree above */
+        while (pp) {
+                node = pp;
+                pp = node->parent;
+
+                if (!bus_match_node_maybe_free(node))
+                        break;
+        }
+
+        return 1;
 }
 
-int bus_match_remove(
+int bus_match_find(
                 struct bus_match_node *root,
                 struct bus_match_component *components,
                 unsigned n_components,
                 sd_bus_message_handler_t callback,
                 void *userdata,
-                uint64_t *cookie) {
+                struct match_callback **ret) {
 
-        unsigned i;
         struct bus_match_node *n, **gc;
+        unsigned i;
         int r;
 
         assert(root);
+        assert(ret);
 
         gc = newa(struct bus_match_node*, n_components);
 
@@ -954,24 +990,8 @@ int bus_match_remove(
         if (r <= 0)
                 return r;
 
-        if (cookie)
-                *cookie = n->leaf.cookie;
-
-        /* Free the leaf */
-        bus_match_node_free(n);
-
-        /* Prune the tree above */
-        for (i = n_components; i > 0; i --) {
-                struct bus_match_node *p = gc[i-1]->parent;
-
-                if (!bus_match_node_maybe_free(gc[i-1]))
-                        break;
-
-                if (!bus_match_node_maybe_free(p))
-                        break;
-        }
-
-        return r;
+        *ret = n->leaf.callback;
+        return 1;
 }
 
 void bus_match_free(struct bus_match_node *node) {
@@ -1065,7 +1085,7 @@ void bus_match_dump(struct bus_match_node *node, unsigned level) {
         } else if (node->type == BUS_MATCH_ROOT)
                 puts(" root");
         else if (node->type == BUS_MATCH_LEAF)
-                printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata);
+                printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
         else
                 putchar('\n');
 
diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h
index 056082b..af5f65d 100644
--- a/src/libsystemd/sd-bus/bus-match.h
+++ b/src/libsystemd/sd-bus/bus-match.h
@@ -58,10 +58,7 @@ struct bus_match_node {
                         uint8_t u8;
                 } value;
                 struct {
-                        sd_bus_message_handler_t callback;
-                        void *userdata;
-                        unsigned last_iteration;
-                        uint64_t cookie;
+                        struct match_callback *callback;
                 } leaf;
                 struct {
                         /* If this is set, then the child is NULL */
@@ -78,8 +75,10 @@ struct bus_match_component {
 
 int bus_match_run(sd_bus *bus, struct bus_match_node *root, sd_bus_message *m);
 
-int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t cookie, struct bus_match_node **ret);
-int bus_match_remove(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t *cookie);
+int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, struct match_callback *callback);
+int bus_match_remove(struct bus_match_node *root, struct match_callback *callback);
+
+int bus_match_find(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, struct match_callback **ret);
 
 void bus_match_free(struct bus_match_node *node);
 
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index 8b12e89..f160e23 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -28,8 +28,9 @@
 #include "bus-type.h"
 #include "bus-signature.h"
 #include "bus-introspect.h"
-#include "bus-objects.h"
 #include "bus-util.h"
+#include "bus-slot.h"
+#include "bus-objects.h"
 
 static int node_vtable_get_userdata(
                 sd_bus *bus,
@@ -38,6 +39,7 @@ static int node_vtable_get_userdata(
                 void **userdata,
                 sd_bus_error *error) {
 
+        sd_bus_slot *s;
         void *u;
         int r;
 
@@ -45,9 +47,13 @@ static int node_vtable_get_userdata(
         assert(path);
         assert(c);
 
-        u = c->userdata;
+        s = container_of(c, sd_bus_slot, node_vtable);
+        u = s->userdata;
         if (c->find) {
+                bus->current_slot = s;
                 r = c->find(bus, path, c->interface, u, &u, error);
+                bus->current_slot = NULL;
+
                 if (r < 0)
                         return r;
                 if (sd_bus_error_is_set(error))
@@ -113,7 +119,10 @@ static int add_enumerated_to_set(
                 if (bus->nodes_modified)
                         return 0;
 
-                r = c->callback(bus, prefix, c->userdata, &children, error);
+                bus->current_slot = container_of(c, sd_bus_slot, node_enumerator);
+                r = c->callback(bus, prefix, bus->current_slot->userdata, &children, error);
+                bus->current_slot = NULL;
+
                 if (r < 0)
                         return r;
                 if (sd_bus_error_is_set(error))
@@ -257,7 +266,10 @@ static int node_callbacks_run(
                 if (r < 0)
                         return r;
 
-                r = c->callback(bus, m, c->userdata, &error_buffer);
+                bus->current_slot = container_of(c, sd_bus_slot, node_callback);
+                r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
+                bus->current_slot = NULL;
+
                 r = bus_maybe_reply_error(m, r, &error_buffer);
                 if (r != 0)
                         return r;
@@ -382,7 +394,11 @@ static int method_callbacks_run(
         m->enforced_reply_signature = strempty(c->vtable->x.method.result);
 
         if (c->vtable->x.method.handler) {
+
+                bus->current_slot = container_of(c->parent, sd_bus_slot, node_vtable);
                 r = c->vtable->x.method.handler(bus, m, u, &error);
+                bus->current_slot = NULL;
+
                 return bus_maybe_reply_error(m, r, &error);
         }
 
@@ -396,6 +412,7 @@ static int method_callbacks_run(
 
 static int invoke_property_get(
                 sd_bus *bus,
+                sd_bus_slot *slot,
                 const sd_bus_vtable *v,
                 const char *path,
                 const char *interface,
@@ -408,6 +425,7 @@ static int invoke_property_get(
         int r;
 
         assert(bus);
+        assert(slot);
         assert(v);
         assert(path);
         assert(interface);
@@ -415,7 +433,11 @@ static int invoke_property_get(
         assert(reply);
 
         if (v->x.property.get) {
+
+                bus->current_slot = slot;
                 r = v->x.property.get(bus, path, interface, property, reply, userdata, error);
+                bus->current_slot = NULL;
+
                 if (r < 0)
                         return r;
                 if (sd_bus_error_is_set(error))
@@ -453,6 +475,7 @@ static int invoke_property_get(
 
 static int invoke_property_set(
                 sd_bus *bus,
+                sd_bus_slot *slot,
                 const sd_bus_vtable *v,
                 const char *path,
                 const char *interface,
@@ -464,6 +487,7 @@ static int invoke_property_set(
         int r;
 
         assert(bus);
+        assert(slot);
         assert(v);
         assert(path);
         assert(interface);
@@ -471,7 +495,11 @@ static int invoke_property_set(
         assert(value);
 
         if (v->x.property.set) {
+
+                bus->current_slot = slot;
                 r = v->x.property.set(bus, path, interface, property, value, userdata, error);
+                bus->current_slot = NULL;
+
                 if (r < 0)
                         return r;
                 if (sd_bus_error_is_set(error))
@@ -527,6 +555,7 @@ static int property_get_set_callbacks_run(
 
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        sd_bus_slot *slot;
         void *u = NULL;
         int r;
 
@@ -544,6 +573,8 @@ static int property_get_set_callbacks_run(
         if (bus->nodes_modified)
                 return 0;
 
+        slot = container_of(c->parent, sd_bus_slot, node_vtable);
+
         *found_object = true;
 
         r = sd_bus_message_new_method_return(m, &reply);
@@ -567,7 +598,7 @@ static int property_get_set_callbacks_run(
                  * PropertiesChanged signals broadcast contents
                  * anyway. */
 
-                r = invoke_property_get(bus, c->vtable, m->path, c->interface, c->member, reply, u, &error);
+                r = invoke_property_get(bus, slot, c->vtable, m->path, c->interface, c->member, reply, u, &error);
                 if (r < 0)
                         return bus_maybe_reply_error(m, r, &error);
 
@@ -598,7 +629,7 @@ static int property_get_set_callbacks_run(
                 if (r < 0)
                         return bus_maybe_reply_error(m, r, &error);
 
-                r = invoke_property_set(bus, c->vtable, m->path, c->interface, c->member, m, u, &error);
+                r = invoke_property_set(bus, slot, c->vtable, m->path, c->interface, c->member, m, u, &error);
                 if (r < 0)
                         return bus_maybe_reply_error(m, r, &error);
 
@@ -626,6 +657,7 @@ static int vtable_append_one_property(
                 void *userdata,
                 sd_bus_error *error) {
 
+        sd_bus_slot *slot;
         int r;
 
         assert(bus);
@@ -646,7 +678,9 @@ static int vtable_append_one_property(
         if (r < 0)
                 return r;
 
-        r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
+        slot = container_of(c, sd_bus_slot, node_vtable);
+
+        r = invoke_property_get(bus, slot, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
         if (r < 0)
                 return r;
         if (bus->nodes_modified)
@@ -783,7 +817,7 @@ static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) {
         assert(bus);
         assert(n);
 
-        if (n->object_manager)
+        if (n->object_managers)
                 return true;
 
         if (n->parent)
@@ -827,7 +861,7 @@ static bool bus_node_exists(
                         return false;
         }
 
-        return !require_fallback && (n->enumerators || n->object_manager);
+        return !require_fallback && (n->enumerators || n->object_managers);
 }
 
 static int process_introspect(
@@ -1421,7 +1455,7 @@ static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
         return n;
 }
 
-static void bus_node_gc(sd_bus *b, struct node *n) {
+void bus_node_gc(sd_bus *b, struct node *n) {
         assert(b);
 
         if (!n)
@@ -1431,7 +1465,7 @@ static void bus_node_gc(sd_bus *b, struct node *n) {
             n->callbacks ||
             n->vtables ||
             n->enumerators ||
-            n->object_manager)
+            n->object_managers)
                 return;
 
         assert(hashmap_remove(b->nodes, n->path) == n);
@@ -1446,12 +1480,13 @@ static void bus_node_gc(sd_bus *b, struct node *n) {
 
 static int bus_add_object(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 bool fallback,
                 const char *path,
                 sd_bus_message_handler_t callback,
                 void *userdata) {
 
-        struct node_callback *c;
+        sd_bus_slot *s;
         struct node *n;
         int r;
 
@@ -1464,136 +1499,49 @@ static int bus_add_object(
         if (!n)
                 return -ENOMEM;
 
-        c = new0(struct node_callback, 1);
-        if (!c) {
+        s = bus_slot_allocate(bus, !slot, BUS_NODE_CALLBACK, sizeof(struct node_callback), userdata);
+        if (!s) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        c->node = n;
-        c->callback = callback;
-        c->userdata = userdata;
-        c->is_fallback = fallback;
+        s->node_callback.callback = callback;
+        s->node_callback.is_fallback = fallback;
 
-        LIST_PREPEND(callbacks, n->callbacks, c);
+        s->node_callback.node = n;
+        LIST_PREPEND(callbacks, n->callbacks, &s->node_callback);
         bus->nodes_modified = true;
 
+        if (slot)
+                *slot = s;
+
         return 0;
 
 fail:
-        free(c);
+        sd_bus_slot_unref(s);
         bus_node_gc(bus, n);
+
         return r;
 }
 
-static int bus_remove_object(
+_public_ int sd_bus_add_object(
                 sd_bus *bus,
-                bool fallback,
+                sd_bus_slot **slot,
                 const char *path,
                 sd_bus_message_handler_t callback,
                 void *userdata) {
 
-        struct node_callback *c;
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(callbacks, c, n->callbacks)
-                if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback)
-                        break;
-        if (!c)
-                return 0;
-
-        LIST_REMOVE(callbacks, n->callbacks, c);
-        free(c);
-
-        bus_node_gc(bus, n);
-        bus->nodes_modified = true;
-
-        return 1;
-}
-
-_public_ int sd_bus_add_object(sd_bus *bus,
-                               const char *path,
-                               sd_bus_message_handler_t callback,
-                               void *userdata) {
-
-        return bus_add_object(bus, false, path, callback, userdata);
-}
-
-_public_ int sd_bus_remove_object(sd_bus *bus,
-                                  const char *path,
-                                  sd_bus_message_handler_t callback,
-                                  void *userdata) {
-
-        return bus_remove_object(bus, false, path, callback, userdata);
-}
-
-_public_ int sd_bus_add_fallback(sd_bus *bus,
-                                 const char *prefix,
-                                 sd_bus_message_handler_t callback,
-                                 void *userdata) {
-
-        return bus_add_object(bus, true, prefix, callback, userdata);
-}
-
-_public_ int sd_bus_remove_fallback(sd_bus *bus,
-                                    const char *prefix,
-                                    sd_bus_message_handler_t callback,
-                                    void *userdata) {
-
-        return bus_remove_object(bus, true, prefix, callback, userdata);
+        return bus_add_object(bus, slot, false, path, callback, userdata);
 }
 
-static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
-        assert(bus);
-
-        if (!w)
-                return;
-
-        if (w->interface && w->node && w->vtable) {
-                const sd_bus_vtable *v;
-
-                for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
-                        struct vtable_member *x = NULL;
-
-                        switch (v->type) {
-
-                        case _SD_BUS_VTABLE_METHOD: {
-                                struct vtable_member key;
-
-                                key.path = w->node->path;
-                                key.interface = w->interface;
-                                key.member = v->x.method.member;
-
-                                x = hashmap_remove(bus->vtable_methods, &key);
-                                break;
-                        }
-
-                        case _SD_BUS_VTABLE_PROPERTY:
-                        case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
-                                struct vtable_member key;
-
-                                key.path = w->node->path;
-                                key.interface = w->interface;
-                                key.member = v->x.property.member;
-                                x = hashmap_remove(bus->vtable_properties, &key);
-                                break;
-                        }}
-
-                        free(x);
-                }
-        }
+_public_ int sd_bus_add_fallback(
+                sd_bus *bus,
+                sd_bus_slot **slot,
+                const char *prefix,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
 
-        free(w->interface);
-        free(w);
+        return bus_add_object(bus, slot, true, prefix, callback, userdata);
 }
 
 static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
@@ -1637,6 +1585,7 @@ static int vtable_member_compare_func(const void *a, const void *b) {
 
 static int add_object_vtable_internal(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 const char *path,
                 const char *interface,
                 const sd_bus_vtable *vtable,
@@ -1644,7 +1593,8 @@ static int add_object_vtable_internal(
                 sd_bus_object_find_t find,
                 void *userdata) {
 
-        struct node_vtable *c = NULL, *i, *existing = NULL;
+        sd_bus_slot *s;
+        struct node_vtable *i, *existing = NULL;
         const sd_bus_vtable *v;
         struct node *n;
         int r;
@@ -1690,25 +1640,23 @@ static int add_object_vtable_internal(
                 }
         }
 
-        c = new0(struct node_vtable, 1);
-        if (!c) {
+        s = bus_slot_allocate(bus, !slot, BUS_NODE_VTABLE, sizeof(struct node_vtable), userdata);
+        if (!s) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        c->node = n;
-        c->is_fallback = fallback;
-        c->vtable = vtable;
-        c->userdata = userdata;
-        c->find = find;
+        s->node_vtable.is_fallback = fallback;
+        s->node_vtable.vtable = vtable;
+        s->node_vtable.find = find;
 
-        c->interface = strdup(interface);
-        if (!c->interface) {
+        s->node_vtable.interface = strdup(interface);
+        if (!s->node_vtable.interface) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+        for (v = s->node_vtable.vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
 
                 switch (v->type) {
 
@@ -1730,9 +1678,9 @@ static int add_object_vtable_internal(
                                 goto fail;
                         }
 
-                        m->parent = c;
+                        m->parent = &s->node_vtable;
                         m->path = n->path;
-                        m->interface = c->interface;
+                        m->interface = s->node_vtable.interface;
                         m->member = v->x.method.member;
                         m->vtable = v;
 
@@ -1773,9 +1721,9 @@ static int add_object_vtable_internal(
                                 goto fail;
                         }
 
-                        m->parent = c;
+                        m->parent = &s->node_vtable;
                         m->path = n->path;
-                        m->interface = c->interface;
+                        m->interface = s->node_vtable.interface;
                         m->member = v->x.property.member;
                         m->vtable = v;
 
@@ -1805,110 +1753,53 @@ static int add_object_vtable_internal(
                 }
         }
 
-        LIST_INSERT_AFTER(vtables, n->vtables, existing, c);
+        s->node_vtable.node = n;
+        LIST_INSERT_AFTER(vtables, n->vtables, existing, &s->node_vtable);
         bus->nodes_modified = true;
 
+        if (slot)
+                *slot = s;
+
         return 0;
 
 fail:
-        if (c)
-                free_node_vtable(bus, c);
-
-        bus_node_gc(bus, n);
-        return r;
-}
-
-static int remove_object_vtable_internal(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                bool fallback,
-                sd_bus_object_find_t find,
-                void *userdata) {
-
-        struct node_vtable *c;
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(interface_name_is_valid(interface), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(vtables, c, n->vtables)
-                if (streq(c->interface, interface) &&
-                    c->is_fallback == fallback &&
-                    c->vtable == vtable &&
-                    c->find == find &&
-                    c->userdata == userdata)
-                        break;
-
-        if (!c)
-                return 0;
-
-        LIST_REMOVE(vtables, n->vtables, c);
-
-        free_node_vtable(bus, c);
+        sd_bus_slot_unref(s);
         bus_node_gc(bus, n);
 
-        bus->nodes_modified = true;
-
-        return 1;
+        return r;
 }
 
 _public_ int sd_bus_add_object_vtable(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 const char *path,
                 const char *interface,
                 const sd_bus_vtable *vtable,
                 void *userdata) {
 
-        return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
-}
-
-_public_ int sd_bus_remove_object_vtable(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                void *userdata) {
-
-        return remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
+        return add_object_vtable_internal(bus, slot, path, interface, vtable, false, NULL, userdata);
 }
 
 _public_ int sd_bus_add_fallback_vtable(
                 sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                sd_bus_object_find_t find,
-                void *userdata) {
-
-        return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
-}
-
-_public_ int sd_bus_remove_fallback_vtable(
-                sd_bus *bus,
-                const char *path,
+                sd_bus_slot **slot,
+                const char *prefix,
                 const char *interface,
                 const sd_bus_vtable *vtable,
                 sd_bus_object_find_t find,
                 void *userdata) {
 
-        return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
+        return add_object_vtable_internal(bus, slot, prefix, interface, vtable, true, find, userdata);
 }
 
 _public_ int sd_bus_add_node_enumerator(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 const char *path,
                 sd_bus_node_enumerator_t callback,
                 void *userdata) {
 
-        struct node_enumerator *c;
+        sd_bus_slot *s;
         struct node *n;
         int r;
 
@@ -1921,61 +1812,28 @@ _public_ int sd_bus_add_node_enumerator(
         if (!n)
                 return -ENOMEM;
 
-        c = new0(struct node_enumerator, 1);
-        if (!c) {
+        s = bus_slot_allocate(bus, !slot, BUS_NODE_ENUMERATOR, sizeof(struct node_enumerator), userdata);
+        if (!s) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        c->node = n;
-        c->callback = callback;
-        c->userdata = userdata;
-
-        LIST_PREPEND(enumerators, n->enumerators, c);
+        s->node_enumerator.callback = callback;
 
+        s->node_enumerator.node = n;
+        LIST_PREPEND(enumerators, n->enumerators, &s->node_enumerator);
         bus->nodes_modified = true;
 
+        if (slot)
+                *slot = s;
+
         return 0;
 
 fail:
-        free(c);
-        bus_node_gc(bus, n);
-        return r;
-}
-
-_public_ int sd_bus_remove_node_enumerator(
-                sd_bus *bus,
-                const char *path,
-                sd_bus_node_enumerator_t callback,
-                void *userdata) {
-
-        struct node_enumerator *c;
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(enumerators, c, n->enumerators)
-                if (c->callback == callback && c->userdata == userdata)
-                        break;
-
-        if (!c)
-                return 0;
-
-        LIST_REMOVE(enumerators, n->enumerators, c);
-        free(c);
-
+        sd_bus_slot_unref(s);
         bus_node_gc(bus, n);
 
-        bus->nodes_modified = true;
-
-        return 1;
+        return r;
 }
 
 static int emit_properties_changed_on_interface(
@@ -2481,8 +2339,10 @@ _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const
         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
 }
 
-_public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
+_public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) {
+        sd_bus_slot *s;
         struct node *n;
+        int r;
 
         assert_return(bus, -EINVAL);
         assert_return(object_path_is_valid(path), -EINVAL);
@@ -2492,28 +2352,24 @@ _public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
         if (!n)
                 return -ENOMEM;
 
-        n->object_manager = true;
-        bus->nodes_modified = true;
-        return 0;
-}
-
-_public_ int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
-        struct node *n;
+        s = bus_slot_allocate(bus, !slot, BUS_NODE_OBJECT_MANAGER, sizeof(struct node_object_manager), NULL);
+        if (!s) {
+                r = -ENOMEM;
+                goto fail;
+        }
 
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
+        s->node_object_manager.node = n;
+        LIST_PREPEND(object_managers, n->object_managers, &s->node_object_manager);
+        bus->nodes_modified = true;
 
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
+        if (slot)
+                *slot = s;
 
-        if (!n->object_manager)
-                return 0;
+        return 0;
 
-        n->object_manager = false;
-        bus->nodes_modified = true;
+fail:
+        sd_bus_slot_unref(s);
         bus_node_gc(bus, n);
 
-        return 1;
+        return r;
 }
diff --git a/src/libsystemd/sd-bus/bus-objects.h b/src/libsystemd/sd-bus/bus-objects.h
index 420edd9..4373fae 100644
--- a/src/libsystemd/sd-bus/bus-objects.h
+++ b/src/libsystemd/sd-bus/bus-objects.h
@@ -24,3 +24,4 @@
 #include "bus-internal.h"
 
 int bus_process_object(sd_bus *bus, sd_bus_message *m);
+void bus_node_gc(sd_bus *b, struct node *n);
diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c
new file mode 100644
index 0000000..8e38992
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-slot.c
@@ -0,0 +1,244 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+#include "bus-control.h"
+#include "bus-objects.h"
+#include "bus-slot.h"
+
+sd_bus_slot *bus_slot_allocate(
+                sd_bus *bus,
+                bool floating,
+                BusSlotType type,
+                size_t extra,
+                void *userdata) {
+
+        sd_bus_slot *slot;
+
+        assert(bus);
+
+        slot = malloc0(offsetof(sd_bus_slot, reply_callback) + extra);
+        if (!slot)
+                return NULL;
+
+        slot->n_ref = 1;
+        slot->type = type;
+        slot->bus = bus;
+        slot->floating = floating;
+        slot->userdata = userdata;
+
+        if (!floating)
+                sd_bus_ref(bus);
+
+        LIST_PREPEND(slots, bus->slots, slot);
+
+        return slot;
+}
+
+_public_ sd_bus_slot* sd_bus_slot_ref(sd_bus_slot *slot) {
+        assert_return(slot, NULL);
+
+        assert(slot->n_ref > 0);
+
+        slot->n_ref++;
+        return slot;
+}
+
+void bus_slot_disconnect(sd_bus_slot *slot) {
+        sd_bus *bus;
+
+        assert(slot);
+
+        switch (slot->type) {
+
+        case _BUS_SLOT_DISCONNECTED:
+                /* Already disconnected... */
+                return;
+
+        case BUS_REPLY_CALLBACK:
+
+                if (slot->reply_callback.cookie != 0)
+                        hashmap_remove(slot->bus->reply_callbacks, &slot->reply_callback.cookie);
+
+                if (slot->reply_callback.timeout != 0)
+                        prioq_remove(slot->bus->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
+
+                break;
+
+        case BUS_FILTER_CALLBACK:
+                slot->bus->filter_callbacks_modified = true;
+                LIST_REMOVE(callbacks, slot->bus->filter_callbacks, &slot->filter_callback);
+                break;
+
+        case BUS_MATCH_CALLBACK:
+
+                if (slot->bus->bus_client)
+                        bus_remove_match_internal(slot->bus, slot->match_callback.match_string, slot->match_callback.cookie);
+
+                slot->bus->match_callbacks_modified = true;
+                bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback);
+
+                free(slot->match_callback.match_string);
+
+                break;
+
+        case BUS_NODE_CALLBACK:
+
+                if (slot->node_callback.node) {
+                        LIST_REMOVE(callbacks, slot->node_callback.node->callbacks, &slot->node_callback);
+                        slot->bus->nodes_modified = true;
+
+                        bus_node_gc(slot->bus, slot->node_callback.node);
+                }
+
+                break;
+
+        case BUS_NODE_ENUMERATOR:
+
+                if (slot->node_enumerator.node) {
+                        LIST_REMOVE(enumerators, slot->node_enumerator.node->enumerators, &slot->node_enumerator);
+                        slot->bus->nodes_modified = true;
+
+                        bus_node_gc(slot->bus, slot->node_enumerator.node);
+                }
+
+                break;
+
+        case BUS_NODE_OBJECT_MANAGER:
+
+                if (slot->node_object_manager.node) {
+                        LIST_REMOVE(object_managers, slot->node_object_manager.node->object_managers, &slot->node_object_manager);
+                        slot->bus->nodes_modified = true;
+
+                        bus_node_gc(slot->bus, slot->node_object_manager.node);
+                }
+
+                break;
+
+        case BUS_NODE_VTABLE:
+
+                if (slot->node_vtable.node && slot->node_vtable.interface && slot->node_vtable.vtable) {
+                        const sd_bus_vtable *v;
+
+                        for (v = slot->node_vtable.vtable; v->type != _SD_BUS_VTABLE_END; v++) {
+                                struct vtable_member *x = NULL;
+
+                                switch (v->type) {
+
+                                case _SD_BUS_VTABLE_METHOD: {
+                                        struct vtable_member key;
+
+                                        key.path = slot->node_vtable.node->path;
+                                        key.interface = slot->node_vtable.interface;
+                                        key.member = v->x.method.member;
+
+                                        x = hashmap_remove(slot->bus->vtable_methods, &key);
+                                        break;
+                                }
+
+                                case _SD_BUS_VTABLE_PROPERTY:
+                                case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
+                                        struct vtable_member key;
+
+                                        key.path = slot->node_vtable.node->path;
+                                        key.interface = slot->node_vtable.interface;
+                                        key.member = v->x.method.member;
+
+
+                                        x = hashmap_remove(slot->bus->vtable_properties, &key);
+                                        break;
+                                }}
+
+                                free(x);
+                        }
+                }
+
+                free(slot->node_vtable.interface);
+
+                if (slot->node_vtable.node) {
+                        LIST_REMOVE(vtables, slot->node_vtable.node->vtables, &slot->node_vtable);
+                        slot->bus->nodes_modified = true;
+
+                        bus_node_gc(slot->bus, slot->node_vtable.node);
+                }
+
+                break;
+        }
+        bus = slot->bus;
+
+        slot->type = _BUS_SLOT_DISCONNECTED;
+        slot->bus = NULL;
+        LIST_REMOVE(slots, bus->slots, slot);
+
+        if (!slot->floating)
+                sd_bus_unref(bus);
+}
+
+_public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) {
+
+        if (!slot)
+                return NULL;
+
+        assert(slot->n_ref > 0);
+
+        if (slot->n_ref > 1) {
+                slot->n_ref --;
+                return NULL;
+        }
+
+        bus_slot_disconnect(slot);
+        free(slot);
+
+        return NULL;
+}
+
+_public_ sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot) {
+        assert_return(slot, NULL);
+
+        return slot->bus;
+}
+
+_public_ void *sd_bus_slot_get_userdata(sd_bus_slot *slot) {
+        assert_return(slot, NULL);
+
+        return slot->userdata;
+}
+
+_public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) {
+        void *ret;
+
+        assert_return(slot, NULL);
+
+        ret = slot->userdata;
+        slot->userdata = userdata;
+
+        return ret;
+}
+
+_public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) {
+        assert_return(slot, NULL);
+        assert_return(slot->type != _BUS_SLOT_DISCONNECTED, NULL);
+
+        if (slot->bus->current_slot != slot)
+                return NULL;
+
+        return slot->bus->current_message;
+}
diff --git a/src/libsystemd/sd-bus/bus-slot.h b/src/libsystemd/sd-bus/bus-slot.h
new file mode 100644
index 0000000..23a15e4
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-slot.h
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+#include "bus-internal.h"
+
+sd_bus_slot *bus_slot_allocate(sd_bus *bus, bool floating, BusSlotType type, size_t extra, void *userdata);
+
+void bus_slot_disconnect(sd_bus_slot *slot);
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index 0f6a2ea..ffa2cf3 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -21,6 +21,7 @@
 
 #include "sd-bus.h"
 #include "set.h"
+#include "bus-util.h"
 #include "bus-internal.h"
 #include "bus-track.h"
 
@@ -29,7 +30,7 @@ struct sd_bus_track {
         sd_bus *bus;
         sd_bus_track_handler_t handler;
         void *userdata;
-        Set *names;
+        Hashmap *names;
         LIST_FIELDS(sd_bus_track, queue);
         Iterator iterator;
         bool in_queue;
@@ -128,11 +129,11 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
                 return NULL;
         }
 
-        while ((n = set_first(track->names)))
+        while ((n = hashmap_first_key(track->names)))
                 sd_bus_track_remove_name(track, n);
 
         bus_track_remove_from_queue(track);
-        set_free(track->names);
+        hashmap_free(track->names);
         sd_bus_unref(track->bus);
         free(track);
 
@@ -157,6 +158,7 @@ static int on_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *use
 }
 
 _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
+        _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
         _cleanup_free_ char *n = NULL;
         const char *match;
         int r;
@@ -164,7 +166,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
         assert_return(track, -EINVAL);
         assert_return(service_name_is_valid(name), -EINVAL);
 
-        r = set_ensure_allocated(&track->names, string_hash_func, string_compare_func);
+        r = hashmap_ensure_allocated(&track->names, string_hash_func, string_compare_func);
         if (r < 0)
                 return r;
 
@@ -172,30 +174,28 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
         if (!n)
                 return -ENOMEM;
 
-        r = set_put(track->names, n);
+        /* First, subscribe to this name */
+        match = MATCH_FOR_NAME(n);
+        r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track);
+        if (r < 0)
+                return r;
+
+        r = hashmap_put(track->names, n, slot);
         if (r == -EEXIST)
                 return 0;
         if (r < 0)
                 return r;
 
-        /* First, subscribe to this name */
-        match = MATCH_FOR_NAME(name);
-        r = sd_bus_add_match(track->bus, match, on_name_owner_changed, track);
-        if (r < 0) {
-                set_remove(track->names, n);
-                return r;
-        }
-
         /* Second, check if it is currently existing, or maybe
          * doesn't, or maybe disappeared already. */
-        r = sd_bus_get_owner(track->bus, name, 0, NULL);
+        r = sd_bus_get_owner(track->bus, n, 0, NULL);
         if (r < 0) {
-                set_remove(track->names, n);
-                sd_bus_remove_match(track->bus, match, on_name_owner_changed, track);
+                hashmap_remove(track->names, n);
                 return r;
         }
 
         n = NULL;
+        slot = NULL;
 
         bus_track_remove_from_queue(track);
         track->modified = true;
@@ -204,22 +204,19 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
 }
 
 _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) {
-        const char *match;
-        _cleanup_free_ char *n = NULL;;
+        _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
+        _cleanup_free_ char *n = NULL;
 
         assert_return(name, -EINVAL);
 
         if (!track)
                 return 0;
 
-        n = set_remove(track->names, (char*) name);
-        if (!n)
+        slot = hashmap_remove2(track->names, (char*) name, (void**) &n);
+        if (!slot)
                 return 0;
 
-        match = MATCH_FOR_NAME(n);
-        sd_bus_remove_match(track->bus, match, on_name_owner_changed, track);
-
-        if (set_isempty(track->names))
+        if (hashmap_isempty(track->names))
                 bus_track_add_to_queue(track);
 
         track->modified = true;
@@ -231,34 +228,40 @@ _public_ unsigned sd_bus_track_count(sd_bus_track *track) {
         if (!track)
                 return 0;
 
-        return set_size(track->names);
+        return hashmap_size(track->names);
 }
 
 _public_ const char* sd_bus_track_contains(sd_bus_track *track, const char *name) {
         assert_return(track, NULL);
         assert_return(name, NULL);
 
-        return set_get(track->names, (void*) name);
+        return hashmap_get(track->names, (void*) name) ? name : NULL;
 }
 
 _public_ const char* sd_bus_track_first(sd_bus_track *track) {
+        const char *n = NULL;
+
         if (!track)
                 return NULL;
 
         track->modified = false;
         track->iterator = NULL;
 
-        return set_iterate(track->names, &track->iterator);
+        hashmap_iterate(track->names, &track->iterator, (const void**) &n);
+        return n;
 }
 
 _public_ const char* sd_bus_track_next(sd_bus_track *track) {
+        const char *n = NULL;
+
         if (!track)
                 return NULL;
 
         if (track->modified)
                 return NULL;
 
-        return set_iterate(track->names, &track->iterator);
+        hashmap_iterate(track->names, &track->iterator, (const void**) &n);
+        return n;
 }
 
 _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) {
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index 84b3fc5..b5b3c85 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -77,7 +77,7 @@ int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
         if (r < 0)
                 return -ENOMEM;
 
-        r = sd_bus_add_match(bus, match, name_owner_change_callback, e);
+        r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
         if (r < 0)
                 return r;
 
@@ -251,17 +251,16 @@ typedef struct AsyncPolkitQuery {
         sd_bus_message *request, *reply;
         sd_bus_message_handler_t callback;
         void *userdata;
-        uint64_t serial;
+        sd_bus_slot *slot;
         Hashmap *registry;
 } AsyncPolkitQuery;
 
-static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
+static void async_polkit_query_free(AsyncPolkitQuery *q) {
 
         if (!q)
                 return;
 
-        if (q->serial > 0 && b)
-                sd_bus_call_async_cancel(b, q->serial);
+        sd_bus_slot_unref(q->slot);
 
         if (q->registry && q->request)
                 hashmap_remove(q->registry, q->request);
@@ -281,8 +280,8 @@ static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userd
         assert(reply);
         assert(q);
 
+        q->slot = sd_bus_slot_unref(q->slot);
         q->reply = sd_bus_message_ref(reply);
-        q->serial = 0;
 
         r = sd_bus_message_rewind(q->request, true);
         if (r < 0) {
@@ -294,7 +293,8 @@ static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userd
         r = bus_maybe_reply_error(q->request, r, &error_buffer);
 
 finish:
-        async_polkit_query_free(bus, q);
+        async_polkit_query_free(q);
+
         return r;
 }
 
@@ -413,15 +413,15 @@ int bus_verify_polkit_async(
 
         r = hashmap_put(*registry, m, q);
         if (r < 0) {
-                async_polkit_query_free(bus, q);
+                async_polkit_query_free(q);
                 return r;
         }
 
         q->registry = *registry;
 
-        r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
+        r = sd_bus_call_async(bus, &q->slot, pk, async_polkit_callback, q, 0);
         if (r < 0) {
-                async_polkit_query_free(bus, q);
+                async_polkit_query_free(q);
                 return r;
         }
 
@@ -436,7 +436,7 @@ void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
         AsyncPolkitQuery *q;
 
         while ((q = hashmap_steal_first(registry)))
-                async_polkit_query_free(bus, q);
+                async_polkit_query_free(q);
 
         hashmap_free(registry);
 #endif
diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
index 8103555..1514fad 100644
--- a/src/libsystemd/sd-bus/bus-util.h
+++ b/src/libsystemd/sd-bus/bus-util.h
@@ -139,12 +139,16 @@ typedef struct UnitInfo {
 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_slot*, sd_bus_slot_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_track*, sd_bus_track_unref);
 
 #define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp)
+#define _cleanup_bus_slot_unref_ _cleanup_(sd_bus_slot_unrefp)
 #define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp)
 #define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp)
+#define _cleanup_bus_track_unref_ _cleanup_(sd_bus_slot_unrefp)
 #define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free)
 
 #define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type)              \
diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c
index 4e396f2..4545047 100644
--- a/src/libsystemd/sd-bus/busctl.c
+++ b/src/libsystemd/sd-bus/busctl.c
@@ -240,7 +240,7 @@ static int monitor(sd_bus *bus, char *argv[]) {
                 if (!m)
                         return log_oom();
 
-                r = sd_bus_add_match(bus, m, NULL, NULL);
+                r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match: %s", strerror(-r));
                         return r;
@@ -250,7 +250,7 @@ static int monitor(sd_bus *bus, char *argv[]) {
         }
 
         STRV_FOREACH(i, arg_matches) {
-                r = sd_bus_add_match(bus, *i, NULL, NULL);
+                r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match: %s", strerror(-r));
                         return r;
@@ -260,7 +260,7 @@ static int monitor(sd_bus *bus, char *argv[]) {
         }
 
         if (!added_something) {
-                r = sd_bus_add_match(bus, "", NULL, NULL);
+                r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match: %s", strerror(-r));
                         return r;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index dc54e21..ea80e9d 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -52,6 +52,7 @@
 #include "bus-container.h"
 #include "bus-protocol.h"
 #include "bus-track.h"
+#include "bus-slot.h"
 
 static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
 static int attach_io_events(sd_bus *b);
@@ -71,43 +72,6 @@ static void bus_close_fds(sd_bus *b) {
         b->input_fd = b->output_fd = -1;
 }
 
-static void bus_node_destroy(sd_bus *b, struct node *n) {
-        struct node_callback *c;
-        struct node_vtable *v;
-        struct node_enumerator *e;
-
-        assert(b);
-
-        if (!n)
-                return;
-
-        while (n->child)
-                bus_node_destroy(b, n->child);
-
-        while ((c = n->callbacks)) {
-                LIST_REMOVE(callbacks, n->callbacks, c);
-                free(c);
-        }
-
-        while ((v = n->vtables)) {
-                LIST_REMOVE(vtables, n->vtables, v);
-                free(v->interface);
-                free(v);
-        }
-
-        while ((e = n->enumerators)) {
-                LIST_REMOVE(enumerators, n->enumerators, e);
-                free(e);
-        }
-
-        if (n->parent)
-                LIST_REMOVE(siblings, n->parent->child, n);
-
-        assert_se(hashmap_remove(b->nodes, n->path) == n);
-        free(n->path);
-        free(n);
-}
-
 static void bus_reset_queues(sd_bus *b) {
         assert(b);
 
@@ -133,15 +97,28 @@ static void bus_reset_queues(sd_bus *b) {
 }
 
 static void bus_free(sd_bus *b) {
-        struct filter_callback *f;
-        struct node *n;
+        sd_bus_slot *s;
 
         assert(b);
-
         assert(!b->track_queue);
 
+        b->state = BUS_CLOSED;
+
         sd_bus_detach_event(b);
 
+        while ((s = b->slots)) {
+                /* At this point only floating slots can still be
+                 * around, because the non-floating ones keep a
+                 * reference to the bus, and we thus couldn't be
+                 * destructing right now... We forcibly disconnect the
+                 * slots here, so that they still can be referenced by
+                 * apps, but are dead. */
+
+                assert(s->floating);
+                bus_slot_disconnect(s);
+                sd_bus_slot_unref(s);
+        }
+
         if (b->default_bus_ptr)
                 *b->default_bus_ptr = NULL;
 
@@ -171,19 +148,12 @@ static void bus_free(sd_bus *b) {
         hashmap_free_free(b->reply_callbacks);
         prioq_free(b->reply_callbacks_prioq);
 
-        while ((f = b->filter_callbacks)) {
-                LIST_REMOVE(callbacks, b->filter_callbacks, f);
-                free(f);
-        }
-
         bus_match_free(&b->match_callbacks);
 
         hashmap_free_free(b->vtable_methods);
         hashmap_free_free(b->vtable_properties);
 
-        while ((n = hashmap_first(b->nodes)))
-                bus_node_destroy(b, n);
-
+        assert(hashmap_isempty(b->nodes));
         hashmap_free(b->nodes);
 
         bus_kernel_flush_memfd(b);
@@ -426,7 +396,7 @@ static int bus_send_hello(sd_bus *bus) {
         if (r < 0)
                 return r;
 
-        return sd_bus_call_async(bus, m, hello_callback, NULL, 0, &bus->hello_cookie);
+        return sd_bus_call_async(bus, NULL, m, hello_callback, NULL, 0);
 }
 
 int bus_start_running(sd_bus *bus) {
@@ -1793,14 +1763,14 @@ static int timeout_compare(const void *a, const void *b) {
 
 _public_ int sd_bus_call_async(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 sd_bus_message *_m,
                 sd_bus_message_handler_t callback,
                 void *userdata,
-                uint64_t usec,
-                uint64_t *cookie) {
+                uint64_t usec) {
 
         _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
-        struct reply_callback *c;
+        _cleanup_bus_slot_unref_ sd_bus_slot *s = NULL;
         int r;
 
         assert_return(bus, -EINVAL);
@@ -1830,55 +1800,37 @@ _public_ int sd_bus_call_async(
         if (r < 0)
                 return r;
 
-        c = new0(struct reply_callback, 1);
-        if (!c)
+        s = bus_slot_allocate(bus, !slot, BUS_REPLY_CALLBACK, sizeof(struct reply_callback), userdata);
+        if (!s)
                 return -ENOMEM;
 
-        c->callback = callback;
-        c->userdata = userdata;
-        c->cookie = BUS_MESSAGE_COOKIE(m);
-        c->timeout = calc_elapse(m->timeout);
+        s->reply_callback.callback = callback;
 
-        r = hashmap_put(bus->reply_callbacks, &c->cookie, c);
+        s->reply_callback.cookie = BUS_MESSAGE_COOKIE(m);
+        r = hashmap_put(bus->reply_callbacks, &s->reply_callback.cookie, &s->reply_callback);
         if (r < 0) {
-                free(c);
+                s->reply_callback.cookie = 0;
                 return r;
         }
 
-        if (c->timeout != 0) {
-                r = prioq_put(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+        s->reply_callback.timeout = calc_elapse(m->timeout);
+        if (s->reply_callback.timeout != 0) {
+                r = prioq_put(bus->reply_callbacks_prioq, &s->reply_callback, &s->reply_callback.prioq_idx);
                 if (r < 0) {
-                        c->timeout = 0;
-                        sd_bus_call_async_cancel(bus, c->cookie);
+                        s->reply_callback.timeout = 0;
                         return r;
                 }
         }
 
-        r = sd_bus_send(bus, m, cookie);
-        if (r < 0) {
-                sd_bus_call_async_cancel(bus, c->cookie);
+        r = sd_bus_send(bus, m, &s->reply_callback.cookie);
+        if (r < 0)
                 return r;
-        }
-
-        return r;
-}
-
-_public_ int sd_bus_call_async_cancel(sd_bus *bus, uint64_t cookie) {
-        struct reply_callback *c;
 
-        assert_return(bus, -EINVAL);
-        assert_return(cookie != 0, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        c = hashmap_remove(bus->reply_callbacks, &cookie);
-        if (!c)
-                return 0;
-
-        if (c->timeout != 0)
-                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+        if (slot)
+                *slot = s;
+        s = NULL;
 
-        free(c);
-        return 1;
+        return r;
 }
 
 int bus_ensure_running(sd_bus *bus) {
@@ -2125,6 +2077,11 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
                 return 0;
         }
 
+        if (c->timeout == 0) {
+                *timeout_usec = (uint64_t) -1;
+                return 0;
+        }
+
         *timeout_usec = c->timeout;
         return 1;
 }
@@ -2161,16 +2118,21 @@ static int process_timeout(sd_bus *bus) {
                 return r;
 
         assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
+        c->timeout = 0;
+
         hashmap_remove(bus->reply_callbacks, &c->cookie);
+        c->cookie = 0;
+
+        bus->current_message = m;
+        bus->current_slot = container_of(c, sd_bus_slot, reply_callback);
 
-        bus->current = m;
         bus->iteration_counter ++;
 
-        r = c->callback(bus, m, c->userdata, &error_buffer);
+        r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
         r = bus_maybe_reply_error(m, r, &error_buffer);
-        free(c);
 
-        bus->current = NULL;
+        bus->current_message = NULL;
+        bus->current_slot = NULL;
 
         return r;
 }
@@ -2191,7 +2153,7 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) {
             m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
                 return -EIO;
 
-        if (m->reply_cookie != bus->hello_cookie)
+        if (m->reply_cookie != 1)
                 return -EIO;
 
         return 0;
@@ -2200,7 +2162,8 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) {
 static int process_reply(sd_bus *bus, sd_bus_message *m) {
         _cleanup_bus_message_unref_ sd_bus_message *synthetic_reply = NULL;
         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-        _cleanup_free_ struct reply_callback *c = NULL;
+        sd_bus_slot *slot;
+        struct reply_callback *c;
         int r;
 
         assert(bus);
@@ -2220,8 +2183,13 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
         if (!c)
                 return 0;
 
-        if (c->timeout != 0)
+        c->cookie = 0;
+        slot = container_of(c, sd_bus_slot, reply_callback);
+
+        if (c->timeout != 0) {
                 prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+                c->timeout = 0;
+        }
 
         if (m->n_fds > 0 && !(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) {
 
@@ -2234,22 +2202,31 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
                                 &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptor"),
                                 &synthetic_reply);
                 if (r < 0)
-                        return r;
+                        goto finish;
 
                 r = bus_seal_synthetic_message(bus, synthetic_reply);
                 if (r < 0)
-                        return r;
+                        goto finish;
 
                 m = synthetic_reply;
         } else {
                 r = sd_bus_message_rewind(m, true);
                 if (r < 0)
-                        return r;
+                        goto finish;
         }
 
-        r = c->callback(bus, m, c->userdata, &error_buffer);
+        bus->current_slot = slot;
+        r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
+        bus->current_slot = NULL;
+
         r = bus_maybe_reply_error(m, r, &error_buffer);
 
+finish:
+        if (slot->floating) {
+                bus_slot_disconnect(slot);
+                sd_bus_slot_unref(slot);
+        }
+
         return r;
 }
 
@@ -2279,7 +2256,10 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) {
                         if (r < 0)
                                 return r;
 
-                        r = l->callback(bus, m, l->userdata, &error_buffer);
+                        bus->current_slot = container_of(l, sd_bus_slot, filter_callback);
+                        r = l->callback(bus, m, bus->current_slot->userdata, &error_buffer);
+                        bus->current_slot = NULL;
+
                         r = bus_maybe_reply_error(m, r, &error_buffer);
                         if (r != 0)
                                 return r;
@@ -2395,7 +2375,7 @@ static int process_message(sd_bus *bus, sd_bus_message *m) {
         assert(bus);
         assert(m);
 
-        bus->current = m;
+        bus->current_message = m;
         bus->iteration_counter++;
 
         log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " error=%s",
@@ -2436,7 +2416,7 @@ static int process_message(sd_bus *bus, sd_bus_message *m) {
         r = bus_process_object(bus, m);
 
 finish:
-        bus->current = NULL;
+        bus->current_message = NULL;
         return r;
 }
 
@@ -2539,17 +2519,23 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
                 if (r < 0)
                         return r;
 
-                if (c->timeout != 0)
+                if (c->timeout != 0) {
                         prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+                        c->timeout = 0;
+                }
 
                 hashmap_remove(bus->reply_callbacks, &c->cookie);
+                c->cookie = 0;
+
+                bus->current_message = m;
+                bus->current_slot = container_of(c, sd_bus_slot, reply_callback);
 
-                bus->current = m;
                 bus->iteration_counter++;
 
-                r = c->callback(bus, m, c->userdata, &error_buffer);
+                r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
                 r = bus_maybe_reply_error(m, r, &error_buffer);
-                free(c);
+
+                bus->current_slot = NULL;
 
                 goto finish;
         }
@@ -2572,7 +2558,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
 
         sd_bus_close(bus);
 
-        bus->current = m;
+        bus->current_message = m;
         bus->iteration_counter++;
 
         r = process_filter(bus, m);
@@ -2591,7 +2577,8 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
         r = 1;
 
 finish:
-        bus->current = NULL;
+        bus->current_message = NULL;
+
         return r;
 }
 
@@ -2608,7 +2595,8 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
         /* We don't allow recursively invoking sd_bus_process(). */
-        assert_return(!bus->current, -EBUSY);
+        assert_return(!bus->current_message, -EBUSY);
+        assert(!bus->current_slot);
 
         switch (bus->state) {
 
@@ -2785,57 +2773,43 @@ _public_ int sd_bus_flush(sd_bus *bus) {
         }
 }
 
-_public_ int sd_bus_add_filter(sd_bus *bus,
-                               sd_bus_message_handler_t callback,
-                               void *userdata) {
+_public_ int sd_bus_add_filter(
+                sd_bus *bus,
+                sd_bus_slot **slot,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
 
-        struct filter_callback *f;
+        sd_bus_slot *s;
 
         assert_return(bus, -EINVAL);
         assert_return(callback, -EINVAL);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
-        f = new0(struct filter_callback, 1);
-        if (!f)
+        s = bus_slot_allocate(bus, !slot, BUS_FILTER_CALLBACK, sizeof(struct filter_callback), userdata);
+        if (!s)
                 return -ENOMEM;
-        f->callback = callback;
-        f->userdata = userdata;
 
-        bus->filter_callbacks_modified = true;
-        LIST_PREPEND(callbacks, bus->filter_callbacks, f);
-        return 0;
-}
+        s->filter_callback.callback = callback;
 
-_public_ int sd_bus_remove_filter(sd_bus *bus,
-                                  sd_bus_message_handler_t callback,
-                                  void *userdata) {
-
-        struct filter_callback *f;
-
-        assert_return(bus, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
+        bus->filter_callbacks_modified = true;
+        LIST_PREPEND(callbacks, bus->filter_callbacks, &s->filter_callback);
 
-        LIST_FOREACH(callbacks, f, bus->filter_callbacks) {
-                if (f->callback == callback && f->userdata == userdata) {
-                        bus->filter_callbacks_modified = true;
-                        LIST_REMOVE(callbacks, bus->filter_callbacks, f);
-                        free(f);
-                        return 1;
-                }
-        }
+        if (slot)
+                *slot = s;
 
         return 0;
 }
 
-_public_ int sd_bus_add_match(sd_bus *bus,
-                              const char *match,
-                              sd_bus_message_handler_t callback,
-                              void *userdata) {
+_public_ int sd_bus_add_match(
+                sd_bus *bus,
+                sd_bus_slot **slot,
+                const char *match,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
 
         struct bus_match_component *components = NULL;
         unsigned n_components = 0;
-        uint64_t cookie = 0;
+        sd_bus_slot *s;
         int r = 0;
 
         assert_return(bus, -EINVAL);
@@ -2846,35 +2820,60 @@ _public_ int sd_bus_add_match(sd_bus *bus,
         if (r < 0)
                 goto finish;
 
+        s = bus_slot_allocate(bus, !slot, BUS_MATCH_CALLBACK, sizeof(struct match_callback), userdata);
+        if (!s) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        s->match_callback.callback = callback;
+        s->match_callback.cookie = ++bus->match_cookie;
+
         if (bus->bus_client) {
-                cookie = ++bus->match_cookie;
 
-                r = bus_add_match_internal(bus, match, components, n_components, cookie);
+                if (!bus->is_kernel) {
+                        /* When this is not a kernel transport, we
+                         * store the original match string, so that we
+                         * can use it to remove the match again */
+
+                        s->match_callback.match_string = strdup(match);
+                        if (!s->match_callback.match_string) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+                }
+
+                r = bus_add_match_internal(bus, s->match_callback.match_string, components, n_components, s->match_callback.cookie);
                 if (r < 0)
                         goto finish;
         }
 
         bus->match_callbacks_modified = true;
-        r = bus_match_add(&bus->match_callbacks, components, n_components, callback, userdata, cookie, NULL);
-        if (r < 0) {
-                if (bus->bus_client)
-                        bus_remove_match_internal(bus, match, cookie);
-        }
+        r = bus_match_add(&bus->match_callbacks, components, n_components, &s->match_callback);
+        if (r < 0)
+                goto finish;
+
+        if (slot)
+                *slot = s;
+        s = NULL;
 
 finish:
         bus_match_parse_free(components, n_components);
+        sd_bus_slot_unref(s);
+
         return r;
 }
 
-_public_ int sd_bus_remove_match(sd_bus *bus,
-                                 const char *match,
-                                 sd_bus_message_handler_t callback,
-                                 void *userdata) {
+int bus_remove_match_by_string(
+                sd_bus *bus,
+                const char *match,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
 
         struct bus_match_component *components = NULL;
         unsigned n_components = 0;
-        int r = 0, q = 0;
-        uint64_t cookie = 0;
+        struct match_callback *c;
+        int r = 0;
 
         assert_return(bus, -EINVAL);
         assert_return(match, -EINVAL);
@@ -2882,17 +2881,18 @@ _public_ int sd_bus_remove_match(sd_bus *bus,
 
         r = bus_match_parse(match, &components, &n_components);
         if (r < 0)
-                return r;
+                goto finish;
 
-        bus->match_callbacks_modified = true;
-        r = bus_match_remove(&bus->match_callbacks, components, n_components, callback, userdata, &cookie);
+        r = bus_match_find(&bus->match_callbacks, components, n_components, NULL, NULL, &c);
+        if (r <= 0)
+                goto finish;
 
-        if (bus->bus_client)
-                q = bus_remove_match_internal(bus, match, cookie);
+        sd_bus_slot_unref(container_of(c, sd_bus_slot, match_callback));
 
+finish:
         bus_match_parse_free(components, n_components);
 
-        return r < 0 ? r : q;
+        return r;
 }
 
 bool bus_pid_changed(sd_bus *bus) {
@@ -3116,10 +3116,16 @@ _public_ sd_event* sd_bus_get_event(sd_bus *bus) {
         return bus->event;
 }
 
-_public_ sd_bus_message* sd_bus_get_current(sd_bus *bus) {
+_public_ sd_bus_message* sd_bus_get_current_message(sd_bus *bus) {
+        assert_return(bus, NULL);
+
+        return bus->current_message;
+}
+
+_public_ sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus) {
         assert_return(bus, NULL);
 
-        return bus->current;
+        return bus->current_slot;
 }
 
 static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus **ret) {
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index c0abc7a..c9eb698 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -100,19 +100,19 @@ static int server_init(sd_bus **_bus) {
                 goto fail;
         }
 
-        r = sd_bus_add_fallback(bus, "/foo/bar", object_callback, NULL);
+        r = sd_bus_add_fallback(bus, NULL, "/foo/bar", object_callback, NULL);
         if (r < 0) {
                 log_error("Failed to add object: %s", strerror(-r));
                 goto fail;
         }
 
-        r = sd_bus_add_match(bus, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
+        r = sd_bus_add_match(bus, NULL, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
         if (r < 0) {
                 log_error("Failed to add match: %s", strerror(-r));
                 goto fail;
         }
 
-        r = sd_bus_add_match(bus, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
+        r = sd_bus_add_match(bus, NULL, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
         if (r < 0) {
                 log_error("Failed to add match: %s", strerror(-r));
                 goto fail;
@@ -490,7 +490,7 @@ static void* client2(void*p) {
                 goto finish;
         }
 
-        r = sd_bus_call_async(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL);
+        r = sd_bus_call_async(bus, NULL, m, quit_callback, &quit, 200 * USEC_PER_MSEC);
         if (r < 0) {
                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
                 goto finish;
diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
index 0ecad18..5ee6eea 100644
--- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
+++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
@@ -72,7 +72,7 @@ static void test_one(
         assert_se(r >= 0);
 
         log_debug("match");
-        r = sd_bus_add_match(b, match, NULL, NULL);
+        r = sd_bus_add_match(b, NULL, match, NULL, NULL);
         assert_se(r >= 0);
 
         log_debug("signal");
diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c
index 34d000f..7bb8b0a 100644
--- a/src/libsystemd/sd-bus/test-bus-kernel.c
+++ b/src/libsystemd/sd-bus/test-bus-kernel.c
@@ -101,7 +101,7 @@ int main(int argc, char *argv[]) {
         assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN));
         assert_se(r == -EHOSTUNREACH);
 
-        r = sd_bus_add_match(b, "interface='waldo.com',member='Piep'", NULL, NULL);
+        r = sd_bus_add_match(b, NULL, "interface='waldo.com',member='Piep'", NULL, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_emit_signal(a, "/foo/bar/waldo", "waldo.com", "Piep", "sss", "I am a string", "/this/is/a/path", "and.this.a.domain.name");
diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c
index c561be2..a62de50 100644
--- a/src/libsystemd/sd-bus/test-bus-match.c
+++ b/src/libsystemd/sd-bus/test-bus-match.c
@@ -28,6 +28,7 @@
 #include "bus-match.h"
 #include "bus-message.h"
 #include "bus-util.h"
+#include "bus-slot.h"
 
 static bool mask[32];
 
@@ -56,31 +57,23 @@ static bool mask_contains(unsigned a[], unsigned n) {
         return true;
 }
 
-static int match_add(struct bus_match_node *root, const char *match, int value) {
+static int match_add(sd_bus_slot *slots, struct bus_match_node *root, const char *match, int value) {
         struct bus_match_component *components = NULL;
         unsigned n_components = 0;
+        sd_bus_slot *s;
         int r;
 
-        r = bus_match_parse(match, &components, &n_components);
-        if (r < 0)
-                return r;
-
-        r = bus_match_add(root, components, n_components, filter, INT_TO_PTR(value), 0, NULL);
-        bus_match_parse_free(components, n_components);
-
-        return r;
-}
-
-static int match_remove(struct bus_match_node *root, const char *match, int value) {
-        struct bus_match_component *components = NULL;
-        unsigned n_components = 0;
-        int r;
+        s = slots + value;
+        zero(*s);
 
         r = bus_match_parse(match, &components, &n_components);
         if (r < 0)
                 return r;
 
-        r = bus_match_remove(root, components, n_components, filter, INT_TO_PTR(value), 0);
+        s->userdata = INT_TO_PTR(value);
+        s->match_callback.callback = filter;
+
+        r = bus_match_add(root, components, n_components, &s->match_callback);
         bus_match_parse_free(components, n_components);
 
         return r;
@@ -90,24 +83,25 @@ int main(int argc, char *argv[]) {
         struct bus_match_node root;
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
         enum bus_match_node_type i;
+        sd_bus_slot slots[15];
 
         zero(root);
         root.type = BUS_MATCH_ROOT;
 
-        assert_se(match_add(&root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0);
-        assert_se(match_add(&root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0);
-        assert_se(match_add(&root, "arg3='test',sender='foo',type='signal',interface='bar.x',", 3) >= 0);
-        assert_se(match_add(&root, "arg3='test',sender='foo',type='method_call',interface='bar.x',", 4) >= 0);
-        assert_se(match_add(&root, "", 5) >= 0);
-        assert_se(match_add(&root, "interface='quux.x'", 6) >= 0);
-        assert_se(match_add(&root, "interface='bar.x'", 7) >= 0);
-        assert_se(match_add(&root, "member='waldo',path='/foo/bar'", 8) >= 0);
-        assert_se(match_add(&root, "path='/foo/bar'", 9) >= 0);
-        assert_se(match_add(&root, "path_namespace='/foo'", 10) >= 0);
-        assert_se(match_add(&root, "path_namespace='/foo/quux'", 11) >= 0);
-        assert_se(match_add(&root, "arg1='two'", 12) >= 0);
-        assert_se(match_add(&root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
-        assert_se(match_add(&root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
+        assert_se(match_add(slots, &root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0);
+        assert_se(match_add(slots, &root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0);
+        assert_se(match_add(slots, &root, "arg3='test',sender='foo',type='signal',interface='bar.x',", 3) >= 0);
+        assert_se(match_add(slots, &root, "arg3='test',sender='foo',type='method_call',interface='bar.x',", 4) >= 0);
+        assert_se(match_add(slots, &root, "", 5) >= 0);
+        assert_se(match_add(slots, &root, "interface='quux.x'", 6) >= 0);
+        assert_se(match_add(slots, &root, "interface='bar.x'", 7) >= 0);
+        assert_se(match_add(slots, &root, "member='waldo',path='/foo/bar'", 8) >= 0);
+        assert_se(match_add(slots, &root, "path='/foo/bar'", 9) >= 0);
+        assert_se(match_add(slots, &root, "path_namespace='/foo'", 10) >= 0);
+        assert_se(match_add(slots, &root, "path_namespace='/foo/quux'", 11) >= 0);
+        assert_se(match_add(slots, &root, "arg1='two'", 12) >= 0);
+        assert_se(match_add(slots, &root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
+        assert_se(match_add(slots, &root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
 
         bus_match_dump(&root, 0);
 
@@ -119,9 +113,8 @@ int main(int argc, char *argv[]) {
         assert_se(bus_match_run(NULL, &root, m) == 0);
         assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14 }, 8));
 
-        assert_se(match_remove(&root, "member='waldo',path='/foo/bar'", 8) > 0);
-        assert_se(match_remove(&root, "arg2path='/prefix/',member='waldo'", 13) > 0);
-        assert_se(match_remove(&root, "interface='bar.xx'", 7) == 0);
+        assert_se(bus_match_remove(&root, &slots[8].match_callback) >= 0);
+        assert_se(bus_match_remove(&root, &slots[13].match_callback) >= 0);
 
         bus_match_dump(&root, 0);
 
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
index e2423c7..e7a445f 100644
--- a/src/libsystemd/sd-bus/test-bus-objects.c
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -200,7 +200,7 @@ static const sd_bus_vtable vtable2[] = {
         SD_BUS_VTABLE_END
 };
 
-static int enumerator_callback(sd_bus *b, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
 
         if (object_path_startswith("/value", path))
                 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
@@ -222,11 +222,11 @@ static void *server(void *p) {
         assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
         assert_se(sd_bus_set_server(bus, 1, id) >= 0);
 
-        assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
-        assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
-        assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
-        assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
-        assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
+        assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
+        assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
+        assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
+        assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
+        assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
 
         assert_se(sd_bus_start(bus) >= 0);
 
diff --git a/src/locale/localed.c b/src/locale/localed.c
index de6e3b2..e3061c8 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -1088,7 +1088,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(bus, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
+        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
         if (r < 0) {
                 log_error("Failed to register object: %s", strerror(-r));
                 return r;
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
index 82323d6..1a2f09c 100644
--- a/src/login/logind-seat-dbus.c
+++ b/src/login/logind-seat-dbus.c
@@ -329,7 +329,7 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void
                 Session *session;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index ffdc558..7d81500 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -493,7 +493,7 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo
                 sd_bus_message *message;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index b5d27e7..4f1a079 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -250,7 +250,7 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void
                 sd_bus_message *message;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
diff --git a/src/login/logind.c b/src/login/logind.c
index 86ce7df..686506c 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -586,49 +586,50 @@ static int manager_connect_bus(Manager *m) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m);
+        r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m);
         if (r < 0) {
                 log_error("Failed to add manager object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
+        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
         if (r < 0) {
                 log_error("Failed to add seat object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/login1/seat", seat_node_enumerator, m);
+        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/seat", seat_node_enumerator, m);
         if (r < 0) {
                 log_error("Failed to add seat enumerator: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m);
+        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m);
         if (r < 0) {
                 log_error("Failed to add session object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/login1/session", session_node_enumerator, m);
+        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/session", session_node_enumerator, m);
         if (r < 0) {
                 log_error("Failed to add session enumerator: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m);
+        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m);
         if (r < 0) {
                 log_error("Failed to add user object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/login1/user", user_node_enumerator, m);
+        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/user", user_node_enumerator, m);
         if (r < 0) {
                 log_error("Failed to add user enumerator: %s", strerror(-r));
                 return r;
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.DBus',"
                              "interface='org.freedesktop.DBus',"
@@ -641,6 +642,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
@@ -653,6 +655,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
@@ -665,6 +668,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.DBus.Properties',"
@@ -676,6 +680,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index 920c995..83ef82d 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -160,7 +160,7 @@ int machine_object_find(sd_bus *bus, const char *path, const char *interface, vo
                 sd_bus_message *message;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
diff --git a/src/machine/machined.c b/src/machine/machined.c
index 20e6f7c..45768d2 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -141,25 +141,26 @@ static int manager_connect_bus(Manager *m) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
+        r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
         if (r < 0) {
                 log_error("Failed to add manager object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
+        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
         if (r < 0) {
                 log_error("Failed to add machine object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
+        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
         if (r < 0) {
                 log_error("Failed to add machine enumerator: %s", strerror(-r));
                 return r;
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
@@ -173,6 +174,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
@@ -186,6 +188,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.DBus.Properties',"
@@ -198,6 +201,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 77c505f..37a572d 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -684,7 +684,7 @@ static int link_set_hostname(Link *link, const char *hostname) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_async(link->manager->bus, m, set_hostname_handler, link, 0, NULL);
+        r = sd_bus_call_async(link->manager->bus, NULL, m, set_hostname_handler, link, 0);
         if (r < 0)
                 log_error_link(link, "Could not set transient hostname: %s", strerror(-r));
 
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index e1e4640..91d8032 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2305,6 +2305,7 @@ static int enable_wait_for_jobs(sd_bus *bus) {
 
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "type='signal',"
                         "sender='org.freedesktop.systemd1',"
                         "interface='org.freedesktop.systemd1.Manager',"
@@ -2364,13 +2365,14 @@ static int check_wait_response(WaitData *d) {
 }
 
 static int wait_for_jobs(sd_bus *bus, Set *s) {
+        _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
         WaitData d = { .set = s };
         int r = 0, q;
 
         assert(bus);
         assert(s);
 
-        q = sd_bus_add_filter(bus, wait_filter, &d);
+        q = sd_bus_add_filter(bus, &slot, wait_filter, &d);
         if (q < 0)
                 return log_oom();
 
@@ -2398,10 +2400,6 @@ static int wait_for_jobs(sd_bus *bus, Set *s) {
                 d.result = NULL;
         }
 
-        q = sd_bus_remove_filter(bus, wait_filter, &d);
-        if (q < 0 && r == 0)
-                r = q;
-
         return r;
 }
 
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index c6787ca..79566d2 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -37,6 +37,7 @@ _SD_BEGIN_DECLARATIONS;
 
 typedef struct sd_bus sd_bus;
 typedef struct sd_bus_message sd_bus_message;
+typedef struct sd_bus_slot sd_bus_slot;
 typedef struct sd_bus_creds sd_bus_creds;
 typedef struct sd_bus_track sd_bus_track;
 
@@ -138,8 +139,7 @@ int sd_bus_get_tid(sd_bus *bus, pid_t *tid);
 int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie);
 int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie);
 int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply);
-int sd_bus_call_async(sd_bus *bus, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec, uint64_t *cookie);
-int sd_bus_call_async_cancel(sd_bus *bus, uint64_t cookie);
+int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec);
 
 int sd_bus_get_fd(sd_bus *bus);
 int sd_bus_get_events(sd_bus *bus);
@@ -148,35 +148,33 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **r);
 int sd_bus_process_priority(sd_bus *bus, int64_t max_priority, sd_bus_message **r);
 int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
 int sd_bus_flush(sd_bus *bus);
-sd_bus_message* sd_bus_get_current(sd_bus *bus);
+sd_bus_message* sd_bus_get_current_message(sd_bus *bus);
+sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus);
 
 int sd_bus_attach_event(sd_bus *bus, sd_event *e, int priority);
 int sd_bus_detach_event(sd_bus *bus);
 sd_event *sd_bus_get_event(sd_bus *bus);
 
-int sd_bus_add_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata);
-int sd_bus_remove_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_filter(sd_bus *bus, sd_bus_slot **slot, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_object(sd_bus *bus, sd_bus_slot **slot, const char *path, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_fallback(sd_bus *bus, sd_bus_slot **slot, const char *prefix, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata);
+int sd_bus_add_fallback_vtable(sd_bus *bus, sd_bus_slot **slot, const char *prefix, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata);
+int sd_bus_add_node_enumerator(sd_bus *bus, sd_bus_slot **slot, const char *path, sd_bus_node_enumerator_t callback, void *userdata);
+int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path);
 
-int sd_bus_add_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
-int sd_bus_remove_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
+/* Slot object */
 
-int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata);
-int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata);
+sd_bus_slot* sd_bus_slot_ref(sd_bus_slot *slot);
+sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot);
 
-int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata);
-int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata);
+sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot);
 
-int sd_bus_add_object_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata);
-int sd_bus_remove_object_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata);
+void *sd_bus_slot_get_userdata(sd_bus_slot *slot);
+void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata);
 
-int sd_bus_add_fallback_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata);
-int sd_bus_remove_fallback_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata);
-
-int sd_bus_add_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata);
-int sd_bus_remove_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata);
-
-int sd_bus_add_object_manager(sd_bus *bus, const char *path);
-int sd_bus_remove_object_manager(sd_bus *bus, const char *path);
+sd_bus_message* sd_bus_slot_get_current_message(sd_bus_slot *slot);
 
 /* Message object */
 
diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
index 3895e32..1b09380 100644
--- a/src/timedate/timedated.c
+++ b/src/timedate/timedated.c
@@ -784,7 +784,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c);
+        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c);
         if (r < 0) {
                 log_error("Failed to register object: %s", strerror(-r));
                 return r;

commit 9a78148e40402b44f361f4fbf63bb97a21aeac0b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu May 15 00:44:29 2014 +0200

    sd-event: reorder header slightly

diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
index 75ee341..5d9b3be 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -99,14 +99,16 @@ int sd_event_get_watchdog(sd_event *e);
 sd_event_source* sd_event_source_ref(sd_event_source *s);
 sd_event_source* sd_event_source_unref(sd_event_source *s);
 
+sd_event *sd_event_source_get_event(sd_event_source *s);
+void* sd_event_source_get_userdata(sd_event_source *s);
+void* sd_event_source_set_userdata(sd_event_source *s, void *userdata);
+
 int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback);
 int sd_event_source_get_pending(sd_event_source *s);
 int sd_event_source_get_priority(sd_event_source *s, int64_t *priority);
 int sd_event_source_set_priority(sd_event_source *s, int64_t priority);
 int sd_event_source_get_enabled(sd_event_source *s, int *enabled);
 int sd_event_source_set_enabled(sd_event_source *s, int enabled);
-void* sd_event_source_get_userdata(sd_event_source *s);
-void* sd_event_source_set_userdata(sd_event_source *s, void *userdata);
 int sd_event_source_get_io_fd(sd_event_source *s);
 int sd_event_source_set_io_fd(sd_event_source *s, int fd);
 int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events);
@@ -119,7 +121,6 @@ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec);
 int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock);
 int sd_event_source_get_signal(sd_event_source *s);
 int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid);
-sd_event *sd_event_source_get_event(sd_event_source *s);
 
 _SD_END_DECLARATIONS;
 

commit c582a3b3e8d263defbda98ecff793431a4cffa93
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu May 15 00:43:44 2014 +0200

    hashmap: add hashmap_remove2() to remove item from hashtable and return both value and key

diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c
index 65b7b74..5c3efa8 100644
--- a/src/shared/hashmap.c
+++ b/src/shared/hashmap.c
@@ -582,6 +582,34 @@ void* hashmap_remove(Hashmap *h, const void *key) {
         return data;
 }
 
+void* hashmap_remove2(Hashmap *h, const void *key, void **rkey) {
+        struct hashmap_entry *e;
+        unsigned hash;
+        void *data;
+
+        if (!h) {
+                if (rkey)
+                        *rkey = NULL;
+                return NULL;
+        }
+
+        hash = bucket_hash(h, key);
+        e = hash_scan(h, hash, key);
+        if (!e) {
+                if (rkey)
+                        *rkey = NULL;
+                return NULL;
+        }
+
+        data = e->value;
+        if (rkey)
+                *rkey = (void*) e->key;
+
+        remove_entry(h, e);
+
+        return data;
+}
+
 int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
         struct hashmap_entry *e;
         unsigned old_hash, new_hash;
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
index 154f68e..bfad970 100644
--- a/src/shared/hashmap.h
+++ b/src/shared/hashmap.h
@@ -69,6 +69,7 @@ void *hashmap_get(Hashmap *h, const void *key);
 void *hashmap_get2(Hashmap *h, const void *key, void **rkey);
 bool hashmap_contains(Hashmap *h, const void *key);
 void *hashmap_remove(Hashmap *h, const void *key);
+void *hashmap_remove2(Hashmap *h, const void *key, void **rkey);
 void *hashmap_remove_value(Hashmap *h, const void *key, void *value);
 int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
 int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value);

commit 4f4f70361a64957c45a2d8f40bfb04c77b454697
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed May 14 22:44:45 2014 +0200

    core: no need to pass bus object to selinux access check calls anymore

diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index 5c364a4..8e4ffc9 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -60,7 +60,7 @@ static int method_cancel(sd_bus *bus, sd_bus_message *message, void *userdata, s
         assert(message);
         assert(j);
 
-        r = selinux_unit_access_check(j->unit, bus, message, "stop", error);
+        r = selinux_unit_access_check(j->unit, message, "stop", error);
         if (r < 0)
                 return r;
 
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 135d314..58e484d 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -360,7 +360,7 @@ static int method_get_unit(sd_bus *bus, sd_bus_message *message, void *userdata,
         if (!u)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
 
-        r = selinux_unit_access_check(u, bus, message, "status", error);
+        r = selinux_unit_access_check(u, message, "status", error);
         if (r < 0)
                 return r;
 
@@ -404,7 +404,7 @@ static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *us
         if (!u)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID %u does not belong to any loaded unit.", pid);
 
-        r = selinux_unit_access_check(u, bus, message, "status", error);
+        r = selinux_unit_access_check(u, message, "status", error);
         if (r < 0)
                 return r;
 
@@ -434,7 +434,7 @@ static int method_load_unit(sd_bus *bus, sd_bus_message *message, void *userdata
         if (r < 0)
                 return r;
 
-        r = selinux_unit_access_check(u, bus, message, "status", error);
+        r = selinux_unit_access_check(u, message, "status", error);
         if (r < 0)
                 return r;
 
@@ -604,7 +604,7 @@ static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, voi
         if (mode < 0)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode);
 
-        r = selinux_access_check(bus, message, "start", error);
+        r = selinux_access_check(message, "start", error);
         if (r < 0)
                 return r;
 
@@ -656,7 +656,7 @@ static int method_get_job(sd_bus *bus, sd_bus_message *message, void *userdata,
         if (!j)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
 
-        r = selinux_unit_access_check(j->unit, bus, message, "status", error);
+        r = selinux_unit_access_check(j->unit, message, "status", error);
         if (r < 0)
                 return r;
 
@@ -685,7 +685,7 @@ static int method_cancel_job(sd_bus *bus, sd_bus_message *message, void *userdat
         if (!j)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
 
-        r = selinux_unit_access_check(j->unit, bus, message, "stop", error);
+        r = selinux_unit_access_check(j->unit, message, "stop", error);
         if (r < 0)
                 return r;
 
@@ -702,7 +702,7 @@ static int method_clear_jobs(sd_bus *bus, sd_bus_message *message, void *userdat
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reboot", error);
+        r = selinux_access_check(message, "reboot", error);
         if (r < 0)
                 return r;
 
@@ -719,7 +719,7 @@ static int method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userd
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reload", error);
+        r = selinux_access_check(message, "reload", error);
         if (r < 0)
                 return r;
 
@@ -740,7 +740,7 @@ static int method_list_units(sd_bus *bus, sd_bus_message *message, void *userdat
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "status", error);
+        r = selinux_access_check(message, "status", error);
         if (r < 0)
                 return r;
 
@@ -805,7 +805,7 @@ static int method_list_jobs(sd_bus *bus, sd_bus_message *message, void *userdata
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "status", error);
+        r = selinux_access_check(message, "status", error);
         if (r < 0)
                 return r;
 
@@ -855,7 +855,7 @@ static int method_subscribe(sd_bus *bus, sd_bus_message *message, void *userdata
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "status", error);
+        r = selinux_access_check(message, "status", error);
         if (r < 0)
                 return r;
 
@@ -888,7 +888,7 @@ static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userda
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "status", error);
+        r = selinux_access_check(message, "status", error);
         if (r < 0)
                 return r;
 
@@ -914,7 +914,7 @@ static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "status", error);
+        r = selinux_access_check(message, "status", error);
         if (r < 0)
                 return r;
 
@@ -945,7 +945,7 @@ static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *us
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "start", error);
+        r = selinux_access_check(message, "start", error);
         if (r < 0)
                 return r;
 
@@ -977,7 +977,7 @@ static int method_remove_snapshot(sd_bus *bus, sd_bus_message *message, void *us
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "stop", error);
+        r = selinux_access_check(message, "stop", error);
         if (r < 0)
                 return r;
 
@@ -1003,7 +1003,7 @@ static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, s
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reload", error);
+        r = selinux_access_check(message, "reload", error);
         if (r < 0)
                 return r;
 
@@ -1031,7 +1031,7 @@ static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reload", error);
+        r = selinux_access_check(message, "reload", error);
         if (r < 0)
                 return r;
 
@@ -1050,7 +1050,7 @@ static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "halt", error);
+        r = selinux_access_check(message, "halt", error);
         if (r < 0)
                 return r;
 
@@ -1070,7 +1070,7 @@ static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, s
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reboot", error);
+        r = selinux_access_check(message, "reboot", error);
         if (r < 0)
                 return r;
 
@@ -1091,7 +1091,7 @@ static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata,
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "halt", error);
+        r = selinux_access_check(message, "halt", error);
         if (r < 0)
                 return r;
 
@@ -1111,7 +1111,7 @@ static int method_halt(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "halt", error);
+        r = selinux_access_check(message, "halt", error);
         if (r < 0)
                 return r;
 
@@ -1131,7 +1131,7 @@ static int method_kexec(sd_bus *bus, sd_bus_message *message, void *userdata, sd
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reboot", error);
+        r = selinux_access_check(message, "reboot", error);
         if (r < 0)
                 return r;
 
@@ -1153,7 +1153,7 @@ static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userda
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reboot", error);
+        r = selinux_access_check(message, "reboot", error);
         if (r < 0)
                 return r;
 
@@ -1217,7 +1217,7 @@ static int method_set_environment(sd_bus *bus, sd_bus_message *message, void *us
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reload", error);
+        r = selinux_access_check(message, "reload", error);
         if (r < 0)
                 return r;
 
@@ -1243,7 +1243,7 @@ static int method_unset_environment(sd_bus *bus, sd_bus_message *message, void *
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reload", error);
+        r = selinux_access_check(message, "reload", error);
         if (r < 0)
                 return r;
 
@@ -1270,7 +1270,7 @@ static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "reload", error);
+        r = selinux_access_check(message, "reload", error);
         if (r < 0)
                 return r;
 
@@ -1306,7 +1306,7 @@ static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *us
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "status", error);
+        r = selinux_access_check(message, "status", error);
         if (r < 0)
                 return r;
 
@@ -1357,7 +1357,7 @@ static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "status", error);
+        r = selinux_access_check(message, "status", error);
         if (r < 0)
                 return r;
 
@@ -1384,7 +1384,7 @@ static int method_get_default_target(sd_bus *bus, sd_bus_message *message, void
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "status", error);
+        r = selinux_access_check(message, "status", error);
         if (r < 0)
                 return r;
 
@@ -1495,7 +1495,7 @@ static int method_enable_unit_files_generic(
 
                 u = manager_get_unit(m, *i);
                 if (u) {
-                        r = selinux_unit_access_check(u, bus, message, verb, error);
+                        r = selinux_unit_access_check(u, message, verb, error);
                         if (r < 0)
                                 return r;
                 }
@@ -1553,7 +1553,7 @@ static int method_disable_unit_files_generic(
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, verb, error);
+        r = selinux_access_check(message, verb, error);
         if (r < 0)
                 return r;
 
@@ -1594,7 +1594,7 @@ static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void
         assert(message);
         assert(m);
 
-        r = selinux_access_check(bus, message, "enable", error);
+        r = selinux_access_check(message, "enable", error);
         if (r < 0)
                 return r;
 
diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c
index 053e35c..2a5ef44 100644
--- a/src/core/dbus-snapshot.c
+++ b/src/core/dbus-snapshot.c
@@ -33,7 +33,7 @@ int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userd
         assert(message);
         assert(s);
 
-        r = selinux_unit_access_check(UNIT(s), bus, message, "stop", error);
+        r = selinux_unit_access_check(UNIT(s), message, "stop", error);
         if (r < 0)
                 return r;
 
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 07e7f20..8f23fe7 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -436,7 +436,7 @@ int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, s
         if (signo <= 0 || signo >= _NSIG)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
 
-        r = selinux_unit_access_check(u, bus, message, "stop", error);
+        r = selinux_unit_access_check(u, message, "stop", error);
         if (r < 0)
                 return r;
 
@@ -455,7 +455,7 @@ int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *use
         assert(message);
         assert(u);
 
-        r = selinux_unit_access_check(u, bus, message, "reload", error);
+        r = selinux_unit_access_check(u, message, "reload", error);
         if (r < 0)
                 return r;
 
@@ -476,7 +476,7 @@ int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *u
         if (r < 0)
                 return r;
 
-        r = selinux_unit_access_check(u, bus, message, "start", error);
+        r = selinux_unit_access_check(u, message, "start", error);
         if (r < 0)
                 return r;
 
@@ -737,7 +737,7 @@ int bus_unit_queue_job(
         }
 
         r = selinux_unit_access_check(
-                        u, bus, message,
+                        u, message,
                         (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
                         type == JOB_STOP ? "stop" : "reload", error);
         if (r < 0)
diff --git a/src/core/dbus.c b/src/core/dbus.c
index e9bf34c..189d925 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -239,7 +239,7 @@ static int selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata,
 
         if (object_path_startswith("/org/freedesktop/systemd1", path)) {
 
-                r = selinux_access_check(bus, message, verb, error);
+                r = selinux_access_check(message, verb, error);
                 if (r < 0)
                         return r;
 
@@ -270,7 +270,7 @@ static int selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata,
         if (!u)
                 return 0;
 
-        r = selinux_unit_access_check(u, bus, message, verb, error);
+        r = selinux_unit_access_check(u, message, verb, error);
         if (r < 0)
                 return r;
 
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index 21c7a8c..53e08af 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -169,7 +169,6 @@ void selinux_access_free(void) {
    still be generated if the access would be denied in enforcing mode.
 */
 int selinux_generic_access_check(
-                sd_bus *bus,
                 sd_bus_message *message,
                 const char *path,
                 const char *permission,
@@ -183,7 +182,6 @@ int selinux_generic_access_check(
         char **cmdline = NULL;
         int r = 0;
 
-        assert(bus);
         assert(message);
         assert(permission);
         assert(error);
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
index 9e89064..27d9e14 100644
--- a/src/core/selinux-access.h
+++ b/src/core/selinux-access.h
@@ -27,18 +27,22 @@
 
 void selinux_access_free(void);
 
-int selinux_generic_access_check(sd_bus *bus, sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);
+int selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);
 
 #ifdef HAVE_SELINUX
 
-#define selinux_access_check(bus, message, permission, error) \
-        selinux_generic_access_check(bus, message, NULL, permission, error)
-#define selinux_unit_access_check(unit, bus, message, permission, error) \
-        ({ Unit *_unit = (unit); selinux_generic_access_check(bus, message, _unit->fragment_path ?: _unit->fragment_path, permission, error); })
+#define selinux_access_check(message, permission, error) \
+        selinux_generic_access_check((message), NULL, (permission), (error))
+
+#define selinux_unit_access_check(unit, message, permission, error) \
+        ({                                                              \
+                Unit *_unit = (unit);                                   \
+                selinux_generic_access_check((message), _unit->fragment_path ?: _unit->fragment_path, (permission), (error)); \
+        })
 
 #else
 
-#define selinux_access_check(bus, message, permission, error) 0
-#define selinux_unit_access_check(unit, bus, message, permission, error) 0
+#define selinux_access_check(message, permission, error) 0
+#define selinux_unit_access_check(unit, message, permission, error) 0
 
 #endif

commit 04552566fa357d3029f06b66690dc28752522e10
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue May 6 19:15:36 2014 +0200

    bus: add userdata API for bus name tracker objects

diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4
index d18d576..14d9dcf 100644
--- a/src/libsystemd/libsystemd.sym.m4
+++ b/src/libsystemd/libsystemd.sym.m4
@@ -331,6 +331,8 @@ m4_ifdef(`ENABLE_KDBUS',
         sd_bus_track_ref;
         sd_bus_track_unref;
         sd_bus_track_get_bus;
+        sd_bus_track_get_userdata;
+        sd_bus_track_set_userdata;
         sd_bus_track_add_sender;
         sd_bus_track_remove_sender;
         sd_bus_track_add_name;
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index e21959d..0f6a2ea 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -312,3 +312,20 @@ void bus_track_dispatch(sd_bus_track *track) {
 
         sd_bus_track_unref(track);
 }
+
+_public_ void *sd_bus_track_get_userdata(sd_bus_track *track) {
+        assert_return(track, NULL);
+
+        return track->userdata;
+}
+
+_public_ void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata) {
+        void *ret;
+
+        assert_return(track, NULL);
+
+        ret = track->userdata;
+        track->userdata = userdata;
+
+        return ret;
+}
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index ff2333f..c6787ca 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -358,7 +358,10 @@ int sd_bus_path_decode(const char *path, const char *prefix, char **ret_external
 int sd_bus_track_new(sd_bus *bus, sd_bus_track **track, sd_bus_track_handler_t handler, void *userdata);
 sd_bus_track* sd_bus_track_ref(sd_bus_track *track);
 sd_bus_track* sd_bus_track_unref(sd_bus_track *track);
+
 sd_bus* sd_bus_track_get_bus(sd_bus_track *track);
+void *sd_bus_track_get_userdata(sd_bus_track *track);
+void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata);
 
 int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m);
 int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m);



More information about the systemd-commits mailing list