cfa1ba1261
Add option to disable CRC for fcb entries. This improves the write throughput significantly at the cost of not detecting corrupted data in flash. This is beneficial for aplications that needs the extra write throughput, where error detection is done elsewhere. Allow the FCB entries in flash to have a valid CRC when CRC is disabled in the FCB. This allows existing solutions to disable CRC checking, while keeping the CRC areas intact. Note that this is a one-way option. Fixes #53707 Signed-off-by: Eivind Jølsgard <eivind.jolsgard@nordicsemi.no>
141 lines
2.9 KiB
C
141 lines
2.9 KiB
C
/*
|
|
* Copyright (c) 2017-2020 Nordic Semiconductor ASA
|
|
* Copyright (c) 2015 Runtime Inc
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include <zephyr/fs/fcb.h>
|
|
#include "fcb_priv.h"
|
|
|
|
static struct flash_sector *
|
|
fcb_new_sector(struct fcb *fcb, int cnt)
|
|
{
|
|
struct flash_sector *prev;
|
|
struct flash_sector *cur;
|
|
int i;
|
|
|
|
prev = NULL;
|
|
i = 0;
|
|
cur = fcb->f_active.fe_sector;
|
|
do {
|
|
cur = fcb_getnext_sector(fcb, cur);
|
|
if (!prev) {
|
|
prev = cur;
|
|
}
|
|
if (cur == fcb->f_oldest) {
|
|
return NULL;
|
|
}
|
|
} while (i++ < cnt);
|
|
return prev;
|
|
}
|
|
|
|
/*
|
|
* Take one of the scratch blocks into use, if at all possible.
|
|
*/
|
|
int
|
|
fcb_append_to_scratch(struct fcb *fcb)
|
|
{
|
|
struct flash_sector *sector;
|
|
int rc;
|
|
|
|
sector = fcb_new_sector(fcb, 0);
|
|
if (!sector) {
|
|
return -ENOSPC;
|
|
}
|
|
rc = fcb_sector_hdr_init(fcb, sector, fcb->f_active_id + 1);
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
fcb->f_active.fe_sector = sector;
|
|
fcb->f_active.fe_elem_off = fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area));
|
|
fcb->f_active_id++;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
fcb_append(struct fcb *fcb, uint16_t len, struct fcb_entry *append_loc)
|
|
{
|
|
struct flash_sector *sector;
|
|
struct fcb_entry *active;
|
|
int cnt;
|
|
int rc;
|
|
uint8_t tmp_str[MAX(8, fcb->f_align)];
|
|
|
|
/* Ensure defined value of padding bytes */
|
|
memset(tmp_str, fcb->f_erase_value, sizeof(tmp_str));
|
|
|
|
cnt = fcb_put_len(fcb, tmp_str, len);
|
|
if (cnt < 0) {
|
|
return cnt;
|
|
}
|
|
cnt = fcb_len_in_flash(fcb, cnt);
|
|
len = fcb_len_in_flash(fcb, len) + fcb_len_in_flash(fcb, FCB_CRC_SZ);
|
|
|
|
__ASSERT_NO_MSG(cnt <= sizeof(tmp_str));
|
|
|
|
rc = k_mutex_lock(&fcb->f_mtx, K_FOREVER);
|
|
if (rc) {
|
|
return -EINVAL;
|
|
}
|
|
active = &fcb->f_active;
|
|
if (active->fe_elem_off + len + cnt > active->fe_sector->fs_size) {
|
|
sector = fcb_new_sector(fcb, fcb->f_scratch_cnt);
|
|
if (!sector || (sector->fs_size <
|
|
fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area)) + len + cnt)) {
|
|
rc = -ENOSPC;
|
|
goto err;
|
|
}
|
|
rc = fcb_sector_hdr_init(fcb, sector, fcb->f_active_id + 1);
|
|
if (rc) {
|
|
goto err;
|
|
}
|
|
fcb->f_active.fe_sector = sector;
|
|
fcb->f_active.fe_elem_off = fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area));
|
|
fcb->f_active_id++;
|
|
}
|
|
|
|
rc = fcb_flash_write(fcb, active->fe_sector, active->fe_elem_off, tmp_str, cnt);
|
|
if (rc) {
|
|
rc = -EIO;
|
|
goto err;
|
|
}
|
|
append_loc->fe_sector = active->fe_sector;
|
|
append_loc->fe_elem_off = active->fe_elem_off;
|
|
append_loc->fe_data_off = active->fe_elem_off + cnt;
|
|
|
|
active->fe_elem_off = append_loc->fe_data_off + len;
|
|
|
|
k_mutex_unlock(&fcb->f_mtx);
|
|
|
|
return 0;
|
|
err:
|
|
k_mutex_unlock(&fcb->f_mtx);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
fcb_append_finish(struct fcb *fcb, struct fcb_entry *loc)
|
|
{
|
|
int rc;
|
|
uint8_t em[fcb->f_align];
|
|
off_t off;
|
|
|
|
(void)memset(em, 0xFF, sizeof(em));
|
|
|
|
rc = fcb_elem_endmarker(fcb, loc, &em[0]);
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
off = loc->fe_data_off + fcb_len_in_flash(fcb, loc->fe_data_len);
|
|
|
|
rc = fcb_flash_write(fcb, loc->fe_sector, off, em, fcb->f_align);
|
|
if (rc) {
|
|
return -EIO;
|
|
}
|
|
return 0;
|
|
}
|