diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst index ade5518aa5..f9602fc8bf 100644 --- a/components/nvs_flash/README.rst +++ b/components/nvs_flash/README.rst @@ -9,10 +9,12 @@ Non-volatile storage (NVS) library is designed to store key-value pairs in flash Underlying storage ^^^^^^^^^^^^^^^^^^ -Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The range of flash sectors to be used by the library is provided to ``nvs_flash_init`` function. +Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses the first partition with ``data`` type and ``nvs`` subtype. Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. +.. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``make erase_flash`` target to erase all contents of the flash chip. + Keys and values ^^^^^^^^^^^^^^^ diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index 7deca54440..6e5af231ab 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -41,6 +41,7 @@ typedef uint32_t nvs_handle; #define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< Internal error; never returned by nvs_ API functions */ #define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */ #define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */ +#define ESP_ERR_NVS_NO_FREE_PAGES (ESP_ERR_NVS_BASE + 0x0d) /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */ /** * @brief Mode of opening the non-volatile storage diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h index 0162a8f8ac..8307fe3521 100644 --- a/components/nvs_flash/include/nvs_flash.h +++ b/components/nvs_flash/include/nvs_flash.h @@ -21,7 +21,11 @@ extern "C" { /** * @brief Initialize NVS flash storage with layout given in the partition table. * - * @return ESP_OK if storage was successfully initialized. + * @return + * - ESP_OK if storage was successfully initialized. + * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages + * (which may happen if NVS partition was truncated) + * - one of the error codes from the underlying flash storage driver */ esp_err_t nvs_flash_init(void); diff --git a/components/nvs_flash/src/nvs_pagemanager.cpp b/components/nvs_flash/src/nvs_pagemanager.cpp index 768b30667a..943f54f2f8 100644 --- a/components/nvs_flash/src/nvs_pagemanager.cpp +++ b/components/nvs_flash/src/nvs_pagemanager.cpp @@ -105,6 +105,11 @@ esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount) } } + // partition should have at least one free page + if (mFreePageList.size() == 0) { + return ESP_ERR_NVS_NO_FREE_PAGES; + } + return ESP_OK; } diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index 282d4de48e..ff35a84d11 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -1108,6 +1108,23 @@ TEST_CASE("read/write failure (TW8406)", "[nvs]") } } +TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]") +{ + const size_t blob_size = 2048; // big enough so that only one can fit into a page + uint8_t blob[blob_size] = {0}; + SpiFlashEmulator emu(5); + TEST_ESP_OK( nvs_flash_init_custom(0, 5) ); + nvs_handle handle; + TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) ); + TEST_ESP_OK( nvs_set_blob(handle, "1", blob, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "2", blob, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "3", blob, blob_size) ); + TEST_ESP_OK( nvs_commit(handle) ); + nvs_close(handle); + // first two pages are now full, third one is writable, last two are empty + // init should fail + TEST_ESP_ERR( nvs_flash_init_custom(0, 3), ESP_ERR_NVS_NO_FREE_PAGES ); +} TEST_CASE("dump all performance data", "[nvs]") { diff --git a/docs/api/storage/nvs_flash.rst b/docs/api/storage/nvs_flash.rst index ce1af94546..b6cf6f2210 100644 --- a/docs/api/storage/nvs_flash.rst +++ b/docs/api/storage/nvs_flash.rst @@ -48,6 +48,7 @@ Macros .. doxygendefine:: ESP_ERR_NVS_PAGE_FULL .. doxygendefine:: ESP_ERR_NVS_INVALID_STATE .. doxygendefine:: ESP_ERR_NVS_INVALID_LENGTH +.. doxygendefine:: ESP_ERR_NVS_NO_FREE_PAGES Type Definitions ^^^^^^^^^^^^^^^^ @@ -61,6 +62,7 @@ Enumerations Functions ^^^^^^^^^ +.. doxygenfunction:: nvs_flash_init .. doxygenfunction:: nvs_open .. doxygenfunction:: nvs_set_i8 .. doxygenfunction:: nvs_set_u8 @@ -86,5 +88,5 @@ Functions .. doxygenfunction:: nvs_erase_all .. doxygenfunction:: nvs_commit .. doxygenfunction:: nvs_close -.. doxygenfunction:: nvs_flash_init +