smartfs improvements #66

Author: Alan Carvalho de Assis <acassis@gmail.com>

    Run nxstyle on all .c and .h and fix all issues

Author: Alin Jerpelea <alin.jerpelea@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 <alin.jerpelea@sony.com>

commit 60927c5fb6a353994341601f55071c618e97682b
Author: Alin Jerpelea <alin.jerpelea@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.
This commit is contained in:
Alin Jerpelea 2020-01-09 10:14:39 -03:00 committed by Alan Carvalho de Assis
parent 255f3008cf
commit ecfdd6e056
2 changed files with 646 additions and 15 deletions

View file

@ -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

View file

@ -118,7 +118,7 @@
#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
* 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
@ -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
****************************************************************************/