src/logger/reader_logger.c \
src/logger/reader_pipe.c \
src/logger/reader_memory.c \
+ src/logger/reader_zero_copy.c \
src/logger/subreader_dlogutil.c \
src/logger/subreader_file.c \
src/logger/subreader_memory.c \
src/logger/subreader_metrics.c \
src/logger/socket.c \
src/logger/writer.c \
+ src/libdlogutil/fdi_zero_copy.c \
src/shared/backend_androidlogger.c \
src/shared/buffer_traits.c \
src/shared/ptrs_list.c \
// If no path, assume first time
first_time = true;
+ if (g_backend.use_zero_copy) {
+ assert(!g_backend.zero_copy_reader);
+ int r = reader_zero_copy_init(&g_backend.zero_copy_reader, l, !first_time);
+ if (r < 0)
+ return r;
+
+ assert(g_backend.zero_copy_reader);
+
+ if (l->qos) {
+ r = reader_add_subreader_metrics(&g_backend.zero_copy_reader->common, l->qos);
+ if (r < 0) {
+ reader_free(&g_backend.zero_copy_reader->common);
+ g_backend.zero_copy_reader = NULL;
+ return r;
+ }
+ }
+ }
+
if (g_backend.use_logger_by_default)
for (log_id_t id = 0; id < LOG_ID_MAX; ++id) {
if (!is_core_buffer(id))
if (is_core_buffer(i))
data->is_buffer_enabled[i] = true;
g_backend.use_logger_by_default = false;
+ g_backend.use_zero_copy = false;
} else if (!strcmp(backend, "logger")) {
g_backend.use_logger_by_default = true;
+ g_backend.use_zero_copy = false;
for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
const char *const logger_device = log_config_get(&conf, log_name_by_id(buf_id));
if (!logger_device)
g_backend.lazy_polling_sleep = 1;
} else if (!strcmp(backend, "zero-copy")) {
- /* At some point the daemon should learn how to read external
- * logs for the purpose of writing persistent /var/log/files.
- *
- * For now, let it just handle KMSG. */
g_backend.use_logger_by_default = false;
+ g_backend.use_zero_copy = true;
} else {
ret = -ENOENT;
goto end;
/* The reader is not yet complete, further subreaders can get added via other config lines.
* Finalisation happens later, in `finalize_init`. */
+ } else if (g_backend.use_zero_copy && core) {
+ if (!g_backend.zero_copy_reader) {
+ r = -ENOENT;
+ goto fail;
+ }
+
+ r = params.compression
+ ? create_memory_subreader_from_dlogutil_line(&g_backend.zero_copy_reader->common, ¶ms, server)
+ : create_file_subreader_from_dlogutil_line(&g_backend.zero_copy_reader->common, ¶ms, DLOGUTIL_SORT_SENT_MONO)
+ ;
+ if (r)
+ goto fail;
+
+ // ditto
} else {
struct reader_pipe *reader = NULL;
r = create_reader_pipe_from_dlogutil_line(¶ms, server, &reader);
return r;
}
+ if (g_backend.zero_copy_reader) {
+ r = reader_cleanup_subless_and_run(&g_backend.zero_copy_reader, server);
+ if (r < 0)
+ return r;
+ }
+
return 0;
}
#include "fd_entity.h"
#include "reader_common.h"
#include "reader_logger.h"
+#include "reader_zero_copy.h"
#include "reader_memory.h"
#include "reader_pipe.h"
#include "socket.h"
* and to unclog pipes. */
int lazy_polling_total;
int lazy_polling_sleep;
+
+ /* I'm not exactly happy with this struct having grown into just
+ * a collection of globals but I am out of mana to prevent it. */
+ bool use_zero_copy;
+ struct reader_zero_copy *zero_copy_reader;
+
} g_backend;
--- /dev/null
+// SPDX-License-Identifier: Apache 2.0
+// (c) 2024 Samsung Electronics
+
+// POSIX
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+// DLog
+#include <logconfig.h>
+#include <queued_entry_timestamp.h>
+#include <zero_copy_backend.h>
+
+// dlog_logger
+#include "logger_internal.h"
+#include "reader_common.h"
+#include "reader_zero_copy.h"
+
+static void *reader_zero_copy_thread(void *userdata);
+
+static void free_reader_zero_copy(struct reader_common *_reader)
+{
+ struct reader_zero_copy *const reader = (struct reader_zero_copy *) _reader;
+ assert(reader);
+}
+
+static const struct reader_ops zero_copy_ops = (struct reader_ops) {
+ .destroy = free_reader_zero_copy,
+ .thread_func = reader_zero_copy_thread,
+};
+
+static struct reader_zero_copy *reader_zero_copy_alloc(struct logger *server)
+{
+ __attribute__((cleanup(free_ptr))) uint16_t *last_offsets = calloc(ZLOGGER_BLOCK_COUNT, sizeof *last_offsets);
+ if (!last_offsets)
+ return NULL;
+
+ __attribute__((cleanup(free_ptr))) char *bitmap = malloc(ZLOGGER_BITMAP_SIZE);
+ if (!bitmap)
+ return NULL;
+
+ __attribute__((cleanup(close_fd))) int fd = open(ZERO_COPY_DUMP_DEVICE_NAME, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
+ return NULL;
+
+ struct reader_zero_copy *const reader = calloc(1, sizeof *reader);
+ if (!reader)
+ return NULL;
+
+ reader->bitmap = bitmap;
+ reader->last_offsets = last_offsets;
+ reader->fd = fd;
+
+ fd = -1;
+ last_offsets = NULL;
+ bitmap = NULL;
+
+ return reader;
+}
+
+int reader_zero_copy_init(struct reader_zero_copy **reader, struct logger *server, bool skip)
+{
+ __attribute__((cleanup(reader_free_ptr))) struct reader_zero_copy *ret = reader_zero_copy_alloc(server);
+ if (!ret)
+ return -ENOMEM;
+
+ reader_common_init(&ret->common, server, &zero_copy_ops);
+
+ ret->dump_initial = !skip;
+
+ *reader = ret;
+ ret = NULL;
+
+ return 0;
+}
+
+static void dump_logs_as_indicated_by_bitmap(struct reader_zero_copy *reader)
+{
+ int r = zero_copy_read_buffer(reader->fd, &reader->items, reader->bitmap, reader->last_offsets);
+ assert(r != -EAGAIN);
+
+ while (reader->items) {
+ struct zlog_entry_list *const item = reader->items;
+ reader->items = item->next;
+
+ dlogutil_entry_s *const entry = item->entry;
+ (void) reader_apply_log_to_subs(&reader->common, entry);
+ free(item);
+ }
+}
+
+static void *reader_zero_copy_thread(void *userdata)
+{
+ struct reader_zero_copy *reader = (struct reader_zero_copy *) userdata;
+
+ if (reader->dump_initial) {
+ memset(reader->bitmap, ~(char)0, ZLOGGER_BITMAP_SIZE);
+ dump_logs_as_indicated_by_bitmap(reader);
+ }
+
+ const int period = reader->common.server->epolltime * USEC_PER_MSEC;
+ while (!reader->common.server->sigmar->exit_signal_received) {
+ (void) ioctl(reader->fd, ZLOGGER_IOCTL_COMMAND_GET_BITMAP, reader->bitmap);
+ dump_logs_as_indicated_by_bitmap(reader);
+ usleep (period);
+ }
+
+ reader_service(&reader->common);
+ reader_thread_finished(&reader->common);
+ return NULL;
+}
+
--- /dev/null
+#pragma once
+
+#include <log_file.h>
+#include <queued_entry_timestamp.h>
+#include "reader_common.h"
+#include "../libdlogutil/fdi_zero_copy.h"
+
+struct reader_zero_copy {
+ struct reader_common common;
+ struct zlog_entry_list *items;
+ uint16_t *last_offsets;
+ char *bitmap;
+ int fd;
+ bool dump_initial;
+};
+
+int reader_zero_copy_init(struct reader_zero_copy **reader, struct logger *server, bool skip);
+