journal-file.c revision eda4b58b50509dc8ad0428a46e20f6c5cf516d58
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen This file is part of systemd.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Copyright 2011 Lennart Poettering
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is free software; you can redistribute it and/or modify it
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen under the terms of the GNU Lesser General Public License as published by
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen (at your option) any later version.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is distributed in the hope that it will be useful, but
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Lesser General Public License for more details.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen You should have received a copy of the GNU Lesser General Public License
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
c6f7c917a1b494d4455800823472227463f87438Tom Gundersen#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem))
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering#define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem))
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/* This is the minimum journal file size */
a501033335ed402c8f7e86fe41a15531ba69abd7Tom Gundersen#define JOURNAL_FILE_SIZE_MIN (4ULL*1024ULL*1024ULL) /* 4 MiB */
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen/* These are the lower and upper bounds if we deduce the max_use value
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen * from the file system size */
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen#define DEFAULT_MAX_USE_LOWER (1ULL*1024ULL*1024ULL) /* 1 MiB */
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen#define DEFAULT_MAX_USE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/* This is the upper bound if we deduce max_size from max_use */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#define DEFAULT_MAX_SIZE_UPPER (128ULL*1024ULL*1024ULL) /* 128 MiB */
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek/* This is the upper bound if we deduce the keep_free value from the
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek * file system size */
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek#define DEFAULT_KEEP_FREE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek/* This is the keep_free value when we can't determine the system
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek#define DEFAULT_KEEP_FREE (1024ULL*1024ULL) /* 1 MB */
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersen/* n_data was the first entry we added after the initial file format design */
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersen#define HEADER_SIZE_MIN ALIGN64(offsetof(Header, n_data))
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/* How many entries to keep in the entry array chain cache at max */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/* How much to increase the journal file size at once each time we allocate something new. */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen#define FILE_SIZE_INCREASE (8ULL*1024ULL*1024ULL) /* 8MB */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int journal_file_set_online(JournalFile *f) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* Write the final tag */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* Sync everything to disk, before we mark the file offline */
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen munmap(f->header, PAGE_ALIGN(sizeof(Header)));
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (f->fd >= 0)
6e37cd2f4af8928d905203108a4331e375d7127cThomas Hindoe Paaboel Andersen hashmap_free_free(f->chain_cache);
6916ec29afd488d91e7e0fcbcc2e006b4e5f28dfTom Gundersen munmap(f->fss_file, PAGE_ALIGN(f->fss_file_size));
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmekstatic int journal_file_init_header(JournalFile *f, JournalFile *template) {
98a375f6d5cac24eb80d6d4e00699851324afdecTom Gundersen htole32(f->compress ? HEADER_INCOMPATIBLE_COMPRESSED : 0);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen htole32(f->seal ? HEADER_COMPATIBLE_SEALED : 0);
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmek r = sd_id128_randomize(&h.file_id);
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen h.tail_entry_seqnum = template->header->tail_entry_seqnum;
74df0fca09b3c31ed19e14ba80f996fdff772417Lennart Poettering if (k != sizeof(h))
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersenstatic int journal_file_refresh_header(JournalFile *f) {
edf029b7fd9a5853a87d3ca99aac2922bb8a277eTom Gundersen r = sd_id128_get_machine(&f->header->machine_id);
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen if (sd_id128_equal(boot_id, f->header->boot_id))
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* Sync the online state to disk */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int journal_file_verify_header(JournalFile *f) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (memcmp(f->header->signature, HEADER_SIGNATURE, 8))
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* In both read and write mode we refuse to open files with
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen * incompatible flags we don't know */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if ((le32toh(f->header->incompatible_flags) & ~HEADER_INCOMPATIBLE_COMPRESSED) != 0)
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen /* When open for writing we refuse to open files with
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen * compatible flags, too */
b3e013148603aa670bc2c060ac63d48e54d76fc2Tom Gundersen if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* The first addition was n_data, so check that we are at least this large */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (le64toh(f->header->header_size) < HEADER_SIZE_MIN)
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (JOURNAL_HEADER_SEALED(f->header) && !JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays))
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen if ((le64toh(f->header->header_size) + le64toh(f->header->arena_size)) > (uint64_t) f->last_stat.st_size)
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen if (le64toh(f->header->tail_object_offset) > (le64toh(f->header->header_size) + le64toh(f->header->arena_size)))
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen if (!VALID64(le64toh(f->header->data_hash_table_offset)) ||
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen !VALID64(le64toh(f->header->field_hash_table_offset)) ||
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen !VALID64(le64toh(f->header->tail_object_offset)) ||
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen !VALID64(le64toh(f->header->entry_array_offset)))
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen if (le64toh(f->header->data_hash_table_offset) < le64toh(f->header->header_size) ||
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen le64toh(f->header->field_hash_table_offset) < le64toh(f->header->header_size) ||
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen le64toh(f->header->tail_object_offset) < le64toh(f->header->header_size) ||
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen le64toh(f->header->entry_array_offset) < le64toh(f->header->header_size))
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen if (!sd_id128_equal(machine_id, f->header->machine_id))
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen log_debug("Journal file %s is already online. Assuming unclean closing.", f->path);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen log_debug("Journal file %s has unknown state %u.", f->path, state);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen f->compress = JOURNAL_HEADER_COMPRESSED(f->header);
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersenstatic int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen /* We assume that this file is not sparse, and we know that
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen * for sure, since we always call posix_fallocate()
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen * ourselves */
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen if (new_size < le64toh(f->header->header_size))
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen if (f->metrics.max_size > 0 && new_size > f->metrics.max_size)
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen if (new_size > f->metrics.min_size && f->metrics.keep_free > 0) {
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen /* Increase by larger blocks at once */
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen new_size = ((new_size+FILE_SIZE_INCREASE-1) / FILE_SIZE_INCREASE) * FILE_SIZE_INCREASE;
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen if (f->metrics.max_size > 0 && new_size > f->metrics.max_size)
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen /* Note that the glibc fallocate() fallback is very
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen inefficient, hence we try to minimize the allocation area
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen as we can. */
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen r = posix_fallocate(f->fd, old_size, new_size - old_size);
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen f->header->arena_size = htole64(new_size - le64toh(f->header->header_size));
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersenstatic int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen /* Avoid SIGBUS on invalid accesses */
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen if (offset + size > (uint64_t) f->last_stat.st_size) {
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen /* Hmm, out of range? Let's refresh the fstat() data
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen * first, before we trust that check. */
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen offset + size > (uint64_t) f->last_stat.st_size)
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen return mmap_cache_get(f->mmap, f->fd, f->prot, context, keep_always, offset, size, &f->last_stat, ret);
d2df0d0ed3a88e491405b403e6022e6619750130Tom Gundersenstatic uint64_t minimum_header_size(Object *o) {
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen [OBJECT_DATA_HASH_TABLE] = sizeof(HashTableObject),
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen [OBJECT_FIELD_HASH_TABLE] = sizeof(HashTableObject),
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen [OBJECT_ENTRY_ARRAY] = sizeof(EntryArrayObject),
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen if (o->object.type >= ELEMENTSOF(table) || table[o->object.type] <= 0)
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen return sizeof(ObjectHeader);
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersenint journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret) {
2c5859afecee81e345fc9526b1083bf79990ffb8Daniel Mack /* Objects may only be located at multiple of 64 bit */
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen /* One context for each type, plus one catch-all for the rest */
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen context = type > 0 && type < _OBJECT_TYPE_MAX ? type : 0;
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen r = journal_file_move_to(f, context, false, offset, sizeof(ObjectHeader), &t);
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen if (s < sizeof(ObjectHeader))
return -EBADMSG;
if (s < minimum_header_size(o))
return -EBADMSG;
return -EBADMSG;
if (s > sizeof(ObjectHeader)) {
o = (Object*) t;
*ret = o;
uint64_t r;
assert(f);
if (seqnum) {
*seqnum = r;
int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) {
uint64_t p;
assert(f);
r = journal_file_set_online(f);
o = (Object*) t;
*ret = o;
*offset = p;
uint64_t s, p;
Object *o;
assert(f);
if (s < DEFAULT_DATA_HASH_TABLE_SIZE)
r = journal_file_append_object(f,
uint64_t s, p;
Object *o;
assert(f);
r = journal_file_append_object(f,
uint64_t s, p;
assert(f);
r = journal_file_move_to(f,
f->data_hash_table = t;
uint64_t s, p;
assert(f);
r = journal_file_move_to(f,
f->field_hash_table = t;
static int journal_file_link_field(
JournalFile *f,
Object *o,
uint64_t p, h;
assert(f);
assert(o);
return -EINVAL;
static int journal_file_link_data(
JournalFile *f,
Object *o,
uint64_t p, h;
assert(f);
assert(o);
return -EINVAL;
JournalFile *f,
assert(f);
return -EBADMSG;
Object *o;
if (ret)
*ret = o;
if (offset)
*offset = p;
JournalFile *f,
assert(f);
return journal_file_find_field_object_with_hash(f,
JournalFile *f,
assert(f);
return -EBADMSG;
Object *o;
goto next;
#ifdef HAVE_XZ
return -EBADMSG;
return -EBADMSG;
if (ret)
*ret = o;
if (offset)
*offset = p;
return -EPROTONOSUPPORT;
if (ret)
*ret = o;
if (offset)
*offset = p;
next:
JournalFile *f,
assert(f);
return journal_file_find_data_object_with_hash(f,
static int journal_file_append_field(
JournalFile *f,
Object *o;
assert(f);
if (ret)
*ret = o;
if (offset)
*offset = p;
#ifdef HAVE_GCRYPT
if (ret)
*ret = o;
if (offset)
*offset = p;
static int journal_file_append_data(
JournalFile *f,
Object *o;
bool compressed = false;
const void *eq;
assert(f);
if (ret)
*ret = o;
if (offset)
*offset = p;
#ifdef HAVE_XZ
if (f->compress &&
if (compressed) {
#ifdef HAVE_GCRYPT
if (ret)
*ret = o;
if (offset)
*offset = p;
assert(o);
assert(o);
assert(o);
uint64_t p) {
Object *o;
assert(f);
assert(p > 0);
n = journal_file_entry_array_n_items(o);
ap = a;
if (hidx > n)
#ifdef HAVE_GCRYPT
if (ap == 0)
uint64_t p) {
assert(f);
assert(p > 0);
if (*idx == 0)
le64_t i;
uint64_t p;
assert(f);
assert(o);
return -EINVAL;
return link_entry_into_array_plus_one(f,
offset);
uint64_t n, i;
assert(f);
assert(o);
return -EINVAL;
r = link_entry_into_array(f,
offset);
/* log_debug("=> %s seqnr=%"PRIu64" n_entries=%"PRIu64, f->path, o->entry.seqnum, f->header->n_entries); */
f->tail_entry_monotonic_valid = true;
n = journal_file_entry_n_items(o);
static int journal_file_append_entry_internal(
JournalFile *f,
Object *o;
assert(f);
#ifdef HAVE_GCRYPT
if (ret)
*ret = o;
if (offset)
assert(f);
int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, uint64_t *seqnum, Object **ret, uint64_t *offset) {
assert(f);
if (!ts) {
if (f->tail_entry_monotonic_valid &&
return -EINVAL;
#ifdef HAVE_GCRYPT
for (i = 0; i < n_iovec; i++) {
uint64_t p;
Object *o;
typedef struct ChainCacheItem {
static void chain_cache_put(
Hashmap *h,
if (!ci) {
if (!ci)
static int generic_array_get(
JournalFile *f,
uint64_t i,
Object *o;
uint64_t p = 0, a, t = 0;
assert(f);
a = first;
uint64_t k;
k = journal_file_entry_array_n_items(o);
goto found;
if (ret)
*ret = o;
if (offset)
*offset = p;
static int generic_array_get_plus_one(
JournalFile *f,
uint64_t i,
Object *o;
assert(f);
if (ret)
*ret = o;
if (offset)
static int generic_array_bisect(
JournalFile *f,
uint64_t n,
bool subtract_one = false;
assert(f);
a = first;
if (r == TEST_LEFT) {
if (right <= 0)
return -EBADMSG;
if (r == TEST_FOUND)
if (r == TEST_RIGHT) {
left = 0;
if (last_index > 0) {
return -EBADMSG;
if (r == TEST_FOUND)
if (r == TEST_RIGHT)
right = x;
return -EBADMSG;
if (r == TEST_FOUND)
if (r == TEST_RIGHT)
right = y;
subtract_one = true;
i = left;
goto found;
return -EBADMSG;
if (r == TEST_FOUND)
if (r == TEST_RIGHT)
right = i;
subtract_one = true;
goto found;
if (subtract_one && t == 0 && i == 0)
chain_cache_put(f->chain_cache, ci, first, a, array->entry_array.items[0], t, subtract_one ? (i > 0 ? i-1 : (uint64_t) -1) : i);
if (subtract_one && i == 0)
p = last_p;
else if (subtract_one)
if (ret)
*ret = o;
if (offset)
*offset = p;
if (idx)
static int generic_array_bisect_plus_one(
JournalFile *f,
uint64_t n,
bool step_back = false;
Object *o;
assert(f);
if (r == TEST_FOUND)
if (r == TEST_LEFT)
if (r == TEST_RIGHT) {
goto found;
if (r == 0 && step_back)
goto found;
if (r > 0 && idx)
(*idx) ++;
if (ret)
*ret = o;
if (offset)
if (idx)
*idx = 0;
assert(f);
assert(p > 0);
if (p == needle)
return TEST_FOUND;
else if (p < needle)
return TEST_LEFT;
return TEST_RIGHT;
JournalFile *f,
uint64_t p,
return generic_array_bisect(f,
Object *o;
assert(f);
assert(p > 0);
return TEST_FOUND;
return TEST_LEFT;
return TEST_RIGHT;
JournalFile *f,
return generic_array_bisect(f,
Object *o;
assert(f);
assert(p > 0);
return TEST_FOUND;
return TEST_LEFT;
return TEST_RIGHT;
JournalFile *f,
return generic_array_bisect(f,
Object *o;
assert(f);
assert(p > 0);
return TEST_FOUND;
return TEST_LEFT;
return TEST_RIGHT;
static inline int find_data_object_by_boot_id(
JournalFile *f,
Object **o,
uint64_t *b) {
JournalFile *f,
Object *o;
assert(f);
return -ENOENT;
return generic_array_bisect_plus_one(f,
JournalFile *f,
uint64_t i, n;
assert(f);
assert(p > 0 || !o);
return -EINVAL;
r = generic_array_bisect(f,
return generic_array_get(f,
JournalFile *f,
uint64_t i, n;
assert(f);
assert(o);
assert(p > 0);
return -EINVAL;
r = generic_array_bisect(f,
if (skip < 0) {
return -EBADMSG;
return generic_array_get(f,
JournalFile *f,
uint64_t n, i;
Object *d;
assert(f);
assert(p > 0 || !o);
return -EINVAL;
return generic_array_get_plus_one(f,
JournalFile *f,
uint64_t p,
Object *d;
assert(f);
return generic_array_bisect_plus_one(f,
JournalFile *f,
Object *o, *d;
uint64_t b, z;
assert(f);
return -ENOENT;
uint64_t p, q;
if (ret)
if (offset)
*offset = q;
JournalFile *f,
Object *d;
assert(f);
return generic_array_bisect_plus_one(f,
JournalFile *f,
Object *d;
assert(f);
return generic_array_bisect_plus_one(f,
Object *o;
uint64_t p;
assert(f);
goto fail;
case OBJECT_UNUSED:
case OBJECT_DATA:
case OBJECT_FIELD:
case OBJECT_ENTRY:
case OBJECT_FIELD_HASH_TABLE:
case OBJECT_DATA_HASH_TABLE:
case OBJECT_ENTRY_ARRAY:
case OBJECT_TAG:
fail:
assert(f);
f->path,
100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))));
100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))));
int journal_file_open(
const char *fname,
int flags,
bool compress,
bool seal,
JournalFile *f;
bool newly_created = false;
return -EINVAL;
return -EINVAL;
return -ENOMEM;
#ifdef HAVE_XZ
#ifdef HAVE_GCRYPT
if (mmap_cache)
if (!f->mmap) {
r = -ENOMEM;
goto fail;
if (!f->path) {
r = -ENOMEM;
goto fail;
if (!f->chain_cache) {
r = -ENOMEM;
goto fail;
if (f->fd < 0) {
r = -errno;
goto fail;
r = -errno;
goto fail;
#ifdef HAVE_XATTR
#ifdef HAVE_GCRYPT
if (f->seal) {
r = journal_file_fss_load(f);
f->seal = false;
goto fail;
r = -errno;
goto fail;
newly_created = true;
r = -EIO;
goto fail;
r = -errno;
goto fail;
if (!newly_created) {
r = journal_file_verify_header(f);
goto fail;
#ifdef HAVE_GCRYPT
r = journal_file_fss_load(f);
goto fail;
if (f->writable) {
if (metrics) {
} else if (template)
r = journal_file_refresh_header(f);
goto fail;
#ifdef HAVE_GCRYPT
r = journal_file_hmac_setup(f);
goto fail;
if (newly_created) {
goto fail;
goto fail;
#ifdef HAVE_GCRYPT
r = journal_file_append_first_tag(f);
goto fail;
goto fail;
r = journal_file_map_data_hash_table(f);
goto fail;
*ret = f;
fail:
size_t l;
assert(f);
assert(*f);
old_file = *f;
return -EINVAL;
return -EINVAL;
return -ENOMEM;
return -errno;
r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file);
*f = new_file;
const char *fname,
int flags,
bool compress,
bool seal,
size_t l;
random_ull()) < 0)
return -ENOMEM;
return -errno;
int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) {
uint64_t i, n;
assert(o);
assert(p);
return -EPERM;
n = journal_file_entry_n_items(o);
uint64_t l, h;
size_t t;
void *data;
Object *u;
return -EBADMSG;
t = (size_t) l;
if ((uint64_t) t != l)
return -E2BIG;
#ifdef HAVE_XZ
if (!uncompress_blob(o->data.payload, l, &from->compress_buffer, &from->compress_buffer_size, &rsize, 0))
return -EBADMSG;
l = rsize;
return -EPROTONOSUPPORT;
assert(m);
if (fs_size > 0) {
if (fs_size > 0) {
assert(f);
if (from) {
return -ENOENT;
if (to) {
return -ENOENT;
int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot_id, usec_t *from, usec_t *to) {
Object *o;
uint64_t p;
assert(f);
if (from) {
if (to) {
r = generic_array_get_plus_one(f,
&o, NULL);
assert(f);
if (le64toh(f->header->n_data) * 4ULL > (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)) * 3ULL) {
log_debug("Data hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items, %llu file size, %"PRIu64" bytes per hash table item), suggesting rotation.",
f->path,
100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))),
if (le64toh(f->header->n_fields) * 4ULL > (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)) * 3ULL) {
log_debug("Field hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items), suggesting rotation.",
f->path,
100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))),
if (max_file_usec > 0) {
usec_t t, h;
if (h > 0 && t > h + max_file_usec)