diff --git a/fs/spiffs/Kconfig b/fs/spiffs/Kconfig index 68df5f55b1..32cc60e4d6 100644 --- a/fs/spiffs/Kconfig +++ b/fs/spiffs/Kconfig @@ -114,6 +114,14 @@ config SPIFFS_CHECK_OUTPUT bool "Enable consistency check SYSLOG output" default n +config SPIFFS_DUMP + bool "Dump Logical FLASH Content" + default n + depends on SPIFFS_CHECK_OUTPUT + ---help--- + Enables support for the FIOC_DUMP IOCTL command which will dump a + terse summary of the state of each FLASH page. + comment "MTD Interface Options" config SPIFFS_MTDDBG diff --git a/fs/spiffs/src/spiffs_check.c b/fs/spiffs/src/spiffs_check.c index c094df83c7..5d3c88d978 100644 --- a/fs/spiffs/src/spiffs_check.c +++ b/fs/spiffs/src/spiffs_check.c @@ -62,6 +62,7 @@ #include +#include #include #include @@ -2027,3 +2028,147 @@ int spiffs_check_objidconsistency(FAR struct spiffs_s *fs) return ret; } + + +/**************************************************************************** + * Name: spiffs_dump + * + * Description: + * Dump logical flash content + * + * Input Parameters: + * fs - A reference to the volume structure + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SPIFFS_DUMP +int spiffs_dump(FAR struct spiffs_s *fs) +{ + FAR int16_t *objlu_buf = (FAR int16_t *)fs->lu_work; + uint32_t pages_per_block; + uint32_t blocks; + uint32_t obj_lupages; + uint32_t data_pgsize; + uint32_t ndata_pages; + int16_t pgndx = 0; + int16_t erase_count; + char buffer[80]; + int entries_per_page; + int len = 0; + int ret = OK; + + entries_per_page = (SPIFFS_GEO_PAGE_SIZE(fs) / sizeof(int16_t)); + + while (pgndx < SPIFFS_GEO_PAGE_COUNT(fs)) + { + /* Check each object lookup page */ + + int obj_lookup_page = 0; + int cur_entry = 0; + + while (ret >= 0 && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) + { + int entry_offset = obj_lookup_page * entries_per_page; + + ret = spiffs_cache_read(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, pgndx * SPIFFS_GEO_PAGE_SIZE(fs) + + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), + SPIFFS_GEO_PAGE_SIZE(fs), fs->lu_work); + + /* Check each entry */ + + while (ret >= 0 && + cur_entry - entry_offset < entries_per_page && + cur_entry < (int)(SPIFFS_GEO_PAGES_PER_BLOCK(fs) - + SPIFFS_OBJ_LOOKUP_PAGES(fs))) + { + int16_t objid = objlu_buf[cur_entry-entry_offset]; + + if (cur_entry == 0) + { + len += snprintf(&buffer[len], 80 - len, "%04x ", pgndx); + } + else if ((cur_entry & 0x3f) == 0) + { + len += snprintf(&buffer[len], 80 - len, " "); + } + + if ((objid == SPIFFS_OBJID_FREE) != 0) + { + len += snprintf(&buffer[len], 80 - len, "."); + } + else if ((objid == SPIFFS_OBJID_DELETED) != 0) + { + len += snprintf(&buffer[len], 80 - len, "x"); + } + else if ((objid & SPIFFS_OBJID_NDXFLAG) != 0) + { + len += snprintf(&buffer[len], 80 - len, "I"); + } + else + { + len += snprintf(&buffer[len], 80 - len, "D"); + } + + cur_entry++; + + if ((cur_entry & 0x3f) == 0) + { + len += snprintf(&buffer[len], 80 - len, "\n"); + spiffs_checkinfo("%s", buffer); + len = 0; + } + } + + obj_lookup_page++; + } + + ret = spiffs_cache_read(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, pgndx), + sizeof(int16_t), (FAR uint8_t *)&erase_count); + if (ret < 0) + { + ferr("ERROR: spiffs_mtd_read() failed: %d\n", ret); + return ret; + } + + if (erase_count != (int16_t)-1) + { + len += snprintf(&buffer[len], 80 - len, " era_cnt=%d\n", erase_count); + } + else + { + len += snprintf(&buffer[len], 80 - len, " era_cnt (N/A)\n"); + } + + spiffs_checkinfo("%s", buffer); + len = 0; + + pgndx++; + } + + spiffs_checkinfo("era_cnt_max: %d\n", fs->max_erase_count); + spiffs_checkinfo("blocks: %d\n", SPIFFS_GEO_PAGE_COUNT(fs)); + spiffs_checkinfo("free_blocks: %d\n", fs->free_blocks); + spiffs_checkinfo("page_alloc: %d\n", fs->alloc_pages); + spiffs_checkinfo("page_delet: %d\n", fs->deleted_pages); + + /* The following duplicates some logic from spiffs_statfs() */ + /* -2 for spare blocks, +1 for emergency page */ + + pages_per_block = SPIFFS_GEO_PAGES_PER_BLOCK(fs); + blocks = SPIFFS_GEO_BLOCK_COUNT(fs); + obj_lupages = SPIFFS_OBJ_LOOKUP_PAGES(fs); + data_pgsize = SPIFFS_DATA_PAGE_SIZE(fs); + ndata_pages = (blocks - 2) * (pages_per_block - obj_lupages) + 1; + + spiffs_checkinfo("used: %ld of %ld\n", + (long)(fs->alloc_pages * data_pgsize), + (long)(ndata_pages * data_pgsize)); + return OK; +} +#endif \ No newline at end of file diff --git a/fs/spiffs/src/spiffs_check.h b/fs/spiffs/src/spiffs_check.h index 403348b491..bc04e74e3f 100644 --- a/fs/spiffs/src/spiffs_check.h +++ b/fs/spiffs/src/spiffs_check.h @@ -147,6 +147,26 @@ int spiffs_check_pgconsistency(FAR struct spiffs_s *fs); int spiffs_check_objidconsistency(FAR struct spiffs_s *fs); + +/**************************************************************************** + * Name: spiffs_dump + * + * Description: + * Dump logical flash content + * + * Input Parameters: + * fs - A reference to the volume structure + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SPIFFS_DUMP +int spiffs_dump(FAR struct spiffs_s *fs); +#endif + #if defined(__cplusplus) } #endif diff --git a/fs/spiffs/src/spiffs_vfs.c b/fs/spiffs/src/spiffs_vfs.c index b50d8a0afd..ffc04b3fff 100644 --- a/fs/spiffs/src/spiffs_vfs.c +++ b/fs/spiffs/src/spiffs_vfs.c @@ -1002,6 +1002,19 @@ static int spiffs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; + /* Dump logical content of FLASH. + * IN: None + * OUT: None + */ + +#ifdef CONFIG_SPIFFS_DUMP + case FIOC_DUMP: + { + ret = spiffs_dump(fs); + } + break; +#endif + default: /* Pass through to the contained MTD driver */ diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index c6adfe0348..5b9005af3a 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -149,17 +149,20 @@ * file system media. * IN: None * OUT: None */ +#define FIOC_DUMP _FIOC(0x0006) /* Dump logical content of media. + * IN: None + * OUT: None */ -#define FIONREAD _FIOC(0x0006) /* IN: Location to return value (int *) +#define FIONREAD _FIOC(0x0007) /* IN: Location to return value (int *) * OUT: Bytes readable from this fd */ -#define FIONWRITE _FIOC(0x0007) /* IN: Location to return value (int *) +#define FIONWRITE _FIOC(0x0008) /* IN: Location to return value (int *) * OUT: Number bytes in send queue */ -#define FIONSPACE _FIOC(0x0008) /* IN: Location to return value (int *) +#define FIONSPACE _FIOC(0x0009) /* IN: Location to return value (int *) * OUT: Free space in send queue. */ -#define FIONUSERFS _FIOC(0x0009) /* IN: Pointer to struct usefs_config_s +#define FIONUSERFS _FIOC(0x000a) /* IN: Pointer to struct usefs_config_s * holding userfs configuration. * OUT: Instance number is returned on * success.