mtd_config_fs : optimize nvs

Signed-off-by: xucheng5 <xucheng5@xiaomi.com>
This commit is contained in:
xucheng5 2023-12-20 11:45:27 +08:00 committed by Xiang Xiao
parent cd80900646
commit 3b79363041

View File

@ -81,11 +81,8 @@
#define NVS_SPECIAL_ATE_ID 0xffffffff
#ifdef CONFIG_MTD_WRITE_ALIGN_SIZE
#define NVS_ALIGN_SIZE CONFIG_MTD_WRITE_ALIGN_SIZE
#else
#define NVS_ALIGN_SIZE 4
#endif
#define NVS_ALIGN_UP(x) (((x) + NVS_ALIGN_SIZE - 1) & ~(NVS_ALIGN_SIZE - 1))
/****************************************************************************
* Private Types
@ -116,11 +113,15 @@ begin_packed_struct struct nvs_ate
uint16_t key_len; /* Key string len */
uint8_t part; /* Part of a multipart data - future extension */
uint8_t crc8; /* Crc8 check of the ate entry */
#if CONFIG_MTD_WRITE_ALIGN_SIZE > 4
uint8_t padding[NVS_ALIGN_SIZE - 4]; /* padding for align */
#if CONFIG_MTD_WRITE_ALIGN_SIZE <= 4
/* stay compatible with situation which align byte be 1 */
uint8_t expired[NVS_ALIGN_SIZE];
uint8_t reserved[4 - NVS_ALIGN_SIZE];
#else
uint8_t padding[NVS_ALIGN_UP(12) - 12];
uint8_t expired[NVS_ALIGN_SIZE];
#endif
uint8_t expired; /* 0xFF-newest entry, others-old entry */
uint8_t reserved[NVS_ALIGN_SIZE - 1];
} end_packed_struct;
/****************************************************************************
@ -163,19 +164,6 @@ static const struct file_operations g_mtdnvs_fops =
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: nvs_al_size
****************************************************************************/
static inline size_t nvs_al_size(size_t len)
{
#ifdef CONFIG_MTD_WRITE_ALIGN_SIZE
return (len + (NVS_ALIGN_SIZE - 1U)) & ~(NVS_ALIGN_SIZE - 1U);
#else
return len;
#endif
}
/****************************************************************************
* Name: nvs_fnv_hash
****************************************************************************/
@ -599,6 +587,40 @@ static int nvs_close_ate_valid(FAR struct nvs_fs *fs,
return 1;
}
/****************************************************************************
* Name: nvs_flash_write_multi_blk
*
* Description:
* Store multi align block in flash
*
* Returned Value:
* number of bytes at the end of addr which is left to write next time.
* zero indicates all bytes were written . On error returns -ERRNO code.
****************************************************************************/
int nvs_flash_write_multi_blk(FAR struct nvs_fs *fs, const uint8_t *addr,
size_t size)
{
size_t blk_cnt;
int left;
int rc;
blk_cnt = size / NVS_ALIGN_SIZE;
left = size % NVS_ALIGN_SIZE;
if (blk_cnt)
{
rc = nvs_flash_data_wrt(fs, addr, size - left);
if (rc)
{
ferr("Write multi data value failed, rc=%d\n", rc);
return rc;
}
}
return left;
}
/****************************************************************************
* Name: nvs_flash_wrt_entry
*
@ -613,8 +635,9 @@ static int nvs_flash_wrt_entry(FAR struct nvs_fs *fs, uint32_t id,
{
int rc;
struct nvs_ate entry;
uint16_t total;
uint8_t *tmp;
uint16_t left;
uint16_t copy_len = 0;
uint8_t buf[NVS_ALIGN_SIZE];
memset(&entry, fs->erasestate, sizeof(entry));
entry.id = id;
@ -624,37 +647,65 @@ static int nvs_flash_wrt_entry(FAR struct nvs_fs *fs, uint32_t id,
nvs_ate_crc8_update(&entry);
/* Let's sew key and data into one, key comes first, then data */
/* Let's save key and data into one, key comes first, then data */
total = nvs_al_size(key_size + len);
tmp = kmm_malloc(total);
if (tmp == NULL)
rc = nvs_flash_write_multi_blk(fs, key, key_size);
if (rc < 0)
{
ferr("malloc size %u failed\n", total);
return -ENOMEM;
}
memcpy(tmp, key, key_size);
memcpy(tmp + key_size, data, len);
memset(tmp + key_size + len, fs->erasestate, total - key_size - len);
rc = nvs_flash_data_wrt(fs, tmp, total);
if (rc)
{
ferr("Write value failed, rc=%d\n", rc);
kmm_free(tmp);
return rc;
}
if (rc)
{
/* Write align block which inlcude part key + part data */
left = rc;
memset(buf, fs->erasestate, NVS_ALIGN_SIZE);
copy_len = (left + len) <= NVS_ALIGN_SIZE ?
len : (NVS_ALIGN_SIZE - left);
memcpy(buf, key + key_size - left, left);
memcpy(buf + left, data, copy_len);
rc = nvs_flash_data_wrt(fs, buf, NVS_ALIGN_SIZE);
if (rc)
{
ferr("Write value failed, rc=%d\n", rc);
return rc;
}
}
rc = nvs_flash_write_multi_blk(fs, data + copy_len, len - copy_len);
if (rc < 0)
{
return rc;
}
if (rc)
{
/* Add padding at the end of data */
left = rc;
memset(buf, fs->erasestate, NVS_ALIGN_SIZE);
memcpy(buf, data + len - left, left);
rc = nvs_flash_data_wrt(fs, buf, NVS_ALIGN_SIZE);
if (rc)
{
ferr("Write value failed, rc=%d\n", rc);
return rc;
}
}
/* Last, let's save entry to flash */
rc = nvs_flash_ate_wrt(fs, &entry);
if (rc)
{
ferr("Write ate failed, rc=%d\n", rc);
kmm_free(tmp);
return rc;
}
kmm_free(tmp);
return 0;
}
@ -699,7 +750,7 @@ static int nvs_recover_last_ate(FAR struct nvs_fs *fs,
data_end_addr &= ADDR_BLOCK_MASK;
data_end_addr += end_ate.offset +
nvs_al_size(end_ate.key_len + end_ate.len);
NVS_ALIGN_UP(end_ate.key_len + end_ate.len);
*addr = ate_end_addr;
}
@ -945,7 +996,7 @@ static int nvs_gc(FAR struct nvs_fs *fs)
return rc;
}
if (gc_ate.expired != fs->erasestate)
if (gc_ate.expired[0] != fs->erasestate)
{
/* Deleted or old ate, ignore it */
@ -971,7 +1022,7 @@ static int nvs_gc(FAR struct nvs_fs *fs)
nvs_ate_crc8_update(&gc_ate);
rc = nvs_flash_block_move(fs, data_addr,
nvs_al_size(gc_ate.key_len + gc_ate.len));
NVS_ALIGN_UP(gc_ate.key_len + gc_ate.len));
if (rc)
{
return rc;
@ -1156,8 +1207,8 @@ static int nvs_startup(FAR struct nvs_fs *fs)
/* Complete write of ate was performed */
fs->data_wra = addr & ADDR_BLOCK_MASK;
fs->data_wra += last_ate.offset + nvs_al_size(last_ate.key_len +
last_ate.len);
fs->data_wra += last_ate.offset +
NVS_ALIGN_UP(last_ate.key_len + last_ate.len);
finfo("recovered data_wra=0x%" PRIx32 "\n", fs->data_wra);
}
@ -1316,7 +1367,7 @@ static int nvs_startup(FAR struct nvs_fs *fs)
if (nvs_ate_valid(fs, &second_ate)
&& second_ate.id == last_ate.id
&& second_ate.expired == fs->erasestate)
&& second_ate.expired[0] == fs->erasestate)
{
finfo("same id at 0x%" PRIx32 ", key_len %" PRIu16 ", "
"offset %" PRIu16 "\n",
@ -1432,7 +1483,7 @@ static ssize_t nvs_read_entry(FAR struct nvs_fs *fs, FAR const uint8_t *key,
{
/* It is old or deleted, return -ENOENT */
if (wlk_ate.expired != fs->erasestate)
if (wlk_ate.expired[0] != fs->erasestate)
{
return -ENOENT;
}
@ -1521,13 +1572,14 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
/* Data now contains input data and input key, input key first. */
data_size = nvs_al_size(key_size + pdata->len);
data_size = NVS_ALIGN_UP(key_size + pdata->len);
/* The maximum data size is block size - 3 ate
* where: 1 ate for data, 1 ate for block close, 1 ate for gc done.
*/
finfo("key_size=%zu, len=%zu\n", key_size, pdata->len);
finfo("key_size=%zu, len=%zu, data_size = %zu\n", key_size,
pdata->len, data_size);
if ((data_size > (fs->geo.erasesize - 3 * sizeof(struct nvs_ate))) ||
((pdata->len > 0) && (pdata->configdata == NULL)))
@ -1587,7 +1639,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
{
/* If prev ate is expired, it is deleted. */
if (wlk_ate.expired != fs->erasestate)
if (wlk_ate.expired[0] != fs->erasestate)
{
/* Skip delete entry as it is already the
* last one.
@ -1611,7 +1663,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
}
}
else if (pdata->len == wlk_ate.len &&
wlk_ate.expired == fs->erasestate)
wlk_ate.expired[0] == fs->erasestate)
{
/* Do not try to compare if lengths are not equal
* or prev one is deleted.
@ -1658,7 +1710,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
/* Nvs is changed after gc, we will look for the old ate.
*/
if (prev_found && wlk_ate.expired == fs->erasestate)
if (prev_found && wlk_ate.expired[0] == fs->erasestate)
{
finfo("prev entry exists, search for it\n");
@ -1701,7 +1753,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
* already expired)
*/
if (prev_found && wlk_ate.expired == fs->erasestate)
if (prev_found && wlk_ate.expired[0] == fs->erasestate)
{
rc = nvs_expire_ate(fs, hist_addr);
finfo("expir prev entry, %" PRIx32 ", rc %d\n",
@ -1871,7 +1923,7 @@ static int nvs_next(FAR struct nvs_fs *fs,
if (nvs_ate_valid(fs, &step_ate)
&& step_ate.id != NVS_SPECIAL_ATE_ID
&& step_ate.expired == fs->erasestate)
&& step_ate.expired[0] == fs->erasestate)
{
break;
}