diff --git a/subsys/fs/nvs/Kconfig b/subsys/fs/nvs/Kconfig index 8b7dfdbab4094d..208be140f2219f 100644 --- a/subsys/fs/nvs/Kconfig +++ b/subsys/fs/nvs/Kconfig @@ -37,6 +37,14 @@ config NVS_DATA_CRC The CRC-32 is transparently stored at the end of the data field, in the NVS data section, so 4 more bytes are needed per NVS element. +config NVS_INIT_BAD_MEMORY_REGION + bool "Non-volatile Storage bad memory region recovery" + help + Enable automatic initialization of a NVS on a memory region that does + not contain a valid NVS. A region containing an invalid NVS can be + caused by corruption or by providing a non-empty region. This option + ensures a new NVS can be created. + module = NVS module-str = nvs source "subsys/logging/Kconfig.template.log_config" diff --git a/subsys/fs/nvs/nvs.c b/subsys/fs/nvs/nvs.c index e45e93e19825df..2c7c4ff5606f47 100644 --- a/subsys/fs/nvs/nvs.c +++ b/subsys/fs/nvs/nvs.c @@ -781,10 +781,23 @@ static int nvs_startup(struct nvs_fs *fs) } } } - /* all sectors are closed, this is not a nvs fs */ + /* all sectors are closed, this is not a nvs fs or irreparably corrupted */ if (closed_sectors == fs->sector_count) { +#ifdef CONFIG_NVS_INIT_BAD_MEMORY_REGION + LOG_WRN("All sectors closed, erasing all sectors..."); + rc = flash_flatten(fs->flash_device, fs->offset, + fs->sector_size * fs->sector_count); + if (rc) { + goto end; + } + + i = fs->sector_count; + addr = ((fs->sector_count - 1) << ADDR_SECT_SHIFT) + + (uint16_t)(fs->sector_size - ate_size); +#else rc = -EDEADLK; goto end; +#endif } if (i == fs->sector_count) { diff --git a/tests/subsys/fs/nvs/prj.conf b/tests/subsys/fs/nvs/prj.conf index 75740e3df33328..c046194738a786 100644 --- a/tests/subsys/fs/nvs/prj.conf +++ b/tests/subsys/fs/nvs/prj.conf @@ -8,3 +8,4 @@ CONFIG_FLASH_MAP=y CONFIG_NVS=y CONFIG_LOG=y CONFIG_NVS_LOG_LEVEL_DBG=y +CONFIG_NVS_INIT_BAD_MEMORY_REGION=y diff --git a/tests/subsys/fs/nvs/src/main.c b/tests/subsys/fs/nvs/src/main.c index 85aaf9f1b79f38..dcd264422b7416 100644 --- a/tests/subsys/fs/nvs/src/main.c +++ b/tests/subsys/fs/nvs/src/main.c @@ -959,3 +959,40 @@ ZTEST_F(nvs, test_nvs_cache_hash_quality) #endif } + +/* + * Test NVS bad region initialization recovery. + */ +ZTEST_F(nvs, test_nvs_init_bad_memory_region) +{ + int err; + uint32_t data; + + err = nvs_mount(&fixture->fs); + zassert_true(err == 0, "nvs_mount call failure: %d", err); + + /* Write bad ATE to each sector */ + for (uint16_t i = 0; i < TEST_SECTOR_COUNT; i++) { + data = 0xdeadbeef; + err = flash_write(fixture->fs.flash_device, + fixture->fs.offset + (fixture->fs.sector_size * (i + 1)) - + sizeof(struct nvs_ate), + &data, sizeof(data)); + zassert_true(err == 0, "flash_write failed: %d", err); + } + + /* Reinitialize the NVS. */ + memset(&fixture->fs, 0, sizeof(fixture->fs)); + (void)setup(); + +#ifdef CONFIG_NVS_INIT_BAD_MEMORY_REGION + err = nvs_mount(&fixture->fs); + zassert_true(err == 0, "nvs_mount call failure: %d", err); + + /* Ensure that the NVS is able to store new content. */ + execute_long_pattern_write(TEST_DATA_ID, &fixture->fs); +#else + err = nvs_mount(&fixture->fs); + zassert_true(err == -EDEADLK, "nvs_mount call ok, expect fail: %d", err); +#endif +}