mirror of
https://github.com/apache/nuttx.git
synced 2026-05-27 11:26:12 +08:00
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:
@@ -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
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user