dlog_logger: handle zero-copy backend 14/305114/7
authorMichal Bloch <m.bloch@samsung.com>
Tue, 23 Jan 2024 11:41:01 +0000 (12:41 +0100)
committerMichal Bloch <m.bloch@samsung.com>
Mon, 19 Feb 2024 12:59:43 +0000 (13:59 +0100)
Change-Id: I13168087ef460e74c203ab0f0311b91f6f2421f2

Makefile.am
src/logger/logger.c
src/logger/logger_internal.h
src/logger/reader_zero_copy.c [new file with mode: 0644]
src/logger/reader_zero_copy.h [new file with mode: 0644]

index 0628605..85735ab 100644 (file)
@@ -163,12 +163,14 @@ dlog_logger_SOURCES = \
        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 \
index 286ccb5..3377c0f 100644 (file)
@@ -548,6 +548,24 @@ int logger_create(struct logger_config_data *data, struct logger *l, struct sign
                // 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))
@@ -877,8 +895,10 @@ int prepare_config_data(struct logger_config_data *data)
                        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)
@@ -899,11 +919,8 @@ int prepare_config_data(struct logger_config_data *data)
                        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;
@@ -985,6 +1002,20 @@ void parse_logfile_config(void *value, void *userdata)
 
                /* 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, &params, server)
+                       : create_file_subreader_from_dlogutil_line(&g_backend.zero_copy_reader->common, &params, DLOGUTIL_SORT_SENT_MONO)
+               ;
+               if (r)
+                       goto fail;
+
+               // ditto
        } else {
                struct reader_pipe *reader = NULL;
                r = create_reader_pipe_from_dlogutil_line(&params, server, &reader);
@@ -1158,6 +1189,12 @@ static int finalize_init(struct logger_config_data *data, struct logger *server)
                        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;
 }
 
index f0c4387..98e3596 100644 (file)
@@ -31,6 +31,7 @@
 #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"
@@ -103,6 +104,12 @@ extern struct backend_data {
         * 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;
 
 
diff --git a/src/logger/reader_zero_copy.c b/src/logger/reader_zero_copy.c
new file mode 100644 (file)
index 0000000..52924a5
--- /dev/null
@@ -0,0 +1,111 @@
+// 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;
+}
+
diff --git a/src/logger/reader_zero_copy.h b/src/logger/reader_zero_copy.h
new file mode 100644 (file)
index 0000000..16a9514
--- /dev/null
@@ -0,0 +1,18 @@
+#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);
+