SmartFS: Implements wear-leveling in the SmartFS. From Ken Pettit
This commit is contained in:
parent
69cb752813
commit
cdc8fc52d1
@ -394,6 +394,117 @@ config MTD_SMART_READAHEAD
|
||||
default n
|
||||
depends on DRVR_READAHEAD
|
||||
|
||||
config MTD_SMART_WEAR_LEVEL
|
||||
bool "Support FLASH wear leveling"
|
||||
depends on MTD_SMART
|
||||
default y
|
||||
---help---
|
||||
Adds extra logic and RAM to guarantee equal wear leveling of the FLASH
|
||||
device by recording and monitoring erase block operations and selecting
|
||||
sector allocations to ensure all erase blocks are worn evenly. This will
|
||||
evenly wear both dynamic and static data on the device.
|
||||
|
||||
if MTD_SMART_WEAR_LEVEL && !SMART_CRC_16
|
||||
|
||||
config MTD_SMART_CONVERT_WEAR_FORMAT
|
||||
bool "Convert existing non wear leveling FLASH to wear leveling"
|
||||
default n
|
||||
---help---
|
||||
Adds a little extra code which detects an existing SMART format on a device
|
||||
that was created prior to the wear leveling implementation. This conversion
|
||||
only works if either no CRC is being used or if CRC-8 is being used as other
|
||||
CRC versions use a different header format and require a mksmartfs on the
|
||||
device even if an existing format is there.
|
||||
|
||||
endif
|
||||
|
||||
config MTD_SMART_ENABLE_CRC
|
||||
bool "Enable Sector CRC error detection"
|
||||
depends on MTD_SMART
|
||||
default n
|
||||
---help---
|
||||
Enables logic to compute and validate a CRC for logical sectors. The
|
||||
CRC is calculated for all bytes in the logical sector. The CRC size is
|
||||
selectable (8-bit, 16-bit, 32-bit). For added protection, larger CRCs should
|
||||
be used with larger (2K - 4K) sector sizes. Enabling CRC protection will
|
||||
cause increased sector relocation and increased erase block erasures since
|
||||
directory and wear-level status updates can no longer be performed in-place
|
||||
and mandate re-writing the information to a new sector.
|
||||
|
||||
An 8-bit CRC protection scheme can be added to an existing non-CRC formatted
|
||||
SMART volume without needing to reformat the drive. As sectors are re-written
|
||||
or relocated, they will be converted to CRC protected sectors.
|
||||
|
||||
choice
|
||||
prompt "CRC level selection"
|
||||
depends on MTD_SMART_ENABLE_CRC
|
||||
default SMART_CRC_8
|
||||
---help---
|
||||
Select the level of CRC protection implemented in the SMART MTD layer.
|
||||
Smaller CRC selection uses less overhead per logical sectors, but also has
|
||||
a higher probability of not detecting multiple bit errors. Devices with
|
||||
larger logical sector sizes should use a larger CRC.
|
||||
|
||||
config SMART_CRC_8
|
||||
bool "CRC-8"
|
||||
|
||||
config SMART_CRC_16
|
||||
bool "CRC-16"
|
||||
|
||||
endchoice
|
||||
|
||||
config MTD_SMART_MINIMIZE_RAM
|
||||
bool "Minimize SMART RAM usage using logical sector cache"
|
||||
depends on MTD_SMART
|
||||
default 0
|
||||
---help---
|
||||
Reduces RAM usage in the SMART MTD layer by replacing the 1-for-1 logical to
|
||||
physical sector map with a smaller cache-based structure. This can save a
|
||||
considerable amount of RAM on devices with a large sector count, but at the
|
||||
expense of increased read/write times when a cache miss occurs. If the
|
||||
requested logical sector has not been cached, then the device will need to be
|
||||
scanned to located it on the physical medium.
|
||||
|
||||
config MTD_SMART_SECTOR_CACHE_SIZE
|
||||
int "Number of entries in the SMART logical sector cache"
|
||||
depends on MTD_SMART_MINIMIZE_RAM
|
||||
default 512
|
||||
---help---
|
||||
Sets the size of the cache used for logical to physical sector mapping. A
|
||||
larger number allows larger files to be "seek"ed randomly without encountering
|
||||
cache misses. Any files larger than CACH_SIZE * SECTOR_SIZE that are seeked
|
||||
start to end will cause the cache to flush forcing manual scanning of the
|
||||
MTD device to find the logical to physical mappings.
|
||||
|
||||
config MTD_SMART_SECTOR_PACK_COUNTS
|
||||
bool "Pack free and release counts when possible"
|
||||
depends on MTD_SMART_MINIMIZE_RAM
|
||||
default y
|
||||
---help---
|
||||
For volumes with 16 sectors per erase block or less, this option causes the
|
||||
free sector and released sector counts used for allocation and garbage
|
||||
collection to be packed such that two values are stored per byte. For
|
||||
volumes with 16 sectors per erase block, the 4 LSBs are packed and all of
|
||||
the high-order bits are packed separately (8 per byte). This squeezes even
|
||||
more RAM out.
|
||||
|
||||
config MTD_SMART_SECTOR_ERASE_DEBUG
|
||||
bool "Track Erase Block erasure counts"
|
||||
depends on MTD_SMART
|
||||
default n
|
||||
---help---
|
||||
Allocates an Erase Block erase count array and keeps track of the number
|
||||
of erases per erase block. This data is then presented on the procfs
|
||||
interface.
|
||||
|
||||
config MTD_SMART_ALLOC_DEBUG
|
||||
bool "RAM Allocation Debug"
|
||||
depends on MTD_SMART
|
||||
default n
|
||||
---help---
|
||||
Records all SMART MTD layer allocations for debug purposes and makes them
|
||||
accessible from the ProcFS interface if it is enabled.
|
||||
|
||||
endif # MTD_SMART
|
||||
|
||||
config MTD_RAMTRON
|
||||
|
0
drivers/mtd/mtd_nand.c
Executable file → Normal file
0
drivers/mtd/mtd_nand.c
Executable file → Normal file
3928
drivers/mtd/smart.c
3928
drivers/mtd/smart.c
File diff suppressed because it is too large
Load Diff
@ -52,4 +52,15 @@ config SMARTFS_MULTI_ROOT_DIRS
|
||||
|
||||
Default: y.
|
||||
|
||||
config SMARTFS_ALIGNED_ACCESS
|
||||
bool "Ensure 16 and 32 bit accesses are alined"
|
||||
default n
|
||||
---help---
|
||||
Performs little endian byte accesses to 16 and 32 values
|
||||
within the directory list to ensure processors that can't
|
||||
handle un-aligned accesses don't bomb out. Default should
|
||||
probably by 'Y', but set to 'N' in case any existing Big
|
||||
Endian instances of SmartFS exist that already have
|
||||
directories with data stored in big endian mode.
|
||||
|
||||
endif
|
||||
|
@ -20,11 +20,12 @@ Features
|
||||
|
||||
This implementation is a full-feature file system from the perspective of
|
||||
file and directory access (i.e. not considering low-level details like the
|
||||
lack of wear-leveling, etc.). The SMART File System was designed specifically
|
||||
lack of bad block management). The SMART File System was designed specifically
|
||||
for small SPI based FLASH parts (1-8 Mbyte for example), though this is not
|
||||
a limitation. It can certainly be used for any size FLASH and can work with
|
||||
any MTD device by binding it with the SMART MTD layer. The FS includes
|
||||
support for:
|
||||
any MTD device by binding it with the SMART MTD layer and has been tested with
|
||||
devices as large as 128MByte (using a 2048 byte sector size with 65534 sectors).
|
||||
The FS includes support for:
|
||||
- Multiple open files from different threads.
|
||||
- Open for read/write access with seek capability.
|
||||
- Appending to end of files in either write, append or read/write
|
||||
@ -32,6 +33,9 @@ Features
|
||||
- Directory support.
|
||||
- Support for multiple mount points on a single volume / partition (see
|
||||
details below).
|
||||
- Selectable FLASH Wear leveling algorithym
|
||||
- Selectable CRC-8 or CRC-16 error detection for sector data
|
||||
- Reduced RAM model for FLASH geometries with large number of sectors (16K-64K)
|
||||
|
||||
General operation
|
||||
=================
|
||||
@ -68,7 +72,7 @@ General operation
|
||||
erase state to non-erase state) to indicate the sector data is valid. When
|
||||
a sector's data needs to be deleted, the RELEASED flag will be "set" to
|
||||
indicate the sector is no longer in use. This is done because the erase
|
||||
block continaing the sector cannot necessarly be erased until all sectors
|
||||
block containing the sector cannot necessarily be erased until all sectors
|
||||
in that block have been "released". This allows sectors in the erase
|
||||
block to remain active while others are inactive until a "garbage collection"
|
||||
operation is needed on the volume to reclaim released sectors.
|
||||
@ -85,10 +89,12 @@ General operation
|
||||
The SMART MTD block layer reserves some logical sector numbers for internal
|
||||
use, including
|
||||
|
||||
Sector 0: The Format Sector. Has a format signture, format version, etc.
|
||||
Sector 1: The 1st (or only) Root Directory entry
|
||||
Sector 2-8: Additional root directories when Multi-Mount points are supported.
|
||||
Sector 9-11: Reserved (maybe for sector wear-leveling, etc.)
|
||||
Sector 0: The Format Sector. Has a format signature, format version, etc.
|
||||
Also contains wear leveling information if enabled.
|
||||
Sector 1-2: Additional wear-leveling info storage if needed.
|
||||
Sector 3: The 1st (or only) Root Directory entry
|
||||
Sector 4-10: Additional root directories when Multi-Mount points are supported.
|
||||
Sector 11-12: Reserved
|
||||
|
||||
To perform allocations, the SMART MTD block layer searches each erase block
|
||||
on the device to identify the one with the most free sectors. Free sectors
|
||||
@ -97,7 +103,8 @@ General operation
|
||||
sectors on the device can be allocated ... the SMART MTD block driver must
|
||||
reserve at least one erase-block worth of unused sectors to perform
|
||||
garbage collection, which will be performed automatically when no free
|
||||
sectors are available.
|
||||
sectors are available. When wear leveling is enabled, the allocator also takes
|
||||
into account the erase block erasure status to maintain level wearing.
|
||||
|
||||
Garbage collection is performed by identifying the erase block with the most
|
||||
"released" sectors (those that were previously allocated but no longer being
|
||||
@ -132,6 +139,133 @@ General operation
|
||||
perform a full page read-modify-write operation on a 256 or even 512
|
||||
byte page.
|
||||
|
||||
Wear Leveling
|
||||
=============
|
||||
|
||||
When wear leveling is enabled, the code automatically writes data across
|
||||
the entire FLASH device in a manner that causes each erase block to be
|
||||
worn (i.e. erased) evenly. This is accomplished by maintaining a 4-bit
|
||||
wear level count for each erase block and forcing less worn blocks to be
|
||||
used for writing new data. The code maintains each block's erase count
|
||||
to be within 16 erases of each other, though through testing, the span
|
||||
so far was never greater than 10 erases of each other.
|
||||
|
||||
As the data in a block is modified repeatedly, the erase count will
|
||||
increase. When the wear level reaches a value of 8 or higher, and the block
|
||||
needs to be erased (because the data in it has been modified, etc.) the code
|
||||
will select an erase block with the lowest wear count and relocate it to
|
||||
this block (with the higher wear count). The idea being that a block with
|
||||
the lowest wear count contains more "static" data and should require fewer
|
||||
additional erase operations. This relocation process will continue on the
|
||||
block (only when it needs to be erased again).
|
||||
|
||||
|
||||
When the wear level of all erase blocks has increased to a level of
|
||||
SMART_WEAR_MIN_LEVEL (currently set to 5), then the wear level counts
|
||||
will all be reduced by this value. This keeps the wear counts normalized
|
||||
so they fit in a 4-bit value. Note that theoretically, it *IS* possible to
|
||||
write data to the flash in a manner that causes the wear count of a single
|
||||
erase block to increment beyond it's maximum value of 15. This would have
|
||||
to be a very, very, very specific and un-predictable write sequence though
|
||||
as data is always spread out across the sectors and relocated dynamically.
|
||||
In the extremely rare event this does occur, the code will automatically
|
||||
cap the maximum wear level at 15 an increment an "uneven wear count"
|
||||
variable to indicate the number times this event has occurred. So far, I
|
||||
have not been able to get the wear count above 10 though my testing.
|
||||
|
||||
The wear level status bits are saved in the format sector (logical sector
|
||||
number zero) with overflow saved in the reserved logical sectors one and
|
||||
two. Additionally, the uneven wear count (and total block erases if
|
||||
PROCFS is enabled) are stored in the format sector. When the PROCFS file
|
||||
system is enabled and a SMARTFS volume is mounted, the SMART block driver
|
||||
details and / or wear level details can be viewed with a command such as:
|
||||
|
||||
cat /proc/fs/smartfs/smart0/status
|
||||
Format version: 1
|
||||
Name Len: 16
|
||||
Total Sectors: 2048
|
||||
Sector Size: 512
|
||||
Format Sector: 1487
|
||||
Dir Sector: 8
|
||||
Free Sectors: 67
|
||||
Released Sectors: 572
|
||||
Unused Sectors: 817
|
||||
Block Erases: 5680
|
||||
Sectors Per Block: 8
|
||||
Sector Utilization:98%
|
||||
Uneven Wear Count: 0
|
||||
|
||||
cat /proc/fs/smartfs/smart0/erasemap
|
||||
DDDCGCCDDCDCCDCBDCCDDGBBDBCDCCDDDCDDDDCCDDCCCGCGDCCDBCDDGBDBDCDD
|
||||
BCCCDDCCDDDCBCCDGCCCBDDCCGBBCBCCGDCCDCBDBCCCDCDDCDDGCDCGDCBCDBDG
|
||||
BCDDCDCBGCCCDDCGBCCGBCCBDDBDDCGDCDDDCGCDDBCDCBDDBCDCGDDCCBCGBCCC
|
||||
GCBCCGCCCDDDBGCCCCGDCCCCCDCDDGBBDACABDBBABCAABCCCDAACBADADDDAECB
|
||||
|
||||
Enabling wear leveling can increase the total number of block erases on the
|
||||
device in favor of even wearing (erasing). This is caused by writing /
|
||||
moving sectors that otherwise don't need to be written to move static data
|
||||
to the more highly worn blocks. This additional write requirement is known
|
||||
as write amplification. To get an idea of the amount of write amplification
|
||||
incurred by enabling wear leveling, I conducted the smart_test example using
|
||||
four different configurations (wear, no wear, CRC-8, no CRC) and the results
|
||||
are shown below. This was done on a 1M Byte simulated FLASH with 4K erase
|
||||
block size, 512 sectors per byte. The smart_test creates a 700K file and
|
||||
then performs 20,000 random seek, write, verify tests. The seek write forces
|
||||
a multitude of sector relocation operations (with or without CRC enabled),
|
||||
causing a boatload of block erases.
|
||||
|
||||
Enabling wear leveling actually decreased the number of erase operations
|
||||
with CRC enabled or disabled. This is only a single test point based one
|
||||
testing method ... results will likely vary based on the method the data
|
||||
is written, the amount of static vs. dynamic data, the amount of free space
|
||||
on the volume, and the volume geometry (erase block size, sector size, etc.).
|
||||
|
||||
The results of the tests are:
|
||||
|
||||
Case Total Block erases
|
||||
================================================
|
||||
No wear leveling CRC-8 6632
|
||||
Wear leveling CRC-8 5585
|
||||
|
||||
No wear leveling no CRC 6658
|
||||
Wear leveling no CRC 5398
|
||||
|
||||
|
||||
Reduced RAM model
|
||||
=================
|
||||
|
||||
On devices with a larger number of logical sectors (i.e. a lot of erase
|
||||
blocks with a small selected sector size), the RAM requirement can become
|
||||
fairly significant. This is caused by the in-memory sector map which
|
||||
keeps track of the logical to physical mapping of all sectors. This is
|
||||
a RAM array which is 2 * totalsectors in size. For a device with 64K
|
||||
sectors, this means 128K of RAM is required just for the sector map, not
|
||||
counting RAM for read/write buffers, erase block management, etc.
|
||||
|
||||
So a reduced RAM model has been added which only keeps track of which
|
||||
logical sectors have been used (a table which is totalsectors / 8 in size)
|
||||
and a configurable sized sector map cache. Each entry in the sector map
|
||||
cache is 6 bytes (logical sector, physical sector and cache entry age).
|
||||
ON DEVICES WITH SMALLER TOTAL SECTOR COUNT, ENABLING THIS OPTION COULD
|
||||
ACTUALLY INCREASE THE RAM FOOTPRINT INSTEAD OF REDUCE IT.
|
||||
|
||||
The sector map cache size should be selected to balance the desired RAM
|
||||
usage and the file system performance. When a logical to physical sector
|
||||
mapping is not found in the cache, the code must perform a physical search
|
||||
of the FLASH to find the requested logical sector. This involves reading
|
||||
the 5-byte header from each sector on the device until the sector is
|
||||
found. Performing a full read, seek or open for append on a large file
|
||||
can cause the sector map cache to flush completely if the file is larger
|
||||
than (cache entries * sector size). For example, in a configuration with
|
||||
256 cache entries and a 512 byte sector size, a full read, seek or open for
|
||||
append on a 128K file will flush the cache.
|
||||
|
||||
An additional RAM savings is realized on FLASH parts that contain 16 or
|
||||
fewer logical sectors per erase block by packing the free and released
|
||||
sector counts into a single byte (plus a little extra for 16 sectors per
|
||||
erase block). A device with a 64K erase block size can benefit from this
|
||||
savings by selecting a 4096 or 8192 byte logical sector size, for example.
|
||||
|
||||
SMART FS Layer
|
||||
==============
|
||||
|
||||
@ -139,7 +273,7 @@ General operation
|
||||
logical sectors, create and destroy sector chains, and perform directory and
|
||||
file I/O operations. Each directory and file on the volume is represented
|
||||
as a chain or "linked list" of logical sectors. Thus the actual physical
|
||||
sectors that a give file or directory uses does not need to be contigous
|
||||
sectors that a give file or directory uses does not need to be contiguous
|
||||
and in fact can (and will) move around over time. To manage the sector
|
||||
chains, the SMARTFS layer adds a "chain header" after the sector's "sector
|
||||
header". This is a 5-byte header which contains the chain type (file or
|
||||
@ -287,35 +421,37 @@ SMARTFS Limitations
|
||||
This implementation has several limitations that you should be aware
|
||||
before opting to use SMARTFS:
|
||||
|
||||
1. No wear leveling has been implemented. The allocation scheme has a
|
||||
bit of inherent wear-leveling since it automatically distributes
|
||||
sector allocations across the device, but no provisions exist to
|
||||
guarantee equal wearing.
|
||||
|
||||
2. There is no CRC or checksum calculations performed on the data stored
|
||||
to FLASH, so no error detection has been implemented. This could be
|
||||
added by "stealing" one of the sequence number bytes in the sector
|
||||
header and incrementing the sector version number.
|
||||
|
||||
3. There is currently no FLASH bad-block management code. The reason for
|
||||
1. There is currently no FLASH bad-block management code. The reason for
|
||||
this is that the FS was geared for Serial NOR FLASH parts. To use
|
||||
SMARTFS with a NAND FLASH, bad block management would need to be added.
|
||||
SMARTFS with a NAND FLASH, bad block management would need to be added,
|
||||
along with a few minor changes to eliminate single bit writes to release
|
||||
a sector, etc.
|
||||
|
||||
4. The released-sector garbage collection process occurs only during a write
|
||||
2. The implementation can support CRC-8 or CRC-16 error detection, and can
|
||||
relocate a failed write operation to a new sector. However with no bad
|
||||
block management implementation, the code will continue it attempts at
|
||||
using failing block / sector, reducing efficiency and possibly successfully
|
||||
saving data in a block with questionable integrity.
|
||||
|
||||
3. The released-sector garbage collection process occurs only during a write
|
||||
when there are no free FLASH sectors. Thus, occasionally, file writing
|
||||
may take a long time. This typically isn't noticable unless the volume
|
||||
may take a long time. This typically isn't noticeable unless the volume
|
||||
is very full and multiple copy / erase cycles must be performed to
|
||||
complete the garbage collection.
|
||||
|
||||
5. The total number of logical sectors on the device must be less than 65534.
|
||||
4. The total number of logical sectors on the device must be 65534 or less.
|
||||
The number of logical sectors is based on the total device / partition
|
||||
size and the selected sector size. For larger flash parts, a larger
|
||||
sector size would need to be used to meet this requirement. This
|
||||
restriction exists because:
|
||||
sector size would need to be used to meet this requirement. Creating a
|
||||
geometry which results in 65536 sectors (a 32MByte FLASH with 512 byte
|
||||
logical sector, for example) will cause the code to automatically reduce
|
||||
the total sector count to 65534, thus "wasting" the last two logical
|
||||
sectors on the device (they will never be used).
|
||||
|
||||
This restriction exists because:
|
||||
|
||||
a. The logical sector number is a 16-bit field (i.e. 65535 is the max).
|
||||
b. The SMART MTD layer reserves 1 logical sector for a format sector.
|
||||
c. Logical sector number 65535 (0xFFFF) is reerved as this is typically
|
||||
b. Logical sector number 65535 (0xFFFF) is reserved as this is typically
|
||||
the "erased state" of the FLASH.
|
||||
|
||||
ioctls
|
||||
@ -339,7 +475,7 @@ ioctls
|
||||
it's erase block.
|
||||
|
||||
BIOC_READSECT
|
||||
Reads data from a logial sector. This uses a structure to identify
|
||||
Reads data from a logical sector. This uses a structure to identify
|
||||
the offset and count of data to be read.
|
||||
|
||||
BIOC_WRITESECT
|
||||
@ -356,8 +492,3 @@ Things to Do
|
||||
- Add reporting of actual FLASH usage for directories (each directory
|
||||
occupies one or more physical sectors, yet the size is reported as
|
||||
zero for directories).
|
||||
- Add sector aging to provide some degree of wear-leveling.
|
||||
- Possibly steal a byte from the sector header's sequence number and
|
||||
implement a sector data verification scheme using a 1-byte CRC.
|
||||
|
||||
|
||||
|
@ -198,9 +198,14 @@
|
||||
#define SMARTFS_SECTOR_TYPE_FILE 2
|
||||
|
||||
#ifndef CONFIG_SMARTFS_DIRDEPTH
|
||||
#define CONFIG_SMARTFS_DIRDEPTH 8
|
||||
# define CONFIG_SMARTFS_DIRDEPTH 8
|
||||
#endif
|
||||
|
||||
/* Buffer flags (when CRC enabled) */
|
||||
|
||||
#define SMARTFS_BFLAG_DIRTY 0x01 /* Set if data changed in the sector */
|
||||
#define SMARTFS_BFLAG_NEWALLOC 0x02 /* Set if sector not written since alloc */
|
||||
|
||||
#define SMARTFS_ERASEDSTATE_16BIT (uint16_t) ((CONFIG_SMARTFS_ERASEDSTATE << 8) | \
|
||||
CONFIG_SMARTFS_ERASEDSTATE)
|
||||
|
||||
@ -211,6 +216,10 @@
|
||||
#define SMARTFS_NEXTSECTOR(h) ( *((uint16_t *) h->nextsector))
|
||||
#define SMARTFS_USED(h) ( *((uint16_t *) h->used))
|
||||
|
||||
#ifdef CONFIG_MTD_SMART_ENABLE_CRC
|
||||
#define CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
@ -252,12 +261,28 @@ struct smartfs_entry_header_s
|
||||
* sector. It manages the sector chain and used bytes in the sector.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_MTD_SMART_ENABLE_CRC) && defined(CONFIG_SMART_CRC_32)
|
||||
struct smartfs_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) */
|
||||
};
|
||||
#elif defined(CONFIG_MTD_SMART_ENABLE_CRC) && defined(CONFIG_SMART_CRC_16)
|
||||
struct smartfs_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 */
|
||||
};
|
||||
#else
|
||||
struct smartfs_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
|
||||
|
||||
/* This structure describes the state of one open file. This structure
|
||||
* is protected by the volume semaphore.
|
||||
@ -266,6 +291,10 @@ struct smartfs_chain_header_s
|
||||
struct smartfs_ofile_s
|
||||
{
|
||||
struct smartfs_ofile_s *fnext; /* Supports a singly linked list */
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
uint8_t* buffer; /* Sector buffer to reduce writes */
|
||||
uint8_t bflags; /* Buffer flags */
|
||||
#endif
|
||||
int16_t crefs; /* Reference count */
|
||||
mode_t oflags; /* Open mode */
|
||||
struct smartfs_entry_s entry; /* Describes the SMARTFS inode entry */
|
||||
@ -331,7 +360,7 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
||||
uint16_t parentdirsector, const char* filename,
|
||||
uint16_t type,
|
||||
mode_t mode, struct smartfs_entry_s *direntry,
|
||||
uint16_t sectorno);
|
||||
uint16_t sectorno, FAR struct smartfs_ofile_s *sf);
|
||||
|
||||
int smartfs_deleteentry(struct smartfs_mountpt_s *fs,
|
||||
struct smartfs_entry_s *entry);
|
||||
@ -340,7 +369,19 @@ int smartfs_countdirentries(struct smartfs_mountpt_s *fs,
|
||||
struct smartfs_entry_s *entry);
|
||||
|
||||
int smartfs_truncatefile(struct smartfs_mountpt_s *fs,
|
||||
struct smartfs_entry_s *entry);
|
||||
struct smartfs_entry_s *entry, FAR struct smartfs_ofile_s *sf);
|
||||
|
||||
uint16_t smartfs_rdle16(FAR const void *val);
|
||||
|
||||
void smartfs_wrle16(void *dest, uint16_t val);
|
||||
|
||||
uint32_t smartfs_rdle32(FAR const void *val);
|
||||
|
||||
void smartfs_wrle32(uint8_t *dest, uint32_t val);
|
||||
|
||||
#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)
|
||||
struct smartfs_mountpt_s* smartfs_get_first_mount(void);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)
|
||||
struct smartfs_mountpt_s* smartfs_get_first_mount(void);
|
||||
|
@ -108,6 +108,7 @@ struct smartfs_procfs_entry_s
|
||||
{
|
||||
const char *name; /* Name of the directory entry */
|
||||
size_t (*read)(FAR struct file *filep, FAR char *buffer, size_t buflen);
|
||||
ssize_t (*write)(FAR struct file *filep, FAR const char *buffer, size_t buflen);
|
||||
uint8_t type;
|
||||
};
|
||||
|
||||
@ -121,6 +122,8 @@ static int smartfs_open(FAR struct file *filep, FAR const char *relpath,
|
||||
static int smartfs_close(FAR struct file *filep);
|
||||
static ssize_t smartfs_read(FAR struct file *filep, FAR char *buffer,
|
||||
size_t buflen);
|
||||
static ssize_t smartfs_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen);
|
||||
|
||||
static int smartfs_dup(FAR const struct file *oldp,
|
||||
FAR struct file *newp);
|
||||
@ -132,6 +135,8 @@ static int smartfs_rewinddir(FAR struct fs_dirent_s *dir);
|
||||
|
||||
static int smartfs_stat(FAR const char *relpath, FAR struct stat *buf);
|
||||
|
||||
static ssize_t smartfs_debug_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen);
|
||||
static size_t smartfs_status_read(FAR struct file *filep, FAR char *buffer,
|
||||
size_t buflen);
|
||||
#ifdef CONFIG_MTD_SMART_ALLOC_DEBUG
|
||||
@ -153,13 +158,14 @@ static size_t smartfs_files_read(FAR struct file *filep, FAR char *buffer,
|
||||
|
||||
static const struct smartfs_procfs_entry_s g_direntry[] =
|
||||
{
|
||||
{ "debuglevel", NULL, smartfs_debug_write, DTYPE_FILE },
|
||||
#ifdef CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG
|
||||
{ "erasemap", smartfs_erasemap_read, DTYPE_FILE },
|
||||
{ "erasemap", smartfs_erasemap_read, NULL, DTYPE_FILE },
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_SMART_ALLOC_DEBUG
|
||||
{ "mem", smartfs_mem_read, DTYPE_FILE },
|
||||
{ "mem", smartfs_mem_read, NULL, DTYPE_FILE },
|
||||
#endif
|
||||
{ "status", smartfs_status_read, DTYPE_FILE }
|
||||
{ "status", smartfs_status_read, NULL, DTYPE_FILE }
|
||||
};
|
||||
|
||||
static const uint8_t g_direntrycount = sizeof(g_direntry) /
|
||||
@ -181,7 +187,7 @@ const struct procfs_operations smartfs_procfsoperations =
|
||||
smartfs_read, /* read */
|
||||
|
||||
/* No write supported */
|
||||
NULL, /* write */
|
||||
smartfs_write, /* write */
|
||||
|
||||
smartfs_dup, /* dup */
|
||||
|
||||
@ -430,7 +436,50 @@ static ssize_t smartfs_read(FAR struct file *filep, FAR char *buffer,
|
||||
{
|
||||
if (priv->level1.direntry < g_direntrycount)
|
||||
{
|
||||
ret = g_direntry[priv->level1.direntry].read(filep, buffer, buflen);
|
||||
if (g_direntry[priv->level1.direntry].read)
|
||||
{
|
||||
ret = g_direntry[priv->level1.direntry].read(filep, buffer, buflen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the file offset */
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
filep->f_pos += ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smartfs_write
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t smartfs_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen)
|
||||
{
|
||||
FAR struct smartfs_file_s *priv;
|
||||
ssize_t ret;
|
||||
|
||||
/* Recover our private data from the struct file instance */
|
||||
|
||||
priv = (FAR struct smartfs_file_s *)filep->f_priv;
|
||||
DEBUGASSERT(priv);
|
||||
|
||||
/* Perform the write based on the directory entry */
|
||||
|
||||
ret = 0;
|
||||
|
||||
if (priv->level1.base.level == 3)
|
||||
{
|
||||
if (priv->level1.direntry < g_direntrycount)
|
||||
{
|
||||
if (g_direntry[priv->level1.direntry].write)
|
||||
{
|
||||
ret = g_direntry[priv->level1.direntry].write(filep, buffer, buflen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,6 +724,8 @@ static int smartfs_stat(const char *relpath, struct stat *buf)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The entry being stat'ed is lowest level */
|
||||
|
||||
if (g_direntry[level1.direntry].type == DTYPE_DIRECTORY)
|
||||
{
|
||||
buf->st_mode |= S_IFDIR;
|
||||
@ -683,6 +734,13 @@ static int smartfs_stat(const char *relpath, struct stat *buf)
|
||||
{
|
||||
buf->st_mode |= S_IFREG;
|
||||
}
|
||||
|
||||
/* Test if the entry is writable */
|
||||
|
||||
if (g_direntry[level1.direntry].write != NULL)
|
||||
{
|
||||
buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -695,6 +753,33 @@ static int smartfs_stat(const char *relpath, struct stat *buf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smartfs_debug_write
|
||||
*
|
||||
* Description: Performs the write operation for the "debug" file
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t smartfs_debug_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen)
|
||||
{
|
||||
struct mtd_smart_debug_data_s debug_data;
|
||||
FAR struct smartfs_file_s *priv;
|
||||
|
||||
priv = (FAR struct smartfs_file_s *) filep->f_priv;
|
||||
|
||||
/* Populate the debug_data structure */
|
||||
|
||||
debug_data.debugcmd = SMART_DEBUG_CMD_SET_DEBUG_LEVEL;
|
||||
debug_data.debugdata = atoi(buffer);
|
||||
|
||||
priv->level1.mount->fs_blkdriver->u.i_bops->ioctl(
|
||||
priv->level1.mount->fs_blkdriver, BIOC_DEBUGCMD,
|
||||
(unsigned long) &debug_data);
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smartfs_status_read
|
||||
*
|
||||
@ -709,9 +794,7 @@ static size_t smartfs_status_read(FAR struct file *filep, FAR char *buffer,
|
||||
FAR struct smartfs_file_s *priv;
|
||||
int ret;
|
||||
size_t len;
|
||||
#if 0 /* Not used */
|
||||
int utilization;
|
||||
#endif
|
||||
|
||||
priv = (FAR struct smartfs_file_s *) filep->f_priv;
|
||||
|
||||
@ -731,7 +814,6 @@ static size_t smartfs_status_read(FAR struct file *filep, FAR char *buffer,
|
||||
|
||||
if (ret == OK)
|
||||
{
|
||||
#if 0 /* Not used */
|
||||
/* Calculate the sector utilization percentage */
|
||||
|
||||
if (procfs_data.blockerases == 0)
|
||||
@ -744,7 +826,6 @@ static size_t smartfs_status_read(FAR struct file *filep, FAR char *buffer,
|
||||
procfs_data.unusedsectors) / (procfs_data.blockerases *
|
||||
procfs_data.sectorsperblk);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Format and return data in the buffer */
|
||||
|
||||
@ -752,18 +833,22 @@ static size_t smartfs_status_read(FAR struct file *filep, FAR char *buffer,
|
||||
"Total Sectors: %d\nSector Size: %d\n"
|
||||
"Format Sector: %d\nDir Sector: %d\n"
|
||||
"Free Sectors: %d\nReleased Sectors: %d\n"
|
||||
"Sectors Per Block: %d\n",
|
||||
//"Unused Sectors: %d\nBlock Erases: %d\n"
|
||||
//"Sectors Per Block: %d\nSector Utilization:%d%%\n",
|
||||
"Unused Sectors: %d\nBlock Erases: %d\n"
|
||||
"Sectors Per Block: %d\nSector Utilization:%d%%\n"
|
||||
#ifdef CONFIG_MTD_SMART_WEAR_LEVEL
|
||||
"Uneven Wear Count: %d\n"
|
||||
#endif
|
||||
,
|
||||
procfs_data.formatversion, procfs_data.namelen,
|
||||
procfs_data.totalsectors, procfs_data.sectorsize,
|
||||
procfs_data.formatsector, procfs_data.dirsector,
|
||||
procfs_data.freesectors, procfs_data.releasesectors,
|
||||
procfs_data.sectorsperblk);
|
||||
#if 0 /* Not used */
|
||||
procfs_data.unusedsectors, procfs_data.blockerases,
|
||||
procfs_data.sectorsperblk, utilization);
|
||||
procfs_data.sectorsperblk, utilization
|
||||
#ifdef CONFIG_MTD_SMART_WEAR_LEVEL
|
||||
, procfs_data.uneven_wearcount
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
/* Indicate we have already provided all the data */
|
||||
|
@ -196,11 +196,27 @@ static int smartfs_open(FAR struct file *filep, const char *relpath,
|
||||
goto errout_with_semaphore;
|
||||
}
|
||||
|
||||
/* Allocate a sector buffer if CRC enabled in the MTD layer */
|
||||
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
sf->buffer = (uint8_t *) kmm_malloc(fs->fs_llformat.availbytes);
|
||||
if (sf->buffer == NULL)
|
||||
{
|
||||
/* Error ... no memory */
|
||||
|
||||
kmm_free(sf);
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_semaphore;
|
||||
}
|
||||
|
||||
sf->bflags = 0;
|
||||
#endif /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
|
||||
|
||||
sf->entry.name = NULL;
|
||||
ret = smartfs_finddirentry(fs, &sf->entry, relpath, &parentdirsector,
|
||||
&filename);
|
||||
|
||||
/* Three possibililities: (1) a node exists for the relpath and
|
||||
/* Three possibilities: (1) a node exists for the relpath and
|
||||
* dirinfo describes the directory entry of the entity, (2) the
|
||||
* node does not exist, or (3) some error occurred.
|
||||
*/
|
||||
@ -240,7 +256,7 @@ static int smartfs_open(FAR struct file *filep, const char *relpath,
|
||||
{
|
||||
/* Truncate the file as part of the open */
|
||||
|
||||
ret = smartfs_truncatefile(fs, &sf->entry);
|
||||
ret = smartfs_truncatefile(fs, &sf->entry, sf);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_buffer;
|
||||
@ -268,7 +284,7 @@ static int smartfs_open(FAR struct file *filep, const char *relpath,
|
||||
|
||||
ret = smartfs_createentry(fs, parentdirsector, filename,
|
||||
SMARTFS_DIRENT_TYPE_FILE, mode,
|
||||
&sf->entry, 0xFFFF);
|
||||
&sf->entry, 0xFFFF, sf);
|
||||
if (ret != OK)
|
||||
{
|
||||
goto errout_with_buffer;
|
||||
@ -426,6 +442,14 @@ static int smartfs_close(FAR struct file *filep)
|
||||
kmm_free(sf->entry.name);
|
||||
sf->entry.name = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
if (sf->buffer)
|
||||
{
|
||||
kmm_free(sf->buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
kmm_free(sf);
|
||||
|
||||
okout:
|
||||
@ -573,6 +597,39 @@ static int smartfs_sync_internal(struct smartfs_mountpt_s *fs,
|
||||
struct smartfs_chain_header_s *header;
|
||||
int ret = OK;
|
||||
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
if (sf->bflags & SMARTFS_BFLAG_DIRTY)
|
||||
{
|
||||
/* Update the header with the number of bytes written */
|
||||
|
||||
header = (struct smartfs_chain_header_s *) sf->buffer;
|
||||
if (*((uint16_t *) header->used) == SMARTFS_ERASEDSTATE_16BIT)
|
||||
{
|
||||
*((uint16_t *) header->used) = sf->byteswritten;
|
||||
}
|
||||
else
|
||||
{
|
||||
*((uint16_t *) header->used) += sf->byteswritten;
|
||||
}
|
||||
|
||||
/* Write the entire sector to FLASH */
|
||||
|
||||
readwrite.logsector = sf->currsector;
|
||||
readwrite.offset = 0;
|
||||
readwrite.count = fs->fs_llformat.availbytes;
|
||||
readwrite.buffer = sf->buffer;
|
||||
ret = FS_IOCTL(fs, BIOC_WRITESECT, (unsigned long) &readwrite);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d writing used bytes for sector %d\n", ret, sf->currsector);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
sf->byteswritten = 0;
|
||||
sf->bflags = 0;
|
||||
}
|
||||
#else /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
|
||||
|
||||
/* Test if we have written bytes to the current sector that
|
||||
* need to be recorded in the chain header's used bytes field. */
|
||||
|
||||
@ -617,6 +674,7 @@ static int smartfs_sync_internal(struct smartfs_mountpt_s *fs,
|
||||
|
||||
sf->byteswritten = 0;
|
||||
}
|
||||
#endif /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
@ -761,6 +819,17 @@ static ssize_t smartfs_write(FAR struct file *filep, const char *buffer,
|
||||
* the current sector first.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
readwrite.count = fs->fs_llformat.availbytes - sf->curroffset;
|
||||
if (readwrite.count > buflen)
|
||||
{
|
||||
readwrite.count = buflen;
|
||||
}
|
||||
|
||||
memcpy(&sf->buffer[sf->curroffset], &buffer[byteswritten], readwrite.count);
|
||||
sf->bflags |= SMARTFS_BFLAG_DIRTY;
|
||||
|
||||
#else /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
|
||||
readwrite.offset = sf->curroffset;
|
||||
readwrite.logsector = sf->currsector;
|
||||
readwrite.buffer = (uint8_t *) &buffer[byteswritten];
|
||||
@ -782,24 +851,74 @@ static ssize_t smartfs_write(FAR struct file *filep, const char *buffer,
|
||||
fdbg("Error %d writing sector %d data\n", ret, sf->currsector);
|
||||
goto errout_with_semaphore;
|
||||
}
|
||||
|
||||
/* Update our control variables */
|
||||
|
||||
sf->entry.datlen += readwrite.count;
|
||||
sf->byteswritten += readwrite.count;
|
||||
sf->filepos += readwrite.count;
|
||||
sf->curroffset += readwrite.count;
|
||||
buflen -= readwrite.count;
|
||||
byteswritten += readwrite.count;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
|
||||
|
||||
/* Update our control variables */
|
||||
|
||||
sf->entry.datlen += readwrite.count;
|
||||
sf->byteswritten += readwrite.count;
|
||||
sf->filepos += readwrite.count;
|
||||
sf->curroffset += readwrite.count;
|
||||
buflen -= readwrite.count;
|
||||
byteswritten += readwrite.count;
|
||||
|
||||
/* Test if we wrote a full sector of data */
|
||||
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
if (sf->curroffset == fs->fs_llformat.availbytes && buflen)
|
||||
{
|
||||
/* First get a new chained sector */
|
||||
|
||||
ret = FS_IOCTL(fs, BIOC_ALLOCSECT, 0xFFFF);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d allocating new sector\n", ret);
|
||||
goto errout_with_semaphore;
|
||||
}
|
||||
|
||||
/* Copy the new sector to the old one and chain it */
|
||||
|
||||
header = (struct smartfs_chain_header_s *) sf->buffer;
|
||||
*((uint16_t *) header->nextsector) = (uint16_t) ret;
|
||||
|
||||
/* Now sync the file to write this sector out */
|
||||
|
||||
ret = smartfs_sync_internal(fs, sf);
|
||||
if (ret != OK)
|
||||
{
|
||||
goto errout_with_semaphore;
|
||||
}
|
||||
|
||||
/* Record the new sector in our tracking variables and
|
||||
* reset the offset to "zero".
|
||||
*/
|
||||
|
||||
if (sf->currsector == SMARTFS_NEXTSECTOR(header))
|
||||
{
|
||||
/* Error allocating logical sector! */
|
||||
|
||||
fdbg("Error - duplicate logical sector %d\n", sf->currsector);
|
||||
}
|
||||
|
||||
sf->bflags = SMARTFS_BFLAG_DIRTY;
|
||||
sf->currsector = SMARTFS_NEXTSECTOR(header);
|
||||
sf->curroffset = sizeof(struct smartfs_chain_header_s);
|
||||
memset(sf->buffer, CONFIG_SMARTFS_ERASEDSTATE, fs->fs_llformat.availbytes);
|
||||
header->type = SMARTFS_DIRENT_TYPE_FILE;
|
||||
}
|
||||
#else /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
|
||||
|
||||
if (sf->curroffset == fs->fs_llformat.availbytes)
|
||||
{
|
||||
/* Sync the file to write this sector out */
|
||||
|
||||
smartfs_sync_internal(fs, sf);
|
||||
ret = smartfs_sync_internal(fs, sf);
|
||||
if (ret != OK)
|
||||
{
|
||||
goto errout_with_semaphore;
|
||||
}
|
||||
|
||||
/* Allocate a new sector if needed */
|
||||
|
||||
@ -833,10 +952,18 @@ static ssize_t smartfs_write(FAR struct file *filep, const char *buffer,
|
||||
* reset the offset to "zero".
|
||||
*/
|
||||
|
||||
if (sf->currsector == SMARTFS_NEXTSECTOR(header))
|
||||
{
|
||||
/* Error allocating logical sector! */
|
||||
|
||||
fdbg("Error - duplicate logical sector %d\n", sf->currsector);
|
||||
}
|
||||
|
||||
sf->currsector = SMARTFS_NEXTSECTOR(header);
|
||||
sf->curroffset = sizeof(struct smartfs_chain_header_s);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
|
||||
}
|
||||
|
||||
ret = byteswritten;
|
||||
@ -968,6 +1095,27 @@ static off_t smartfs_seek_internal(struct smartfs_mountpt_s *fs,
|
||||
sf->filepos += SMARTFS_USED(header);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
|
||||
/* When using sector buffering, we must read in the last buffer to our
|
||||
* sf->buffer in case any changes are made.
|
||||
*/
|
||||
|
||||
if (sf->currsector != SMARTFS_ERASEDSTATE_16BIT)
|
||||
{
|
||||
readwrite.logsector = sf->currsector;
|
||||
readwrite.offset = 0;
|
||||
readwrite.count = fs->fs_llformat.availbytes;
|
||||
readwrite.buffer = (uint8_t *) sf->buffer;
|
||||
ret = FS_IOCTL(fs, BIOC_READSECT, (unsigned long) &readwrite);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d reading sector %d header\n", ret, sf->currsector);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now calculate the offset */
|
||||
|
||||
sf->curroffset = sizeof(struct smartfs_chain_header_s) + newpos - sf->filepos;
|
||||
@ -1465,6 +1613,11 @@ static int smartfs_statfs(struct inode *mountpt, struct statfs *buf)
|
||||
buf->f_namelen = fs->fs_llformat.namesize;
|
||||
buf->f_bsize = fs->fs_llformat.sectorsize;
|
||||
buf->f_blocks = fs->fs_llformat.nsectors;
|
||||
if (buf->f_blocks == 65535)
|
||||
{
|
||||
buf->f_blocks++;
|
||||
}
|
||||
|
||||
buf->f_bfree = fs->fs_llformat.nfreesectors;
|
||||
buf->f_bavail = fs->fs_llformat.nfreesectors;
|
||||
buf->f_files = 0;
|
||||
@ -1596,7 +1749,7 @@ static int smartfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode
|
||||
/* Create the directory */
|
||||
|
||||
ret = smartfs_createentry(fs, parentdirsector, filename,
|
||||
SMARTFS_DIRENT_TYPE_DIR, mode, &entry, 0xFFFF);
|
||||
SMARTFS_DIRENT_TYPE_DIR, mode, &entry, 0xFFFF, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
goto errout_with_semaphore;
|
||||
@ -1840,7 +1993,7 @@ int smartfs_rename(struct inode *mountpt, const char *oldrelpath,
|
||||
mode = oldentry.flags & SMARTFS_DIRENT_MODE;
|
||||
type = oldentry.flags & SMARTFS_DIRENT_TYPE;
|
||||
ret = smartfs_createentry(fs, newparentdirsector, newfilename,
|
||||
type, mode, &newentry, oldentry.firstsector);
|
||||
type, mode, &newentry, oldentry.firstsector, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
goto errout_with_semaphore;
|
||||
|
@ -116,6 +116,92 @@ void smartfs_semgive(struct smartfs_mountpt_s *fs)
|
||||
sem_post(fs->fs_sem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smartfs_rdle16
|
||||
*
|
||||
* Description:
|
||||
* Get a (possibly unaligned) 16-bit little endian value.
|
||||
*
|
||||
* Input Parameters:
|
||||
* val - A pointer to the first byte of the little endian value.
|
||||
*
|
||||
* Returned Value:
|
||||
* A uint16_t representing the whole 16-bit integer value
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint16_t smartfs_rdle16(FAR const void *val)
|
||||
{
|
||||
return (uint16_t)((FAR const uint8_t *)val)[1] << 8 |
|
||||
(uint16_t)((FAR const uint8_t *)val)[0];
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smartfs_wrle16
|
||||
*
|
||||
* Description:
|
||||
* Put a (possibly unaligned) 16-bit little endian value.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dest - A pointer to the first byte to save the little endian value.
|
||||
* val - The 16-bit value to be saved.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void smartfs_wrle16(FAR void *dest, uint16_t val)
|
||||
{
|
||||
((FAR uint8_t *) dest)[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
|
||||
((FAR uint8_t *) dest)[1] = val >> 8;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smartfs_rdle32
|
||||
*
|
||||
* Description:
|
||||
* Get a (possibly unaligned) 32-bit little endian value.
|
||||
*
|
||||
* Input Parameters:
|
||||
* val - A pointer to the first byte of the little endian value.
|
||||
*
|
||||
* Returned Value:
|
||||
* A uint32_t representing the whole 32-bit integer value
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t smartfs_rdle32(FAR const void *val)
|
||||
{
|
||||
/* Little endian means LS halfword first in byte stream */
|
||||
|
||||
return (uint32_t)smartfs_rdle16(&((FAR const uint8_t *)val)[2]) << 16 |
|
||||
(uint32_t)smartfs_rdle16(val);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smartfs_wrle32
|
||||
*
|
||||
* Description:
|
||||
* Put a (possibly unaligned) 32-bit little endian value.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dest - A pointer to the first byte to save the little endian value.
|
||||
* val - The 32-bit value to be saved.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void smartfs_wrle32(uint8_t *dest, uint32_t val)
|
||||
{
|
||||
/* Little endian means LS halfword first in byte stream */
|
||||
|
||||
smartfs_wrle16(dest, (uint16_t)(val & 0xffff));
|
||||
smartfs_wrle16(dest+2, (uint16_t)(val >> 16));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smartfs_mount
|
||||
*
|
||||
@ -132,7 +218,7 @@ int smartfs_mount(struct smartfs_mountpt_s *fs, bool writeable)
|
||||
FAR struct inode *inode;
|
||||
struct geometry geo;
|
||||
int ret = OK;
|
||||
#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS
|
||||
#if defined(CONFIG_SMARTFS_MULTI_ROOT_DIRS)
|
||||
struct smartfs_mountpt_s *nextfs;
|
||||
#endif
|
||||
|
||||
@ -235,10 +321,11 @@ int smartfs_mount(struct smartfs_mountpt_s *fs, bool writeable)
|
||||
g_mounthead = fs;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_SMARTFS_MULTI_ROOT_DIRS */
|
||||
|
||||
fs->fs_rwbuffer = (char *) kmm_malloc(fs->fs_llformat.availbytes);
|
||||
fs->fs_workbuffer = (char *) kmm_malloc(256);
|
||||
fs->fs_rootsector = SMARTFS_ROOT_DIR_SECTOR;
|
||||
#endif /* CONFIG_SMARTFS_MULTI_ROOT_DIRS */
|
||||
|
||||
/* We did it! */
|
||||
|
||||
@ -545,10 +632,17 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs,
|
||||
{
|
||||
/* Test if this entry is valid and active */
|
||||
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
if (((smartfs_rdle16(&entry->flags) & SMARTFS_DIRENT_EMPTY) ==
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_EMPTY)) ||
|
||||
((smartfs_rdle16(&entry->flags) & SMARTFS_DIRENT_ACTIVE) !=
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_ACTIVE)))
|
||||
#else
|
||||
if (((entry->flags & SMARTFS_DIRENT_EMPTY) ==
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_EMPTY)) ||
|
||||
((entry->flags & SMARTFS_DIRENT_ACTIVE) !=
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_ACTIVE)))
|
||||
#endif
|
||||
{
|
||||
/* This entry isn't valid, skip it */
|
||||
|
||||
@ -576,9 +670,15 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs,
|
||||
|
||||
/* Fill in the entry */
|
||||
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
direntry->firstsector = smartfs_rdle16(&entry->firstsector);
|
||||
direntry->flags = smartfs_rdle16(&entry->flags);
|
||||
direntry->utc = smartfs_rdle32(&entry->utc);
|
||||
#else
|
||||
direntry->firstsector = entry->firstsector;
|
||||
direntry->flags = entry->flags;
|
||||
direntry->utc = entry->utc;
|
||||
#endif
|
||||
direntry->dsector = readwrite.logsector;
|
||||
direntry->doffset = offset;
|
||||
direntry->dfirst = dirstack[depth];
|
||||
@ -595,9 +695,17 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs,
|
||||
* a rudimentary check.
|
||||
*/
|
||||
|
||||
if ((entry->flags & SMARTFS_DIRENT_TYPE) == SMARTFS_DIRENT_TYPE_FILE)
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
if ((smartfs_rdle16(&entry->flags) & SMARTFS_DIRENT_TYPE) ==
|
||||
SMARTFS_DIRENT_TYPE_FILE)
|
||||
{
|
||||
dirsector = smartfs_rdle16(&entry->firstsector);
|
||||
#else
|
||||
if ((entry->flags & SMARTFS_DIRENT_TYPE) ==
|
||||
SMARTFS_DIRENT_TYPE_FILE)
|
||||
{
|
||||
dirsector = entry->firstsector;
|
||||
#endif
|
||||
readwrite.count = sizeof(struct smartfs_chain_header_s);
|
||||
readwrite.buffer = (uint8_t *)fs->fs_rwbuffer;
|
||||
readwrite.offset = 0;
|
||||
@ -634,8 +742,13 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs,
|
||||
{
|
||||
/* Validate it's a directory */
|
||||
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
if ((smartfs_rdle16(&entry->flags) & SMARTFS_DIRENT_TYPE) !=
|
||||
SMARTFS_DIRENT_TYPE_DIR)
|
||||
#else
|
||||
if ((entry->flags & SMARTFS_DIRENT_TYPE) !=
|
||||
SMARTFS_DIRENT_TYPE_DIR)
|
||||
#endif
|
||||
{
|
||||
/* Not a directory! Report the error */
|
||||
|
||||
@ -653,7 +766,11 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs,
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
dirstack[++depth] = smartfs_rdle16(&entry->firstsector);
|
||||
#else
|
||||
dirstack[++depth] = entry->firstsector;
|
||||
#endif
|
||||
segment = ptr + 1;
|
||||
break;
|
||||
}
|
||||
@ -727,7 +844,7 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
||||
uint16_t parentdirsector, const char* filename,
|
||||
uint16_t type,
|
||||
mode_t mode, struct smartfs_entry_s *direntry,
|
||||
uint16_t sectorno)
|
||||
uint16_t sectorno, FAR struct smartfs_ofile_s *sf)
|
||||
{
|
||||
struct smart_read_write_s readwrite;
|
||||
int ret;
|
||||
@ -784,8 +901,13 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
||||
{
|
||||
/* Check if this entry is available */
|
||||
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
if ((smartfs_rdle16(&entry->flags) == SMARTFS_ERASEDSTATE_16BIT) ||
|
||||
((smartfs_rdle16(&entry->flags) &
|
||||
#else
|
||||
if ((entry->flags == SMARTFS_ERASEDSTATE_16BIT) ||
|
||||
((entry->flags &
|
||||
#endif
|
||||
(SMARTFS_DIRENT_EMPTY | SMARTFS_DIRENT_ACTIVE) ) ==
|
||||
(~SMARTFS_ERASEDSTATE_16BIT &
|
||||
(SMARTFS_DIRENT_EMPTY | SMARTFS_DIRENT_ACTIVE) )))
|
||||
@ -848,11 +970,24 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
||||
/* We found an insertion point. Create the entry at sector,offset */
|
||||
|
||||
#if CONFIG_SMARTFS_ERASEDSTATE == 0xFF
|
||||
entry->flags = (uint16_t) (SMARTFS_DIRENT_ACTIVE | SMARTFS_DIRENT_DELETING |
|
||||
SMARTFS_DIRENT_RESERVED | type | (mode & SMARTFS_DIRENT_MODE));
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
smartfs_wrle16(&entry->flags, (uint16_t) (SMARTFS_DIRENT_ACTIVE |
|
||||
SMARTFS_DIRENT_DELETING | SMARTFS_DIRENT_RESERVED | type | (mode &
|
||||
SMARTFS_DIRENT_MODE)));
|
||||
#else
|
||||
entry->flags = (uint16_t) (SMARTFS_DIRENT_EMPTY | type | (mode & SMARTFS_DIRENT_MODE));
|
||||
entry->flags = (uint16_t) (SMARTFS_DIRENT_ACTIVE |
|
||||
SMARTFS_DIRENT_DELETING | SMARTFS_DIRENT_RESERVED | type | (mode &
|
||||
SMARTFS_DIRENT_MODE));
|
||||
#endif
|
||||
#else /* CONFIG_SMARTFS_ERASEDSTATE == 0xFF */
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
smartfs_wrle16(&entry->flags, (uint16_t) (SMARTFS_DIRENT_EMPTY | type |
|
||||
(mode & SMARTFS_DIRENT_MODE)));
|
||||
#else
|
||||
entry->flags = (uint16_t) (SMARTFS_DIRENT_EMPTY | type |
|
||||
(mode & SMARTFS_DIRENT_MODE));
|
||||
#endif
|
||||
#endif /* CONFIG_SMARTFS_ERASEDSTATE == 0xFF */
|
||||
|
||||
if (sectorno == 0xFFFF)
|
||||
{
|
||||
@ -868,24 +1003,40 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
||||
|
||||
/* Set the newly allocated sector's type (file or dir) */
|
||||
|
||||
if ((type & SMARTFS_DIRENT_TYPE) == SMARTFS_DIRENT_TYPE_DIR)
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
if (sf)
|
||||
{
|
||||
chainheader->type = SMARTFS_SECTOR_TYPE_DIR;
|
||||
/* Using sector buffer and we have an open file context. Just update
|
||||
* the sector buffer in the open file context.
|
||||
*/
|
||||
|
||||
memset(sf->buffer, CONFIG_SMARTFS_ERASEDSTATE, fs->fs_llformat.availbytes);
|
||||
chainheader = (struct smartfs_chain_header_s *) sf->buffer;
|
||||
chainheader->type = SMARTFS_SECTOR_TYPE_FILE;
|
||||
sf->bflags = SMARTFS_BFLAG_DIRTY | SMARTFS_BFLAG_NEWALLOC;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
chainheader->type = SMARTFS_SECTOR_TYPE_FILE;
|
||||
}
|
||||
if ((type & SMARTFS_DIRENT_TYPE) == SMARTFS_DIRENT_TYPE_DIR)
|
||||
{
|
||||
chainheader->type = SMARTFS_SECTOR_TYPE_DIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
chainheader->type = SMARTFS_SECTOR_TYPE_FILE;
|
||||
}
|
||||
|
||||
readwrite.count = 1;
|
||||
readwrite.offset = offsetof(struct smartfs_chain_header_s, type);
|
||||
readwrite.buffer = (uint8_t *) &chainheader->type;
|
||||
readwrite.logsector = nextsector;
|
||||
ret = FS_IOCTL(fs, BIOC_WRITESECT, (unsigned long) &readwrite);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d setting new sector type for sector %d\n",ret, nextsector);
|
||||
goto errout;
|
||||
readwrite.count = 1;
|
||||
readwrite.offset = offsetof(struct smartfs_chain_header_s, type);
|
||||
readwrite.buffer = (uint8_t *) &chainheader->type;
|
||||
readwrite.logsector = nextsector;
|
||||
ret = FS_IOCTL(fs, BIOC_WRITESECT, (unsigned long) &readwrite);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d setting new sector type for sector %d\n",ret, nextsector);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -897,8 +1048,13 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
||||
|
||||
/* Create the directory entry to be written in the parent's sector */
|
||||
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
smartfs_wrle16(&entry->firstsector, nextsector);
|
||||
smartfs_wrle16(&entry->utc, time(NULL));
|
||||
#else
|
||||
entry->firstsector = nextsector;
|
||||
entry->utc = 0;
|
||||
entry->utc = time(NULL);
|
||||
#endif
|
||||
memset(entry->name, 0, fs->fs_llformat.namesize);
|
||||
strncpy(entry->name, filename, fs->fs_llformat.namesize);
|
||||
|
||||
@ -919,8 +1075,13 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
||||
direntry->firstsector = nextsector;
|
||||
direntry->dsector = psector;
|
||||
direntry->doffset = offset;
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
direntry->flags = smartfs_rdle16(&entry->flags);
|
||||
direntry->utc = smartfs_rdle32(&entry->utc);
|
||||
#else
|
||||
direntry->flags = entry->flags;
|
||||
direntry->utc = 0;
|
||||
direntry->utc = entry->utc;
|
||||
#endif
|
||||
direntry->datlen = 0;
|
||||
if (direntry->name == NULL)
|
||||
{
|
||||
@ -1006,7 +1167,7 @@ int smartfs_deleteentry(struct smartfs_mountpt_s *fs,
|
||||
ret = FS_IOCTL(fs, BIOC_READSECT, (unsigned long) &readwrite);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error reading directory info at sector %s\n", entry->dsector);
|
||||
fdbg("Error reading directory info at sector %d\n", entry->dsector);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@ -1014,10 +1175,18 @@ int smartfs_deleteentry(struct smartfs_mountpt_s *fs,
|
||||
|
||||
direntry = (struct smartfs_entry_header_s *) &fs->fs_rwbuffer[entry->doffset];
|
||||
#if CONFIG_SMARTFS_ERASEDSTATE == 0xFF
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
smartfs_wrle16(&direntry->flags, smartfs_rdle16(&direntry->flags) & ~SMARTFS_DIRENT_ACTIVE);
|
||||
#else
|
||||
direntry->flags &= ~SMARTFS_DIRENT_ACTIVE;
|
||||
#endif
|
||||
#else /* CONFIG_SMARTFS_ERASEDSTATE == 0xFF */
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
smartfs_wrle16(&direntry->flags, smartfs_rdle16(&direntry->flags) | SMARTFS_DIRENT_ACTIVE);
|
||||
#else
|
||||
direntry->flags |= SMARTFS_DIRENT_ACTIVE;
|
||||
#endif
|
||||
#endif /* CONFIG_SMARTFS_ERASEDSTATE == 0xFF */
|
||||
|
||||
/* Write the updated flags back to the sector */
|
||||
|
||||
@ -1027,7 +1196,7 @@ int smartfs_deleteentry(struct smartfs_mountpt_s *fs,
|
||||
ret = FS_IOCTL(fs, BIOC_WRITESECT, (unsigned long) &readwrite);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error marking entry inactive at sector %s\n", entry->dsector);
|
||||
fdbg("Error marking entry inactive at sector %d\n", entry->dsector);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@ -1046,10 +1215,17 @@ int smartfs_deleteentry(struct smartfs_mountpt_s *fs,
|
||||
/* Test the next entry */
|
||||
|
||||
direntry = (struct smartfs_entry_header_s *) &fs->fs_rwbuffer[offset];
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
if (((smartfs_rdle16(&direntry->flags) & SMARTFS_DIRENT_EMPTY) !=
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_EMPTY)) &&
|
||||
((smartfs_rdle16(&direntry->flags) & SMARTFS_DIRENT_ACTIVE) ==
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_ACTIVE)))
|
||||
#else
|
||||
if (((direntry->flags & SMARTFS_DIRENT_EMPTY) !=
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_EMPTY)) &&
|
||||
((direntry->flags & SMARTFS_DIRENT_ACTIVE) ==
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_ACTIVE)))
|
||||
#endif
|
||||
{
|
||||
/* Count this entry */
|
||||
count++;
|
||||
@ -1190,10 +1366,17 @@ int smartfs_countdirentries(struct smartfs_mountpt_s *fs,
|
||||
direntry = (struct smartfs_entry_header_s *) &fs->fs_rwbuffer[offset];
|
||||
while (offset + entrysize < readwrite.count)
|
||||
{
|
||||
#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
|
||||
if (((smartfs_rdle16(&direntry->flags) & SMARTFS_DIRENT_EMPTY) !=
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_EMPTY)) &&
|
||||
((smartfs_rdle16(&direntry->flags) & SMARTFS_DIRENT_ACTIVE) ==
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_ACTIVE)))
|
||||
#else
|
||||
if (((direntry->flags & SMARTFS_DIRENT_EMPTY) !=
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_EMPTY)) &&
|
||||
((direntry->flags & SMARTFS_DIRENT_ACTIVE) ==
|
||||
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_ACTIVE)))
|
||||
#endif
|
||||
{
|
||||
/* Count this entry */
|
||||
count++;
|
||||
@ -1223,7 +1406,7 @@ errout:
|
||||
****************************************************************************/
|
||||
|
||||
int smartfs_truncatefile(struct smartfs_mountpt_s *fs,
|
||||
struct smartfs_entry_s *entry)
|
||||
struct smartfs_entry_s *entry, FAR struct smartfs_ofile_s *sf)
|
||||
{
|
||||
int ret;
|
||||
uint16_t nextsector;
|
||||
@ -1263,6 +1446,15 @@ int smartfs_truncatefile(struct smartfs_mountpt_s *fs,
|
||||
|
||||
if (nextsector == entry->firstsector)
|
||||
{
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
|
||||
/* When we have a sector buffer in use, simply skip the first sector */
|
||||
|
||||
nextsector = sector;
|
||||
continue;
|
||||
|
||||
#else
|
||||
|
||||
/* Fill our buffer with erased data */
|
||||
|
||||
memset(fs->fs_rwbuffer, CONFIG_SMARTFS_ERASEDSTATE, fs->fs_llformat.availbytes);
|
||||
@ -1281,6 +1473,7 @@ int smartfs_truncatefile(struct smartfs_mountpt_s *fs,
|
||||
/* Set the entry's data length to zero ... we just truncated */
|
||||
|
||||
entry->datlen = 0;
|
||||
#endif /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1299,6 +1492,31 @@ int smartfs_truncatefile(struct smartfs_mountpt_s *fs,
|
||||
nextsector = sector;
|
||||
}
|
||||
|
||||
/* Now deal with the first sector in the event we are using a sector buffer
|
||||
like we would be if CRC is enabled.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
|
||||
if (sf)
|
||||
{
|
||||
/* Using sector buffer and we have an open file context. Just update
|
||||
* the sector buffer in the open file context.
|
||||
*/
|
||||
|
||||
readwrite.logsector = entry->firstsector;
|
||||
readwrite.offset = 0;
|
||||
readwrite.count = sizeof(struct smartfs_chain_header_s);
|
||||
readwrite.buffer = (uint8_t *) fs->fs_rwbuffer;
|
||||
ret = FS_IOCTL(fs, BIOC_READSECT, (unsigned long) &readwrite);
|
||||
|
||||
memset(sf->buffer, CONFIG_SMARTFS_ERASEDSTATE, fs->fs_llformat.availbytes);
|
||||
header = (struct smartfs_chain_header_s *) sf->buffer;
|
||||
header->type = SMARTFS_SECTOR_TYPE_FILE;
|
||||
sf->bflags = SMARTFS_BFLAG_DIRTY;
|
||||
entry->datlen = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = OK;
|
||||
|
||||
errout:
|
||||
|
@ -200,6 +200,12 @@
|
||||
* ProcFS data.
|
||||
* OUT: None (ioctl return value provides
|
||||
* success/failure indication). */
|
||||
#define BIOC_DEBUGCMD _BIOC(0x000B) /* Send driver specific debug command /
|
||||
* data to the block device.
|
||||
* IN: Pointer to a struct defined for
|
||||
* the block with specific debug
|
||||
* command and data.
|
||||
* OUT: None. */
|
||||
|
||||
/* NuttX MTD driver ioctl definitions ***************************************/
|
||||
|
||||
|
@ -89,6 +89,20 @@ struct smart_read_write_s
|
||||
const uint8_t *buffer; /* Pointer to the data to write */
|
||||
};
|
||||
|
||||
/* The following defines the procfs data exchange interface between the
|
||||
* SMART MTD and FS layers.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)
|
||||
struct smart_procfs_data_s
|
||||
{
|
||||
#ifdef CONFIG_MTD_SMART_ERASE_DEBUG
|
||||
const uint16_t *erasecounts; /* Pointer to the erase counts array */
|
||||
uint16_t erasesize; /* Number of entries in the erase counts array */
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
@ -50,6 +50,9 @@
|
||||
* Pre-Processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define SMART_DEBUG_CMD_SET_DEBUG_LEVEL 1
|
||||
#define SMART_DEBUG_CMD_SHOW_LOGMAP 2
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
@ -91,6 +94,19 @@ struct mtd_smart_procfs_data_s
|
||||
FAR const struct smart_alloc_s *allocs; /* Array of allocations */
|
||||
uint16_t alloccount; /* Number of items in the array */
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_SMART_WEAR_LEVEL
|
||||
uint32_t uneven_wearcount; /* Number of uneven block erases */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* The following defines debug command data passed from the procfs layer to
|
||||
the SMART MTD layer for debug purposes.
|
||||
*/
|
||||
|
||||
struct mtd_smart_debug_data_s
|
||||
{
|
||||
uint8_t debugcmd; /* Debug command */
|
||||
uint32_t debugdata; /* Debug data */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
Loading…
x
Reference in New Issue
Block a user