[systemd-commits] 12 commits - configure.ac src/journal src/shared
Michal Schmidt
michich at kemper.freedesktop.org
Fri Dec 12 15:48:41 PST 2014
configure.ac | 38 ++++++++--
src/journal/journal-authenticate.c | 4 -
src/journal/journal-authenticate.h | 2
src/journal/journal-def.h | 6 -
src/journal/journal-file.c | 26 ++++---
src/journal/journal-file.h | 22 ------
src/journal/journal-verify.c | 10 +-
src/journal/mmap-cache.c | 134 +++++++++++--------------------------
src/journal/mmap-cache.h | 10 --
src/journal/sd-journal.c | 15 ----
src/journal/test-mmap-cache.c | 10 +-
src/shared/hashmap.c | 24 +++---
src/shared/hashmap.h | 8 +-
13 files changed, 130 insertions(+), 179 deletions(-)
New commits:
commit 69adae5168da231c6cf319f708860954701b25ed
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Wed Dec 3 18:25:44 2014 +0100
journal: replace contexts hashmap with a plain array
try_context() is such a hot path that the hashmap lookup is expensive.
The number of contexts is small - it is the number of object types.
Using a hashmap is overkill. A plain array will do.
Before:
$ time ./journalctl --since=2014-06-01 --until=2014-07-01 > /dev/null
real 0m9.445s
user 0m9.228s
sys 0m0.213s
After:
$ time ./journalctl --since=2014-06-01 --until=2014-07-01 > /dev/null
real 0m5.438s
user 0m5.266s
sys 0m0.170s
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 82e50fc..7cdaf29 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -376,6 +376,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
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;
}
diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
index 949f978..4c940aa 100644
--- a/src/journal/mmap-cache.c
+++ b/src/journal/mmap-cache.c
@@ -76,7 +76,7 @@ struct MMapCache {
Hashmap *fds;
- Hashmap *contexts;
+ Context *contexts[MMAP_CACHE_MAX_CONTEXTS];
LIST_HEAD(Window, unused);
Window *last_unused;
@@ -231,18 +231,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;
@@ -250,11 +245,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;
}
@@ -264,8 +256,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);
}
@@ -314,15 +308,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);
@@ -374,7 +367,7 @@ static int try_context(
assert(size > 0);
assert(ret);
- c = hashmap_get(m->contexts, UINT_TO_PTR(context+1));
+ c = m->contexts[context];
if (!c)
return 0;
@@ -557,6 +550,7 @@ int mmap_cache_get(
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);
diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h
index 543a2bf..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);
commit 634ed0ee3466e5e5f78d3acbe9782650ff456288
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Wed Dec 3 18:23:23 2014 +0100
journal: delete unused function mmap_cache_close_context
This never had any callers. Contexts are freed when the MMapCache is
freed.
diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
index f34d260..949f978 100644
--- a/src/journal/mmap-cache.c
+++ b/src/journal/mmap-cache.c
@@ -591,18 +591,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 3e2ffbb..543a2bf 100644
--- a/src/journal/mmap-cache.h
+++ b/src/journal/mmap-cache.h
@@ -42,7 +42,6 @@ int mmap_cache_get(
struct stat *st,
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);
commit 7a9dabea7eabd4dd87f8774234265590d34761da
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Fri Dec 12 23:20:05 2014 +0100
journal: push type_to_context conversion down to journal_file_move_to()
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 1d73be1..82e50fc 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -379,7 +379,7 @@ static unsigned type_to_context(ObjectType type) {
return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0;
}
-static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
+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);
@@ -396,7 +396,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);
+ 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) {
@@ -430,7 +430,7 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset
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;
@@ -450,7 +450,7 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset
return -EBADMSG;
if (s > sizeof(ObjectHeader)) {
- r = journal_file_move_to(f, type_to_context(type), false, offset, s, &t);
+ r = journal_file_move_to(f, type, false, offset, s, &t);
if (r < 0)
return r;
commit 7851983162ef851d5b9ce12bd88de86fc402f88a
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Wed Dec 10 15:18:49 2014 +0100
journal: have a named enum ObjectType
diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index 0e31c8d..b3e2601 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);
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 005e5fa..ab089cb 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -52,7 +52,7 @@ typedef struct HashItem HashItem;
typedef struct FSSHeader FSSHeader;
/* Object types */
-enum {
+typedef enum ObjectType {
OBJECT_UNUSED, /* also serves as "any type" or "additional context" */
OBJECT_DATA,
OBJECT_FIELD,
@@ -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 6ee0fff..1d73be1 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -374,7 +374,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
return 0;
}
-static unsigned type_to_context(int type) {
+static unsigned type_to_context(ObjectType type) {
/* One context for each type, plus one catch-all for the rest */
return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0;
}
@@ -417,7 +417,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;
@@ -487,7 +487,7 @@ 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;
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 5e8065c..a4a172b 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -160,13 +160,13 @@ static inline bool VALID_EPOCH(uint64_t u) {
#define JOURNAL_HEADER_COMPRESSED_LZ4(h) \
(!!(le32toh((h)->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED_LZ4))
-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);
uint64_t journal_file_entry_n_items(Object *o) _pure_;
uint64_t journal_file_entry_array_n_items(Object *o) _pure_;
uint64_t journal_file_hash_table_n_items(Object *o) _pure_;
-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 journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, uint64_t *seqno, Object **ret, uint64_t *offset);
int journal_file_find_data_object(JournalFile *f, const void *data, uint64_t size, Object **ret, uint64_t *offset);
commit d05089d86ef032b245c7f928e623b88c82998ab0
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Fri Dec 12 22:51:24 2014 +0100
journal: consistently use OBJECT_<type> names instead of numbers
Note that numbers 0 and -1 are both replaced with OBJECT_UNUSED,
because they are treated the same everywhere (e.g. type_to_context()
translates them both to 0).
diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index fd3b821..0e31c8d 100644
--- a/src/journal/journal-authenticate.c
+++ b/src/journal/journal-authenticate.c
@@ -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-def.h b/src/journal/journal-def.h
index e55fa19..005e5fa 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -53,7 +53,7 @@ typedef struct FSSHeader FSSHeader;
/* Object types */
enum {
- OBJECT_UNUSED,
+ OBJECT_UNUSED, /* also serves as "any type" or "additional context" */
OBJECT_DATA,
OBJECT_FIELD,
OBJECT_ENTRY,
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 4632326..6ee0fff 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -376,7 +376,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
static unsigned type_to_context(int type) {
/* One context for each type, plus one catch-all for the rest */
- return type > 0 && type < _OBJECT_TYPE_MAX ? type : 0;
+ return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0;
}
static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
@@ -446,7 +446,7 @@ 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)) {
@@ -494,7 +494,7 @@ int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object *
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);
@@ -507,7 +507,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;
@@ -2294,7 +2294,7 @@ void journal_file_dump(JournalFile *f) {
p = le64toh(f->header->header_size);
while (p != 0) {
- r = journal_file_move_to_object(f, -1, p, &o);
+ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
if (r < 0)
goto fail;
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 75792a5..b03335e 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -865,7 +865,7 @@ int journal_file_verify(
if (show_progress)
draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
- r = journal_file_move_to_object(f, -1, p, &o);
+ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
if (r < 0) {
error(p, "invalid object");
goto fail;
@@ -1085,11 +1085,11 @@ int journal_file_verify(
q = last_tag;
while (q <= p) {
- r = journal_file_move_to_object(f, -1, q, &o);
+ r = journal_file_move_to_object(f, OBJECT_UNUSED, q, &o);
if (r < 0)
goto fail;
- r = journal_file_hmac_put_object(f, -1, o, q);
+ r = journal_file_hmac_put_object(f, OBJECT_UNUSED, o, q);
if (r < 0)
goto fail;
@@ -1097,7 +1097,7 @@ int journal_file_verify(
}
/* Position might have changed, let's reposition things */
- r = journal_file_move_to_object(f, -1, p, &o);
+ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
if (r < 0)
goto fail;
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 028060d..be08a92 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -2588,10 +2588,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;
commit 2df65e7d964295f2763fae3b8bc3ade5d4e0fbe3
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Wed Dec 10 16:37:29 2014 +0100
journal: consistently allow type==0 to mean "any type"
If type==0 and a non-NULL object were given as arguments to
journal_file_hmac_put_object(), its object type check would fail and it
would return -EBADMSG.
All existing callers use either a positive type or -1. Still, for
behavior consistency with journal_file_move_to_object() let's allow
type 0 to pass.
diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index f9bd686..fd3b821 100644
--- a/src/journal/journal-authenticate.c
+++ b/src/journal/journal-authenticate.c
@@ -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 > 0 && o->object.type != type)
return -EBADMSG;
}
commit d3d3208f607693b8fde5226efa0cc15ec17670a0
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Fri Dec 12 18:06:22 2014 +0100
journal: move type_to_context() to journal-file.c
It has no other callers. It does not need to be in the header file.
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index f706990..4632326 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -374,6 +374,11 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
return 0;
}
+static unsigned type_to_context(int type) {
+ /* One context for each type, plus one catch-all for the rest */
+ return type > 0 && type < _OBJECT_TYPE_MAX ? type : 0;
+}
+
static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
assert(f);
assert(ret);
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index c5a92bc..5e8065c 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -205,9 +205,3 @@ int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *
int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to);
bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec);
-
-
-static unsigned type_to_context(int type) {
- /* One context for each type, plus one catch-all for the rest */
- return type > 0 && type < _OBJECT_TYPE_MAX ? type : 0;
-}
commit 1b8951e5bd9b2bf1722098a861055cae0bb52088
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Fri Dec 12 21:52:18 2014 +0100
journal: remove journal_file_object_keep/release functions
The only user is sd_journal_enumerate_unique() and, as explained in
the previous commit (fed67c38e3 "journal: map objects to context set by
caller, not by actual object type"), the use of them there is now
superfluous. Let's remove them.
This reverts major parts of commits:
ae97089d49 journal: fix access to munmapped memory in
sd_journal_enumerate_unique
06cc69d44c sd-journal: fix sd_journal_enumerate_unique skipping values
Tested with an "--enable-debug" build and "journalctl --list-boots".
It gives the expected number of results. Additionally, if I then revert
the previous commit ("journal: map objects to context set by caller, not
to actual object type"), it crashes with SIGSEGV, as expected.
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 01b7f89..f706990 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -391,7 +391,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, context, keep_always, offset, size, &f->last_stat, ret);
}
static uint64_t minimum_header_size(Object *o) {
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 211e121..c5a92bc 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -211,15 +211,3 @@ static unsigned type_to_context(int type) {
/* One context for each type, plus one catch-all for the rest */
return type > 0 && type < _OBJECT_TYPE_MAX ? type : 0;
}
-
-static inline int journal_file_object_keep(JournalFile *f, Object *o, uint64_t offset, void **release_cookie) {
- unsigned context = type_to_context(o->object.type);
- uint64_t s = le64toh(o->object.size);
-
- return mmap_cache_get(f->mmap, f->fd, f->prot, context, true,
- offset, s, &f->last_stat, NULL, release_cookie);
-}
-
-static inline int journal_file_object_release(JournalFile *f, void *release_cookie) {
- return mmap_cache_release(f->mmap, f->fd, release_cookie);
-}
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 91de45f..75792a5 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -368,7 +368,7 @@ static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
c = (a + b) / 2;
- r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL);
+ r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
if (r < 0)
return r;
diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
index c57c162..f34d260 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;
@@ -191,7 +191,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? */
#ifdef ENABLE_DEBUG_MMAP_CACHE
/* Unmap unused windows immediately to expose use-after-unmap
@@ -364,8 +364,7 @@ static int try_context(
bool keep_always,
uint64_t offset,
size_t size,
- void **ret,
- void **release_cookie) {
+ void **ret) {
Context *c;
@@ -373,6 +372,7 @@ 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));
if (!c)
@@ -390,12 +390,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;
}
@@ -407,8 +404,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;
@@ -439,10 +435,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;
}
@@ -455,8 +448,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;
@@ -469,6 +461,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);
@@ -538,10 +531,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:
@@ -558,8 +548,7 @@ int mmap_cache_get(
uint64_t offset,
size_t size,
struct stat *st,
- void **ret,
- void **release_cookie) {
+ void **ret) {
int r;
@@ -567,16 +556,17 @@ int mmap_cache_get(
assert(m->n_ref > 0);
assert(fd >= 0);
assert(size > 0);
+ assert(ret);
/* 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;
@@ -585,39 +575,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) {
diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h
index 76e5316..3e2ffbb 100644
--- a/src/journal/mmap-cache.h
+++ b/src/journal/mmap-cache.h
@@ -40,12 +40,7 @@ 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);
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 23aad74..028060d 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -2563,7 +2563,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) {
@@ -2604,10 +2603,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;
@@ -2652,10 +2647,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/journal/test-mmap-cache.c b/src/journal/test-mmap-cache.c
index 1227b62..3fcd774 100644
--- a/src/journal/test-mmap-cache.c
+++ b/src/journal/test-mmap-cache.c
@@ -49,23 +49,23 @@ int main(int argc, char *argv[]) {
assert_se(z >= 0);
unlink(pz);
- r = mmap_cache_get(m, x, PROT_READ, 0, false, 1, 2, NULL, &p, NULL);
+ r = mmap_cache_get(m, x, PROT_READ, 0, false, 1, 2, NULL, &p);
assert_se(r >= 0);
- r = mmap_cache_get(m, x, PROT_READ, 0, false, 2, 2, NULL, &q, NULL);
+ r = mmap_cache_get(m, x, PROT_READ, 0, false, 2, 2, NULL, &q);
assert_se(r >= 0);
assert_se((uint8_t*) p + 1 == (uint8_t*) q);
- r = mmap_cache_get(m, x, PROT_READ, 1, false, 3, 2, NULL, &q, NULL);
+ r = mmap_cache_get(m, x, PROT_READ, 1, false, 3, 2, NULL, &q);
assert_se(r >= 0);
assert_se((uint8_t*) p + 2 == (uint8_t*) q);
- r = mmap_cache_get(m, x, PROT_READ, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p, NULL);
+ r = mmap_cache_get(m, x, PROT_READ, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p);
assert_se(r >= 0);
- r = mmap_cache_get(m, x, PROT_READ, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q, NULL);
+ r = mmap_cache_get(m, x, PROT_READ, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q);
assert_se(r >= 0);
assert_se((uint8_t*) p + 1 == (uint8_t*) q);
commit fed67c38e3f1cecf4c0571f5603d47b35bff6576
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Fri Dec 12 18:21:55 2014 +0100
journal: map objects to context set by caller, not by actual object type
When the caller of journal_file_move_to_object() specifies type==0,
the object header is at first mapped in context 0. Then after the header
is checked, the whole object is mapped in a context determined by
the actual object type (which is not even range-checked using
type_to_context()). This looks wrong. It should map in the
caller-specified context.
An old comment in sd_journal_enumerate_unique() supports this view:
/* We do not use the type context here, but 0 instead,
* so that we can look at this data object at the same
* time as one on another file */
Clearly the expectation was that the data object will remain mapped
in context 0 without being pushed away by mapping other objects in
context OBJECT_DATA.
I suspect that this was the real bug that got fixed by ae97089d49
"journal: fix access to munmapped memory in sd_journal_enumerate_unique".
In other words, journal_file_object_keep/release are superfluous after
applying this patch.
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 622eb16..01b7f89 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -445,7 +445,7 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec
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_to_context(type), false, offset, s, &t);
if (r < 0)
return r;
commit fad5a6c66e73d3df20846906121d52159e1f6bf4
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Fri Dec 12 17:57:22 2014 +0100
journal: add debug mode for mmap-cache (--enable-debug=mmap-cache)
This is useful for exposing unsafe access to mmapped objects after
the context that they were mapped in was already moved.
For example:
journal_file_move_to_object(f1, OBJECT_DATA, p1, &o1);
journal_file_move_to_object(f2, OBJECT_DATA, p2, &o2);
t = o1->object.type; /* this usually works, but is unsafe */
diff --git a/configure.ac b/configure.ac
index ea74fcd..e14f3cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1328,9 +1328,9 @@ AC_ARG_ENABLE(tests,
AM_CONDITIONAL(ENABLE_TESTS, [test x$enable_tests = xyes])
AC_ARG_ENABLE(debug,
- [AC_HELP_STRING([--enable-debug@<:@=LIST@:>@], [enable extra debugging (hashmap)])],
+ [AC_HELP_STRING([--enable-debug@<:@=LIST@:>@], [enable extra debugging (hashmap,mmap-cache)])],
[if test "x$enableval" = "xyes"; then
- enableval="hashmap"
+ enableval="hashmap,mmap-cache"
fi
saved_ifs="$IFS"
IFS="$IFS$PATH_SEPARATOR,"
@@ -1339,6 +1339,9 @@ AC_ARG_ENABLE(debug,
hashmap)
enable_debug_hashmap=yes
;;
+ mmap-cache)
+ enable_debug_mmap_cache=yes
+ ;;
esac
done
IFS="$saved_ifs"],[])
@@ -1348,6 +1351,9 @@ AS_IF([test x$enable_debug_hashmap = xyes], [
AC_DEFINE(ENABLE_DEBUG_HASHMAP, 1, [Define if hashmap debugging is to be enabled])
enable_debug="hashmap $enable_debug"
])
+AS_IF([test x$enable_debug_mmap_cache = xyes], [
+ AC_DEFINE(ENABLE_DEBUG_MMAP_CACHE, 1, [Define if mmap cache debugging is to be enabled])
+ enable_debug="mmap-cache $enable_debug"
])
test -z "$enable_debug" && enable_debug="none"
diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
index b7db6f1..c57c162 100644
--- a/src/journal/mmap-cache.c
+++ b/src/journal/mmap-cache.c
@@ -83,7 +83,13 @@ struct MMapCache {
};
#define WINDOWS_MIN 64
-#define WINDOW_SIZE (8ULL*1024ULL*1024ULL)
+
+#ifdef ENABLE_DEBUG_MMAP_CACHE
+/* Tiny windows increase mmap activity and the chance of exposing unsafe use. */
+# define WINDOW_SIZE (page_size())
+#else
+# define WINDOW_SIZE (8ULL*1024ULL*1024ULL)
+#endif
MMapCache* mmap_cache_new(void) {
MMapCache *m;
@@ -187,11 +193,17 @@ static void context_detach_window(Context *c) {
if (!w->contexts && w->keep_always == 0) {
/* Not used anymore? */
+#ifdef ENABLE_DEBUG_MMAP_CACHE
+ /* Unmap unused windows immediately to expose use-after-unmap
+ * by SIGSEGV. */
+ window_free(w);
+#else
LIST_PREPEND(unused, c->cache->unused, w);
if (!c->cache->last_unused)
c->cache->last_unused = w;
w->in_unused = true;
+#endif
}
}
commit fc86aa0ed204922dcafa85353cb10e1aa7d91a76
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Fri Dec 12 17:48:13 2014 +0100
configure.ac: add a generic --enable-debug, replace --enable-hashmap-debug
There will be more debugging options later.
--enable-debug will enable them all.
--enable-debug=hashmap will enable only hashmap debugging.
Also rename the C #define to ENABLE_DEBUG_* pattern.
diff --git a/configure.ac b/configure.ac
index 9218ed3..ea74fcd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1323,16 +1323,33 @@ AS_IF([test "x$0" != "x./configure"], [
])
AC_ARG_ENABLE(tests,
- [AC_HELP_STRING([--disable-tests], [disable tests])],
- enable_tests=$enableval, enable_tests=yes)
+ [AC_HELP_STRING([--disable-tests], [disable tests])],
+ enable_tests=$enableval, enable_tests=yes)
AM_CONDITIONAL(ENABLE_TESTS, [test x$enable_tests = xyes])
-AC_ARG_ENABLE(hashmap-debug,
- [AC_HELP_STRING([--enable-hashmap-debug], [enable hashmap debugging])],
- enable_hashmap_debug=$enableval, enable_hashmap_debug=no)
-AS_IF([test x$enable_hashmap_debug = xyes], [
- AC_DEFINE(ENABLE_HASHMAP_DEBUG, 1, [Define if hashmap debugging is to be enabled])
+AC_ARG_ENABLE(debug,
+ [AC_HELP_STRING([--enable-debug@<:@=LIST@:>@], [enable extra debugging (hashmap)])],
+ [if test "x$enableval" = "xyes"; then
+ enableval="hashmap"
+ fi
+ saved_ifs="$IFS"
+ IFS="$IFS$PATH_SEPARATOR,"
+ for name in $enableval; do
+ case $name in
+ hashmap)
+ enable_debug_hashmap=yes
+ ;;
+ esac
+ done
+ IFS="$saved_ifs"],[])
+
+enable_debug=""
+AS_IF([test x$enable_debug_hashmap = xyes], [
+ AC_DEFINE(ENABLE_DEBUG_HASHMAP, 1, [Define if hashmap debugging is to be enabled])
+ enable_debug="hashmap $enable_debug"
+])
])
+test -z "$enable_debug" && enable_debug="none"
AC_SUBST([dbuspolicydir], [$with_dbuspolicydir])
AC_SUBST([dbussessionservicedir], [$with_dbussessionservicedir])
@@ -1419,6 +1436,7 @@ AC_MSG_RESULT([
SysV compatibility: ${SYSTEM_SYSV_COMPAT}
compatibility libraries: ${have_compat_libs}
utmp/wtmp support: ${have_utmp}
+ extra debugging: ${enable_debug}
prefix: ${prefix}
rootprefix: ${with_rootprefix}
diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c
index 18c2c0e..f2a8a77 100644
--- a/src/shared/hashmap.c
+++ b/src/shared/hashmap.c
@@ -137,7 +137,7 @@ typedef uint8_t dib_raw_t;
#define DIB_FREE UINT_MAX
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
struct hashmap_debug_info {
LIST_FIELDS(struct hashmap_debug_info, debug_list);
unsigned max_entries; /* high watermark of n_entries */
@@ -158,9 +158,9 @@ static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
#define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug;
-#else /* !ENABLE_HASHMAP_DEBUG */
+#else /* !ENABLE_DEBUG_HASHMAP */
#define HASHMAP_DEBUG_FIELDS
-#endif /* ENABLE_HASHMAP_DEBUG */
+#endif /* ENABLE_DEBUG_HASHMAP */
enum HashmapType {
HASHMAP_TYPE_PLAIN,
@@ -552,7 +552,7 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) {
dibs = dib_raw_ptr(h);
assert(dibs[idx] != DIB_RAW_FREE);
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
h->debug.rem_count++;
h->debug.last_rem_idx = idx;
#endif
@@ -631,7 +631,7 @@ static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *
assert(e->p.b.key == i->next_key);
}
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
i->prev_idx = idx;
#endif
@@ -688,7 +688,7 @@ static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
}
idx = i->idx;
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
i->prev_idx = idx;
#endif
@@ -711,7 +711,7 @@ static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
return IDX_NIL;
}
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
if (i->idx == IDX_FIRST) {
i->put_count = h->debug.put_count;
i->rem_count = h->debug.rem_count;
@@ -799,7 +799,7 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
shared_hash_key_initialized= true;
}
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug);
h->debug.func = func;
h->debug.file = file;
@@ -854,7 +854,7 @@ static void hashmap_free_no_clear(HashmapBase *h) {
assert(!h->has_indirect);
assert(!h->n_direct_entries);
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
#endif
@@ -961,7 +961,7 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
dib_raw_t raw_dib, *dibs;
unsigned dib, distance;
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
h->debug.put_count++;
#endif
@@ -1055,7 +1055,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
n_entries_inc(h);
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
#endif
@@ -1283,7 +1283,7 @@ int hashmap_replace(Hashmap *h, const void *key, void *value) {
idx = bucket_scan(h, hash, key);
if (idx != IDX_NIL) {
e = plain_bucket_at(h, idx);
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
/* Although the key is equal, the key pointer may have changed,
* and this would break our assumption for iterating. So count
* this operation as incompatible with iteration. */
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
index 72c4adc..894f679 100644
--- a/src/shared/hashmap.h
+++ b/src/shared/hashmap.h
@@ -32,7 +32,7 @@
* will be treated as empty hashmap for all read operations. That way it is not
* necessary to instantiate an object for each Hashmap use.
*
- * If ENABLE_HASHMAP_DEBUG is defined (by configuring with --enable-hashmap-debug),
+ * If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap),
* the implemention will:
* - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
* - perform extra checks for invalid use of iterators
@@ -57,7 +57,7 @@ typedef struct Set Set; /* Stores just keys */
typedef struct {
unsigned idx; /* index of an entry to be iterated next */
const void *next_key; /* expected value of that entry's key pointer */
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
unsigned put_count; /* hashmap's put_count recorded at start of iteration */
unsigned rem_count; /* hashmap's rem_count in previous iteration */
unsigned prev_idx; /* idx in previous iteration */
@@ -129,7 +129,7 @@ extern const struct hash_ops devt_hash_ops = {
(Hashmap*)(h), \
(void)0)
-#ifdef ENABLE_HASHMAP_DEBUG
+#ifdef ENABLE_DEBUG_HASHMAP
# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
# define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__
# define HASHMAP_DEBUG_PASS_ARGS , func, file, line
commit 90df619ef505145a62b25bbe8d95ae595a6a9511
Author: Michal Schmidt <mschmidt at redhat.com>
Date: Fri Dec 12 17:42:28 2014 +0100
shared/hashmap.h: fix comment
An early version used underscore prefixes for internal functions, but
the current version uses the prefix "internal_".
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
index 9c6e0ca..72c4adc 100644
--- a/src/shared/hashmap.h
+++ b/src/shared/hashmap.h
@@ -43,7 +43,7 @@
/* The base type for all hashmap and set types. Many functions in the
* implementation take (HashmapBase*) parameters and are run-time polymorphic,
* though the API is not meant to be polymorphic (do not call functions
- * prefixed with two underscores directly). */
+ * internal_*() directly). */
typedef struct HashmapBase HashmapBase;
/* Specific hashmap/set types */
More information about the systemd-commits
mailing list