mmap-cache.c revision 69adae5168da231c6cf319f708860954701b25ed
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering This file is part of systemd.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Copyright 2012 Lennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering systemd is free software; you can redistribute it and/or modify it
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering under the terms of the GNU Lesser General Public License as published by
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering (at your option) any later version.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering systemd is distributed in the hope that it will be useful, but
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Lesser General Public License for more details.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering You should have received a copy of the GNU Lesser General Public License
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d025f1e4dca8fc1436aff76f9e6185fe3e728daaZbigniew Jędrzejewski-Szmektypedef struct FileDescriptor FileDescriptor;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Context *contexts[MMAP_CACHE_MAX_CONTEXTS];
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering/* Tiny windows increase mmap activity and the chance of exposing unsafe use. */
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering# define WINDOW_SIZE (8ULL*1024ULL*1024ULL)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering LIST_REMOVE(unused, w->cache->unused, w);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering LIST_FOREACH(by_window, c, w->contexts) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering_pure_ static bool window_matches(Window *w, int fd, int prot, uint64_t offset, size_t size) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!m->last_unused || m->n_windows <= WINDOWS_MIN) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /* Allocate a new window */
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /* Reuse an existing one */
e9f600f2fb4b0df55c7a8fb4b4d09f9979997223Lennart Poetteringstatic void context_detach_window(Context *c) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /* Not used anymore? */
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /* Unmap unused windows immediately to expose use-after-unmap
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering * by SIGSEGV. */
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering LIST_PREPEND(unused, c->cache->unused, w);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic void context_attach_window(Context *c, Window *w) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /* Used again? */
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering LIST_REMOVE(unused, c->cache->unused, w);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic Context *context_add(MMapCache *m, unsigned id) {
4b94f3b8f7693f076e5c85bc2c02cf028192d8deZbigniew Jędrzejewski-Szmek c->cache->contexts[c->id] = NULL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_se(hashmap_remove(f->cache->fds, INT_TO_PTR(f->fd + 1)));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic FileDescriptor* fd_add(MMapCache *m, int fd) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering f = hashmap_get(m->fds, INT_TO_PTR(fd + 1));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = hashmap_ensure_allocated(&m->fds, NULL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = hashmap_put(m->fds, UINT_TO_PTR(fd + 1), f);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic void mmap_cache_free(MMapCache *m) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering for (i = 0; i < MMAP_CACHE_MAX_CONTEXTS; i++)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart PoetteringMMapCache* mmap_cache_unref(MMapCache *m) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!window_matches(c->window, fd, prot, offset, size)) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /* Drop the reference to the window, since it's unnecessary now */
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset);
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering f = hashmap_get(m->fds, INT_TO_PTR(fd + 1));
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering if (window_matches(w, fd, prot, offset, size))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering *ret = (uint8_t*) w->ptr + (offset - w->offset);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt woffset = offset & ~((uint64_t) page_size() - 1ULL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering delta = PAGE_ALIGN((WINDOW_SIZE - wsize) / 2);
if (st) {
return -EADDRNOTAVAIL;
if (d != MAP_FAILED)
return -errno;
r = make_room(m);
return -ENOMEM;
goto outofmem;
goto outofmem;
w = window_add(m);
goto outofmem;
w->ptr = d;
w->fd = f;
c->window = w;
return -ENOMEM;
int mmap_cache_get(
MMapCache *m,
int fd,
int prot,
unsigned context,
bool keep_always,
void **ret) {
assert(m);
m->n_hit ++;
m->n_hit ++;
m->n_missed++;
FileDescriptor *f;
assert(m);
fd_free(f);
assert(m);
return m->n_hit;
assert(m);
return m->n_missed;