diff --git a/fs/spiffs/Kconfig b/fs/spiffs/Kconfig index f21e6f1b71..912e4320ad 100644 --- a/fs/spiffs/Kconfig +++ b/fs/spiffs/Kconfig @@ -38,6 +38,8 @@ config SPIFFS_CACHEDBG bool "Enable cache debug output" default n depends on DEBUG_FS_INFO + ---help--- + Dumps cache debug output. Depends on CONFIG_DEBUG_FS_INFO comment "Garbage Collection (GC) Options" @@ -95,6 +97,8 @@ config SPIFFS_GCDBG bool "Enable garbage collection debug output" default n depends on DEBUG_FS_INFO + ---help--- + Dumps garbage collection debug output. Depends on CONFIG_DEBUG_FS_INFO comment "Consistency Check Options" @@ -110,6 +114,24 @@ config SPIFFS_CHECK_OUTPUT bool "Enable consistency check SYSLOG output" default n +comment "MTD Interface Options" + +config SPIFFS_MTDDBG + bool "Enable MTD Interface DEBUG" + default n + depends on DEBUG_FS_INFO + ---help--- + Dumps MTD debug output. Depends on CONFIG_DEBUG_FS_INFO + +config SPIFFS_MTDDUMP + bool "Enable MTD Data Dump" + default n + depends on SPIFFS_MTDDBG + ---help--- + Dumps every byte of data going to and coming from FLASH. You + probably do not want this unless you are debugging a particular + MTD interfacing issue. + comment "SPIFFS Core Options" config SPIFFS_NO_BLIND_WRITES diff --git a/fs/spiffs/src/spiffs.h b/fs/spiffs/src/spiffs.h index f7c32863cb..5b0bc9463a 100644 --- a/fs/spiffs/src/spiffs.h +++ b/fs/spiffs/src/spiffs.h @@ -145,6 +145,7 @@ struct spiffs_s FAR struct mtd_dev_s *mtd; /* The contained MTD interface */ FAR uint8_t *lu_work; /* Primary work buffer, size of a logical page */ FAR uint8_t *work; /* Secondary work buffer, size of a logical page */ + FAR uint8_t *mtd_work; /* MTD I/O buffer for read-modify-write */ FAR void *cache; /* Cache memory */ #ifdef CONFIG_HAVE_LONG_LONG off64_t media_size; /* Physical size of the SPI flash */ diff --git a/fs/spiffs/src/spiffs_cache.c b/fs/spiffs/src/spiffs_cache.c index 504531c58b..bf5a801ec1 100644 --- a/fs/spiffs/src/spiffs_cache.c +++ b/fs/spiffs/src/spiffs_cache.c @@ -400,6 +400,9 @@ ssize_t spiffs_cache_read(FAR struct spiffs_s *fs, uint8_t op, int16_t objid, FAR struct spiffs_cache_page_s *cp; int ret = OK; + spiffs_cacheinfo("op=%02x, objid=%04x addr=%ld len=%lu\n", + op, objid, (long)addr, (unsigned long)len); + cache = spiffs_get_cache(fs); cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr)); @@ -512,6 +515,9 @@ size_t spiffs_cache_write(FAR struct spiffs_s *fs, uint8_t op, int16_t objid, int16_t pgndx; int ret = OK; + spiffs_cacheinfo("op=%02x, objid=%04x addr=%ld len=%lu\n", + op, objid, (long)addr, (unsigned long)len); + pgndx = SPIFFS_PADDR_TO_PAGE(fs, addr); cache = spiffs_get_cache(fs); cp = spiffs_cache_page_get(fs, pgndx); diff --git a/fs/spiffs/src/spiffs_core.h b/fs/spiffs/src/spiffs_core.h index 6eb474f7e4..d80c62963e 100644 --- a/fs/spiffs/src/spiffs_core.h +++ b/fs/spiffs/src/spiffs_core.h @@ -361,7 +361,7 @@ begin_packed_struct struct spiffs_page_header_s uint8_t flags; /* flags */ } end_packed_struct; -/* object index header page header */ +/* Object index header page header */ begin_packed_struct struct spiffs_pgobj_ndxheader_s { @@ -371,7 +371,7 @@ begin_packed_struct struct spiffs_pgobj_ndxheader_s uint8_t name[CONFIG_SPIFFS_NAME_MAX]; /* name of object */ } end_packed_struct; -/* object index page header */ +/* Object index page header */ begin_packed_struct struct spiffs_page_objndx_s { diff --git a/fs/spiffs/src/spiffs_mtd.c b/fs/spiffs/src/spiffs_mtd.c index 69bafb10d6..1a3feb74bc 100644 --- a/fs/spiffs/src/spiffs_mtd.c +++ b/fs/spiffs/src/spiffs_mtd.c @@ -52,9 +52,21 @@ #include "spiffs_mtd.h" /**************************************************************************** - * Private Data + * Private Functions ****************************************************************************/ +#ifdef CONFIG_SPIFFS_MTDDUMP +static inline void spiffs_mtd_dump(FAR const char *msg, + FAR const uint8_t *buffer, + unsigned int buflen) +{ + lib_dumpbuffer(msg, buffer, buflen); +} + +#else +# define spiffs_mtd_dump(m,b,l) +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -80,16 +92,17 @@ ssize_t spiffs_mtd_write(FAR struct spiffs_s *fs, off_t offset, size_t len, FAR const uint8_t *src) { - int16_t blksize; - size_t blkoffset; size_t remaining; - ssize_t nblocks; ssize_t ret; off_t blkmask; off_t blkstart; off_t blkend; + int16_t blksize; + int16_t nblocks; + int16_t blkoffset; - finfo("offset=%ld len=%lu\n", (long)offset, (unsigned long)len); + spiffs_mtdinfo("offset=%ld len=%lu\n", (long)offset, (unsigned long)len); + spiffs_mtd_dump("Writing", src, len); DEBUGASSERT(fs != NULL && fs->mtd != NULL && src != NULL && len > 0); @@ -118,8 +131,8 @@ ssize_t spiffs_mtd_write(FAR struct spiffs_s *fs, off_t offset, size_t len, blkstart = offset / blksize; blkend = (offset + len - 1) / blksize; - finfo("blkoffset=%lu blkstart=%ld blkend=%ld\n", - blkoffset, blkstart, blkend); + spiffs_mtdinfo("blkoffset=%d blkstart=%ld blkend=%ld\n", + blkoffset, (long)blkstart, (long)blkend); /* Check if we have to do a read-modify-write on the first block. We * need to do this if the blkoffset is not zero. In that case we need @@ -128,11 +141,10 @@ ssize_t spiffs_mtd_write(FAR struct spiffs_s *fs, off_t offset, size_t len, if (blkoffset != 0) { - FAR uint8_t *wptr = fs->work; - size_t maxcopy; - ssize_t nbytes; + FAR uint8_t *wptr = fs->mtd_work; + int16_t maxcopy; + int16_t nbytes; -#warning "REVISIT: is fs->work available here?" ret = MTD_BREAD(fs->mtd, blkstart, 1, wptr); if (ret < 0) { @@ -140,15 +152,23 @@ ssize_t spiffs_mtd_write(FAR struct spiffs_s *fs, off_t offset, size_t len, return (ssize_t)ret; } + spiffs_mtd_dump("Read leading partial block", wptr, blksize); + /* Copy the data in place */ maxcopy = blksize - blkoffset; nbytes = MIN(remaining, maxcopy); + spiffs_mtdinfo("Leading partial block: " + "blkstart=%ld blkoffset=%d nbytes=%d\n", + (long)blkstart, blkoffset, nbytes); + memcpy(&wptr[blkoffset], src, nbytes); /* Write back the modified block */ + spiffs_mtd_dump("Write leading partial block", wptr, blksize); + ret = MTD_BWRITE(fs->mtd, blkstart, 1, wptr); if (ret < 0) { @@ -174,12 +194,14 @@ ssize_t spiffs_mtd_write(FAR struct spiffs_s *fs, off_t offset, size_t len, nblocks++; } - finfo("Whole blocks=%d blkstart=%lu remaining=%lu\n", - nblocks, (unsigned long)blkstart, - (unsigned long)remaining); + spiffs_mtdinfo("Whole blocks=%d blkstart=%lu remaining=%lu\n", + nblocks, (unsigned long)blkstart, + (unsigned long)remaining); if (nblocks > 0) { + spiffs_mtd_dump("Write whole blocks", src, blksize * nblocks); + ret = MTD_BWRITE(fs->mtd, blkstart, nblocks, src); if (ret < 0) { @@ -202,21 +224,30 @@ ssize_t spiffs_mtd_write(FAR struct spiffs_s *fs, off_t offset, size_t len, if (remaining > 0) { -#warning "REVISIT: is fs->work available here?" - ret = MTD_BREAD(fs->mtd, blkend, 1, fs->work); + ret = MTD_BREAD(fs->mtd, blkend, 1, fs->mtd_work); if (ret < 0) { ferr("ERROR: MTD_BREAD() failed: %d\n", ret); return (ssize_t)ret; } + spiffs_mtd_dump("Read trailing partial block", + fs->mtd_work, blksize); + /* Copy the data in place */ - memcpy(fs->work, src, remaining); + spiffs_mtdinfo("Trailing partial block: " + "blkend=%ld remaining=%lu\n", + (long)blkend, (unsigned long)remaining); + + memcpy(fs->mtd_work, src, remaining); /* Write back the modified block */ - ret = MTD_BWRITE(fs->mtd, blkend, 1, fs->work); + spiffs_mtd_dump("Write trailing partial block", + fs->mtd_work, blksize); + + ret = MTD_BWRITE(fs->mtd, blkend, 1, fs->mtd_work); if (ret < 0) { ferr("ERROR: MTD_BWRITE() failed: %d\n", ret); @@ -249,16 +280,19 @@ ssize_t spiffs_mtd_write(FAR struct spiffs_s *fs, off_t offset, size_t len, ssize_t spiffs_mtd_read(FAR struct spiffs_s *fs, off_t offset, size_t len, FAR uint8_t *dest) { - int16_t blksize; - int16_t nblocks; - size_t blkoffset; +#ifdef CONFIG_SPIFFS_MTDDUMP + FAR uint8_t *saved_dest = dest; +#endif size_t remaining; ssize_t ret; off_t blkmask; off_t blkstart; off_t blkend; + int16_t blksize; + int16_t nblocks; + int16_t blkoffset; - finfo("offset=%ld len=%lu\n", (long)offset, (unsigned long)len); + spiffs_mtdinfo("offset=%ld len=%lu\n", (long)offset, (unsigned long)len); DEBUGASSERT(fs != NULL && fs->mtd != NULL && dest != NULL && len > 0); @@ -285,8 +319,8 @@ ssize_t spiffs_mtd_read(FAR struct spiffs_s *fs, off_t offset, size_t len, blkstart = offset / blksize; blkend = (offset + len - 1) / blksize; - finfo("blkoffset=%lu blkstart=%ld blkend=%ld\n", - blkoffset, blkstart, blkend); + spiffs_mtdinfo("blkoffset=%d blkstart=%ld blkend=%ld\n", + blkoffset, (long)blkstart, (long)blkend); /* Check if we have to do a partial read on the first block. We * need to do this if the blkoffset is not zero. In that case we need @@ -295,11 +329,10 @@ ssize_t spiffs_mtd_read(FAR struct spiffs_s *fs, off_t offset, size_t len, if (blkoffset != 0) { - FAR uint8_t *wptr = fs->work; + FAR uint8_t *wptr = fs->mtd_work; size_t maxcopy; ssize_t nbytes; -#warning "REVISIT: is fs->work available here?" ret = MTD_BREAD(fs->mtd, blkstart, 1, wptr); if (ret < 0) { @@ -307,11 +340,17 @@ ssize_t spiffs_mtd_read(FAR struct spiffs_s *fs, off_t offset, size_t len, return (ssize_t)ret; } + spiffs_mtd_dump("Read leading partial block", wptr, blksize); + /* Copy the data from the block */ maxcopy = blksize - blkoffset; nbytes = MIN(remaining, maxcopy); + spiffs_mtdinfo("Leading partial block: " + "blkstart=%ld blkoffset=%d nbytes=%d\n", + (long)blkstart, blkoffset, nbytes); + memcpy(dest, &wptr[blkoffset], nbytes); /* Update block numbers and counts */ @@ -332,9 +371,9 @@ ssize_t spiffs_mtd_read(FAR struct spiffs_s *fs, off_t offset, size_t len, nblocks++; } - finfo("Whole blocks=%d blkstart=%lu remaining=%lu\n", - nblocks, (unsigned long)blkstart, - (unsigned long)remaining); + spiffs_mtdinfo("Whole blocks=%d blkstart=%lu remaining=%lu\n", + nblocks, (unsigned long)blkstart, + (unsigned long)remaining); if (nblocks > 0) { @@ -345,6 +384,8 @@ ssize_t spiffs_mtd_read(FAR struct spiffs_s *fs, off_t offset, size_t len, return (ssize_t)ret; } + spiffs_mtd_dump("Read whole blocks", dest, blksize * nblocks); + dest += (remaining & ~blkmask); remaining = (remaining & blkmask); @@ -360,8 +401,7 @@ ssize_t spiffs_mtd_read(FAR struct spiffs_s *fs, off_t offset, size_t len, if (remaining > 0) { -#warning "REVISIT: is fs->work available here?" - ret = MTD_BREAD(fs->mtd, blkend, 1, fs->work); + ret = MTD_BREAD(fs->mtd, blkend, 1, fs->mtd_work); if (ret < 0) { ferr("ERROR: MTD_BREAD() failed: %d\n", ret); @@ -370,10 +410,17 @@ ssize_t spiffs_mtd_read(FAR struct spiffs_s *fs, off_t offset, size_t len, /* Copy the data from the block */ - memcpy(dest, fs->work, remaining); + spiffs_mtdinfo("Trailing partial block: " + "blkend=%ld remaining=%lu\n", + (long)blkend, (unsigned long)remaining); + spiffs_mtd_dump("Read trailing partial block", + fs->mtd_work, blksize); + + memcpy(dest, fs->mtd_work, remaining); } } + spiffs_mtd_dump("Read", saved_dest, len); return (ssize_t)len; } @@ -401,7 +448,7 @@ ssize_t spiffs_mtd_erase(FAR struct spiffs_s *fs, off_t offset, size_t len) off_t eblkend; ssize_t nerased; - finfo("offset=%ld len=%lu\n", (long)offset, (unsigned long)len); + spiffs_mtdinfo("offset=%ld len=%lu\n", (long)offset, (unsigned long)len); DEBUGASSERT(fs != NULL && fs->mtd != NULL); diff --git a/fs/spiffs/src/spiffs_mtd.h b/fs/spiffs/src/spiffs_mtd.h index 6d8e078e05..7eaf6c9495 100644 --- a/fs/spiffs/src/spiffs_mtd.h +++ b/fs/spiffs/src/spiffs_mtd.h @@ -66,6 +66,24 @@ extern "C" #define SPIFFS_GEO_PAGE_SIZE(fs) ((fs)->geo.blocksize) #define SPIFFS_GEO_PAGES_PER_BLOCK(fs) ((fs)->pages_per_block) +/* Debug */ + +#ifdef CONFIG_SPIFFS_MTDDBG +# ifdef CONFIG_CPP_HAVE_VARARGS +# define spiffs_mtdinfo(format, ...) _info(format, ##__VA_ARGS__) +# else +# define spiffs_mtdinfo _info +# endif +#else +# ifdef CONFIG_CPP_HAVE_VARARGS +# define spiffs_mtdinfo(format, ...) +# else +# define spiffs_mtdinfo (void) +# endif +#endif + +/* Commonly used Macros */ + #ifndef MIN # define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif diff --git a/fs/spiffs/src/spiffs_vfs.c b/fs/spiffs/src/spiffs_vfs.c index 897628ab0b..631847fa02 100644 --- a/fs/spiffs/src/spiffs_vfs.c +++ b/fs/spiffs/src/spiffs_vfs.c @@ -1355,13 +1355,16 @@ static int spiffs_bind(FAR struct inode *mtdinode, FAR const void *data, spiffs_cache_initialize(fs); - /* Allocate the memory work buffer comprising 2*config->page_size bytes + /* Allocate the memory work buffer comprising 3*config->page_size bytes * used throughout all file system operations. * * NOTE: Currently page size is equivalent to block size. + * + * REVISIT: The MTD work buffer was added. With some careful analysis, + * it should, however, be possible to get by with fewer page buffers. */ - work_size = SPIFFS_GEO_PAGE_SIZE(fs) << 1; + work_size = 3 * SPIFFS_GEO_PAGE_SIZE(fs); work = (FAR uint8_t *)kmm_malloc(work_size); if (work == NULL) @@ -1371,8 +1374,9 @@ static int spiffs_bind(FAR struct inode *mtdinode, FAR const void *data, goto errout_with_cache; } - fs->work = &work[0]; - fs->lu_work = &work[work_size >> 1]; + fs->work = &work[0]; + fs->lu_work = &work[SPIFFS_GEO_PAGE_SIZE(fs)]; + fs->mtd_work = &work[2 * SPIFFS_GEO_PAGE_SIZE(fs)]; (void)nxsem_init(&fs->exclsem.sem, 0, 1);