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
+8
View File
@@ -201,6 +201,14 @@ config MTD_CONFIG_BLOCKSIZE_MULTIPLE
---help--- ---help---
The size of a multiple of blocksize compared to erasize 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 endif # MTD_CONFIG
comment "MTD Device Drivers" comment "MTD Device Drivers"
+134 -28
View File
@@ -55,6 +55,8 @@
#define NVS_ADDR_BLOCK_SHIFT 16 #define NVS_ADDR_BLOCK_SHIFT 16
#define NVS_ADDR_OFFS_MASK 0x0000FFFF #define NVS_ADDR_OFFS_MASK 0x0000FFFF
#define NVS_CACHE_NO_ADDR 0xffffffff
#define NVS_ATE(name, size) \ #define NVS_ATE(name, size) \
char name##_buf[size]; \ char name##_buf[size]; \
FAR struct nvs_ate *name = (FAR struct nvs_ate *)name##_buf FAR struct nvs_ate *name = (FAR struct nvs_ate *)name##_buf
@@ -80,6 +82,9 @@ struct nvs_fs
mutex_t nvs_lock; mutex_t nvs_lock;
FAR struct pollfd *fds; FAR struct pollfd *fds;
pollevent_t events; pollevent_t events;
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
uint32_t cache[CONFIG_MTD_CONFIG_CACHE_SIZE];
#endif
}; };
/* Allocation Table Entry */ /* Allocation Table Entry */
@@ -135,6 +140,36 @@ static const struct file_operations g_mtdnvs_fops =
* Private Functions * 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 * 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); size_t ate_size = nvs_ate_size(fs);
int rc; 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); rc = nvs_flash_wrt(fs, fs->ate_wra, entry, ate_size);
fs->ate_wra -= 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; int rc;
finfo("Erasing addr %" PRIx32 "\n", addr); 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, rc = MTD_ERASE(fs->mtd,
CONFIG_MTD_CONFIG_BLOCKSIZE_MULTIPLE * CONFIG_MTD_CONFIG_BLOCKSIZE_MULTIPLE *
(addr >> NVS_ADDR_BLOCK_SHIFT), (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. * 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; wlk_addr = fs->ate_wra;
while (1) while (1)
{ {
@@ -1481,6 +1535,10 @@ static int nvs_startup(FAR struct nvs_fs *fs)
"key_len %" PRIu16 ", offset %" PRIu16 "\n", "key_len %" PRIu16 ", offset %" PRIu16 "\n",
last_addr, last_ate->id, last_ate->key_len, last_addr, last_ate->id, last_ate->key_len,
last_ate->offset); last_ate->offset);
#if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
fs->cache[nvs_cache_index(last_ate->id)] = last_addr;
#endif
while (1) while (1)
{ {
second_addr = wlk_addr; second_addr = wlk_addr;
@@ -1491,37 +1549,42 @@ static int nvs_startup(FAR struct nvs_fs *fs)
} }
if (nvs_ate_valid(fs, second_ate) if (nvs_ate_valid(fs, second_ate)
&& second_ate->id == last_ate->id
&& !nvs_ate_expired(fs, second_ate)) && !nvs_ate_expired(fs, second_ate))
{ {
finfo("same id at 0x%" PRIx32 ", key_len %" PRIu16 ", " #if CONFIG_MTD_CONFIG_CACHE_SIZE > 0
"offset %" PRIu16 "\n", fs->cache[nvs_cache_index(second_ate->id)] = second_addr;
second_addr, second_ate->key_len, #endif
second_ate->offset); if (second_ate->id == last_ate->id)
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))
{ {
finfo("old ate found at 0x%" PRIx32 "\n", second_addr); finfo("same id at 0x%" PRIx32 ", key_len %" PRIu16 ", "
rc = nvs_expire_ate(fs, second_addr); "offset %" PRIu16 "\n", second_addr,
if (rc < 0) 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", finfo("old ate found at 0x%" PRIx32 "\n",
second_addr); second_addr);
return rc; rc = nvs_expire_ate(fs, second_addr);
} if (rc < 0)
{
ferr("expire ate failed, addr %" PRIx32 "\n",
second_addr);
return rc;
}
goto end; goto end;
} }
else else
{ {
fwarn("hash conflict\n"); 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 rd_addr;
uint32_t hist_addr; uint32_t hist_addr;
uint32_t hash_id; uint32_t hash_id;
bool hit = true;
int rc; int rc;
hash_id = nvs_fnv_hash(key, key_size) % 0xfffffffd + 1; 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; rd_addr = wlk_addr;
do 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) if (wlk_addr == fs->ate_wra)
{ {
return -ENOENT; return -ENOENT;
@@ -1687,6 +1772,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
bool prev_found = false; bool prev_found = false;
uint32_t hash_id; uint32_t hash_id;
uint16_t block_to_write_befor_gc; uint16_t block_to_write_befor_gc;
bool hit = true;
#ifdef CONFIG_MTD_CONFIG_NAMED #ifdef CONFIG_MTD_CONFIG_NAMED
FAR const uint8_t *key; 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. */ /* 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) 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) if (wlk_addr == fs->ate_wra)
{ {
break; break;