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.