journal-file.c revision b788cc23aa50682fe80c1b78cc5e42aaf7d76bc5
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2011 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*16ULL)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define DEFAULT_FIELD_HASH_TABLE_SIZE (2047ULL*16ULL)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define DEFAULT_WINDOW_SIZE (128ULL*1024ULL*1024ULL)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define COMPRESSION_SIZE_THRESHOLD (64ULL)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* This is the minimum journal file size */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define JOURNAL_FILE_SIZE_MIN (64ULL*1024ULL)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* These are the lower and upper bounds if we deduce the max_use value
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * from the file system size */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define DEFAULT_MAX_USE_LOWER (1ULL*1024ULL*1024ULL) /* 1 MiB */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define DEFAULT_MAX_USE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* This is the upper bound if we deduce max_size from max_use */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define DEFAULT_MAX_SIZE_UPPER (16ULL*1024ULL*1024ULL) /* 16 MiB */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* This is the upper bound if we deduce the keep_free value from the
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * file system size */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define DEFAULT_KEEP_FREE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* This is the keep_free value when we can't determine the system
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define DEFAULT_KEEP_FREE (1024ULL*1024ULL) /* 1 MB */
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poetteringstatic const char signature[] = { 'L', 'P', 'K', 'S', 'H', 'H', 'R', 'H' };
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (t = 0; t < _WINDOW_MAX; t++)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering munmap(f->windows[t].ptr, f->windows[t].size);
free(f);
Header h;
ssize_t k;
assert(f);
zero(h);
if (template) {
return -errno;
return -EIO;
assert(f);
f->tail_entry_monotonic_valid = true;
assert(f);
return -EBADMSG;
#ifdef HAVE_XZ
return -EPROTONOSUPPORT;
return -EPROTONOSUPPORT;
if ((uint64_t) f->last_stat.st_size < (le64toh(f->header->arena_offset) + le64toh(f->header->arena_size)))
return -ENODATA;
if (f->writable) {
return -EHOSTDOWN;
return -ESHUTDOWN;
assert(f);
old_size =
return -E2BIG;
available = 0;
return -E2BIG;
return -errno;
return -errno;
static int journal_file_map(
JournalFile *f,
void **_window,
void **ret) {
void *window;
assert(f);
return -EADDRNOTAVAIL;
return -errno;
if (_window)
if (_woffset)
if (_wsize)
static int journal_file_move_to(JournalFile *f, int wt, uint64_t offset, uint64_t size, void **ret) {
void *p = NULL;
Window *w;
assert(f);
if (w->ptr) {
return -errno;
delta = 0;
return -EADDRNOTAVAIL;
if (size <= 0)
return -EADDRNOTAVAIL;
r = journal_file_map(f,
assert(o);
Object *o;
uint64_t s;
assert(f);
o = (Object*) t;
if (s < sizeof(ObjectHeader))
return -EBADMSG;
return -EBADMSG;
if (s > sizeof(ObjectHeader)) {
o = (Object*) t;
if (!verify_hash(o))
return -EBADMSG;
*ret = o;
uint64_t r;
assert(f);
if (seqnum) {
*seqnum = r;
static int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) {
uint64_t p;
assert(f);
o = (Object*) t;
*ret = o;
*offset = p;
uint64_t s, p;
Object *o;
assert(f);
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;
uint64_t p, h;
assert(f);
assert(o);
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_data(JournalFile *f, const void *data, uint64_t size, Object **ret, uint64_t *offset) {
Object *o;
bool compressed = false;
assert(f);
if (ret)
*ret = o;
if (offset)
*offset = p;
#ifdef HAVE_XZ
if (f->compress &&
if (compressed) {
f->header->incompatible_flags = htole32(le32toh(f->header->incompatible_flags) | HEADER_INCOMPATIBLE_COMPRESSED);
if (!compressed)
if (ret)
*ret = o;
if (offset)
*offset = p;
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)
if (ap == 0)
*first = q;
uint64_t p) {
assert(f);
assert(p > 0);
if (*idx == 0)
uint64_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);
r = link_entry_into_array(f,
offset);
log_error("=> %s seqnr=%lu n_entries=%lu", f->path, (unsigned long) o->entry.seqnum, (unsigned long) 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);
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 (!f->writable)
return -EPERM;
if (!ts) {
if (f->tail_entry_monotonic_valid &&
return -EINVAL;
return -EINVAL;
for (i = 0; i < n_iovec; i++) {
uint64_t p;
Object *o;
uint64_t i,
Object *o;
uint64_t p = 0, a;
assert(f);
a = first;
uint64_t n;
n = journal_file_entry_array_n_items(o);
if (ret)
*ret = o;
if (offset)
*offset = p;
uint64_t i,
Object *o;
assert(f);
if (ret)
*ret = o;
if (offset)
uint64_t n,
bool subtract_one = false;
assert(f);
a = first;
if (right <= 0)
return -EBADMSG;
if (r == TEST_FOUND)
if (r == TEST_RIGHT) {
left = 0;
subtract_one = true;
i = left;
goto found;
return -EBADMSG;
if (r == TEST_FOUND)
if (r == TEST_RIGHT)
right = i;
if (subtract_one && t == 0 && i == 0)
if (subtract_one && i == 0)
p = last_p;
else if (subtract_one)
if (ret)
*ret = o;
if (offset)
*offset = p;
if (idx)
uint64_t n,
assert(f);
else if (r == TEST_FOUND) {
Object *o;
if (ret)
*ret = o;
if (offset)
if (idx)
*idx = 0;
} else if (r == TEST_RIGHT)
(*idx) ++;
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;
JournalFile *f,
Object *o;
return -ENOENT;
return generic_array_bisect_plus_one(f,
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 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,
Object *d;
return generic_array_bisect_plus_one(f,
JournalFile *f,
Object *d;
return generic_array_bisect_plus_one(f,
Object *o;
uint64_t p;
assert(f);
f->path,
goto fail;
case OBJECT_UNUSED:
case OBJECT_DATA:
case OBJECT_ENTRY:
case OBJECT_FIELD_HASH_TABLE:
case OBJECT_DATA_HASH_TABLE:
case OBJECT_ENTRY_ARRAY:
fail:
int journal_file_open(
const char *fname,
int flags,
JournalFile *f;
bool newly_created = false;
return -EINVAL;
return -ENOMEM;
if (!f->path) {
r = -ENOMEM;
goto fail;
if (f->fd < 0) {
r = -errno;
goto fail;
r = -errno;
goto fail;
newly_created = true;
goto fail;
r = -errno;
goto fail;
r = -EIO;
goto fail;
r = -errno;
goto fail;
if (!newly_created) {
r = journal_file_verify_header(f);
goto fail;
if (f->writable) {
r = journal_file_refresh_header(f);
goto fail;
if (newly_created) {
goto fail;
goto fail;
goto fail;
r = journal_file_map_data_hash_table(f);
goto fail;
if (ret)
*ret = f;
fail:
size_t l;
assert(f);
assert(*f);
old_file = *f;
return -EINVAL;
return -EINVAL;
return -ENOMEM;
free(p);
return -errno;
*f = new_file;
struct vacuum_info {
char *filename;
const struct vacuum_info *a, *b;
a = _a;
b = _b;
DIR *d;
if (max_use <= 0)
return -errno;
size_t q;
goto finish;
if (!de)
r = -ENOMEM;
goto finish;
free(p);
free(p);
struct vacuum_info *j;
free(p);
r = -ENOMEM;
goto finish;
list = j;
n_list ++;
for(i = 0; i < n_list; i++) {
r = -errno;
goto finish;
for (i = 0; i < n_list; i++)
closedir(d);
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;
return -EINVAL;
return -EINVAL;
n = journal_file_entry_n_items(o);
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))
return -EBADMSG;
l = rsize;
return -EPROTONOSUPPORT;
assert(m);
if (fs_size > 0) {
if (fs_size > 0) {