Skip to content

Commit

Permalink
logging: allow storing log history in flash
Browse files Browse the repository at this point in the history
When CONFIG_LOG_BACKEND_RPC_HISTORY_STORAGE_FCB option
is set, define the "log_history" flash partition and enable
storing the log history using Flash Circular Buffer.

Signed-off-by: Damian Krolik <[email protected]>
  • Loading branch information
Damian-Nordic committed Feb 5, 2025
1 parent fe91d1d commit a04fa83
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 3 deletions.
1 change: 1 addition & 0 deletions subsys/logging/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ if (CONFIG_LOG_FORWARDER_RPC OR CONFIG_LOG_BACKEND_RPC)
zephyr_library_sources_ifdef(CONFIG_LOG_FORWARDER_RPC log_forwarder_rpc.c)
zephyr_library_sources_ifdef(CONFIG_LOG_BACKEND_RPC log_backend_rpc.c)
zephyr_library_sources_ifdef(CONFIG_LOG_BACKEND_RPC_HISTORY_STORAGE_RAM log_backend_rpc_history_ram.c)
zephyr_library_sources_ifdef(CONFIG_LOG_BACKEND_RPC_HISTORY_STORAGE_FCB log_backend_rpc_history_fcb.c)
endif()
19 changes: 16 additions & 3 deletions subsys/logging/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ choice LOG_BACKEND_RPC_HISTORY_STORAGE_CHOICE
config LOG_BACKEND_RPC_HISTORY_STORAGE_RAM
bool "RAM buffer"

config LOG_BACKEND_RPC_HISTORY_STORAGE_FCB
bool "Flash Circular Buffer"
help
Stores the log history in Flash Circular Buffer located in the "log_history"
flash partition. Note that enabling this option may significantly increase
the flash wear, so this option is not meant the production environments,
and extra caution should be taken when using this functionality.

endchoice # LOG_BACKEND_RPC_HISTORY_STORAGE_CHOICE

config LOG_BACKEND_RPC_HISTORY_UPLOAD_THREAD_STACK_SIZE
Expand All @@ -64,12 +72,17 @@ config LOG_BACKEND_RPC_HISTORY_UPLOAD_CHUNK_SIZE
default 1024

config LOG_BACKEND_RPC_HISTORY_SIZE
int "Log history size"
depends on LOG_BACKEND_RPC_HISTORY_STORAGE_RAM
default 16384
hex "Log history size"
default 0x4000 if LOG_BACKEND_RPC_HISTORY_STORAGE_RAM
default 0x8000 if LOG_BACKEND_RPC_HISTORY_STORAGE_FCB
help
Size of the ring buffer used to store the log history, in bytes.

config LOG_BACKEND_RPC_HISTORY_STORAGE_FCB_NUM_SECTORS
int "Log history FCB maximum number of flash sectors"
default 64
depends on LOG_BACKEND_RPC_HISTORY_STORAGE_FCB

endif # LOG_BACKEND_RPC_HISTORY

config LOG_BACKEND_RPC_CRASH_LOG
Expand Down
155 changes: 155 additions & 0 deletions subsys/logging/log_backend_rpc_history_fcb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include "log_backend_rpc_history.h"

#include <zephyr/fs/fcb.h>
#include <zephyr/sys/util.h>

#define LOG_HISTORY_MAGIC 0x7d2ac863
#define LOG_HISTORY_AREA FIXED_PARTITION_ID(log_history)

static struct fcb fcb;
static struct flash_sector fcb_sectors[CONFIG_LOG_BACKEND_RPC_HISTORY_STORAGE_FCB_NUM_SECTORS];
static struct fcb_entry last_popped;
static bool erase_oldest;
static K_MUTEX_DEFINE(fcb_lock);

void log_rpc_history_init(void)
{
int rc;
uint32_t sector_cnt = ARRAY_SIZE(fcb_sectors);

rc = flash_area_get_sectors(LOG_HISTORY_AREA, &sector_cnt, fcb_sectors);

if (rc) {
goto out;
}

fcb.f_magic = LOG_HISTORY_MAGIC;
fcb.f_sectors = fcb_sectors;
fcb.f_sector_cnt = (uint8_t)sector_cnt;
erase_oldest = true;

rc = fcb_init(LOG_HISTORY_AREA, &fcb);

if (rc) {
goto out;
}

rc = fcb_clear(&fcb);

out:
__ASSERT_NO_MSG(rc == 0);
}

void log_rpc_history_push(const union log_msg_generic *msg)
{
int rc;
size_t len;
struct fcb_entry entry;

len = log_msg_generic_get_wlen(&msg->buf) * sizeof(uint32_t);

k_mutex_lock(&fcb_lock, K_FOREVER);
rc = fcb_append(&fcb, len, &entry);

if (rc == -ENOSPC && erase_oldest) {
/*
* The log history FCB is full but overwriting is enabled.
* Erase the oldest FCB page and try again.
* Note that the "last popped" location is cleared so that the next log transfer
* starts from the updated oldest log message.
*/
rc = fcb_rotate(&fcb);

if (rc) {
goto out;
}

memset(&last_popped, 0, sizeof(last_popped));
rc = fcb_append(&fcb, len, &entry);
}

if (rc) {
goto out;
}

rc = flash_area_write(fcb.fap, FCB_ENTRY_FA_DATA_OFF(entry), msg, len);

if (rc) {
goto out;
}

rc = fcb_append_finish(&fcb, &entry);

out:
k_mutex_unlock(&fcb_lock);

#ifdef LOG_HISTORY_DEBUG
__ASSERT_NO_MSG(rc == 0);
#endif
}

void log_rpc_history_set_overwriting(bool overwriting)
{
k_mutex_lock(&fcb_lock, K_FOREVER);

erase_oldest = overwriting;

k_mutex_unlock(&fcb_lock);
}

union log_msg_generic *log_rpc_history_pop(void)
{
int rc;
struct fcb_entry entry = last_popped;
union log_msg_generic *msg = NULL;

k_mutex_lock(&fcb_lock, K_FOREVER);
rc = fcb_getnext(&fcb, &entry);

if (rc) {
rc = 0;
goto out;
}

msg = (union log_msg_generic *)k_malloc(entry.fe_data_len);

if (!msg) {
goto out;
}

rc = flash_area_read(fcb.fap, FCB_ENTRY_FA_DATA_OFF(entry), msg, entry.fe_data_len);

if (rc) {
goto out;
}

last_popped = entry;

while (fcb.f_oldest != last_popped.fe_sector) {
rc = fcb_rotate(&fcb);

if (rc) {
goto out;
}
}

out:
k_mutex_unlock(&fcb_lock);

#ifdef LOG_HISTORY_DEBUG
__ASSERT_NO_MSG(rc == 0);
#endif

return msg;
}

void log_rpc_history_free(const union log_msg_generic *msg)
{
k_free((void *)msg);
}
4 changes: 4 additions & 0 deletions subsys/partition_manager/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ if(CONFIG_WIFI_NRF70 AND CONFIG_NRF_WIFI_PATCHES_EXT_FLASH_STORE)
ncs_add_partition_manager_config(pm.yml.wifi)
endif()

if(CONFIG_LOG_BACKEND_RPC_HISTORY_STORAGE_FCB)
ncs_add_partition_manager_config(pm.yml.log_history)
endif()

# We are using partition manager if we are a child image or if we are
# the root image and the 'partition_manager' target exists.
zephyr_compile_definitions(
Expand Down
7 changes: 7 additions & 0 deletions subsys/partition_manager/pm.yml.log_history
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <zephyr/autoconf.h>

log_history:
size: CONFIG_LOG_BACKEND_RPC_HISTORY_SIZE
placement:
before: [end]
align: {start: CONFIG_FPROTECT_BLOCK_SIZE}

0 comments on commit a04fa83

Please sign in to comment.