Hi,
I have found a bug in the fds module (Flash Data Storage), which lead to losing "installed pages". If it was a swap page, fds module will be bricked.
Tested on SDK 14.2.0, but it is present in 15.2.0. Hardware is not relevant, but I tested it with PCA10040 (nRF52832).
Pages used by fds are taged with 2 magic words. Please see code below:
// Tags a page as swap, i.e., reserved for GC. static ret_code_t page_tag_write_swap(void) { // The tag needs to be statically allocated since it is not buffered by fstorage. static uint32_t const page_tag_swap[] = {FDS_PAGE_TAG_MAGIC, FDS_PAGE_TAG_SWAP}; return nrf_fstorage_write(&m_fs, (uint32_t)m_swap_page.p_addr, page_tag_swap, FDS_PAGE_TAG_SIZE * sizeof(uint32_t), NULL); } // Tags a page as data, i.e, ready for storage. static ret_code_t page_tag_write_data(uint32_t const * const p_page_addr) { // The tag needs to be statically allocated since it is not buffered by fstorage. static uint32_t const page_tag_data[] = {FDS_PAGE_TAG_MAGIC, FDS_PAGE_TAG_DATA}; return nrf_fstorage_write(&m_fs, (uint32_t)p_page_addr, page_tag_data, FDS_PAGE_TAG_SIZE * sizeof(uint32_t), NULL); }
The problem occures, when this process is interrupted (with reset). It may result in writing only first word:
#define FDS_PAGE_TAG_MAGIC (0xDEADC0DE)
After reset, fds is checking this magic tag to determine page type. It uses these functions:
// Reads a page tag, and determines if the page is used to store data or as swap. static fds_page_type_t page_identify(uint32_t const * const p_page_addr) { if ( (p_page_addr == NULL) // Should never happen. || (p_page_addr[FDS_PAGE_TAG_WORD_0] != FDS_PAGE_TAG_MAGIC)) { return FDS_PAGE_UNDEFINED; } switch (p_page_addr[FDS_PAGE_TAG_WORD_1]) { case FDS_PAGE_TAG_SWAP: return FDS_PAGE_SWAP; case FDS_PAGE_TAG_DATA: return FDS_PAGE_DATA; default: return FDS_PAGE_UNDEFINED; } } static bool page_is_erased(uint32_t const * const p_page_addr) { for (uint32_t i = 0; i < FDS_PAGE_SIZE; i++) { if (*(p_page_addr + i) != FDS_ERASED_WORD) { return false; } } return true; }
This fuction will classify this page as FDS_PAGE_UNDEFINED and unerased.
I would like to propose a change in page_is_erased() function.
static bool page_is_erased(uint32_t const * const p_page_addr) { if ((p_page_addr[FDS_PAGE_TAG_WORD_0] != FDS_ERASED_WORD) && (p_page_addr[FDS_PAGE_TAG_WORD_0] != FDS_PAGE_TAG_MAGIC)) { return false; } for (uint32_t i = FDS_PAGE_TAG_WORD_1; i < FDS_PAGE_SIZE; i++) { if (*(p_page_addr + i) != FDS_ERASED_WORD) { return false; } } return true; }
Thanks to that, module will correctly classify this page as FDS_PAGE_ERASED.