journal-file.c revision 2a59ea54f136f8fcf6a4e1bdfc51448c81281a3e
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/***
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer This file is part of systemd.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Copyright 2011 Lennart Poettering
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer systemd is free software; you can redistribute it and/or modify it
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer under the terms of the GNU General Public License as published by
4be4833ece2856e0cacc09f8f8b2c02b320751faMartin Pitt the Free Software Foundation; either version 2 of the License, or
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier (at your option) any later version.
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier systemd is distributed in the hope that it will be useful, but
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier WITHOUT ANY WARRANTY; without even the implied warranty of
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier General Public License for more details.
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier You should have received a copy of the GNU General Public License
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier along with systemd; If not, see <http://www.gnu.org/licenses/>.
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier***/
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/mman.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <errno.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/uio.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <unistd.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/statvfs.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <fcntl.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <stddef.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "journal-def.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "journal-file.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "lookup3.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "compress.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*16ULL)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#define DEFAULT_FIELD_HASH_TABLE_SIZE (2047ULL*16ULL)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#define DEFAULT_WINDOW_SIZE (128ULL*1024ULL*1024ULL)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#define COMPRESSION_SIZE_THRESHOLD (64ULL)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalierstatic const char signature[] = { 'L', 'P', 'K', 'S', 'H', 'H', 'R', 'H' };
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#define ALIGN64(x) (((x) + 7ULL) & ~7ULL)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevaliervoid journal_file_close(JournalFile *f) {
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier int t;
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier assert(f);
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier if (f->header && f->writable)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier f->header->state = STATE_OFFLINE;
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier for (t = 0; t < _WINDOW_MAX; t++)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier if (f->windows[t].ptr)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier munmap(f->windows[t].ptr, f->windows[t].size);
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier if (f->fd >= 0)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier close_nointr_nofail(f->fd);
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier free(f->path);
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#ifdef HAVE_XZ
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier free(f->compress_buffer);
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#endif
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier free(f);
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek}
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int journal_file_init_header(JournalFile *f, JournalFile *template) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier Header h;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier ssize_t k;
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek int r;
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(f);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier zero(h);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier memcpy(h.signature, signature, 8);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier h.arena_offset = htole64(ALIGN64(sizeof(h)));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = sd_id128_randomize(&h.file_id);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (r < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (template) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier h.seqnum_id = template->header->seqnum_id;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier h.seqnum = template->header->seqnum;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier } else
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier h.seqnum_id = h.file_id;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier k = pwrite(f->fd, &h, sizeof(h), 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (k < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (k != sizeof(h))
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -EIO;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int journal_file_refresh_header(JournalFile *f) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier int r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier sd_id128_t boot_id;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(f);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = sd_id128_get_machine(&f->header->machine_id);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (r < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = sd_id128_get_boot(&boot_id);
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek if (r < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (sd_id128_equal(boot_id, f->header->boot_id))
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier f->tail_entry_monotonic_valid = true;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier f->header->boot_id = boot_id;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier f->header->state = STATE_ONLINE;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int journal_file_verify_header(JournalFile *f) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(f);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (memcmp(f->header, signature, 8))
739d81ddd005fae2bb82edce5b8a6173c7c48b34Zbigniew Jędrzejewski-Szmek return -EBADMSG;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
b8667ee4162cd2510363602b417cecede9fd2ccaZbigniew Jędrzejewski-Szmek#ifdef HAVE_XZ
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if ((le64toh(f->header->incompatible_flags) & ~HEADER_INCOMPATIBLE_COMPRESSED) != 0)
739d81ddd005fae2bb82edce5b8a6173c7c48b34Zbigniew Jędrzejewski-Szmek return -EPROTONOSUPPORT;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier#else
b8667ee4162cd2510363602b417cecede9fd2ccaZbigniew Jędrzejewski-Szmek if (f->header->incompatible_flags != 0)
b8667ee4162cd2510363602b417cecede9fd2ccaZbigniew Jędrzejewski-Szmek return -EPROTONOSUPPORT;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier#endif
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if ((uint64_t) f->last_stat.st_size < (le64toh(f->header->arena_offset) + le64toh(f->header->arena_size)))
739d81ddd005fae2bb82edce5b8a6173c7c48b34Zbigniew Jędrzejewski-Szmek return -ENODATA;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (f->writable) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier uint32_t state;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier sd_id128_t machine_id;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier int r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = sd_id128_get_machine(&machine_id);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (r < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (!sd_id128_equal(machine_id, f->header->machine_id))
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -EHOSTDOWN;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier state = f->header->state;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (state == STATE_ONLINE)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Journal file %s is already online. Assuming unclean closing. Ignoring.", f->path);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier else if (state == STATE_ARCHIVED)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -ESHUTDOWN;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier else if (state != STATE_OFFLINE)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Journal file %s has unknown state %u. Ignoring.", f->path, state);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier uint64_t old_size, new_size;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(f);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* We assume that this file is not sparse, and we know that
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * for sure, since we always call posix_fallocate()
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * ourselves */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier old_size =
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier le64toh(f->header->arena_offset) +
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier le64toh(f->header->arena_size);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier new_size = PAGE_ALIGN(offset + size);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (new_size < le64toh(f->header->arena_offset))
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier new_size = le64toh(f->header->arena_offset);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (new_size <= old_size)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (f->metrics.max_size > 0 &&
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier new_size > f->metrics.max_size)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -E2BIG;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (new_size > f->metrics.min_size &&
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier f->metrics.keep_free > 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier struct statvfs svfs;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (fstatvfs(f->fd, &svfs) >= 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier uint64_t available;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier available = svfs.f_bfree * svfs.f_bsize;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (available >= f->metrics.keep_free)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier available -= f->metrics.keep_free;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier else
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier available = 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (new_size - old_size > available)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -E2BIG;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Note that the glibc fallocate() fallback is very
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier inefficient, hence we try to minimize the allocation area
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier as we can. */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (posix_fallocate(f->fd, old_size, new_size - old_size) < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (fstat(f->fd, &f->last_stat) < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier f->header->arena_size = new_size - htole64(f->header->arena_offset);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int journal_file_map(
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier JournalFile *f,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier uint64_t offset,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier uint64_t size,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier void **_window,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier uint64_t *_woffset,
4be4833ece2856e0cacc09f8f8b2c02b320751faMartin Pitt uint64_t *_wsize,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier void **ret) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier uint64_t woffset, wsize;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier void *window;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(f);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(size > 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(ret);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier woffset = offset & ~((uint64_t) page_size() - 1ULL);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier wsize = size + (offset - woffset);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier wsize = PAGE_ALIGN(wsize);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Avoid SIGBUS on invalid accesses */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (woffset + wsize > (uint64_t) PAGE_ALIGN(f->last_stat.st_size))
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -EADDRNOTAVAIL;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier window = mmap(NULL, wsize, f->prot, MAP_SHARED, f->fd, woffset);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (window == MAP_FAILED)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (_window)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier *_window = window;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (_woffset)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier *_woffset = woffset;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (_wsize)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier *_wsize = wsize;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier *ret = (uint8_t*) window + (offset - woffset);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int journal_file_move_to(JournalFile *f, int wt, uint64_t offset, uint64_t size, void **ret) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier void *p;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier uint64_t delta;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier int r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier Window *w;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(f);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(ret);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(wt >= 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(wt < _WINDOW_MAX);
25b47f96d9601ff566257b2a31bfb5f4bd25d661Marko Myllynen
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier w = f->windows + wt;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (_likely_(w->ptr &&
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier w->offset <= offset &&
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier w->offset + w->size >= offset + size)) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier *ret = (uint8_t*) w->ptr + (offset - w->offset);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (w->ptr) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (munmap(w->ptr, w->size) < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier w->ptr = NULL;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier w->size = w->offset = 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (size < DEFAULT_WINDOW_SIZE) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* If the default window size is larger then what was
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * asked for extend the mapping a bit in the hope to
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * minimize needed remappings later on. We add half
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * the window space before and half behind the
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * requested mapping */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier delta = PAGE_ALIGN((DEFAULT_WINDOW_SIZE - size) / 2);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (offset < delta)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier delta = offset;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier offset -= delta;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier size += (DEFAULT_WINDOW_SIZE - delta);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer } else
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier delta = 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (offset > (uint64_t) f->last_stat.st_size)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -EADDRNOTAVAIL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (offset + size > (uint64_t) f->last_stat.st_size)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size = PAGE_ALIGN((uint64_t) f->last_stat.st_size - offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (size <= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EADDRNOTAVAIL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_map(f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer offset, size,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer &w->ptr, &w->offset, &w->size,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer &p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ret = (uint8_t*) p + delta;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic bool verify_hash(Object *o) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t h1, h2;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (o->object.type == OBJECT_DATA && !(o->object.flags & OBJECT_COMPRESSED)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer h1 = le64toh(o->data.hash);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } else if (o->object.type == OBJECT_FIELD) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer h1 = le64toh(o->field.hash);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer h2 = hash64(o->field.payload, le64toh(o->object.size) - offsetof(Object, field.payload));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } else
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return true;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return h1 == h2;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Object *o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t s;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(ret);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(type < _OBJECT_TYPE_MAX);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to(f, type >= 0 ? type : WINDOW_UNKNOWN, offset, sizeof(ObjectHeader), &t);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (r < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier o = (Object*) t;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier s = le64toh(o->object.size);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (s < sizeof(ObjectHeader))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EBADMSG;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (type >= 0 && o->object.type != type)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EBADMSG;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (s > sizeof(ObjectHeader)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to(f, o->object.type, offset, s, &t);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o = (Object*) t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!verify_hash(o))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EBADMSG;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ret = o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic uint64_t journal_file_seqnum(JournalFile *f, uint64_t *seqnum) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = le64toh(f->header->seqnum) + 1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (seqnum) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* If an external seqnum counter was passed, we update
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * both the local and the external one, and set it to
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * the maximum of both */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (*seqnum + 1 > r)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = *seqnum + 1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *seqnum = r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->header->seqnum = htole64(r);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (f->header->first_seqnum == 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->header->first_seqnum = htole64(r);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Object *tail, *o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(size >= sizeof(ObjectHeader));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(ret);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = le64toh(f->header->tail_object_offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (p == 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = le64toh(f->header->arena_offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to_object(f, -1, p, &tail);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p += ALIGN64(le64toh(tail->object.size));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_allocate(f, p, size);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to(f, type, p, size, &t);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o = (Object*) t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer zero(o->object);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->object.type = type;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->object.size = htole64(size);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->header->tail_object_offset = htole64(p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->header->n_objects = htole64(le64toh(f->header->n_objects) + 1);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ret = o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *offset = p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int journal_file_setup_data_hash_table(JournalFile *f) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t s, p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Object *o;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer s = DEFAULT_DATA_HASH_TABLE_SIZE;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_append_object(f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer OBJECT_DATA_HASH_TABLE,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer offsetof(Object, hash_table.items) + s,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer &o, &p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer memset(o->hash_table.items, 0, s);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->header->data_hash_table_offset = htole64(p + offsetof(Object, hash_table.items));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->header->data_hash_table_size = htole64(s);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int journal_file_setup_field_hash_table(JournalFile *f) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t s, p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Object *o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer s = DEFAULT_FIELD_HASH_TABLE_SIZE;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_append_object(f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer OBJECT_FIELD_HASH_TABLE,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer offsetof(Object, hash_table.items) + s,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer &o, &p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer memset(o->hash_table.items, 0, s);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->header->field_hash_table_offset = htole64(p + offsetof(Object, hash_table.items));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->header->field_hash_table_size = htole64(s);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int journal_file_map_data_hash_table(JournalFile *f) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t s, p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = le64toh(f->header->data_hash_table_offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer s = le64toh(f->header->data_hash_table_size);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to(f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer WINDOW_DATA_HASH_TABLE,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p, s,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer &t);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->data_hash_table = t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int journal_file_map_field_hash_table(JournalFile *f) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t s, p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = le64toh(f->header->field_hash_table_offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer s = le64toh(f->header->field_hash_table_size);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to(f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer WINDOW_FIELD_HASH_TABLE,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p, s,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer &t);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->field_hash_table = t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int journal_file_link_data(JournalFile *f, Object *o, uint64_t offset, uint64_t hash) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t p, h;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(offset > 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(o->object.type == OBJECT_DATA);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->data.next_hash_offset = o->data.next_field_offset = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->data.entry_offset = o->data.entry_array_offset = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->data.n_entries = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer h = hash % (le64toh(f->header->data_hash_table_size) / sizeof(HashItem));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = le64toh(f->data_hash_table[h].head_hash_offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (p == 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Only entry in the hash table is easy */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->data_hash_table[h].head_hash_offset = htole64(offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } else {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Temporarily move back to the previous data object,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * to patch in pointer */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->data.next_hash_offset = htole64(offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to_object(f, OBJECT_DATA, offset, &o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->data_hash_table[h].tail_hash_offset = htole64(offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint journal_file_find_data_object_with_hash(
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer JournalFile *f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const void *data, uint64_t size, uint64_t hash,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Object **ret, uint64_t *offset) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t p, osize, h;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(data || size == 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer osize = offsetof(Object, data.payload) + size;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (f->header->data_hash_table_size == 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EBADMSG;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer h = hash % (le64toh(f->header->data_hash_table_size) / sizeof(HashItem));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = le64toh(f->data_hash_table[h].head_hash_offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while (p > 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Object *o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (le64toh(o->data.hash) != hash)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto next;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (o->object.flags & OBJECT_COMPRESSED) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#ifdef HAVE_XZ
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t l, rsize;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer l = le64toh(o->object.size);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (l <= offsetof(Object, data.payload))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EBADMSG;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer l -= offsetof(Object, data.payload);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EBADMSG;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (rsize == size &&
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer memcmp(f->compress_buffer, data, size) == 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (ret)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ret = o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (offset)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *offset = p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#else
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EPROTONOSUPPORT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#endif
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } else if (le64toh(o->object.size) == osize &&
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer memcmp(o->data.payload, data, size) == 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (ret)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ret = o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (offset)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *offset = p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer next:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = le64toh(o->data.next_hash_offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint journal_file_find_data_object(
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer JournalFile *f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const void *data, uint64_t size,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Object **ret, uint64_t *offset) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t hash;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(data || size == 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer hash = hash64(data, size);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return journal_file_find_data_object_with_hash(f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer data, size, hash,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer ret, offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int journal_file_append_data(JournalFile *f, const void *data, uint64_t size, Object **ret, uint64_t *offset) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t hash, p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t osize;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Object *o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer bool compressed = false;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(data || size == 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer hash = hash64(data, size);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else if (r > 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (ret)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ret = o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (offset)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *offset = p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer osize = offsetof(Object, data.payload) + size;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_append_object(f, OBJECT_DATA, osize, &o, &p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->data.hash = htole64(hash);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#ifdef HAVE_XZ
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (f->compress &&
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size >= COMPRESSION_SIZE_THRESHOLD) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t rsize;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer compressed = compress_blob(data, size, o->data.payload, &rsize);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (compressed) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->object.size = htole64(offsetof(Object, data.payload) + rsize);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->object.flags |= OBJECT_COMPRESSED;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer f->header->incompatible_flags = htole32(le32toh(f->header->incompatible_flags) | HEADER_INCOMPATIBLE_COMPRESSED);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_debug("Compressed data object %lu -> %lu", (unsigned long) size, (unsigned long) rsize);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#endif
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!compressed)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer memcpy(o->data.payload, data, size);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_link_data(f, o, p, hash);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (ret)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ret = o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (offset)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *offset = p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyeruint64_t journal_file_entry_n_items(Object *o) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(o->object.type == htole64(OBJECT_ENTRY));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return (le64toh(o->object.size) - offsetof(Object, entry.items)) / sizeof(EntryItem);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic uint64_t journal_file_entry_array_n_items(Object *o) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(o->object.type == htole64(OBJECT_ENTRY_ARRAY));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return (le64toh(o->object.size) - offsetof(Object, entry_array.items)) / sizeof(uint64_t);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int link_entry_into_array(JournalFile *f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t *first,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t *idx,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t p) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t n = 0, ap = 0, q, i, a, hidx;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Object *o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(first);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(idx);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(p > 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer a = le64toh(*first);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer i = hidx = le64toh(*idx);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while (a > 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer n = journal_file_entry_array_n_items(o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (i < n) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->entry_array.items[i] = htole64(p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *idx = htole64(hidx + 1);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer i -= n;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer ap = a;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer a = le64toh(o->entry_array.next_entry_array_offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (hidx > n)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer n = (hidx+1) * 2;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer n = n * 2;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (n < 4)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer n = 4;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_append_object(f, OBJECT_ENTRY_ARRAY,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer offsetof(Object, entry_array.items) + n * sizeof(uint64_t),
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer &o, &q);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->entry_array.items[i] = htole64(p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (ap == 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *first = q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, ap, &o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer o->entry_array.next_entry_array_offset = htole64(q);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *idx = htole64(hidx + 1);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int link_entry_into_array_plus_one(JournalFile *f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t *extra,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t *first,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t *idx,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t p) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(extra);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(first);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(idx);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(p > 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (*idx == 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *extra = htole64(p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t i;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer i = le64toh(*idx) - 1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = link_entry_into_array(f, first, &i, p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *idx = htole64(le64toh(*idx) + 1);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int journal_file_link_entry_item(JournalFile *f, Object *o, uint64_t offset, uint64_t i) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t p;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(f);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(o);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(offset > 0);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer p = le64toh(o->entry.items[i].object_offset);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (p == 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return link_entry_into_array_plus_one(f,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer &o->data.entry_offset,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer &o->data.entry_array_offset,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer &o->data.n_entries,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer offset);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerstatic int journal_file_link_entry(JournalFile *f, Object *o, uint64_t offset) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t n, i;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(f);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(o);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(offset > 0);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(o->object.type == OBJECT_ENTRY);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Link up the entry itself */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = link_entry_into_array(f,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer &f->header->entry_array_offset,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer &f->header->n_entries,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer offset);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_error("=> %s seqnr=%lu n_entries=%lu", f->path, (unsigned long) o->entry.seqnum, (unsigned long) f->header->n_entries);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (f->header->head_entry_realtime == 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer f->header->head_entry_realtime = o->entry.realtime;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer f->header->tail_entry_realtime = o->entry.realtime;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer f->header->tail_entry_monotonic = o->entry.monotonic;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer f->tail_entry_monotonic_valid = true;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Link up the items */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer n = journal_file_entry_n_items(o);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer for (i = 0; i < n; i++) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = journal_file_link_entry_item(f, o, offset, i);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerstatic int journal_file_append_entry_internal(
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer JournalFile *f,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const dual_timestamp *ts,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t xor_hash,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const EntryItem items[], unsigned n_items,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t *seqnum,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Object **ret, uint64_t *offset) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t np;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t osize;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Object *o;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(f);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(items || n_items == 0);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(ts);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer osize = offsetof(Object, entry.items) + (n_items * sizeof(EntryItem));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = journal_file_append_object(f, OBJECT_ENTRY, osize, &o, &np);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
c53158818d8cdaf46b3f1b5299b9bda118a1043fThomas Hindoe Paaboel Andersen return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer o->entry.seqnum = htole64(journal_file_seqnum(f, seqnum));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer memcpy(o->entry.items, items, n_items * sizeof(EntryItem));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer o->entry.realtime = htole64(ts->realtime);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer o->entry.monotonic = htole64(ts->monotonic);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer o->entry.xor_hash = htole64(xor_hash);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer o->entry.boot_id = f->header->boot_id;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = journal_file_link_entry(f, o, np);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (ret)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer *ret = o;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (offset)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer *offset = np;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerstatic void journal_file_post_change(JournalFile *f) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(f);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* inotify() does not receive IN_MODIFY events from file
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * accesses done via mmap(). After each access we hence
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * trigger IN_MODIFY by truncating the journal file to its
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * current size which triggers IN_MODIFY. */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer __sync_synchronize();
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (ftruncate(f->fd, f->last_stat.st_size) < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_error("Failed to to truncate file to its own size: %m");
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint 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) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unsigned i;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer EntryItem *items;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t xor_hash = 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer struct dual_timestamp _ts;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(f);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(iovec || n_iovec == 0);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!f->writable)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EPERM;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!ts) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dual_timestamp_get(&_ts);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer ts = &_ts;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (f->tail_entry_monotonic_valid &&
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer ts->monotonic < le64toh(f->header->tail_entry_monotonic))
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (ts->realtime < le64toh(f->header->tail_entry_realtime))
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer items = new(EntryItem, n_iovec);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!items)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -ENOMEM;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer for (i = 0; i < n_iovec; i++) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t p;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Object *o;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = journal_file_append_data(f, iovec[i].iov_base, iovec[i].iov_len, &o, &p);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto finish;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer xor_hash ^= le64toh(o->data.hash);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer items[i].object_offset = htole64(p);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer items[i].hash = o->data.hash;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = journal_file_append_entry_internal(f, ts, xor_hash, items, n_iovec, seqnum, ret, offset);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer journal_file_post_change(f);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerfinish:
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer free(items);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerstatic int generic_array_get(JournalFile *f,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t first,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t i,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Object **ret, uint64_t *offset) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Object *o;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t p, a;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(f);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer a = first;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer while (a > 0) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t n;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer n = journal_file_entry_array_n_items(o);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (i < n) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer p = le64toh(o->entry_array.items[i]);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer break;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer i -= n;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer a = le64toh(o->entry_array.next_entry_array_offset);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (a <= 0 || p <= 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (ret)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer *ret = o;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (offset)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer *offset = p;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 1;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerstatic int generic_array_get_plus_one(JournalFile *f,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t extra,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t first,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t i,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Object **ret, uint64_t *offset) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Object *o;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(f);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (i == 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to_object(f, OBJECT_ENTRY, extra, &o);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (ret)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ret = o;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (offset)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *offset = extra;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return generic_array_get(f, first, i-1, ret, offset);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerenum {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer TEST_FOUND,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer TEST_LEFT,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer TEST_RIGHT
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer};
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int generic_array_bisect(JournalFile *f,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t first,
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer uint64_t n,
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer uint64_t needle,
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer direction_t direction,
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer Object **ret,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t *offset,
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer uint64_t *idx) {
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer uint64_t a, p, t = 0, i = 0, last_p = 0;
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer bool subtract_one = false;
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer Object *o, *array = NULL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(test_object);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer a = first;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while (a > 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint64_t left, right, k, lp;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &array);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer k = journal_file_entry_array_n_items(array);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer right = MIN(k, n);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (right <= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer i = right - 1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer lp = p = le64toh(array->entry_array.items[i]);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (p <= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EBADMSG;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = test_object(f, p, needle);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r == TEST_FOUND)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r == TEST_RIGHT) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer left = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer right -= 1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (;;) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (left == right) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (direction == DIRECTION_UP)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer subtract_one = true;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer i = left;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto found;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(left < right);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer i = (left + right) / 2;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = le64toh(array->entry_array.items[i]);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (p <= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EBADMSG;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = test_object(f, p, needle);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r == TEST_FOUND)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r == TEST_RIGHT)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer right = i;
else
left = i + 1;
}
}
if (k > n)
return 0;
last_p = lp;
n -= k;
t += k;
a = le64toh(array->entry_array.next_entry_array_offset);
}
return 0;
found:
if (subtract_one && t == 0 && i == 0)
return 0;
if (subtract_one && i == 0)
p = last_p;
else if (subtract_one)
p = le64toh(array->entry_array.items[i-1]);
else
p = le64toh(array->entry_array.items[i]);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
if (ret)
*ret = o;
if (offset)
*offset = p;
if (idx)
*idx = t + i - (subtract_one ? 1 : 0);
return 1;
}
static int generic_array_bisect_plus_one(JournalFile *f,
uint64_t extra,
uint64_t first,
uint64_t n,
uint64_t needle,
int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
direction_t direction,
Object **ret,
uint64_t *offset,
uint64_t *idx) {
int r;
assert(f);
assert(test_object);
if (n <= 0)
return 0;
/* This bisects the array in object 'first', but first checks
* an extra */
r = test_object(f, extra, needle);
if (r < 0)
return r;
else if (r == TEST_FOUND) {
Object *o;
r = journal_file_move_to_object(f, OBJECT_ENTRY, extra, &o);
if (r < 0)
return r;
if (ret)
*ret = o;
if (offset)
*offset = extra;
if (idx)
*idx = 0;
return 1;
} else if (r == TEST_RIGHT)
return 0;
r = generic_array_bisect(f, first, n-1, needle, test_object, direction, ret, offset, idx);
if (r > 0)
(*idx) ++;
return r;
}
static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
int r;
assert(f);
assert(p > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
if (le64toh(o->entry.seqnum) == needle)
return TEST_FOUND;
else if (le64toh(o->entry.seqnum) < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
}
int journal_file_move_to_entry_by_seqnum(
JournalFile *f,
uint64_t seqnum,
direction_t direction,
Object **ret,
uint64_t *offset) {
return generic_array_bisect(f,
le64toh(f->header->entry_array_offset),
le64toh(f->header->n_entries),
seqnum,
test_object_seqnum,
direction,
ret, offset, NULL);
}
static int test_object_realtime(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
int r;
assert(f);
assert(p > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
if (le64toh(o->entry.realtime) == needle)
return TEST_FOUND;
else if (le64toh(o->entry.realtime) < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
}
int journal_file_move_to_entry_by_realtime(
JournalFile *f,
uint64_t realtime,
direction_t direction,
Object **ret,
uint64_t *offset) {
return generic_array_bisect(f,
le64toh(f->header->entry_array_offset),
le64toh(f->header->n_entries),
realtime,
test_object_realtime,
direction,
ret, offset, NULL);
}
static int test_object_monotonic(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
int r;
assert(f);
assert(p > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
if (le64toh(o->entry.monotonic) == needle)
return TEST_FOUND;
else if (le64toh(o->entry.monotonic) < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
}
int journal_file_move_to_entry_by_monotonic(
JournalFile *f,
sd_id128_t boot_id,
uint64_t monotonic,
direction_t direction,
Object **ret,
uint64_t *offset) {
char t[8+32+1] = "_BOOT_ID=";
Object *o;
int r;
sd_id128_to_string(boot_id, t + 8);
r = journal_file_find_data_object(f, t, strlen(t), &o, NULL);
if (r < 0)
return r;
else if (r == 0)
return -ENOENT;
return generic_array_bisect_plus_one(f,
le64toh(o->data.entry_offset),
le64toh(o->data.entry_array_offset),
le64toh(o->data.n_entries),
monotonic,
test_object_monotonic,
direction,
ret, offset, NULL);
}
static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle) {
assert(f);
assert(p > 0);
if (p == needle)
return TEST_FOUND;
else if (p < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
}
int journal_file_next_entry(
JournalFile *f,
Object *o, uint64_t p,
direction_t direction,
Object **ret, uint64_t *offset) {
uint64_t i, n;
int r;
assert(f);
assert(p > 0 || !o);
n = le64toh(f->header->n_entries);
if (n <= 0)
return 0;
if (!o)
i = direction == DIRECTION_DOWN ? 0 : n - 1;
else {
if (o->object.type != OBJECT_ENTRY)
return -EINVAL;
r = generic_array_bisect(f,
le64toh(f->header->entry_array_offset),
le64toh(f->header->n_entries),
p,
test_object_offset,
DIRECTION_DOWN,
NULL, NULL,
&i);
if (r <= 0)
return r;
if (direction == DIRECTION_DOWN) {
if (i >= n - 1)
return 0;
i++;
} else {
if (i <= 0)
return 0;
i--;
}
}
/* And jump to it */
return generic_array_get(f,
le64toh(f->header->entry_array_offset),
i,
ret, offset);
}
int journal_file_skip_entry(
JournalFile *f,
Object *o, uint64_t p,
int64_t skip,
Object **ret, uint64_t *offset) {
uint64_t i, n;
int r;
assert(f);
assert(o);
assert(p > 0);
if (o->object.type != OBJECT_ENTRY)
return -EINVAL;
r = generic_array_bisect(f,
le64toh(f->header->entry_array_offset),
le64toh(f->header->n_entries),
p,
test_object_offset,
DIRECTION_DOWN,
NULL, NULL,
&i);
if (r <= 0)
return r;
/* Calculate new index */
if (skip < 0) {
if ((uint64_t) -skip >= i)
i = 0;
else
i = i - (uint64_t) -skip;
} else
i += (uint64_t) skip;
n = le64toh(f->header->n_entries);
if (n <= 0)
return -EBADMSG;
if (i >= n)
i = n-1;
return generic_array_get(f,
le64toh(f->header->entry_array_offset),
i,
ret, offset);
}
int journal_file_next_entry_for_data(
JournalFile *f,
Object *o, uint64_t p,
uint64_t data_offset,
direction_t direction,
Object **ret, uint64_t *offset) {
uint64_t n, i;
int r;
Object *d;
assert(f);
assert(p > 0 || !o);
r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d);
if (r < 0)
return r;
n = le64toh(d->data.n_entries);
if (n <= 0)
return n;
if (!o)
i = direction == DIRECTION_DOWN ? 0 : n - 1;
else {
if (o->object.type != OBJECT_ENTRY)
return -EINVAL;
r = generic_array_bisect_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
le64toh(d->data.n_entries),
p,
test_object_offset,
DIRECTION_DOWN,
NULL, NULL,
&i);
if (r <= 0)
return r;
if (direction == DIRECTION_DOWN) {
if (i >= n - 1)
return 0;
i++;
} else {
if (i <= 0)
return 0;
i--;
}
}
return generic_array_get_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
i,
ret, offset);
}
int journal_file_move_to_entry_by_seqnum_for_data(
JournalFile *f,
uint64_t data_offset,
uint64_t seqnum,
direction_t direction,
Object **ret, uint64_t *offset) {
Object *d;
int r;
r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d);
if (r <= 0)
return r;
return generic_array_bisect_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
le64toh(d->data.n_entries),
seqnum,
test_object_seqnum,
direction,
ret, offset, NULL);
}
int journal_file_move_to_entry_by_realtime_for_data(
JournalFile *f,
uint64_t data_offset,
uint64_t realtime,
direction_t direction,
Object **ret, uint64_t *offset) {
Object *d;
int r;
r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d);
if (r <= 0)
return r;
return generic_array_bisect_plus_one(f,
le64toh(d->data.entry_offset),
le64toh(d->data.entry_array_offset),
le64toh(d->data.n_entries),
realtime,
test_object_realtime,
direction,
ret, offset, NULL);
}
void journal_file_dump(JournalFile *f) {
char a[33], b[33], c[33];
Object *o;
int r;
uint64_t p;
assert(f);
printf("File Path: %s\n"
"File ID: %s\n"
"Machine ID: %s\n"
"Boot ID: %s\n"
"Arena size: %llu\n"
"Objects: %lu\n"
"Entries: %lu\n",
f->path,
sd_id128_to_string(f->header->file_id, a),
sd_id128_to_string(f->header->machine_id, b),
sd_id128_to_string(f->header->boot_id, c),
(unsigned long long) le64toh(f->header->arena_size),
(unsigned long) le64toh(f->header->n_objects),
(unsigned long) le64toh(f->header->n_entries));
p = le64toh(f->header->arena_offset);
while (p != 0) {
r = journal_file_move_to_object(f, -1, p, &o);
if (r < 0)
goto fail;
switch (o->object.type) {
case OBJECT_UNUSED:
printf("Type: OBJECT_UNUSED\n");
break;
case OBJECT_DATA:
printf("Type: OBJECT_DATA\n");
break;
case OBJECT_ENTRY:
printf("Type: OBJECT_ENTRY %llu %llu %llu\n",
(unsigned long long) le64toh(o->entry.seqnum),
(unsigned long long) le64toh(o->entry.monotonic),
(unsigned long long) le64toh(o->entry.realtime));
break;
case OBJECT_FIELD_HASH_TABLE:
printf("Type: OBJECT_FIELD_HASH_TABLE\n");
break;
case OBJECT_DATA_HASH_TABLE:
printf("Type: OBJECT_DATA_HASH_TABLE\n");
break;
case OBJECT_ENTRY_ARRAY:
printf("Type: OBJECT_ENTRY_ARRAY\n");
break;
}
if (o->object.flags & OBJECT_COMPRESSED)
printf("Flags: COMPRESSED\n");
if (p == le64toh(f->header->tail_object_offset))
p = 0;
else
p = p + ALIGN64(le64toh(o->object.size));
}
return;
fail:
log_error("File corrupt");
}
int journal_file_open(
const char *fname,
int flags,
mode_t mode,
JournalFile *template,
JournalFile **ret) {
JournalFile *f;
int r;
bool newly_created = false;
assert(fname);
if ((flags & O_ACCMODE) != O_RDONLY &&
(flags & O_ACCMODE) != O_RDWR)
return -EINVAL;
f = new0(JournalFile, 1);
if (!f)
return -ENOMEM;
f->fd = -1;
f->flags = flags;
f->mode = mode;
f->writable = (flags & O_ACCMODE) != O_RDONLY;
f->prot = prot_from_flags(flags);
f->metrics.max_size = DEFAULT_MAX_SIZE;
f->metrics.min_size = DEFAULT_MIN_SIZE;
f->metrics.keep_free = DEFAULT_KEEP_FREE;
f->path = strdup(fname);
if (!f->path) {
r = -ENOMEM;
goto fail;
}
f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode);
if (f->fd < 0) {
r = -errno;
goto fail;
}
if (fstat(f->fd, &f->last_stat) < 0) {
r = -errno;
goto fail;
}
if (f->last_stat.st_size == 0 && f->writable) {
newly_created = true;
r = journal_file_init_header(f, template);
if (r < 0)
goto fail;
if (fstat(f->fd, &f->last_stat) < 0) {
r = -errno;
goto fail;
}
}
if (f->last_stat.st_size < (off_t) sizeof(Header)) {
r = -EIO;
goto fail;
}
f->header = mmap(NULL, PAGE_ALIGN(sizeof(Header)), prot_from_flags(flags), MAP_SHARED, f->fd, 0);
if (f->header == MAP_FAILED) {
f->header = NULL;
r = -errno;
goto fail;
}
if (!newly_created) {
r = journal_file_verify_header(f);
if (r < 0)
goto fail;
}
if (f->writable) {
r = journal_file_refresh_header(f);
if (r < 0)
goto fail;
}
if (newly_created) {
r = journal_file_setup_field_hash_table(f);
if (r < 0)
goto fail;
r = journal_file_setup_data_hash_table(f);
if (r < 0)
goto fail;
}
r = journal_file_map_field_hash_table(f);
if (r < 0)
goto fail;
r = journal_file_map_data_hash_table(f);
if (r < 0)
goto fail;
if (ret)
*ret = f;
return 0;
fail:
journal_file_close(f);
return r;
}
int journal_file_rotate(JournalFile **f) {
char *p;
size_t l;
JournalFile *old_file, *new_file = NULL;
int r;
assert(f);
assert(*f);
old_file = *f;
if (!old_file->writable)
return -EINVAL;
if (!endswith(old_file->path, ".journal"))
return -EINVAL;
l = strlen(old_file->path);
p = new(char, l + 1 + 16 + 1 + 32 + 1 + 16 + 1);
if (!p)
return -ENOMEM;
memcpy(p, old_file->path, l - 8);
p[l-8] = '@';
sd_id128_to_string(old_file->header->seqnum_id, p + l - 8 + 1);
snprintf(p + l - 8 + 1 + 32, 1 + 16 + 1 + 16 + 8 + 1,
"-%016llx-%016llx.journal",
(unsigned long long) le64toh((*f)->header->seqnum),
(unsigned long long) le64toh((*f)->header->tail_entry_realtime));
r = rename(old_file->path, p);
free(p);
if (r < 0)
return -errno;
old_file->header->state = le32toh(STATE_ARCHIVED);
r = journal_file_open(old_file->path, old_file->flags, old_file->mode, old_file, &new_file);
journal_file_close(old_file);
*f = new_file;
return r;
}
struct vacuum_info {
off_t usage;
char *filename;
uint64_t realtime;
sd_id128_t seqnum_id;
uint64_t seqnum;
};
static int vacuum_compare(const void *_a, const void *_b) {
const struct vacuum_info *a, *b;
a = _a;
b = _b;
if (sd_id128_equal(a->seqnum_id, b->seqnum_id)) {
if (a->seqnum < b->seqnum)
return -1;
else if (a->seqnum > b->seqnum)
return 1;
else
return 0;
}
if (a->realtime < b->realtime)
return -1;
else if (a->realtime > b->realtime)
return 1;
else
return memcmp(&a->seqnum_id, &b->seqnum_id, 16);
}
int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t min_free) {
DIR *d;
int r = 0;
struct vacuum_info *list = NULL;
unsigned n_list = 0, n_allocated = 0, i;
uint64_t sum = 0;
assert(directory);
if (max_use <= 0)
max_use = DEFAULT_MAX_USE;
d = opendir(directory);
if (!d)
return -errno;
for (;;) {
int k;
struct dirent buf, *de;
size_t q;
struct stat st;
char *p;
unsigned long long seqnum, realtime;
sd_id128_t seqnum_id;
k = readdir_r(d, &buf, &de);
if (k != 0) {
r = -k;
goto finish;
}
if (!de)
break;
if (!dirent_is_file_with_suffix(de, ".journal"))
continue;
q = strlen(de->d_name);
if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8)
continue;
if (de->d_name[q-8-16-1] != '-' ||
de->d_name[q-8-16-1-16-1] != '-' ||
de->d_name[q-8-16-1-16-1-32-1] != '@')
continue;
if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
continue;
if (!S_ISREG(st.st_mode))
continue;
p = strdup(de->d_name);
if (!p) {
r = -ENOMEM;
goto finish;
}
de->d_name[q-8-16-1-16-1] = 0;
if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
free(p);
continue;
}
if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
free(p);
continue;
}
if (n_list >= n_allocated) {
struct vacuum_info *j;
n_allocated = MAX(n_allocated * 2U, 8U);
j = realloc(list, n_allocated * sizeof(struct vacuum_info));
if (!j) {
free(p);
r = -ENOMEM;
goto finish;
}
list = j;
}
list[n_list].filename = p;
list[n_list].usage = (uint64_t) st.st_blksize * (uint64_t) st.st_blocks;
list[n_list].seqnum = seqnum;
list[n_list].realtime = realtime;
list[n_list].seqnum_id = seqnum_id;
sum += list[n_list].usage;
n_list ++;
}
qsort(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
for(i = 0; i < n_list; i++) {
struct statvfs ss;
if (fstatvfs(dirfd(d), &ss) < 0) {
r = -errno;
goto finish;
}
if (sum <= max_use &&
(uint64_t) ss.f_bavail * (uint64_t) ss.f_bsize >= min_free)
break;
if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
log_debug("Deleted archived journal %s/%s.", directory, list[i].filename);
sum -= list[i].usage;
} else if (errno != ENOENT)
log_warning("Failed to delete %s/%s: %m", directory, list[i].filename);
}
finish:
for (i = 0; i < n_list; i++)
free(list[i].filename);
free(list);
if (d)
closedir(d);
return r;
}