diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-05-17 03:13:58 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-05-17 04:26:27 +0200 |
commit | 45fbe937d7ca8d0da9ea276d57bc70ebd41c285e (patch) | |
tree | 95b216605530430206c7d863bca4d1d610382d25 /src/libsystemd-bus/bus-kernel.c | |
parent | d5a2b9a6f455468a0f29483303657ab4fd7013d8 (diff) |
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.
Diffstat (limited to 'src/libsystemd-bus/bus-kernel.c')
-rw-r--r-- | src/libsystemd-bus/bus-kernel.c | 35 |
1 files changed, 28 insertions, 7 deletions
diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c index ede78d7bef..699d24185e 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) { |