mtd/nvs: add nvs cache buffer

improve the speed of finding the target ate

Signed-off-by: guohao15 <guohao15@xiaomi.com>
This commit is contained in:
guohao15
2024-10-30 16:48:37 +08:00
committed by Xiang Xiao
parent 9d471f353d
commit 0af8d03d88
2 changed files with 142 additions and 28 deletions

View File

@@ -201,6 +201,14 @@ config MTD_CONFIG_BLOCKSIZE_MULTIPLE
---help---
The size of a multiple of blocksize compared to erasize
config MTD_CONFIG_CACHE_SIZE
int "Non-volatile Storage lookup cache size"
default 0
depends on MTD_CONFIG_FAIL_SAFE
help
Number of entries in Non-volatile Storage lookup cache.
It is recommended that it be a power of 2.
endif # MTD_CONFIG
comment "MTD Device Drivers"

View File

@@ -55,6 +55,8 @@
#define NVS_ADDR_BLOCK_SHIFT 16
#define NVS_ADDR_OFFS_MASK 0x0000FFFF
#define NVS_CACHE_NO_ADDR 0xffffffff
#define NVS_ATE(name, size) \
char name##_buf[size]; \
FAR struct nvs_ate *name = (FAR struct nvs_ate *)name##_buf
@@ -80,6 +82,9 @@ struct nvs_fs
mutex_t nvs_lock;
FAR struct pollfd *fds;
pollevent_t events;
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
uint32_t cache[CONFIG_MTD_CONFIG_CACHE_SIZE];
#endif
};
/* Allocation Table Entry */
@@ -135,6 +140,36 @@ static const struct file_operations g_mtdnvs_fops =
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: nvs_cache_index
****************************************************************************/
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
static inline size_t nvs_cache_index(uint32_t id)
{
return id % CONFIG_MTD_CONFIG_CACHE_SIZE;
}
/****************************************************************************
* Name: nvs_invalid_cache
****************************************************************************/
static void nvs_invalid_cache(struct nvs_fs *fs, uint32_t sector)
{
FAR uint32_t *cache_entry = fs->cache;
FAR const uint32_t *cache_end =
&fs->cache[CONFIG_MTD_CONFIG_CACHE_SIZE];
for (; cache_entry < cache_end; ++cache_entry)
{
if ((*cache_entry >> NVS_ADDR_BLOCK_SHIFT) == sector)
{
*cache_entry = NVS_CACHE_NO_ADDR;
}
}
}
#endif /* CONFIG_MTD_CONFIG_CACHE_SIZE */
/****************************************************************************
* Name: nvs_fnv_hash
****************************************************************************/
@@ -374,6 +409,16 @@ static int nvs_flash_ate_wrt(FAR struct nvs_fs *fs,
size_t ate_size = nvs_ate_size(fs);
int rc;
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
/* 0xFFFF is a special-purpose identifier. Exclude it from the cache */
if (entry->id != nvs_special_ate_id(fs))
{
fs->cache[nvs_cache_index(entry->id)] = fs->ate_wra;
}
#endif
rc = nvs_flash_wrt(fs, fs->ate_wra, entry, ate_size);
fs->ate_wra -= ate_size;
@@ -581,6 +626,11 @@ static int nvs_flash_erase_block(FAR struct nvs_fs *fs, uint32_t addr)
int rc;
finfo("Erasing addr %" PRIx32 "\n", addr);
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
nvs_invalid_cache(fs, addr >> NVS_ADDR_BLOCK_SHIFT);
#endif
rc = MTD_ERASE(fs->mtd,
CONFIG_MTD_CONFIG_BLOCKSIZE_MULTIPLE *
(addr >> NVS_ADDR_BLOCK_SHIFT),
@@ -1457,6 +1507,10 @@ static int nvs_startup(FAR struct nvs_fs *fs)
* We need to set old entry expired.
*/
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
memset(fs->cache, 0xff, sizeof(fs->cache));
#endif
wlk_addr = fs->ate_wra;
while (1)
{
@@ -1481,6 +1535,10 @@ static int nvs_startup(FAR struct nvs_fs *fs)
"key_len %" PRIu16 ", offset %" PRIu16 "\n",
last_addr, last_ate->id, last_ate->key_len,
last_ate->offset);
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
fs->cache[nvs_cache_index(last_ate->id)] = last_addr;
#endif
while (1)
{
second_addr = wlk_addr;
@@ -1491,37 +1549,42 @@ static int nvs_startup(FAR struct nvs_fs *fs)
}
if (nvs_ate_valid(fs, second_ate)
&& second_ate->id == last_ate->id
&& !nvs_ate_expired(fs, second_ate))
{
finfo("same id at 0x%" PRIx32 ", key_len %" PRIu16 ", "
"offset %" PRIu16 "\n",
second_addr, second_ate->key_len,
second_ate->offset);
if ((second_ate->key_len == last_ate->key_len) &&
!nvs_flash_direct_cmp(fs,
(last_addr &
NVS_ADDR_BLOCK_MASK) +
last_ate->offset,
(second_addr &
NVS_ADDR_BLOCK_MASK) +
second_ate->offset,
last_ate->key_len))
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
fs->cache[nvs_cache_index(second_ate->id)] = second_addr;
#endif
if (second_ate->id == last_ate->id)
{
finfo("old ate found at 0x%" PRIx32 "\n", second_addr);
rc = nvs_expire_ate(fs, second_addr);
if (rc < 0)
finfo("same id at 0x%" PRIx32 ", key_len %" PRIu16 ", "
"offset %" PRIu16 "\n", second_addr,
second_ate->key_len, second_ate->offset);
if ((second_ate->key_len == last_ate->key_len) &&
!nvs_flash_direct_cmp(fs,
(last_addr &
NVS_ADDR_BLOCK_MASK) +
last_ate->offset,
(second_addr &
NVS_ADDR_BLOCK_MASK) +
second_ate->offset,
last_ate->key_len))
{
ferr("expire ate failed, addr %" PRIx32 "\n",
second_addr);
return rc;
}
finfo("old ate found at 0x%" PRIx32 "\n",
second_addr);
rc = nvs_expire_ate(fs, second_addr);
if (rc < 0)
{
ferr("expire ate failed, addr %" PRIx32 "\n",
second_addr);
return rc;
}
goto end;
}
else
{
fwarn("hash conflict\n");
goto end;
}
else
{
fwarn("hash conflict\n");
}
}
}
@@ -1589,10 +1652,19 @@ static ssize_t nvs_read_entry(FAR struct nvs_fs *fs, FAR const uint8_t *key,
uint32_t rd_addr;
uint32_t hist_addr;
uint32_t hash_id;
bool hit = true;
int rc;
hash_id = nvs_fnv_hash(key, key_size) % 0xfffffffd + 1;
wlk_addr = fs->ate_wra;
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
wlk_addr = fs->cache[nvs_cache_index(hash_id)];
if (wlk_addr == NVS_CACHE_NO_ADDR)
#endif
{
wlk_addr = fs->ate_wra;
hit = false;
}
rd_addr = wlk_addr;
do
@@ -1627,6 +1699,19 @@ static ssize_t nvs_read_entry(FAR struct nvs_fs *fs, FAR const uint8_t *key,
}
}
/* There are two types of hash conflicts found by cache, one is hash_id
* conflict and the other is hash_id % CONFIG_MTD_CONFIG_CACHE_SIZE
* conflict, both of which require traversing flash from the flash
* beginning.
*/
if (hit)
{
wlk_addr = fs->ate_wra;
hit = false;
continue;
}
if (wlk_addr == fs->ate_wra)
{
return -ENOENT;
@@ -1687,6 +1772,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
bool prev_found = false;
uint32_t hash_id;
uint16_t block_to_write_befor_gc;
bool hit = true;
#ifdef CONFIG_MTD_CONFIG_NAMED
FAR const uint8_t *key;
@@ -1726,7 +1812,14 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
/* Find latest entry with same id. */
wlk_addr = fs->ate_wra;
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
wlk_addr = fs->cache[nvs_cache_index(hash_id)];
if (wlk_addr == NVS_CACHE_NO_ADDR)
#endif
{
wlk_addr = fs->ate_wra;
hit = false;
}
while (1)
{
@@ -1754,6 +1847,19 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
}
}
/* There are two types of hash conflicts found by cache, one is hash_id
* conflict and the other is hash_id % CONFIG_MTD_CONFIG_CACHE_SIZE
* conflict, both of which require traversing flash from the flash
* beginning.
*/
if (hit)
{
wlk_addr = fs->ate_wra;
hit = false;
continue;
}
if (wlk_addr == fs->ate_wra)
{
break;