Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/littlefs-project/littlefs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lfs.c
AgeCommit message (Collapse)Author
2018-10-20Added 2GiB file size limit and EFBIG reportingChristopher Haster
On disk, littlefs uses 32-bit integers to track file size. This sets a theoretical limit of 4GiB for files. However, the API passes file sizes around as signed numbers, with negative values representing error codes. This means that not all of the APIs will work with file sizes > 2GiB. Because of related complications over in FUSE land, I've added the LFS_FILE_MAX constant and proper error reporting if file writes/seeks exceed the 2GiB limit. In v2 this will join the other constants that get stored in the superblock to help portability. Since littlefs is targeting microcontrollers, it's likely this will be a sufficient solution. Note that it's still possible to enable partial-support for 4GiB files by defining LFS_FILE_MAX during compilation. This will work for most of the APIs, except lfs_file_seek, lfs_file_tell, and lfs_file_size. We can also consider improving support for 4GiB files, by making seek a bit more complicated and adding a lfs_file_stat function. I'll leave this for a future improvement if there's interest. Found by cgrozemuller
2018-10-20Fixed issue where a rename causes a split and pushes dir out of syncChristopher Haster
The issue happens when a rename causes a split in the destination pair. If the destination pair is the same as the source pair, this triggers the logic to keep both pairs in sync. Unfortunately, this logic didn't work, because the source entry still resides in the old source pair, unlike the destination pair, which is now in the new pair created by the split. The best fix for now is to refetch the source pair after the changes to the destination pair. This isn't the most efficient solution, but fortunately this bug has already been fixed in the revamped move logic in littlefs v2 (currently in progress). Found by ohoc
2018-09-29Fix -Wsign-compare errorVincent Dupont
2018-09-27Added -Wjump-misses-init and fixed uninitialized warningsChristopher Haster
2018-09-27Fixed possible infinite loop in deorphan stepChristopher Haster
Normally, the linked-list of directory pairs should terminate at a null pointer. However, it is possible if the filesystem is corrupted, that that this linked-list forms a cycle. This should never happen with littlefs's power resilience, but if it does we should recover appropriately. Modified lfs_deorphan to notice if we have a cycle and return LFS_ERR_CORRUPT in that situation. Found by kneko715
2018-09-04Fixed issue with corruption due to different cache sizesChristopher Haster
The lfs_cache_zero function that was recently added assumed a single cache size, which is incorrect. This would cause a buffer overflow if read_size != prog_size. Since lfs_cache_zero is only used for scrubbing prog caches, the fix here is to use lfs_cache_drop instead on read caches. Info in read caches should never make its way to disk. Found by nstcl
2018-07-20Fix memory leaks in lfs_mount and lfs_formatFreddie Chopin
Squashed: - Change lfs_deinit() return to void to simplify error handling - Move lfs_deinit() before lfs_init() - Fix memory leaks in lfs_init() - Fix memory leaks in lfs_format() - Fix memory leaks in lfs_mount()
2018-07-18Merge pull request #76 from ARMmbed/fix-corrupt-readChristopher Haster
Add handling for corrupt as initial state of blocks
2018-07-18Added file config structure and lfs_file_opencfgDamien George
The optional config structure options up the possibility of adding file-level configuration in a backwards compatible manner. Also adds possibility to open multiple files with LFS_NO_MALLOC enabled thanks to dpgeorge Also bumped minor version to v1.5
2018-07-16Added handling for corrupt as initial state of blocksfix-corrupt-readChristopher Haster
Before this, littlefs incorrectly assumed corrupt blocks were only the result of our own modification. This would be fine for most cases of freshly erased storage, but for storage with block-level ECC this wasn't always true. Fortunately, it's quite easy for littlefs to handle this case correctly, as long as corrupt storage always reports that it is corrupt, which for most forms of ECC is the case unless we perform a write on the storage. found by rojer
2018-07-11Use PRIu32 and PRIx32 format specifiers to fix warningsFreddie Chopin
When using "%d" or "%x" with uint32_t types, arm-none-eabi-gcc reports warnings like below: -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- In file included from lfs.c:8: lfs_util.h:45:12: warning: format '%d' expects argument of type 'int', but argument 4 has type 'lfs_block_t' {aka 'long unsigned int'} [-Wformat=] printf("lfs debug:%d: " fmt "\n", __LINE__, __VA_ARGS__) ^~~~~~~~~~~~~~~~ lfs.c:2512:21: note: in expansion of macro 'LFS_DEBUG' LFS_DEBUG("Found partial move %d %d", ^~~~~~~~~ lfs.c:2512:55: note: format string is defined here LFS_DEBUG("Found partial move %d %d", ~^ %ld -- >8 -- >8 -- >8 -- >8 -- >8 -- >8 -- Fix this by replacing "%d" and "%x" with `"%" PRIu32` and `"%" PRIx32`.
2018-07-10Fixed information leaks through reused cachesChristopher Haster
As a shortcut, littlefs never bother to zero any of the buffers is used. It didn't need to because it would always write out the entirety of the data it needed. Unfortunately, this, combined with the extra padding used to align buffers to the nearest prog size, would lead to uninitialized data getting written out to disk. This means unrelated file data could be written to different parts of storage, or worse, information leaked from the malloc calls could be written out to disk unnecessarily. found by rojer
2018-07-02Fixed shadowed variable warningsDamien George
- Fixed shadowed variable warnings in lfs_dir_find. - Fixed unused parameter warnings when LFS_NO_MALLOC is enabled. - Added extra warning flags to CFLAGS. - Updated tests so they don't shadow the "size" variable for -Wshadow
2018-06-21Changed license to BSD-3-Clauselicense-bsd-3Christopher Haster
For better compatibility with GPL v2 With permissions from: - aldot - Sim4n6 - jrast
2018-04-30Added error when opening multiple files with a statically allocated bufferv1.3Christopher Haster
Opening multiple files simultaneously is not supported without dynamic memory, but the previous behaviour would just let the files overwrite each other, which could lead to bad errors down the line found by husigeza
2018-04-22Fixed issue with trailing dots in file pathsfix-trailing-dotsChristopher Haster
Paths such as the following were causing issues: /tea/hottea/. /tea/hottea/.. Unfortunately the existing structure for path lookup didn't make it very easy to introduce proper handling in this case without duplicating the entire skip logic for paths. So the lfs_dir_find function had to be restructured a bit. One odd side-effect of this is that now lfs_dir_find includes the initial fetch operation. This kinda breaks the fetch -> op pattern of the dir functions, but does come with a nice code size reduction.
2018-04-11Fixed lookahead overflow and removed unbounded lookahead pointersChristopher Haster
As pointed out by davidefer, the lookahead pointer modular arithmetic does not work around integer overflow when the pointer size is not a multiple of the block count. To avoid overflow problems, the easy solution is to stop trying to work around integer overflows and keep the lookahead offset inside the block device. To make this work, the ack was modified into a resetable counter that is decremented every block allocation. As a plus, quite a bit of the allocation logic ended up simplified.
2018-04-09Fixed issue with lookahead trusting old lookahead blocksChristopher Haster
One of the big simplifications in littlefs's implementation is the complete lack of tracking free blocks, allowing operations to simply drop blocks that are no longer in use. However, this means the lookahead buffer can easily contain outdated blocks that were previously deleted. This is usually fine, as littlefs will rescan the storage if it can't find a free block in the lookahead buffer, but after changes that caused littlefs to more conservatively respect the alloc acks (e611cf5), any scanned blocks after an ack would be incorrectly trusted. The fix is to eagerly scan ahead in the lookahead when we allocate so that alloc acks are better able to discredit old lookahead blocks. Since usually alloc acks are tightly coupled to allocations of one or two blocks, this allows littlefs to properly rescan every set of allocations. This may still be a concern if there is a long series of worn out blocks, but in the worst case littlefs will conservatively avoid using blocks it's not sure about. Found by davidefer
2018-03-19Removed the uninitialized read for invalid superblocksChristopher Haster
2018-03-01Fixed issue updating dir struct when extended dir chainChristopher Haster
Like most of the lfs_dir_t functions, lfs_dir_append is responsible for updating the lfs_dir_t struct if the underlying directory block is moved. This property makes handling worn out blocks much easier by removing the amount of state that needs to be considered during a directory update. However, extending the dir chain is a bit of a corner case. It's not changing the old block, but callers of lfs_dir_append do assume the "entry" will reside in "dir" after lfs_dir_append completes. This issue only occurs when creating files, since mkdir does not use the entry after lfs_dir_append. Unfortunately, the tests against extending the directory chain were all made using mkdir. Found by schouleu
2018-03-01Fixed handling of root as target for create operationsChristopher Haster
Before this patch, when calling lfs_mkdir or lfs_file_open with root as the target, littlefs wouldn't find the path properly and happily run into undefined behaviour. The fix is to populate a directory entry for root in the lfs_dir_find function. As an added plus, this allowed several special cases around root to be completely dropped.
2018-02-19Added more configurable utilsChristopher Haster
Note: It's still expected to modify lfs_utils.h when porting littlefs to a new target/system. There's just too much room for system-specific improvements, such as taking advantage of CRC hardware. Rather, encouraging modification of lfs_util.h and making it easy to modify and debug should result in better integration with the consuming systems. This just adds a bunch of quality-of-life improvements that should help development and integration in littlefs. - Macros that require no side-effects are all-caps - System includes are only brought in when needed - Malloc/free wrappers - LFS_NO_* checks for quickly disabling things at the command line - At least a little-bit more docs
2018-02-19Added conversion to/from little-endian on diskChristopher Haster
Required to support big-endian processors, with the most notable being the PowerPC architecture. On little-endian architectures, these conversions can be optimized out and have no code impact. Initial patch provided by gmouchard
2018-02-08Fix incorrect lookahead population before ackChristopher Haster
Rather than tracking all in-flight blocks blocks during a lookahead, littlefs uses an ack scheme to mark the first allocated block that hasn't reached the disk yet. littlefs assumes all blocks since the last ack are bad or in-flight, and uses this to know when it's out of storage. However, these unacked allocations were still being populated in the lookahead buffer. If the whole block device fits in the lookahead buffer, _and_ littlefs managed to scan around the whole storage while an unacked block was still in-flight, it would assume the block was free and misallocate it. The fix is to only fill the lookahead buffer up to the last ack. The internal free structure was restructured to simplify the runtime calculation of lookahead size.
2018-02-04Fixed some minor error code differencesChristopher Haster
- Write on read-only file to return LFS_ERR_BADF - Renaming directory onto file to return LFS_ERR_NOTEMPTY - Changed LFS_ERR_INVAL in lfs_file_seek to assert
2018-02-04Fixed error check when truncating files to larger sizeChristopher Haster
2018-02-04Silenced more of aldot's warningsChristopher Haster
Flags used: -Wall -Wextra -Wshadow -Wwrite-strings -Wundef -Wstrict-prototypes -Wunused -Wunused-parameter -Wunused-function -Wunused-value -Wmissing-prototypes -Wmissing-declarations -Wold-style-definition
2018-02-04Commentary typo fixBernhard Reutner-Fischer
2018-02-04Silence shadow warningsBernhard Reutner-Fischer
2018-01-26Add version info for software library and on-disk structuresChristopher Haster
An annoying part of filesystems is that the software library can change independently of the on-disk structures. For this reason versioning is very important, and must be handled separately for the software and on-disk parts. In this patch, littlefs provides two version numbers at compile time, with major and minor parts, in the form of 6 macros. LFS_VERSION // Library version, uint32_t encoded LFS_VERSION_MAJOR // Major - Backwards incompatible changes LFS_VERSION_MINOR // Minor - Feature additions LFS_DISK_VERSION // On-disk version, uint32_t encoded LFS_DISK_VERSION_MAJOR // Major - Backwards incompatible changes LFS_DISK_VERSION_MINOR // Minor - Feature additions Note that littlefs will error if it finds a major version number that is different, or a minor version number that has regressed.
2018-01-21Added lfs_file_truncateChristopher Haster
As a copy-on-write filesystem, the truncate function is a very nice function to have, as it can take advantage of reusing the data already written out to disk.
2018-01-12Reduced ctz traverse runtime by 2xChristopher Haster
Unfortunately for us, the ctz skip-list does not offer very much benefit for full traversals. Since the information about which blocks are in use are spread throughout the file, we can't use the fast-lanes embedded in the skip-list without missing blocks. However, it turns out we can at least use the 2nd level of the skip-list without missing any blocks. From an asymptotic analysis, a constant speed up isn't interesting, but from a pragmatic perspective, a 2x speedup is not bad.
2018-01-12Added error code LFS_ERR_NOTEMPTYChristopher Haster
As noted by itayzafrir, removing a non-empty directory should error with ENOTEMPTY, not EINVAL
2018-01-11Added asserts on geometry and updated config documentationChristopher Haster
littlefs had an unwritten assumption that the block device's program size would be a multiple of the read size, and the block size would be a multiple of the program size. This has already caused confusion for users. Added a note and assert to catch unexpected geometries early. Also found that the prog/erase functions indicated they must return LFS_ERR_CORRUPT to catch bad blocks. This is no longer true as errors are found by CRC.
2018-01-11Fixed file truncation without writesChristopher Haster
In the open call, the LFS_O_TRUNC flag was correctly zeroing the file, but it wasn't actually writing the change out to disk. This went unnoticed because in the cases where the truncate was followed by a file write, the updated contents would be written out correctly. Marking the file as dirty if the file isn't already truncated fixes the problem with the least impact. Also added better test cases around truncating files.
2018-01-04Fixed positive seek bounds checkingChristopher Haster
This bug was a result of an annoying corner case around intermingling signed and unsigned offsets. The boundary check that prevents seeking a file to a position before the file was preventing valid seeks with positive offsets. This corner case is a bit more complicated than it looks because the offset is signed, while the size of the file is unsigned. Simply casting both to signed or unsigned offsets won't handle large files.
2017-12-27Fixed issue with immediate exhaustion and small unaligned storageChristopher Haster
This was a small hole in the logic that handles initializing the lookahead buffer. To imitate exhaustion (so the block allocator will trigger a scan), the lookahead buffer is rewound a full lookahead and set up to look like it is exhausted. However, unlike normal allocation, this rewind was not kept aligned to a multiple of the scan size, which is limited by both the lookahead buffer and the total storage size. This bug went unnoticed for so long because it only causes problems when the block device is both: 1. Not aligned to the lookahead buffer (not a power of 2) 2. Smaller than the lookahead buffer While this seems like a strange corner case for a block device, this turned out to be very common for internal flash, especially when a handleful of blocks are reserved for code.
2017-11-22Added directory list for synchronizing in flight directoriesChristopher Haster
As it was, if a user operated on a directory while at the same time iterating over the directory, the directory objects could fall out of sync. In the best case, files may be skipped while removing everything in a file, in the worst case, a very poorly timed directory relocate could be missed. Simple fix is to add the same directory tracking that is currently in use for files, at a small code+complexity cost.
2017-11-17Fixed standard name mismatch LFS_ERR_EXISTS -> LFS_ERR_EXISTChristopher Haster
Matches the standard EEXIST name found on most systems. Other than this name, all other common constant names were consistent in this manner.
2017-11-17Added sticky-bit for preventing file syncs after write errorsChristopher Haster
Short story, files are no longer committed to directories during file sync/close if the last write did not complete successfully. This avoids a set of interesting user-experience issues related to the end-of-life behaviour of the filesystem. As a filesystem approaches end-of-life, the chances of running into LFS_ERR_NOSPC grows rather quickly. Since this condition occurs after at the end of a devices life, it's likely that operating in these conditions hasn't been tested thoroughly. In the specific case of file-writes, you can hit an LFS_ERR_NOSPC after parts of the file have been written out. If the program simply continues and closes the file, the file is written out half completed. Since littlefs has a strong garuntee the prevents half-writes, it's unlikely this state of the file would be expected. To make things worse, since close is also responsible for memory cleanup, it's actually _impossible_ to continue working as it was without leaking memory. By prevent the file commits, end-of-life behaviour should at least retain a previous copy of the filesystem without any surprises.
2017-11-17Modified lfs_ctz_extend to be a little bit saferChristopher Haster
Specifically around error handling. As is, incorrectly handled errors could cause higher code to get uninitialized blocks, potentially leading to writes to arbitray blocks on storage.
2017-11-16Fixed issue with committing directories to bad-blocks that are stuckChristopher Haster
This is only an issue in the weird case that are worn down block is left in the odd state of not being able to change the data that resides on the block. That being said, this does pop up often when simulating wear on block devices. Currently, directory commits checked if the write succeeded by crcing the block to avoid the additional RAM cost for another buffer. However, before this commit, directory commits just checked if the block crc was valid, rather than comparing to the expected crc. This would usually work, unless the block was stuck in a state with valid crc. The fix is to simply compare with the expected crc to find errors.
2017-11-10Fixed corner case with immediate exhaustion and lookahead==block_countChristopher Haster
The previous math for determining if we scanned all of disk wasn't set up correctly in the lfs_mount function. If lookahead == block_count the lfs_alloc function would think we had already searched the entire disk. This is only an issue if we manage to exhaust a block on the first pass after mount, since lfs_alloc_ack resets the lookahead region into a valid state after a succesful block allocation.
2017-11-10Fixed issue with aggressively rounding down lookahead configurationChristopher Haster
The littlefs allows buffers to be passed statically in the case that a system does not have a heap. Unfortunately, this means we can't round up in the case of an unaligned lookahead buffer. Double unfortunately, rounding down after clamping to the block device size could result in a lookahead of zero for block devices < 32 blocks large. The assert in littlefs does catch this case, but rounding down prevents support for < 32 block devices. The solution is to simply require a 32-bit aligned buffer with an assert. This avoids runtime problems while allowing a user to pass in the correct buffer for < 32 block devices. Rounding up can be handled at higher API levels.
2017-11-10Removed stray newline in LFS_ERROR for versionChristopher Haster
2017-10-31Removed toolchain specific warningsChristopher Haster
- Comparisons with differently signed integer types - Incorrectly signed constant - Unreachable default returns - Leaked uninitialized variables in relocate goto statements
2017-10-30Adopted alternative implementation for lfs_ctz_indexChristopher Haster
Same runtime cost, however reduces the logic and avoids one of the two big branches. See the DESIGN.md for more info. Now uses these equations instead of the messy guess and correct method: n = (N - w/8(popcount(N/(B-2w/8)) + 2)) / (B-2w/8) off = N - (B-w2/8)n - w/8popcount(n)
2017-10-18Adopted lfs_ctz_index implementation using popcountChristopher Haster
This reduces the O(n^2logn) runtime to read a file to only O(nlog). The extra O(n) did not touch the disk, so it isn't a problem until the files become very large, but this solution comes with very little cost. Long story short, you can find the block index + offset pair for a CTZ linked-list with this series of formulas: n' = floor(N / (B - 2w/8)) N' = (B - 2w/8)n' + (w/8)popcount(n') off' = N - N' n, off = n'-1, off'+B if off' < 0 n', off'+(w/8)(ctz(n')+1) if off' >= 0 For the long story, you will need to see the updated DESIGN.md
2017-10-18Slight name change with ctz skip-list functionsChristopher Haster
changed: lfs_index -> lfs_ctz_index lfs_index_find -> lfs_ctz_find lfs_index_append -> lfs_ctz_append lfs_index_traverse -> lfs_ctz_traverse
2017-10-13Removed clamping to block size in ctz linked-listChristopher Haster
Initially, I was concerned that the number of pointers in the ctz linked-list could exceed the storage in a block. Long story short this isn't really possible outside of extremely small block sizes. Since clamping impacts the layout of files on disk, removing the block size removed quite a bit of logic and corner cases. Replaced with an assert on block size during initialization. --- Long story long, the minimum block size needed to store all ctz pointers in a filesystem can be found with this formula: B = (w/8)*log2(2^w / (B - 2*(w/8))) where: B = block size in bytes w = pointer width in bits It's not a very pretty formula, but does give us some useful info if we apply some math: min block size: 32 bit ctz linked-list = 104 bytes 64 bit ctz linked-list = 448 bytes For littlefs, 128 bytes is a perfectly reasonable minimum block size.