FileDescriptor *by_fd;
};
+static int mmap_cache_peek_fd_index(MMapCache *m, int fd, unsigned *fd_index);
+
static void mmap_cache_window_unmap(MMapCache *m, unsigned w) {
Window *v;
assert(w < m->n_windows);
v = m->windows + w;
+ assert(v->n_ref == 0);
+
+ if (m->lru_last != (unsigned) -1) {
+ assert(m->windows[m->lru_last].lru_next == (unsigned) -1);
+ m->windows[m->lru_last].lru_next = w;
+ }
+
v->lru_prev = m->lru_last;
v->lru_next = (unsigned) -1;
v = m->windows + w;
- if (v->lru_prev == (unsigned) -1)
+ if (v->lru_prev == (unsigned) -1) {
+ assert(m->lru_first == w);
m->lru_first = v->lru_next;
- else
+ } else {
+ assert(m->windows[v->lru_prev].lru_next == w);
m->windows[v->lru_prev].lru_next = v->lru_next;
+ }
- if (v->lru_next == (unsigned) -1)
+ if (v->lru_next == (unsigned) -1) {
+ assert(m->lru_last == w);
m->lru_last = v->lru_prev;
- else
+ } else {
+ assert(m->windows[v->lru_next].lru_prev == w);
m->windows[v->lru_next].lru_prev = v->lru_prev;
+ }
}
static void mmap_cache_fd_add(MMapCache *m, unsigned fd_index, unsigned w) {
assert(fd_index < m->n_fds);
v = m->windows + w;
+ assert(m->by_fd[fd_index].fd == v->fd);
+
+ if (m->by_fd[fd_index].windows != (unsigned) -1) {
+ assert(m->windows[m->by_fd[fd_index].windows].by_fd_prev == (unsigned) -1);
+ m->windows[m->by_fd[fd_index].windows].by_fd_prev = w;
+ }
+
v->by_fd_next = m->by_fd[fd_index].windows;
v->by_fd_prev = (unsigned) -1;
assert(fd_index < m->n_fds);
v = m->windows + w;
- if (v->by_fd_prev == (unsigned) -1)
+ assert(m->by_fd[fd_index].fd == v->fd);
+ assert(v->by_fd_next == (unsigned) -1 || m->windows[v->by_fd_next].fd == v->fd);
+ assert(v->by_fd_prev == (unsigned) -1 || m->windows[v->by_fd_prev].fd == v->fd);
+
+ if (v->by_fd_prev == (unsigned) -1) {
+ assert(m->by_fd[fd_index].windows == w);
m->by_fd[fd_index].windows = v->by_fd_next;
- else
+ } else {
+ assert(m->windows[v->by_fd_prev].by_fd_next == w);
m->windows[v->by_fd_prev].by_fd_next = v->by_fd_next;
+ }
- if (v->by_fd_next != (unsigned) -1)
+ if (v->by_fd_next != (unsigned) -1) {
+ assert(m->windows[v->by_fd_next].by_fd_prev == w);
m->windows[v->by_fd_next].by_fd_prev = v->by_fd_prev;
+ }
}
static void mmap_cache_context_unset(MMapCache *m, unsigned c) {
v = m->windows + w;
v->n_ref ++;
+
if (v->n_ref == 1)
mmap_cache_window_remove_lru(m, w);
}
mmap_cache_free(m);
return NULL;
}
-
memset(m->by_context, -1, m->contexts_max * sizeof(unsigned));
m->by_fd = new(FileDescriptor, m->fds_max);
}
static int mmap_cache_allocate_window(MMapCache *m, unsigned *w) {
+ Window *v;
+ unsigned fd_index;
+
assert(m);
assert(w);
return -E2BIG;
*w = m->lru_first;
+ v = m->windows + *w;
+ assert(v->n_ref == 0);
+
mmap_cache_window_unmap(m, *w);
+
+ if (v->fd >= 0) {
+ assert_se(mmap_cache_peek_fd_index(m, v->fd, &fd_index) > 0);
+ mmap_cache_fd_remove(m, fd_index, *w);
+ }
+
mmap_cache_window_remove_lru(m, *w);
return 0;
if (wsize < WINDOW_SIZE) {
uint64_t delta;
- delta = (WINDOW_SIZE - wsize) / 2;
+ delta = PAGE_ALIGN((WINDOW_SIZE - wsize) / 2);
if (delta > offset)
woffset = 0;
v->size = wsize;
v->n_ref = 0;
- v->lru_prev = v->lru_next = (unsigned) -1;
-
+ mmap_cache_window_add_lru(m, w);
mmap_cache_fd_add(m, fd_index, w);
mmap_cache_context_set(m, context, w);
return 0;
}
+static int mmap_cache_peek_fd_index(MMapCache *m, int fd, unsigned *fd_index) {
+ FileDescriptor *j;
+ unsigned r;
+
+ assert(m);
+ assert(fd >= 0);
+ assert(fd_index);
+
+ for (r = 0; r < m->n_fds; r++)
+ assert(m->by_fd[r].windows == (unsigned) -1 ||
+ m->windows[m->by_fd[r].windows].fd == m->by_fd[r].fd);
+
+ j = bsearch(&fd, m->by_fd, m->n_fds, sizeof(FileDescriptor), fd_cmp);
+ if (!j)
+ return 0;
+
+ *fd_index = (unsigned) (j - m->by_fd);
+ return 1;
+}
+
static int mmap_cache_get_fd_index(MMapCache *m, int fd, unsigned *fd_index) {
FileDescriptor *j;
+ int r;
assert(m);
assert(fd >= 0);
assert(fd_index);
- j = bsearch(&fd, m->by_fd, m->n_fds, sizeof(m->by_fd[0]), fd_cmp);
- if (!j) {
- if (m->n_fds >= m->fds_max)
- return -E2BIG;
+ r = mmap_cache_peek_fd_index(m, fd, fd_index);
+ if (r != 0)
+ return r;
- j = m->by_fd + m->n_fds ++;
- j->fd = fd;
- j->windows = (unsigned) -1;
+ if (m->n_fds >= m->fds_max)
+ return -E2BIG;
- qsort(m->by_fd, m->n_fds, sizeof(m->by_fd[0]), fd_cmp);
- j = bsearch(&fd, m->by_fd, m->n_fds, sizeof(m->by_fd[0]), fd_cmp);
- }
+ j = m->by_fd + m->n_fds ++;
+ j->fd = fd;
+ j->windows = (unsigned) -1;
- *fd_index = (unsigned) (j - m->by_fd);
- return 0;
+ qsort(m->by_fd, m->n_fds, sizeof(FileDescriptor), fd_cmp);
+
+ return mmap_cache_peek_fd_index(m, fd, fd_index);
}
static bool mmap_cache_test_window(
static int mmap_cache_find(
MMapCache *m,
+ int fd,
unsigned fd_index,
unsigned context,
uint64_t offset,
unsigned w;
assert(m);
+ assert(fd >= 0);
assert(fd_index < m->n_fds);
assert(context < m->contexts_max);
assert(size > 0);
w = m->by_fd[fd_index].windows;
while (w != (unsigned) -1) {
+ v = m->windows + w;
+ assert(v->fd == fd);
+
if (mmap_cache_test_window(m, w, offset, size))
break;
- w = m->windows[w].by_fd_next;
+ w = v->by_fd_next;
}
if (w == (unsigned) -1)
mmap_cache_context_set(m, context, w);
- v = m->windows + w;
*ret = (uint8_t*) v->ptr + (offset - v->offset);
return 1;
}
if (r != 0)
return r;
+ /* Hmm, drop the reference to the current one, since it wasn't
+ * good enough */
+ mmap_cache_context_unset(m, context);
+
/* OK, let's find the chain for this FD */
r = mmap_cache_get_fd_index(m, fd, &fd_index);
if (r < 0)
return r;
/* And let's look through the available mmaps */
- r = mmap_cache_find(m, fd_index, context, offset, size, ret);
+ r = mmap_cache_find(m, fd, fd_index, context, offset, size, ret);
if (r != 0)
return r;
}
void mmap_cache_close_fd(MMapCache *m, int fd) {
- FileDescriptor *j;
unsigned fd_index, c, w;
+ int r;
assert(m);
assert(fd > 0);
- j = bsearch(&fd, m->by_fd, m->n_fds, sizeof(m->by_fd[0]), fd_cmp);
- if (!j)
+ r = mmap_cache_peek_fd_index(m, fd, &fd_index);
+ if (r <= 0)
return;
- fd_index = (unsigned) (j - m->by_fd);
for (c = 0; c < m->contexts_max; c++) {
w = m->by_context[c];
w = m->by_fd[fd_index].windows;
while (w != (unsigned) -1) {
+ Window *v;
+
+ v = m->windows + w;
+ assert(v->fd == fd);
- mmap_cache_fd_remove(m, fd_index, w);
mmap_cache_window_unmap(m, w);
+ mmap_cache_fd_remove(m, fd_index, w);
+ v->fd = -1;
w = m->by_fd[fd_index].windows;
}
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);
}