#include "mmap-cache.h"
#define WINDOW_SIZE (8ULL*1024ULL*1024ULL)
-#define WINDOWS_MAX 32
+
+#define DEFAULT_WINDOWS_MAX 64
+#define DEFAULT_FDS_MAX 32
+#define DEFAULT_CONTEXTS_MAX 32
typedef struct Window {
int fd;
free(m);
}
-MMapCache* mmap_cache_new(unsigned contexts_max, unsigned fds_max) {
+MMapCache* mmap_cache_new(void) {
MMapCache *m;
- assert(contexts_max > 0);
- assert(fds_max > 0);
-
m = new0(MMapCache, 1);
if (!m)
return NULL;
- m->contexts_max = contexts_max;
- m->fds_max = fds_max;
- m->windows_max = MAX(m->contexts_max, WINDOWS_MAX);
+ m->contexts_max = DEFAULT_CONTEXTS_MAX;
+ m->fds_max = DEFAULT_FDS_MAX;
+ m->windows_max = DEFAULT_WINDOWS_MAX;
m->n_ref = 1;
m->lru_first = (unsigned) -1;
m->lru_last = (unsigned) -1;
Window *v;
v = m->windows + w;
+ assert(v->n_ref == 0);
if (v->ptr) {
mmap_cache_window_unmap(m, w);
unsigned fd_index,
int prot,
unsigned context,
+ bool keep_always,
uint64_t offset,
uint64_t size,
+ struct stat *st,
void **ret) {
unsigned w;
wsize = WINDOW_SIZE;
}
+ if (st) {
+ /* Memory maps that are larger then the files
+ underneath have undefined behavior. Hence, clamp
+ things to the file size if we know it */
+
+ if (woffset >= (uint64_t) st->st_size)
+ return -EADDRNOTAVAIL;
+
+ if (woffset + wsize > (uint64_t) st->st_size)
+ wsize = PAGE_ALIGN(st->st_size - woffset);
+ }
+
for (;;) {
d = mmap(NULL, wsize, prot, MAP_SHARED, fd, woffset);
if (d != MAP_FAILED)
v->offset = woffset;
v->size = wsize;
- v->n_ref = 0;
- mmap_cache_window_add_lru(m, w);
+ if (keep_always)
+ v->n_ref = 1;
+ else {
+ v->n_ref = 0;
+ mmap_cache_window_add_lru(m, w);
+ }
+
mmap_cache_fd_add(m, fd_index, w);
mmap_cache_context_set(m, context, w);
if (r != 0)
return r;
- if (m->n_fds >= m->fds_max)
- return -E2BIG;
+ if (m->n_fds >= m->fds_max) {
+ unsigned k;
+ FileDescriptor *n;
+
+ k = m->n_fds * 2;
+ n = realloc(m->by_fd, sizeof(FileDescriptor) * k);
+ if (!n)
+ return -ENOMEM;
+
+ m->fds_max = k;
+ m->by_fd = n;
+ }
j = m->by_fd + m->n_fds ++;
j->fd = fd;
int fd,
int prot,
unsigned context,
+ bool keep_always,
uint64_t offset,
uint64_t size,
+ struct stat *st,
void **ret) {
unsigned fd_index;
assert(m);
assert(fd >= 0);
- assert(context < m->contexts_max);
assert(size > 0);
assert(ret);
+ if (context >= m->contexts_max) {
+ unsigned k, *n;
+ Window *w;
+
+ /* Increase the number of contexts if necessary, and
+ * make sure we have twice the number of windows */
+
+ k = context * 2;
+ n = realloc(m->by_context, sizeof(unsigned) * k);
+ if (!n)
+ return -ENOMEM;
+ memset(n + m->contexts_max, -1, (k - m->contexts_max) * sizeof(unsigned));
+ m->contexts_max = k;
+ m->by_context = n;
+
+ k = MAX(m->windows_max, m->contexts_max*2);
+ w = realloc(m->windows, sizeof(Window) * k);
+ if (!w)
+ return -ENOMEM;
+
+ m->windows_max = k;
+ m->windows = w;
+ }
+
/* Maybe the current pointer for this context is already the
* right one? */
r = mmap_cache_current(m, fd, context, offset, size, ret);
return r;
/* Not found? Then, let's add it */
- return mmap_cache_put(m, fd, fd_index, prot, context, offset, size, ret);
+ return mmap_cache_put(m, fd, fd_index, prot, context, keep_always, offset, size, st, ret);
}
void mmap_cache_close_fd(MMapCache *m, int fd) {
m->n_fds --;
}
-void mmap_cache_close_fd_range(MMapCache *m, int fd, uint64_t p) {
- unsigned fd_index, c, w;
- int r;
-
- assert(m);
- assert(fd > 0);
-
- /* This drops all windows that include space right of the
- * specified offset. This is useful to ensure that after the
- * file size is extended we drop our mappings of the end and
- * create it anew, since otherwise it is undefined whether
- * mapping will continue to work as intended. */
-
- r = mmap_cache_peek_fd_index(m, fd, &fd_index);
- if (r <= 0)
- return;
-
- for (c = 0; c < m->contexts_max; c++) {
- w = m->by_context[c];
-
- if (w != (unsigned) -1 && m->windows[w].fd == fd)
- mmap_cache_context_unset(m, c);
- }
-
- w = m->by_fd[fd_index].windows;
- while (w != (unsigned) -1) {
- Window *v;
-
- v = m->windows + w;
- assert(v->fd == fd);
- assert(v->by_fd_next == (unsigned) -1 ||
- m->windows[v->by_fd_next].fd == fd);
-
- if (v->offset + v->size > p) {
-
- mmap_cache_window_unmap(m, w);
- mmap_cache_fd_remove(m, fd_index, w);
- v->fd = -1;
-
- w = m->by_fd[fd_index].windows;
- } else
- w = v->by_fd_next;
- }
-}
-
void mmap_cache_close_context(MMapCache *m, unsigned context) {
mmap_cache_context_unset(m, context);
}