diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 44661427842..d803bbfca30 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -1125,6 +1125,16 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset return 0; } +int journal_file_pin_object(JournalFile *f, Object *o) { + assert(f); + assert(o); + + /* This attaches the mmap window that provides the object to the 'pinning' category. So, reading + * another object with the same type will not invalidate the object, until this function is called + * for another object. */ + return mmap_cache_fd_pin(f->cache_fd, type_to_category(o->object.type), o, le64toh(o->object.size)); +} + int journal_file_read_object_header(JournalFile *f, ObjectType type, uint64_t offset, Object *ret) { ssize_t n; Object o; diff --git a/src/libsystemd/sd-journal/journal-file.h b/src/libsystemd/sd-journal/journal-file.h index 6c46dff4c45..183a5e43bb4 100644 --- a/src/libsystemd/sd-journal/journal-file.h +++ b/src/libsystemd/sd-journal/journal-file.h @@ -208,6 +208,7 @@ static inline bool VALID_EPOCH(uint64_t u) { FLAGS_SET(le32toh((h)->incompatible_flags), HEADER_INCOMPATIBLE_COMPACT) int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret); +int journal_file_pin_object(JournalFile *f, Object *o); int journal_file_read_object_header(JournalFile *f, ObjectType type, uint64_t offset, Object *ret); int journal_file_tail_end_by_pread(JournalFile *f, uint64_t *ret_offset); diff --git a/src/libsystemd/sd-journal/mmap-cache.c b/src/libsystemd/sd-journal/mmap-cache.c index 3f22d83b282..973ade64c0f 100644 --- a/src/libsystemd/sd-journal/mmap-cache.c +++ b/src/libsystemd/sd-journal/mmap-cache.c @@ -384,6 +384,49 @@ found: return 0; } +int mmap_cache_fd_pin( + MMapFileDescriptor *f, + MMapCacheCategory c, + void *addr, + size_t size) { + + MMapCache *m = mmap_cache_fd_cache(f); + Window *w; + + assert(addr); + assert(c >= 0 && c < _MMAP_CACHE_CATEGORY_MAX); + assert(size > 0); + + if (f->sigbus) + return -EIO; + + /* Check if the current category is the right one. */ + if (window_matches_by_addr(m->windows_by_category[c], f, addr, size)) { + m->n_category_cache_hit++; + w = m->windows_by_category[c]; + goto found; + } + + /* Search for a matching mmap. */ + LIST_FOREACH(windows, i, f->windows) + if (window_matches_by_addr(i, f, addr, size)) { + m->n_window_list_hit++; + w = i; + goto found; + } + + m->n_missed++; + return -EADDRNOTAVAIL; /* Not found. */ + +found: + if (FLAGS_SET(w->flags, WINDOW_KEEP_ALWAYS)) + return 0; /* The window will never unmapped. */ + + /* Attach the window to the 'pinning' category. */ + category_attach_window(m, MMAP_CACHE_CATEGORY_PIN, w); + return 1; +} + void mmap_cache_stats_log_debug(MMapCache *m) { assert(m); diff --git a/src/libsystemd/sd-journal/mmap-cache.h b/src/libsystemd/sd-journal/mmap-cache.h index 7568746e932..1fbc236bda9 100644 --- a/src/libsystemd/sd-journal/mmap-cache.h +++ b/src/libsystemd/sd-journal/mmap-cache.h @@ -20,6 +20,7 @@ typedef enum MMapCacheCategory { MMAP_CACHE_CATEGORY_ENTRY_ARRAY = OBJECT_ENTRY_ARRAY, MMAP_CACHE_CATEGORY_TAG = OBJECT_TAG, MMAP_CACHE_CATEGORY_HEADER, /* for reading file header */ + MMAP_CACHE_CATEGORY_PIN, /* for temporary pinning a object */ _MMAP_CACHE_CATEGORY_MAX, _MMAP_CACHE_CATEGORY_INVALID = -EINVAL, } MMapCacheCategory; @@ -43,6 +44,13 @@ int mmap_cache_fd_get( size_t size, struct stat *st, void **ret); + +int mmap_cache_fd_pin( + MMapFileDescriptor *f, + MMapCacheCategory c, + void *addr, + size_t size); + int mmap_cache_add_fd(MMapCache *m, int fd, int prot, MMapFileDescriptor **ret); MMapCache* mmap_cache_fd_cache(MMapFileDescriptor *f); MMapFileDescriptor* mmap_cache_fd_free(MMapFileDescriptor *f); diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c index c61573f8606..73a65da7502 100644 --- a/src/libsystemd/sd-journal/sd-journal.c +++ b/src/libsystemd/sd-journal/sd-journal.c @@ -3190,20 +3190,14 @@ _public_ int sd_journal_enumerate_unique( continue; } - /* 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, OBJECT_UNUSED, j->unique_offset, &o); + r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o); if (r < 0) return r; - /* Let's do the type check by hand, since we used 0 context above. */ - if (o->object.type != OBJECT_DATA) - return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), - "%s:offset " OFSfmt ": object has type %d, expected %d", - j->unique_file->path, - j->unique_offset, - o->object.type, OBJECT_DATA); + /* Let's pin the data object, so we can look at it at the same time as one on another file. */ + r = journal_file_pin_object(j->unique_file, o); + if (r < 0) + return r; r = journal_file_data_payload(j->unique_file, o, j->unique_offset, NULL, 0, j->data_threshold, &odata, &ol);