From: Lennart Poettering Date: Fri, 17 May 2013 01:13:58 +0000 (+0200) Subject: bus: add minimal locking around the memfd cache X-Git-Tag: v205~220 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=45fbe937d7ca8d0da9ea276d57bc70ebd41c285e bus: add minimal locking around the memfd cache We want to allow clients to process an sd_bus_message on a different thread than it was received on. Since unreffing a bus message might readd some of its memfds to the memfd cache add some minimal locking around the cache. --- diff --git a/Makefile.am b/Makefile.am index 526598277..66f12e903 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1749,6 +1749,10 @@ libsystemd_bus_la_LIBADD = \ libsystemd-shared.la \ libsystemd-daemon.la +libsystemd_bus_la_CFLAGS = \ + $(AM_CFLAGS) \ + -pthread + noinst_LTLIBRARIES += \ libsystemd-bus.la diff --git a/TODO b/TODO index f609b4b5a..390106aad 100644 --- a/TODO +++ b/TODO @@ -42,7 +42,6 @@ Features: - port systemd to new library - implement busname unit type in systemd - move to gvariant - - minimal locking around the memfd cache - keep the connection fds around as long as the bus is open - merge busctl into systemctl or so? - synthesize sd_bus_message objects from kernel messages diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h index b6975c54a..8f87bea78 100644 --- a/src/libsystemd-bus/bus-internal.h +++ b/src/libsystemd-bus/bus-internal.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "hashmap.h" #include "prioq.h" @@ -169,6 +170,13 @@ struct sd_bus { void *kdbus_buffer; + /* We do locking around the memfd cache, since we want to + * allow people to process a sd_bus_message in a different + * thread then it was generated on and free it there. Since + * adding something to the memfd cache might happen when a + * message is released, we hence need to protect this bit with + * a mutex. */ + pthread_mutex_t memfd_cache_mutex; struct memfd_cache memfd_cache[MEMFD_CACHE_MAX]; unsigned n_memfd_cache; diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c index ede78d7be..699d24185 100644 --- a/src/libsystemd-bus/bus-kernel.c +++ b/src/libsystemd-bus/bus-kernel.c @@ -721,6 +721,7 @@ int bus_kernel_create(const char *name, char **s) { int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) { struct memfd_cache *c; + int fd; assert(address); assert(size); @@ -728,8 +729,12 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) { if (!bus || !bus->is_kernel) return -ENOTSUP; + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); + if (bus->n_memfd_cache <= 0) { - int fd, r; + int r; + + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd); if (r < 0) @@ -747,8 +752,18 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) { *address = c->address; *size = c->size; + fd = c->fd; + + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); - return c->fd; + return fd; +} + +static void close_and_munmap(int fd, void *address, size_t size) { + if (size > 0) + assert_se(munmap(address, PAGE_ALIGN(size)) == 0); + + close_nointr_nofail(fd); } void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) { @@ -757,13 +772,17 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) { assert(fd >= 0); assert(size == 0 || address); - if (!bus || !bus->is_kernel || - bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { + if (!bus || !bus->is_kernel) { + close_and_munmap(fd, address, size); + return; + } + + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); - if (size > 0) - assert_se(munmap(address, PAGE_ALIGN(size)) == 0); + if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); - close_nointr_nofail(fd); + close_and_munmap(fd, address, size); return; } @@ -780,6 +799,8 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) { c->size = MEMFD_CACHE_ITEM_SIZE_MAX; } else c->size = size; + + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); } void bus_kernel_flush_memfd(sd_bus *b) { diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index fd19ff32b..5e66a3116 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "util.h" #include "macro.h" @@ -106,6 +107,8 @@ static void bus_free(sd_bus *b) { bus_kernel_flush_memfd(b); + assert_se(pthread_mutex_destroy(&b->memfd_cache_mutex) == 0); + free(b); } @@ -125,6 +128,8 @@ int sd_bus_new(sd_bus **ret) { r->negotiate_fds = true; r->original_pid = getpid(); + assert_se(pthread_mutex_init(&r->memfd_cache_mutex, NULL) == 0); + /* We guarantee that wqueue always has space for at least one * entry */ r->wqueue = new(sd_bus_message*, 1);