  
          if (s->mmap)
                  mmap_cache_unref(s->mmap);
+diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
+index b7db6f1..f6f669d 100644
+--- a/src/journal/mmap-cache.c
++++ b/src/journal/mmap-cache.c
+@@ -38,7 +38,7 @@ typedef struct FileDescriptor FileDescriptor;
+ struct Window {
+         MMapCache *cache;
+ 
+-        unsigned keep_always;
++        bool keep_always;
+         bool in_unused;
+ 
+         int prot;
+@@ -76,7 +76,7 @@ struct MMapCache {
+ 
+ 
+         Hashmap *fds;
+-        Hashmap *contexts;
++        Context *contexts[MMAP_CACHE_MAX_CONTEXTS];
+ 
+         LIST_HEAD(Window, unused);
+         Window *last_unused;
+@@ -185,7 +185,7 @@ static void context_detach_window(Context *c) {
+         c->window = NULL;
+         LIST_REMOVE(by_window, w->contexts, c);
+ 
+-        if (!w->contexts && w->keep_always == 0) {
++        if (!w->contexts && !w->keep_always) {
+                 /* Not used anymore? */
+                 LIST_PREPEND(unused, c->cache->unused, w);
+                 if (!c->cache->last_unused)
+@@ -219,18 +219,13 @@ static void context_attach_window(Context *c, Window *w) {
+ 
+ static Context *context_add(MMapCache *m, unsigned id) {
+         Context *c;
+-        int r;
+ 
+         assert(m);
+ 
+-        c = hashmap_get(m->contexts, UINT_TO_PTR(id + 1));
++        c = m->contexts[id];
+         if (c)
+                 return c;
+ 
+-        r = hashmap_ensure_allocated(&m->contexts, NULL);
+-        if (r < 0)
+-                return NULL;
+-
+         c = new0(Context, 1);
+         if (!c)
+                 return NULL;
+@@ -238,11 +233,8 @@ static Context *context_add(MMapCache *m, unsigned id) {
+         c->cache = m;
+         c->id = id;
+ 
+-        r = hashmap_put(m->contexts, UINT_TO_PTR(id + 1), c);
+-        if (r < 0) {
+-                free(c);
+-                return NULL;
+-        }
++        assert(!m->contexts[id]);
++        m->contexts[id] = c;
+ 
+         return c;
+ }
+@@ -252,8 +244,10 @@ static void context_free(Context *c) {
+ 
+         context_detach_window(c);
+ 
+-        if (c->cache)
+-                assert_se(hashmap_remove(c->cache->contexts, UINT_TO_PTR(c->id + 1)));
++        if (c->cache) {
++                assert(c->cache->contexts[c->id] == c);
++                c->cache->contexts[c->id] = NULL;
++        }
+ 
+         free(c);
+ }
+@@ -302,15 +296,14 @@ static FileDescriptor* fd_add(MMapCache *m, int fd) {
+ }
+ 
+ static void mmap_cache_free(MMapCache *m) {
+-        Context *c;
+         FileDescriptor *f;
++        int i;
+ 
+         assert(m);
+ 
+-        while ((c = hashmap_first(m->contexts)))
+-                context_free(c);
+-
+-        hashmap_free(m->contexts);
++        for (i = 0; i < MMAP_CACHE_MAX_CONTEXTS; i++)
++                if (m->contexts[i])
++                        context_free(m->contexts[i]);
+ 
+         while ((f = hashmap_first(m->fds)))
+                 fd_free(f);
+@@ -352,8 +345,7 @@ static int try_context(
+                 bool keep_always,
+                 uint64_t offset,
+                 size_t size,
+-                void **ret,
+-                void **release_cookie) {
++                void **ret) {
+ 
+         Context *c;
+ 
+@@ -361,8 +353,9 @@ static int try_context(
+         assert(m->n_ref > 0);
+         assert(fd >= 0);
+         assert(size > 0);
++        assert(ret);
+ 
+-        c = hashmap_get(m->contexts, UINT_TO_PTR(context+1));
++        c = m->contexts[context];
+         if (!c)
+                 return 0;
+ 
+@@ -378,12 +371,9 @@ static int try_context(
+                 return 0;
+         }
+ 
+-        c->window->keep_always += keep_always;
++        c->window->keep_always |= keep_always;
+ 
+-        if (ret)
+-                *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset);
+-        if (keep_always && release_cookie)
+-                *release_cookie = c->window;
++        *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset);
+         return 1;
+ }
+ 
+@@ -395,8 +385,7 @@ static int find_mmap(
+                 bool keep_always,
+                 uint64_t offset,
+                 size_t size,
+-                void **ret,
+-                void **release_cookie) {
++                void **ret) {
+ 
+         FileDescriptor *f;
+         Window *w;
+@@ -427,10 +416,7 @@ static int find_mmap(
+         context_attach_window(c, w);
+         w->keep_always += keep_always;
+ 
+-        if (ret)
+-                *ret = (uint8_t*) w->ptr + (offset - w->offset);
+-        if (keep_always && release_cookie)
+-                *release_cookie = c->window;
++        *ret = (uint8_t*) w->ptr + (offset - w->offset);
+         return 1;
+ }
+ 
+@@ -443,8 +429,7 @@ static int add_mmap(
+                 uint64_t offset,
+                 size_t size,
+                 struct stat *st,
+-                void **ret,
+-                void **release_cookie) {
++                void **ret) {
+ 
+         uint64_t woffset, wsize;
+         Context *c;
+@@ -457,6 +442,7 @@ static int add_mmap(
+         assert(m->n_ref > 0);
+         assert(fd >= 0);
+         assert(size > 0);
++        assert(ret);
+ 
+         woffset = offset & ~((uint64_t) page_size() - 1ULL);
+         wsize = size + (offset - woffset);
+@@ -526,10 +512,7 @@ static int add_mmap(
+         c->window = w;
+         LIST_PREPEND(by_window, w->contexts, c);
+ 
+-        if (ret)
+-                *ret = (uint8_t*) w->ptr + (offset - w->offset);
+-        if (keep_always && release_cookie)
+-                *release_cookie = c->window;
++        *ret = (uint8_t*) w->ptr + (offset - w->offset);
+         return 1;
+ 
+ outofmem:
+@@ -546,8 +529,7 @@ int mmap_cache_get(
+                 uint64_t offset,
+                 size_t size,
+                 struct stat *st,
+-                void **ret,
+-                void **release_cookie) {
++                void **ret) {
+ 
+         int r;
+ 
+@@ -555,16 +537,18 @@ int mmap_cache_get(
+         assert(m->n_ref > 0);
+         assert(fd >= 0);
+         assert(size > 0);
++        assert(ret);
++        assert(context < MMAP_CACHE_MAX_CONTEXTS);
+ 
+         /* Check whether the current context is the right one already */
+-        r = try_context(m, fd, prot, context, keep_always, offset, size, ret, release_cookie);
++        r = try_context(m, fd, prot, context, keep_always, offset, size, ret);
+         if (r != 0) {
+                 m->n_hit ++;
+                 return r;
+         }
+ 
+         /* Search for a matching mmap */
+-        r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret, release_cookie);
++        r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret);
+         if (r != 0) {
+                 m->n_hit ++;
+                 return r;
+@@ -573,39 +557,7 @@ int mmap_cache_get(
+         m->n_missed++;
+ 
+         /* Create a new mmap */
+-        return add_mmap(m, fd, prot, context, keep_always, offset, size, st, ret, release_cookie);
+-}
+-
+-int mmap_cache_release(
+-                MMapCache *m,
+-                int fd,
+-                void *release_cookie) {
+-
+-        FileDescriptor *f;
+-        Window *w;
+-
+-        assert(m);
+-        assert(m->n_ref > 0);
+-        assert(fd >= 0);
+-
+-        f = hashmap_get(m->fds, INT_TO_PTR(fd + 1));
+-        if (!f)
+-                return -EBADF;
+-
+-        assert(f->fd == fd);
+-
+-        LIST_FOREACH(by_fd, w, f->windows)
+-                if (w == release_cookie)
+-                        break;
+-
+-        if (!w)
+-                return -ENOENT;
+-
+-        if (w->keep_always == 0)
+-                return -ENOLCK;
+-
+-        w->keep_always -= 1;
+-        return 0;
++        return add_mmap(m, fd, prot, context, keep_always, offset, size, st, ret);
+ }
+ 
+ void mmap_cache_close_fd(MMapCache *m, int fd) {
+@@ -621,18 +573,6 @@ void mmap_cache_close_fd(MMapCache *m, int fd) {
+         fd_free(f);
+ }
+ 
+-void mmap_cache_close_context(MMapCache *m, unsigned context) {
+-        Context *c;
+-
+-        assert(m);
+-
+-        c = hashmap_get(m->contexts, UINT_TO_PTR(context + 1));
+-        if (!c)
+-                return;
+-
+-        context_free(c);
+-}
+-
+ unsigned mmap_cache_get_hit(MMapCache *m) {
+         assert(m);
+ 
+diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h
+index 76e5316..fe2c83d 100644
+--- a/src/journal/mmap-cache.h
++++ b/src/journal/mmap-cache.h
+@@ -25,6 +25,8 @@
+ #include <stdbool.h>
+ #include <sys/stat.h>
+ 
++#define MMAP_CACHE_MAX_CONTEXTS 8
++
+ typedef struct MMapCache MMapCache;
+ 
+ MMapCache* mmap_cache_new(void);
+@@ -40,14 +42,8 @@ int mmap_cache_get(
+         uint64_t offset,
+         size_t size,
+         struct stat *st,
+-        void **ret,
+-        void **release_cookie);
+-int mmap_cache_release(
+-        MMapCache *m,
+-        int fd,
+-        void *release_cookie);
++        void **ret);
+ void mmap_cache_close_fd(MMapCache *m, int fd);
+-void mmap_cache_close_context(MMapCache *m, unsigned context);
+ 
+ unsigned mmap_cache_get_hit(MMapCache *m);
+ unsigned mmap_cache_get_missed(MMapCache *m);
+diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
+index cf21c4d..cb7fc32 100644
+--- a/src/journal/sd-journal.c
++++ b/src/journal/sd-journal.c
+@@ -87,7 +87,7 @@ static void detach_location(sd_journal *j) {
+         j->current_field = 0;
+ 
+         ORDERED_HASHMAP_FOREACH(f, j->files, i)
+-                f->current_offset = 0;
++                journal_file_reset_location(f);
+ }
+ 
+ static void reset_location(sd_journal *j) {
+@@ -114,20 +114,19 @@ static void init_location(Location *l, LocationType type, JournalFile *f, Object
+         l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
+ }
+ 
+-static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o,
+-                         direction_t direction, uint64_t offset) {
++static void set_location(sd_journal *j, JournalFile *f, Object *o) {
+         assert(j);
+-        assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
+         assert(f);
+         assert(o);
+ 
+-        init_location(&j->current_location, type, f, o);
++        init_location(&j->current_location, LOCATION_DISCRETE, f, o);
+ 
+         j->current_file = f;
+         j->current_field = 0;
+ 
+-        f->last_direction = direction;
+-        f->current_offset = offset;
++        /* Let f know its candidate entry was picked. */
++        assert(f->location_type == LOCATION_SEEK);
++        f->location_type = LOCATION_DISCRETE;
+ }
+ 
+ static int match_is_valid(const void *data, size_t size) {
+@@ -413,144 +412,51 @@ _public_ void sd_journal_flush_matches(sd_journal *j) {
+         detach_location(j);
+ }
+ 
+-static int compare_entry_order(JournalFile *af, Object *_ao,
+-                               JournalFile *bf, uint64_t bp) {
+-
+-        uint64_t a, b;
+-        Object *ao, *bo;
+-        int r;
+-
+-        assert(af);
+-        assert(bf);
+-        assert(_ao);
+-
+-        /* The mmap cache might invalidate the object from the first
+-         * file if we look at the one from the second file. Hence
+-         * temporarily copy the header of the first one, and look at
+-         * that only. */
+-        ao = alloca(offsetof(EntryObject, items));
+-        memcpy(ao, _ao, offsetof(EntryObject, items));
+-
+-        r = journal_file_move_to_object(bf, OBJECT_ENTRY, bp, &bo);
+-        if (r < 0)
+-                return strcmp(af->path, bf->path);
+-
+-        /* We operate on two different files here, hence we can access
+-         * two objects at the same time, which we normally can't.
+-         *
+-         * If contents and timestamps match, these entries are
+-         * identical, even if the seqnum does not match */
+-
+-        if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id) &&
+-            ao->entry.monotonic == bo->entry.monotonic &&
+-            ao->entry.realtime == bo->entry.realtime &&
+-            ao->entry.xor_hash == bo->entry.xor_hash)
+-                return 0;
+-
+-        if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) {
+-
+-                /* If this is from the same seqnum source, compare
+-                 * seqnums */
+-                a = le64toh(ao->entry.seqnum);
+-                b = le64toh(bo->entry.seqnum);
+-
+-                if (a < b)
+-                        return -1;
+-                if (a > b)
+-                        return 1;
+-
+-                /* Wow! This is weird, different data but the same
+-                 * seqnums? Something is borked, but let's make the
+-                 * best of it and compare by time. */
+-        }
+-
+-        if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) {
+-
+-                /* If the boot id matches, compare monotonic time */
+-                a = le64toh(ao->entry.monotonic);
+-                b = le64toh(bo->entry.monotonic);
+-
+-                if (a < b)
+-                        return -1;
+-                if (a > b)
+-                        return 1;
+-        }
+-
+-        /* Otherwise, compare UTC time */
+-        a = le64toh(ao->entry.realtime);
+-        b = le64toh(bo->entry.realtime);
+-
+-        if (a < b)
+-                return -1;
+-        if (a > b)
+-                return 1;
+-
+-        /* Finally, compare by contents */
+-        a = le64toh(ao->entry.xor_hash);
+-        b = le64toh(bo->entry.xor_hash);
+-
+-        if (a < b)
+-                return -1;
+-        if (a > b)
+-                return 1;
+-
+-        return 0;
+-}
+-
+-_pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) {
+-        uint64_t a;
+-
+-        assert(af);
+-        assert(ao);
++_pure_ static int compare_with_location(JournalFile *f, Location *l) {
++        assert(f);
+         assert(l);
++        assert(f->location_type == LOCATION_SEEK);
+         assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK);
+ 
+         if (l->monotonic_set &&
+-            sd_id128_equal(ao->entry.boot_id, l->boot_id) &&
++            sd_id128_equal(f->current_boot_id, l->boot_id) &&
+             l->realtime_set &&
+-            le64toh(ao->entry.realtime) == l->realtime &&
++            f->current_realtime == l->realtime &&
+             l->xor_hash_set &&
+-            le64toh(ao->entry.xor_hash) == l->xor_hash)
++            f->current_xor_hash == l->xor_hash)
+                 return 0;
+ 
+         if (l->seqnum_set &&
+-            sd_id128_equal(af->header->seqnum_id, l->seqnum_id)) {
+-
+-                a = le64toh(ao->entry.seqnum);
++            sd_id128_equal(f->header->seqnum_id, l->seqnum_id)) {
+ 
+-                if (a < l->seqnum)
++                if (f->current_seqnum < l->seqnum)
+                         return -1;
+-                if (a > l->seqnum)
++                if (f->current_seqnum > l->seqnum)
+                         return 1;
+         }
+ 
+         if (l->monotonic_set &&
+-            sd_id128_equal(ao->entry.boot_id, l->boot_id)) {
++            sd_id128_equal(f->current_boot_id, l->boot_id)) {
+ 
+-                a = le64toh(ao->entry.monotonic);
+-
+-                if (a < l->monotonic)
++                if (f->current_monotonic < l->monotonic)
+                         return -1;
+-                if (a > l->monotonic)
++                if (f->current_monotonic > l->monotonic)
+                         return 1;
+         }
+ 
+         if (l->realtime_set) {
+ 
+-                a = le64toh(ao->entry.realtime);
+-
+-                if (a < l->realtime)
++                if (f->current_realtime < l->realtime)
+                         return -1;
+-                if (a > l->realtime)
++                if (f->current_realtime > l->realtime)
+                         return 1;
+         }
+ 
+         if (l->xor_hash_set) {
+-                a = le64toh(ao->entry.xor_hash);
+ 
+-                if (a < l->xor_hash)
++                if (f->current_xor_hash < l->xor_hash)
+                         return -1;
+-                if (a > l->xor_hash)
++                if (f->current_xor_hash > l->xor_hash)
+                         return 1;
+         }
+ 
+@@ -766,9 +672,9 @@ static int find_location_with_matches(
+                 /* No matches is simple */
+ 
+                 if (j->current_location.type == LOCATION_HEAD)
+-                        return journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, ret, offset);
++                        return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset);
+                 if (j->current_location.type == LOCATION_TAIL)
+-                        return journal_file_next_entry(f, NULL, 0, DIRECTION_UP, ret, offset);
++                        return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset);
+                 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
+                         return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
+                 if (j->current_location.monotonic_set) {
+@@ -779,7 +685,7 @@ static int find_location_with_matches(
+                 if (j->current_location.realtime_set)
+                         return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
+ 
+-                return journal_file_next_entry(f, NULL, 0, direction, ret, offset);
++                return journal_file_next_entry(f, 0, direction, ret, offset);
+         } else
+                 return find_location_for_match(j, j->level0, f, direction, ret, offset);
+ }
+@@ -791,49 +697,61 @@ static int next_with_matches(
+                 Object **ret,
+                 uint64_t *offset) {
+ 
+-        Object *c;
+-        uint64_t cp;
+-
+         assert(j);
+         assert(f);
+         assert(ret);
+         assert(offset);
+ 
+-        c = *ret;
+-        cp = *offset;
+-
+         /* No matches is easy. We simple advance the file
+          * pointer by one. */
+         if (!j->level0)
+-                return journal_file_next_entry(f, c, cp, direction, ret, offset);
++                return journal_file_next_entry(f, f->current_offset, direction, ret, offset);
+ 
+         /* If we have a match then we look for the next matching entry
+          * with an offset at least one step larger */
+-        return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? cp+1 : cp-1, direction, ret, offset);
++        return next_for_match(j, j->level0, f,
++                              direction == DIRECTION_DOWN ? f->current_offset + 1
++                                                          : f->current_offset - 1,
++                              direction, ret, offset);
+ }
+ 
+-static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) {
++static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction) {
+         Object *c;
+-        uint64_t cp;
++        uint64_t cp, n_entries;
+         int r;
+ 
+         assert(j);
+         assert(f);
+ 
+-        if (f->last_direction == direction && f->current_offset > 0) {
+-                cp = f->current_offset;
++        n_entries = le64toh(f->header->n_entries);
+ 
+-                r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c);
+-                if (r < 0)
+-                        return r;
++        /* If we hit EOF before, we don't need to look into this file again
++         * unless direction changed or new entries appeared. */
++        if (f->last_direction == direction && f->location_type == LOCATION_TAIL &&
++            n_entries == f->last_n_entries)
++                return 0;
+ 
+-                r = next_with_matches(j, f, direction, &c, &cp);
+-                if (r <= 0)
+-                        return r;
++        f->last_n_entries = n_entries;
++
++        if (f->last_direction == direction && f->current_offset > 0) {
++                /* LOCATION_SEEK here means we did the work in a previous
++                 * iteration and the current location already points to a
++                 * candidate entry. */
++                if (f->location_type != LOCATION_SEEK) {
++                        r = next_with_matches(j, f, direction, &c, &cp);
++                        if (r <= 0)
++                                return r;
++
++                        journal_file_save_location(f, c, cp);
++                }
+         } else {
++                f->last_direction = direction;
++
+                 r = find_location_with_matches(j, f, direction, &c, &cp);
+                 if (r <= 0)
+                         return r;
++
++                journal_file_save_location(f, c, cp);
+         }
+ 
+         /* OK, we found the spot, now let's advance until an entry
+@@ -848,30 +766,25 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc
+                 if (j->current_location.type == LOCATION_DISCRETE) {
+                         int k;
+ 
+-                        k = compare_with_location(f, c, &j->current_location);
++                        k = compare_with_location(f, &j->current_location);
+ 
+                         found = direction == DIRECTION_DOWN ? k > 0 : k < 0;
+                 } else
+                         found = true;
+ 
+-                if (found) {
+-                        if (ret)
+-                                *ret = c;
+-                        if (offset)
+-                                *offset = cp;
++                if (found)
+                         return 1;
+-                }
+ 
+                 r = next_with_matches(j, f, direction, &c, &cp);
+                 if (r <= 0)
+                         return r;
++
++                journal_file_save_location(f, c, cp);
+         }
+ }
+ 
+ static int real_journal_next(sd_journal *j, direction_t direction) {
+         JournalFile *f, *new_file = NULL;
+-        uint64_t new_offset = 0;
+-        uint64_t p = 0;
+         Iterator i;
+         Object *o;
+         int r;
+@@ -882,38 +795,38 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
+         ORDERED_HASHMAP_FOREACH(f, j->files, i) {
+                 bool found;
+ 
+-                r = next_beyond_location(j, f, direction, &o, &p);
++                r = next_beyond_location(j, f, direction);
+                 if (r < 0) {
+                         log_debug("Can't iterate through %s, ignoring: %s", f->path, strerror(-r));
+                         remove_file_real(j, f);
+                         continue;
+-                } else if (r == 0)
++                } else if (r == 0) {
++                        f->location_type = LOCATION_TAIL;
+                         continue;
++                }
+ 
+                 if (!new_file)
+                         found = true;
+                 else {
+                         int k;
+ 
+-                        k = compare_entry_order(f, o, new_file, new_offset);
++                        k = journal_file_compare_locations(f, new_file);
+ 
+                         found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
+                 }
+ 
+-                if (found) {
++                if (found)
+                         new_file = f;
+-                        new_offset = p;
+-                }
+         }
+ 
+         if (!new_file)
+                 return 0;
+ 
+-        r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_offset, &o);
++        r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o);
+         if (r < 0)
+                 return r;
+ 
+-        set_location(j, LOCATION_DISCRETE, new_file, o, direction, new_offset);
++        set_location(j, new_file, o);
+ 
+         return 1;
+ }
+@@ -2526,7 +2439,6 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
+                 size_t ol;
+                 bool found;
+                 int r;
+-                void *release_cookie;
+ 
+                 /* Proceed to next data object in the field's linked list */
+                 if (j->unique_offset == 0) {
+@@ -2552,10 +2464,10 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
+                         continue;
+                 }
+ 
+-                /* We do not use the type context here, but 0 instead,
+-                 * so that we can look at this data object at the same
++                /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
++                 * instead, so that we can look at this data object at the same
+                  * time as one on another file */
+-                r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o);
++                r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o);
+                 if (r < 0)
+                         return r;
+ 
+@@ -2567,10 +2479,6 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
+                         return -EBADMSG;
+                 }
+ 
+-                r = journal_file_object_keep(j->unique_file, o, j->unique_offset, &release_cookie);
+-                if (r < 0)
+-                        return r;
+-
+                 r = return_data(j, j->unique_file, o, &odata, &ol);
+                 if (r < 0)
+                         return r;
+@@ -2615,10 +2523,6 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
+                                 found = true;
+                 }
+ 
+-                r = journal_file_object_release(j->unique_file, release_cookie);
+-                if (r < 0)
+-                        return r;
+-
+                 if (found)
+                         continue;
+ 
 diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
 index 372f3ed..d56ee51 100644
 --- a/src/libsystemd-network/network-internal.c

                         if (direction == DIRECTION_UP) {
                                 i = n;
                                 subtract_one = true;
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index f50faf4..03579fd 100644
--- a/src/journal/journalctl.c

-        return r < 0 ? EXIT_FAILURE : r;
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c
index 7dd8878..70a9a13 100644
--- a/src/journal-remote/journal-remote-parse.c
+++ b/src/journal-remote/journal-remote-parse.c
@@ -344,22 +344,25 @@ int process_data(RemoteSource *source) {
                    LLLLLLLL0011223344...\n
                 */
                 sep = memchr(line, '=', n);
-                if (sep)
+                if (sep) {
                         /* chomp newline */
                         n--;
-                else
+
+                        r = iovw_put(&source->iovw, line, n);
+                        if (r < 0)
+                                return r;
+                } else {
                         /* replace \n with = */
                         line[n-1] = '=';
-                log_trace("Received: %.*s", (int) n, line);
 
-                r = iovw_put(&source->iovw, line, n);
-                if (r < 0) {
-                        log_error("Failed to put line in iovect");
-                        return r;
+                        source->field_len = n;
+                        source->state = STATE_DATA_START;
+
+                        /* we cannot put the field in iovec until we have all data */
                 }
 
-                if (!sep)
-                        source->state = STATE_DATA_START;
+                log_trace("Received: %.*s (%s)", (int) n, line, sep ? "text" : "binary");
+
                 return 0; /* continue */
         }
 
@@ -382,6 +385,7 @@ int process_data(RemoteSource *source) {
 
         case STATE_DATA: {
                 void *data;
+                char *field;
 
                 assert(source->data_size > 0);
 
@@ -396,11 +400,12 @@ int process_data(RemoteSource *source) {
 
                 assert(data);
 
-                r = iovw_put(&source->iovw, data, source->data_size);
-                if (r < 0) {
-                        log_error("failed to put binary buffer in iovect");
+                field = (char*) data - sizeof(uint64_t) - source->field_len;
+                memmove(field + sizeof(uint64_t), field, source->field_len);
+
+                r = iovw_put(&source->iovw, field + sizeof(uint64_t), source->field_len + source->data_size);
+                if (r < 0)
                         return r;
-                }
 
                 source->state = STATE_DATA_FINISH;
 
diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h
index 8499f4e..22db550 100644
--- a/src/journal-remote/journal-remote-parse.h
+++ b/src/journal-remote/journal-remote-parse.h
@@ -42,7 +42,9 @@ typedef struct RemoteSource {
         size_t offset;     /* offset to the beginning of live data in the buffer */
         size_t scanned;    /* number of bytes since the beginning of data without a newline */
         size_t filled;     /* total number of bytes in the buffer */
-        size_t data_size;  /* size of the binary data chunk being processed */
+
+        size_t field_len;  /* used for binary fields: the field name length */
+        size_t data_size;  /* and the size of the binary data chunk being processed */
 
         struct iovec_wrapper iovw;
 
diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index 5ab1982..1f980ee 100644
--- a/src/journal/journal-authenticate.c
+++ b/src/journal/journal-authenticate.c
@@ -229,7 +229,7 @@ int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) {
         return 0;
 }
 
-int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p) {
+int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p) {
         int r;
 
         assert(f);
@@ -246,7 +246,7 @@ int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p
                 if (r < 0)
                         return r;
         } else {
-                if (type >= 0 && o->object.type != type)
+                if (type > OBJECT_UNUSED && o->object.type != type)
                         return -EBADMSG;
         }
 
diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h
index 0aaf836..565fe84 100644
--- a/src/journal/journal-authenticate.h
+++ b/src/journal/journal-authenticate.h
@@ -33,7 +33,7 @@ int journal_file_append_first_tag(JournalFile *f);
 int journal_file_hmac_setup(JournalFile *f);
 int journal_file_hmac_start(JournalFile *f);
 int journal_file_hmac_put_header(JournalFile *f);
-int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p);
+int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p);
 
 int journal_file_fss_load(JournalFile *f);
 int journal_file_parse_verification_key(JournalFile *f, const char *key);
diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h
index e55fa19..ab089cb 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -52,8 +52,8 @@ typedef struct HashItem HashItem;
 typedef struct FSSHeader FSSHeader;
 
 /* Object types */
-enum {
-        OBJECT_UNUSED,
+typedef enum ObjectType {
+        OBJECT_UNUSED, /* also serves as "any type" or "additional context" */
         OBJECT_DATA,
         OBJECT_FIELD,
         OBJECT_ENTRY,
@@ -62,7 +62,7 @@ enum {
         OBJECT_ENTRY_ARRAY,
         OBJECT_TAG,
         _OBJECT_TYPE_MAX
-};
+} ObjectType;
 
 /* Object flags */
 enum {
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 8a2c0fc..c55a4dc 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -374,7 +374,13 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
         return 0;
 }
 
-static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
+static unsigned type_to_context(ObjectType type) {
+        /* One context for each type, plus one catch-all for the rest */
+        assert_cc(_OBJECT_TYPE_MAX <= MMAP_CACHE_MAX_CONTEXTS);
+        return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0;
+}
+
+static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
         assert(f);
         assert(ret);
 
@@ -391,7 +397,7 @@ static int journal_file_move_to(JournalFile *f, int context, bool keep_always, u
                         return -EADDRNOTAVAIL;
         }
 
-        return mmap_cache_get(f->mmap, f->fd, f->prot, context, keep_always, offset, size, &f->last_stat, ret, NULL);
+        return mmap_cache_get(f->mmap, f->fd, f->prot, type_to_context(type), keep_always, offset, size, &f->last_stat, ret);
 }
 
 static uint64_t minimum_header_size(Object *o) {
@@ -412,7 +418,7 @@ static uint64_t minimum_header_size(Object *o) {
         return table[o->object.type];
 }
 
-int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret) {
+int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret) {
         int r;
         void *t;
         Object *o;
@@ -425,7 +431,7 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec
         if (!VALID64(offset))
                 return -EFAULT;
 
-        r = journal_file_move_to(f, type_to_context(type), false, offset, sizeof(ObjectHeader), &t);
+        r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t);
         if (r < 0)
                 return r;
 
@@ -441,11 +447,11 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec
         if (s < minimum_header_size(o))
                 return -EBADMSG;
 
-        if (type > 0 && o->object.type != type)
+        if (type > OBJECT_UNUSED && o->object.type != type)
                 return -EBADMSG;
 
         if (s > sizeof(ObjectHeader)) {
-                r = journal_file_move_to(f, o->object.type, false, offset, s, &t);
+                r = journal_file_move_to(f, type, false, offset, s, &t);
                 if (r < 0)
                         return r;
 
@@ -482,14 +488,14 @@ static uint64_t journal_file_entry_seqnum(JournalFile *f, uint64_t *seqnum) {
         return r;
 }
 
-int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) {
+int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, Object **ret, uint64_t *offset) {
         int r;
         uint64_t p;
         Object *tail, *o;
         void *t;
 
         assert(f);
-        assert(type > 0 && type < _OBJECT_TYPE_MAX);
+        assert(type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX);
         assert(size >= sizeof(ObjectHeader));
         assert(offset);
         assert(ret);
@@ -502,7 +508,7 @@ int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object *
         if (p == 0)
                 p = le64toh(f->header->header_size);
         else {
-                r = journal_file_move_to_object(f, -1, p, &tail);
+                r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &tail);
                 if (r < 0)
                         return r;
 
@@ -1657,7 +1663,7 @@ static int generic_array_bisect(
                         }
                 }
 
