+
+int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) {
+ struct memfd_cache *c;
+
+ assert(address);
+ assert(size);
+
+ if (!bus || !bus->is_kernel)
+ return -ENOTSUP;
+
+ if (bus->n_memfd_cache <= 0) {
+ int fd, r;
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd);
+ if (r < 0)
+ return -errno;
+
+ *address = NULL;
+ *size = 0;
+ return fd;
+ }
+
+ c = &bus->memfd_cache[-- bus->n_memfd_cache];
+
+ assert(c->fd >= 0);
+ assert(c->size == 0 || c->address);
+
+ *address = c->address;
+ *size = c->size;
+
+ return c->fd;
+}
+
+void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) {
+ struct memfd_cache *c;
+
+ assert(fd >= 0);
+ assert(size == 0 || address);
+
+ if (!bus || !bus->is_kernel ||
+ bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
+
+ if (size > 0)
+ assert_se(munmap(address, PAGE_ALIGN(size)) == 0);
+
+ close_nointr_nofail(fd);
+ return;
+ }
+
+ c = &bus->memfd_cache[bus->n_memfd_cache++];
+ c->fd = fd;
+ c->address = address;
+
+ /* If overly long, let's return a bit to the OS */
+ if (size > MEMFD_CACHE_ITEM_SIZE_MAX) {
+ uint64_t sz = MEMFD_CACHE_ITEM_SIZE_MAX;
+
+ ioctl(bus->input_fd, KDBUS_CMD_MEMFD_SIZE_SET, &sz);
+
+ c->size = MEMFD_CACHE_ITEM_SIZE_MAX;
+ } else
+ c->size = size;
+}
+
+void bus_kernel_flush_memfd(sd_bus *b) {
+ unsigned i;
+
+ assert(b);
+
+ for (i = 0; i < b->n_memfd_cache; i++) {
+ if (b->memfd_cache[i].size > 0)
+ assert_se(munmap(b->memfd_cache[i].address, PAGE_ALIGN(b->memfd_cache[i].size)) == 0);
+
+ close_nointr_nofail(b->memfd_cache[i].fd);
+ }
+}