You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/01/09 13:17:11 UTC

[incubator-nuttx] branch master updated: smartfs improvements #66

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new ecfdd6e  smartfs improvements #66
ecfdd6e is described below

commit ecfdd6e05632ca807cbb05cf4760eabfb5dd0f84
Author: Alin Jerpelea <al...@sony.com>
AuthorDate: Thu Jan 9 10:14:39 2020 -0300

    smartfs improvements #66
    
    Author: Alan Carvalho de Assis <ac...@gmail.com>
    
        Run nxstyle on all .c and .h and fix all issues
    
    Author: Alin Jerpelea <al...@sony.com>
    
        drivers: mtd: smart: Add smartfs fsck feature
    
        Support fsck to check and repair the smartfs file system. If the power
        loss occurs during writing into the flash, the dead space are created
        in flash after the next power cycle. To avoid this problem, introduce
        fsck and keep the consistency of file system in initializing smartfs.
    
        Signed-off-by: Alin Jerpelea <al...@sony.com>
    
    commit 60927c5fb6a353994341601f55071c618e97682b
    Author: Alin Jerpelea <al...@sony.com>
    Date:   Thu Dec 28 18:27:21 2017 +0900
    
        drivers: mtd: smart: Fix duplicate sector selection in SmartFS
    
        Add care for 16-bit sequence without CRC.
    
        drivers: mtd: smart: Check CRC of duplicate sectors
    
        In the illegal case by power-loss, when the multiple logical sectors are
        duplicated, we compare the sequence number of each sector and select the newer
        sector. Just in case, add CRC check for the newer sector. If the newer sector
        has CRC error, then we use the older sector.
    
        drivers: mtd: smart: SPI-Flash recovery from the initial error state
    
        The FLASH may be not erased in the initial delivery state.
        Just in case for the recovery of this fatal situation,
        after once erasing the sector, return the sector as a free sector.
    
        drivers: mtd: smart: Fix error handling in smartfs mtd driver
    
        Add error handling in relocate sector.
    
        drivers: mtd: smart: Fix initialize sector sequence value in smartfs
    
        Fix initialization of sequence value into sector header and also avoid
        unaligned memory access when CONFIG_MTD_SMART_ENABLE_CRC=n.
    
        drivers: mtd: smart: Fix handling of duplicate sector in smartfs
    
        In smartfs scan, if duplicate logical sector is found on the device,
        then smartfs selects the winner sector by comparing sequence number,
        and the loser sector is soon released. Fix a bug this loser sector
        is registered into logical-to-physical sector mapping table.
---
 drivers/mtd/Kconfig |  15 ++
 drivers/mtd/smart.c | 646 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 646 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index a80159d..e987fd6 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -775,6 +775,21 @@ config SMART_CRC_16
 
 endchoice # CRC level selection
 
+config MTD_SMART_FSCK
+	bool "Enable SMART file system check"
+	default n
+	depends on FS_WRITABLE
+	---help---
+		Enables fsck to check and repair the SMART file system.
+
+config MTD_SMART_FSCK_ENABLE_CRC
+	bool "Enable SMART file system CRC check during fsck"
+	default n
+	depends on MTD_SMART_FSCK && MTD_SMART_ENABLE_CRC
+	---help---
+		Enables CRC check during fsck. It's possible to check the file
+		system strictly, but it takes long time to do fsck.
+
 config MTD_SMART_MINIMIZE_RAM
 	bool "Minimize SMART RAM usage using logical sector cache"
 	depends on MTD_SMART
diff --git a/drivers/mtd/smart.c b/drivers/mtd/smart.c
index b7a5954..c239fe0 100644
--- a/drivers/mtd/smart.c
+++ b/drivers/mtd/smart.c
@@ -118,8 +118,8 @@
 
 #define SMART_FIRST_DIR_SECTOR      3       /* First root directory sector */
 #define SMART_FIRST_ALLOC_SECTOR    12      /* First logical sector number we will
-                                             * use for assignment of requested Alloc
-                                             * sectors.  All entries below this are
+                                             * use for assignment of requested alloc
+                                             * sectors. All entries below this are
                                              * reserved (some for root dir entries,
                                              * other for our use, such as format
                                              * sector, etc. */
@@ -156,6 +156,10 @@
 #define SMART_WEARFLAGS_FORCE_REORG         0x01
 #define SMART_WEARFLAGS_WRITE_NEEDED        0x02
 
+#define SET_BITMAP(m, n) do { (m)[(n) / 8] |= 1 << ((n) % 8); } while (0)
+#define CLR_BITMAP(m, n) do { (m)[(n) / 8] &= ~(1 << ((n) % 8)); } while (0)
+#define ISSET_BITMAP(m, n) ((m)[(n) / 8] & (1 << ((n) % 8)))
+
 #ifdef CONFIG_MTD_SMART_WEAR_LEVEL
 
 /****************************************************************************
@@ -364,6 +368,36 @@ typedef uint32_t crc_t;
 
 #endif
 
+/* Following two definitions copied from internal definition of fs/smartfs.
+ * Because needed to search chain_header and entry_header.
+ */
+
+#if defined(CONFIG_MTD_SMART_ENABLE_CRC) && defined(CONFIG_SMART_CRC_32)
+struct smart_chain_header_s
+{
+  uint8_t           nextsector[4];/* Next logical sector in the chain */
+  uint8_t           used[4];      /* Number of bytes used in this sector */
+  uint8_t           type;         /* Type of sector entry (file or dir) */
+};
+#else
+struct smart_chain_header_s
+{
+  uint8_t           type;         /* Type of sector entry (file or dir) */
+  uint8_t           nextsector[2];/* Next logical sector in the chain */
+  uint8_t           used[2];      /* Number of bytes used in this sector */
+};
+#endif
+
+struct smart_entry_header_s
+{
+  uint16_t          flags;        /* Flags, including permissions:
+                                   *  15:   Empty entry
+                                   *  14:   Active entry
+                                   *  12-0: Permissions bits */
+  int16_t           firstsector;  /* Sector number of the name */
+  uint32_t          utc;          /* Time stamp */
+};
+
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
@@ -391,6 +425,9 @@ static inline int smart_allocsector(FAR struct smart_struct_s *dev,
 #endif
 static int smart_readsector(FAR struct smart_struct_s *dev, unsigned long arg);
 
+#ifdef CONFIG_MTD_SMART_ENABLE_CRC
+static int smart_validate_crc(FAR struct smart_struct_s *dev);
+#endif
 #ifdef CONFIG_MTD_SMART_WEAR_LEVEL
 static int smart_read_wearstatus(FAR struct smart_struct_s *dev);
 static int smart_relocate_static_data(FAR struct smart_struct_s *dev, uint16_t block);
@@ -399,6 +436,10 @@ static int smart_relocate_static_data(FAR struct smart_struct_s *dev, uint16_t b
 static int smart_relocate_sector(FAR struct smart_struct_s *dev,
                  uint16_t oldsector, uint16_t newsector);
 
+#ifdef CONFIG_MTD_SMART_FSCK
+static int smart_fsck(FAR struct smart_struct_s *dev);
+#endif
+
 #ifdef CONFIG_SMART_DEV_LOOP
 static ssize_t smart_loop_read(FAR struct file *filep, FAR char *buffer,
                  size_t buflen);
@@ -657,7 +698,8 @@ static uint8_t smart_get_count(FAR struct smart_struct_s *dev,
 
       if (dev->sectorsperblk == 16)
         {
-          if (pcount[(dev->geo.neraseblocks >> 1) + (block >> 3)] & (1 << (block & 0x07)))
+          if (pcount[(dev->geo.neraseblocks >> 1) +
+              (block >> 3)] & (1 << (block & 0x07)))
             {
               count |= 0x10;
             }
@@ -1865,11 +1907,13 @@ static int smart_scan(FAR struct smart_struct_s *dev)
   uint16_t  totalsectors;
   uint16_t  sectorsize, prerelease;
   uint16_t  logicalsector;
+  uint16_t  winner;
   uint16_t  loser;
   uint32_t  readaddress;
   uint32_t  offset;
   uint16_t  seq1;
   uint16_t  seq2;
+  uint16_t  seqwrap;
   struct    smart_sect_header_s header;
 #ifdef CONFIG_MTD_SMART_MINIMIZE_RAM
   int       dupsector;
@@ -1991,10 +2035,16 @@ static int smart_scan(FAR struct smart_struct_s *dev)
 
   /* Now scan the MTD device */
 
+  /* At first, set the loser sector as the invalid value */
+
+  loser = totalsectors;
+
   for (sector = 0; sector < totalsectors; sector++)
     {
       finfo("Scan sector %d\n", sector);
 
+      winner = sector;
+
       /* Calculate the read address for this sector */
 
       readaddress = sector * dev->mtdblkspersector * dev->geo.blocksize;
@@ -2169,7 +2219,8 @@ static int smart_scan(FAR struct smart_struct_s *dev)
            */
 
 #if SMART_STATUS_VERSION == 1
-          if (header.status & SMART_STATUS_CRC)
+          if ((header.status & SMART_STATUS_CRC) !=
+                  (CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_CRC))
             {
               seq2 = header.seq;
             }
@@ -2256,27 +2307,31 @@ static int smart_scan(FAR struct smart_struct_s *dev)
             }
 
 #if SMART_STATUS_VERSION == 1
-          if (header.status & SMART_STATUS_CRC)
+          if ((header.status & SMART_STATUS_CRC) !=
+                  (CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_CRC))
             {
               seq1 = header.seq;
+              seqwrap = 0xf0;
             }
           else
             {
               seq1 = *((FAR uint16_t *) &header.seq);
+              seqwrap = 0xfff0;
             }
 #else
           seq1 = header.seq;
+          seqwrap = 0xf0;
 #endif
 
           /* Now determine who wins */
 
-          if ((seq1 > 0xfff0 && seq2 < 10) || seq2 > seq1)
+          if ((seq1 > seqwrap && seq2 < 10) || seq2 > seq1)
             {
               /* Seq 2 is the winner ... bigger or it wrapped */
 
+              winner = sector;
 #ifndef CONFIG_MTD_SMART_MINIMIZE_RAM
               loser = dev->smap[logicalsector];
-              dev->smap[logicalsector] = sector;
 #else
               loser = dupsector;
 #endif
@@ -2286,8 +2341,57 @@ static int smart_scan(FAR struct smart_struct_s *dev)
               /* We keep the original mapping and seq2 is the loser */
 
               loser = sector;
+#ifndef CONFIG_MTD_SMART_MINIMIZE_RAM
+              winner = dev->smap[logicalsector];
+#else
+              winner = smart_cache_lookup(dev, logicalsector);
+#endif
             }
 
+          finfo("Duplicate Sector winner=%d, loser=%d\n", winner, loser);
+
+#ifdef CONFIG_MTD_SMART_ENABLE_CRC
+          /* Check CRC of the winner sector just in case */
+
+          ret = MTD_BREAD(dev->mtd, winner * dev->mtdblkspersector,
+                          dev->mtdblkspersector, (FAR uint8_t *) dev->rwbuffer);
+          if (ret == dev->mtdblkspersector)
+            {
+              /* Validate the CRC of the read-back data */
+
+              ret = smart_validate_crc(dev);
+            }
+
+          if (ret != OK)
+            {
+              /* The winner sector has CRC error, so we select the loser sector.
+               * After swapping the winner and the loser sector, we will release
+               * the loser sector with CRC error.
+               */
+
+              if (sector == winner)
+                {
+                  /* winner: sector(CRC error) -> origin
+                   * loser : origin            -> sector(CRC error)
+                   */
+
+                  winner = loser;
+                  loser = sector;
+                }
+              else
+                {
+                  /* winner: origin(CRC error) -> sector
+                   * loser : sector            -> origin(CRC error)
+                   */
+
+                  loser = winner;
+                  winner = sector;
+                }
+
+              finfo("Duplicate Sector winner=%d, loser=%d\n", winner, loser);
+            }
+#endif  /* CONFIG_MTD_SMART_ENABLE_CRC */
+
           /* Now release the loser sector */
 
           readaddress = loser  * dev->mtdblkspersector * dev->geo.blocksize;
@@ -2312,10 +2416,17 @@ static int smart_scan(FAR struct smart_struct_s *dev)
             }
         }
 
+      /* Test if this sector is loser of duplicate logical sector */
+
+      if (sector == loser)
+        {
+          continue;
+        }
+
 #ifndef CONFIG_MTD_SMART_MINIMIZE_RAM
       /* Update the logical to physical sector map */
 
-      dev->smap[logicalsector] = sector;
+      dev->smap[logicalsector] = winner;
 #else
       /* Mark the logical sector as used in the bitmap */
 
@@ -2323,7 +2434,7 @@ static int smart_scan(FAR struct smart_struct_s *dev)
 
       if (logicalsector < SMART_FIRST_ALLOC_SECTOR)
         {
-          smart_add_sector_to_cache(dev, logicalsector, sector, __LINE__);
+          smart_add_sector_to_cache(dev, logicalsector, winner, __LINE__);
         }
 #endif
     }
@@ -2403,6 +2514,9 @@ static int smart_scan(FAR struct smart_struct_s *dev)
 #endif  /* CONFIG_MTD_SMART_CONVERT_WEAR_FORMAT */
 #endif  /* CONFIG_MTD_SMART_WEAR_LEVEL && SMART_STATUS_VERSION == 1 */
 
+#ifdef CONFIG_MTD_SMART_FSCK
+  smart_fsck(dev);
+#endif
 #ifdef CONFIG_MTD_SMART_WEAR_LEVEL
   /* Read the wear leveling status bits */
 
@@ -3156,7 +3270,8 @@ static int smart_relocate_sector(FAR struct smart_struct_s *dev,
   /* Increment the sequence number and clear the "commit" flag */
 
 #if SMART_STATUS_VERSION == 1
-  if (header->status & SMART_STATUS_CRC)
+  if ((header->status & SMART_STATUS_CRC) !=
+          (CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_CRC))
     {
 #endif
       /* Using 8-bit sequence */
@@ -3209,6 +3324,11 @@ static int smart_relocate_sector(FAR struct smart_struct_s *dev,
 
   ret = MTD_BWRITE(dev->mtd, newsector * dev->mtdblkspersector,
                    dev->mtdblkspersector, (FAR uint8_t *) dev->rwbuffer);
+  if (ret != dev->mtdblkspersector)
+    {
+      ferr("Error writing to new sector %d\n", newsector);
+      goto errout;
+    }
 
 #else   /* CONFIG_MTD_SMART_ENABLE_CRC */
 
@@ -3222,6 +3342,11 @@ static int smart_relocate_sector(FAR struct smart_struct_s *dev,
 
   ret = MTD_BWRITE(dev->mtd, newsector * dev->mtdblkspersector,
                    dev->mtdblkspersector, (FAR uint8_t *) dev->rwbuffer);
+  if (ret != dev->mtdblkspersector)
+    {
+      ferr("Error writing to new sector %d\n", newsector);
+      goto errout;
+    }
 
   /* Commit the sector */
 
@@ -3255,10 +3380,7 @@ static int smart_relocate_sector(FAR struct smart_struct_s *dev,
       ferr("ERROR: Error %d releasing old sector %d\n" -ret, oldsector);
     }
 
-#ifndef CONFIG_MTD_SMART_ENABLE_CRC
 errout:
-#endif
-
   return ret;
 }
 
@@ -3762,6 +3884,21 @@ retry:
           dev->lastallocblock = allocblock;
           break;
         }
+      else
+        {
+          /* The FLASH may be not erased in the initial delivery state.
+           * Just in case for the recovery of this fatal situation,
+           * after once erasing the sector, return the sector as a free sector.
+           */
+
+          if (1 == dev->availsectperblk)
+            {
+              MTD_ERASE(dev->mtd, allocblock, 1);
+              physicalsector = i;
+              dev->lastallocblock = allocblock;
+              break;
+            }
+        }
     }
 
   if (physicalsector == 0xffff)
@@ -4202,7 +4339,7 @@ static int smart_write_alloc_sector(FAR struct smart_struct_s *dev,
 #ifdef CONFIG_MTD_SMART_ENABLE_CRC
   header->seq = 0;
 #else
-  *((FAR uint16_t *) &header->crc8) = 0;
+  *((FAR uint16_t *) &header->seq) = 0;
 #endif  /* CONFIG_MTD_SMART_ENABLE_CRC */
 #else
   header->seq = 0;
@@ -4483,7 +4620,8 @@ static int smart_writesector(FAR struct smart_struct_s *dev,
       /* Update the sequence number to indicate the sector was moved */
 
 #if SMART_STATUS_VERSION == 1
-      if (header->status & SMART_STATUS_CRC)
+      if ((header->status & SMART_STATUS_CRC) !=
+              (CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_CRC))
         {
 #endif
           header->seq++;
@@ -5416,6 +5554,484 @@ ok_out:
   return ret;
 }
 
+#ifdef CONFIG_MTD_SMART_FSCK
+
+/****************************************************************************
+ * Name: smart_fsck_crc
+ *
+ * Description: Validate CRC to check smartfs filesystem
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_MTD_SMART_FSCK_ENABLE_CRC
+static int smart_fsck_crc(FAR struct smart_struct_s *dev, uint16_t physsector)
+{
+  int ret;
+
+  ret = MTD_BREAD(dev->mtd, physsector * dev->mtdblkspersector,
+                  dev->mtdblkspersector, (FAR uint8_t *)dev->rwbuffer);
+  if (ret != dev->mtdblkspersector)
+    {
+      ferr("ERROR: Error reading phys sector %d\n", physsector);
+      return ret;
+    }
+
+  ret = smart_validate_crc(dev);
+  if (ret != OK)
+    {
+      ferr("ERROR: Error validating sector %d CRC\n", physsector);
+      return ret;
+    }
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: smart_fsck_file
+ *
+ * Description: fsck for file entry
+ *
+ ****************************************************************************/
+
+static int smart_fsck_file(FAR struct smart_struct_s *dev,
+                           FAR uint8_t *checkmap, uint16_t logsector)
+{
+  int                               ret = OK;
+  ssize_t                           size;
+  uint32_t                          readaddress;
+  FAR struct smart_sect_header_s    *header;
+  FAR struct smart_chain_header_s   *chain;
+  FAR uint8_t                       *usedmap;
+  size_t                            mapsize;
+  uint16_t                          physsector;
+  int                               i;
+
+  if (logsector >= dev->totalsectors)
+    {
+      ret = -EINVAL;
+      return ret;
+    }
+
+  /* Allocate a bitmap table for sectors this file is using */
+
+  mapsize = (dev->totalsectors + 7) / 8;
+  usedmap = (FAR uint8_t *)kmm_zalloc(mapsize);
+  if (!usedmap)
+    {
+      ferr("ERROR: Out of memory used map\n");
+      return OK;
+    }
+
+  do
+    {
+      /* Read the header for file sector */
+
+#ifndef CONFIG_MTD_SMART_MINIMIZE_RAM
+      physsector = dev->smap[logsector];
+#else
+      physsector = smart_cache_lookup(dev, logsector);
+#endif
+
+      if (physsector >= dev->totalsectors)
+        {
+          ret = -ENXIO;
+          ferr("ERROR: Invalid phys sector %d\n", physsector);
+          break;
+        }
+
+#ifdef CONFIG_MTD_SMART_FSCK_ENABLE_CRC
+      if (smart_fsck_crc(dev, physsector) != OK)
+        {
+          ret = -ENOENT;
+          ferr("ERROR: CRC phys sector %d\n", physsector);
+          break;
+        }
+#endif
+
+      readaddress = physsector * dev->mtdblkspersector * dev->geo.blocksize;
+      size = MTD_READ(dev->mtd, readaddress,
+                      sizeof(struct smart_sect_header_s) +
+                      sizeof(struct smart_chain_header_s),
+                      (uint8_t *)dev->rwbuffer);
+      if (size != (sizeof(struct smart_sect_header_s) +
+                   sizeof(struct smart_chain_header_s)))
+        {
+          ret = -EIO;
+          ferr("Error reading phys sector %d\n", physsector);
+          break;
+        }
+
+      header = (struct smart_sect_header_s *) & dev->rwbuffer[0];
+      chain = (struct smart_chain_header_s *) &
+               dev->rwbuffer[sizeof(struct smart_sect_header_s)];
+
+      /* Test if the sector has live data (not free or not released) */
+
+      if (((header->status & SMART_STATUS_COMMITTED) ==
+           (CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_COMMITTED)) ||
+          ((header->status & SMART_STATUS_RELEASED) !=
+           (CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_RELEASED)))
+        {
+          ret = -ENOENT;
+          ferr("ERROR: status(%02x) phys sector %d\n", header->status, physsector);
+          break;
+        }
+
+      SET_BITMAP(usedmap, logsector);
+
+      /* next logical sector */
+
+      logsector = *(uint16_t *)chain->nextsector;
+    }
+  while (logsector != 0xffff);
+
+  if (ret == OK)
+    {
+      /* These sectors in use are not removed */
+
+      for (i = 0; i < mapsize; i++)
+        {
+          checkmap[i] &= ~usedmap[i];
+        }
+    }
+  else
+    {
+      /* This file has any corruption, these sectors will be removed */
+
+      for (i = 0; i < mapsize; i++)
+        {
+          checkmap[i] |= usedmap[i];
+        }
+    }
+
+  kmm_free(usedmap);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: smart_fsck_directory
+ *
+ * Description: fsck for directory entry
+ *
+ ****************************************************************************/
+
+static int smart_fsck_directory(FAR struct smart_struct_s *dev,
+                                FAR uint8_t *checkmap, uint16_t logsector)
+{
+  int                               ret = OK;
+  int                               relocate = 0;
+  ssize_t                           size;
+  FAR uint8_t                       *rwbuffer;
+  FAR struct smart_sect_header_s    *header;
+  FAR struct smart_chain_header_s   *chain;
+  FAR struct smart_entry_header_s   *entry;
+  uint16_t                          entrysector;
+  uint16_t                          physsector;
+  uint16_t                          nextsector;
+  uint16_t                          newsector;
+  int                               entrysize;
+  FAR uint8_t                       *bottom;
+  FAR uint8_t                       *cur;
+#ifdef CONFIG_DEBUG_FS_INFO
+  char                              entryname[dev->namesize + 1];
+#endif
+
+  if ((logsector < SMART_FIRST_DIR_SECTOR) || (logsector >= dev->totalsectors))
+    {
+      ret = -EINVAL;
+      ferr("ERROR: Invalid log sector %d\n", logsector);
+      return ret;
+    }
+
+  /* Allocate sector buffer for Directory entry */
+
+  rwbuffer = (uint8_t *)kmm_malloc(dev->sectorsize);
+  if (!rwbuffer)
+    {
+      ferr("ERROR: Out of memory sector buffer\n");
+      return OK;
+    }
+
+  /* Read the Directory entry sector */
+
+#ifndef CONFIG_MTD_SMART_MINIMIZE_RAM
+  physsector = dev->smap[logsector];
+#else
+  physsector = smart_cache_lookup(dev, logsector);
+#endif
+  if (physsector >= dev->totalsectors)
+    {
+      ret = -ENXIO;
+      ferr("ERROR: Invalid phys sector %d\n", physsector);
+      goto errout;
+    }
+
+  size = MTD_BREAD(dev->mtd, physsector * dev->mtdblkspersector,
+                   dev->mtdblkspersector, rwbuffer);
+  if (size != dev->mtdblkspersector)
+    {
+      ret = -EIO;
+      ferr("ERROR: reading phys sector %d\n", physsector);
+      goto errout;
+    }
+
+  header = (struct smart_sect_header_s *) & rwbuffer[0];
+  chain = (struct smart_chain_header_s *) &
+           rwbuffer[sizeof(struct smart_sect_header_s)];
+  entry = (struct smart_entry_header_s *) &
+           rwbuffer[sizeof(struct smart_sect_header_s) +
+                    sizeof(struct smart_chain_header_s)];
+
+#ifdef CONFIG_MTD_SMART_FSCK_ENABLE_CRC
+  /* Check CRC */
+
+  if (smart_fsck_crc(dev, physsector) != OK)
+    {
+      ret = -ENOENT;
+      ferr("ERROR: CRC phys sector %d\n", physsector);
+      goto errout;
+    }
+#endif
+
+  /* Test if the sector has live data (not free or not released) */
+
+  if (((header->status & SMART_STATUS_COMMITTED) ==
+       (CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_COMMITTED)) ||
+      ((header->status & SMART_STATUS_RELEASED) !=
+       (CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_RELEASED)))
+    {
+      ret = -ENOENT;
+      ferr("ERROR: status(%02x) phys sector %d\n", header->status, physsector);
+      goto errout;
+    }
+
+  /* Check next sector recursively */
+
+  nextsector = *(uint16_t *)chain->nextsector;
+
+  if (nextsector != 0xffff)
+    {
+      finfo("Check next log sector %d\n", nextsector);
+
+      ret = smart_fsck_directory(dev, checkmap, nextsector);
+
+      if (ret != OK)
+        {
+          /* Invalidate the next sector */
+
+          ferr("Invalidate next log sector %d\n", nextsector);
+
+          *(uint16_t *)chain->nextsector = 0xffff;
+        }
+    }
+
+#define SMARTFS_DIRENT_EMPTY      0x8000  /* Set to non-erase state when entry used */
+#define SMARTFS_DIRENT_ACTIVE     0x4000  /* Set to erase state when entry is active */
+#define SMARTFS_DIRENT_TYPE       0x2000  /* Indicates the type of entry (file/dir) */
+#define SMARTFS_DIRENT_DELETING   0x1000  /* Directory entry is being deleted */
+#define SMARTFS_DIRENT_RESERVED   0x0E00  /* Reserved bits */
+
+  /* Check file or directory under this directory entry */
+
+  entrysize = sizeof(struct smart_entry_header_s) + dev->namesize;
+  bottom = rwbuffer + dev->sectorsize;
+  cur = &rwbuffer[sizeof(struct smart_sect_header_s) +
+                  sizeof(struct smart_chain_header_s)];
+
+  while ((cur + entrysize) <= bottom)
+    {
+      ret = OK;
+
+      entry = (struct smart_entry_header_s *)cur;
+
+      if (entry->flags == 0xffff)
+        {
+          /* Test if the empty entry is exist or not? */
+
+          break;
+        }
+
+#ifdef CONFIG_DEBUG_FS_INFO
+      strncpy(entryname,
+              (const char *) (cur + sizeof(struct smart_entry_header_s)),
+              dev->namesize);
+      entryname[dev->namesize] = '\0';
+#endif
+      finfo("Check entry (name=%s flags=%02x logsector=%02x)\n",
+            entryname, entry->flags, entry->firstsector);
+
+      if (entry->flags & SMARTFS_DIRENT_ACTIVE)
+        {
+          entrysector = entry->firstsector;
+
+          if (entry->flags & SMARTFS_DIRENT_TYPE)
+            {
+              /* This entry is for directory */
+
+              ret = smart_fsck_directory(dev, checkmap, entrysector);
+            }
+          else
+            {
+              /* This entry is for file */
+
+              ret = smart_fsck_file(dev, checkmap, entrysector);
+            }
+        }
+
+      if (ret != OK)
+        {
+          finfo("Remove entry (name=%s flags=%02x)\n", entryname, entry->flags);
+          if ((cur + (2 * entrysize)) <= bottom)
+            {
+              /* Truncate the current entry and overwrite with next entries */
+
+              memmove(cur, cur + entrysize, bottom - (cur + entrysize));
+              memset(bottom - entrysize, CONFIG_SMARTFS_ERASEDSTATE, entrysize);
+            }
+          else
+            {
+              /* Only erase the current entry if next entry does not
+               * exist
+               */
+
+              memset(cur, CONFIG_SMARTFS_ERASEDSTATE, entrysize);
+              cur += entrysize;
+            }
+
+          relocate = 1;
+        }
+      else
+        {
+          cur += entrysize;
+        }
+    }
+
+  /* Relocate sector */
+
+  if (relocate)
+    {
+      newsector = smart_findfreephyssector(dev, FALSE);
+      if (newsector == 0xffff)
+        {
+          ret = -ENOSPC;
+          ferr("Can't find a free sector for relocation\n");
+          goto errout;
+        }
+
+      memcpy(dev->rwbuffer, rwbuffer, dev->sectorsize);
+
+      ret = smart_relocate_sector(dev, physsector, newsector);
+      if (ret < 0)
+        {
+          ret = -EIO;
+          ferr("Can't relocate\n");
+          goto errout;
+        }
+
+      /* Update the variables */
+
+#ifndef CONFIG_MTD_SMART_MINIMIZE_RAM
+      dev->smap[*((FAR uint16_t *)header->logicalsector)] = newsector;
+#else
+      smart_update_cache(dev, *((FAR uint16_t *)header->logicalsector), newsector);
+#endif
+
+#ifdef CONFIG_MTD_SMART_PACK_COUNTS
+      smart_add_count(dev, dev->freecount, newsector / dev->sectorsperblk, -1);
+#else
+      dev->freecount[newsector / dev->sectorsperblk]--;
+#endif
+    }
+
+  kmm_free(rwbuffer);
+  CLR_BITMAP(checkmap, logsector);
+  return OK;
+
+errout:
+  kmm_free(rwbuffer);
+  SET_BITMAP(checkmap, logsector);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: smart_fsck
+ *
+ * Description: Check and repair the file system
+ *
+ ****************************************************************************/
+
+static int smart_fsck(FAR struct smart_struct_s *dev)
+{
+  uint16_t      logsector;
+#ifndef CONFIG_MTD_SMART_MINIMIZE_RAM
+  uint16_t      physsector;
+#endif
+  FAR uint8_t   *checkmap;
+  size_t        mapsize;
+  uint8_t       rootdirentries;
+  int           x;
+
+  finfo("Entry\n");
+
+  /* Allocate a bitmap table for filesystem check */
+
+  mapsize = (dev->totalsectors + 7) / 8;
+  checkmap = (FAR uint8_t *)kmm_zalloc(mapsize);
+  if (!checkmap)
+    {
+      ferr("ERROR: Out of memory fsck map\n");
+      return -ENOMEM;
+    }
+
+  /* Set all of the sectors have live data into the check bitmap */
+
+#ifndef CONFIG_MTD_SMART_MINIMIZE_RAM
+  for (logsector = 0; logsector < dev->totalsectors; logsector++)
+    {
+      physsector = dev->smap[logsector];
+      if (physsector < dev->totalsectors)
+        {
+          SET_BITMAP(checkmap, logsector);
+        }
+    }
+#else
+  memcpy(checkmap, dev->sbitmap, mapsize);
+#endif
+
+  /* Check if the sector can be available from root directories */
+
+#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS
+  rootdirentries = dev->rootdirentries;
+#else
+  rootdirentries = 1;
+#endif
+
+  for (x = 0; x < rootdirentries; x++)
+    {
+      smart_fsck_directory(dev, checkmap, SMART_FIRST_DIR_SECTOR + x);
+    }
+
+  /* Release the invalid sector except for format or directory entry sector */
+
+  for (logsector = SMART_FIRST_ALLOC_SECTOR;
+       logsector < dev->totalsectors; logsector++)
+    {
+      if (ISSET_BITMAP(checkmap, logsector))
+        {
+          smart_freesector(dev, logsector);
+        }
+    }
+
+  /* Free the bitmap table for filesystem check */
+
+  kmm_free(checkmap);
+
+  return OK;
+}
+
+#endif /* CONFIG_MTD_SMART_FSCK */
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/