Commit Graph

42 Commits

Author SHA1 Message Date
Christopher Haster
74fe46de3d
Merge pull request #233 from ARMmbed/discourage-no-wear-leveling
Change block_cycles disable from 0 to -1
2019-07-28 21:35:48 -05:00
Christopher Haster
e8c023aab0 Changed FUSE branch to v2 (previously v2-alpha) 2019-07-28 20:43:12 -05:00
Christopher Haster
ef1c926940 Increased testing to include geometries that can't be fully tested
This is primarily to get better test coverage over devices with very
large erase/prog/read sizes. The unfortunate state of the tests is
that most of them rely on a specific block device size, so that
ENOSPC and ECORRUPT errors occur in specific situations.

This should be improved in the future, but at least for now we can
open up some of the simpler tests to run on these different
configurations.

Also added testing over both 0x00 and 0xff erase values in emubd.

Also added a number of small file tests that expose issues prevalent
on NAND devices.
2019-07-26 19:50:17 -05:00
Christopher Haster
abd90cb84c Fixed 32-bit/64-bit Ubuntu multilib issue in Travis 2019-07-01 19:34:06 -05:00
Christopher Haster
f35fb8c148 Fixed migration test condition for prefix branches
Both the littlefs-fuse and littlefs-migration test jobs depend on
the external littlefs-fuse repo. But unfortunately, the automatic
patching to update the external repo with the version under test
does not work with the prefix branches.

In this case we can just skip these tests, they've already been tested
multiple times to get to this point.
2019-04-16 18:29:44 -05:00
Christopher Haster
25a843aab7 Fixed .travis.yml to use explicit branch names for migration testing
This lets us actually update the littlefs-fuse repo instead of being
bound to master for v1.
2019-04-12 15:13:00 -05:00
Christopher Haster
a32be1d875 Merge remote-tracking branch 'origin/master' into v2-alpha 2019-04-08 15:12:36 -05:00
Christopher Haster
7e110b44c0 Added automatic version prefixing to releases
The script itself is a part of .travis.yml, using ./scripts/prefix.py
for applying prefixes to the source code.

This purpose of the automatic job is to provide a branch containing
version prefixes, to avoid name conflicts in binaries containing
different major versions of littlefs with only a git clone.

As a part of each release, two branches and a tag are created:
- vN        - moving branch
- vN-prefix - moving branch
- vN.N.N    - immutable tag

The major version branch (vM) is created on major releases, but updated
every patch release. The patch version tag (vM.M.P) is created every
patch release. Patch releases occur every time a commit is merged into
master, though multiple merges may be coalesced.

The major prefix branch (vM-prefix) is modified with the ./scripts/prefix.py
script. Note that this branch is updated as a synthetic merge commit
with the previous history of vM-prefix. The reason for this is to allow
users to easily update vM-prefix with a `git pull` as they would for
other branches.

A---B---C---D---E master, v1, v1.7.3
     \       \   \
      F-------G---H v1-prefix
2019-04-08 13:55:35 -05:00
Christopher Haster
9568f8ee2d Added v1->v2 migration into CI
Also fixed issue where migration would not handle large dirs due to v1
iteration changing the pair of the directory.
2019-04-01 22:12:08 -05:00
Christopher Haster
4ad09d6c4e Added migration from littlefs v1
This is the help the introduction of littlefs v2, which is disk
incompatible with littlefs v1. While v2 can't mount v1, what we can
do is provide an optional migration, which can convert v1 into v2
partially in-place.

At worse, we only need to carry over the readonly operations on v1,
which are much less complicated than the write operations, so the extra
code cost may be as low as 25% of the v1 code size. Also, because v2
contains only metadata changes, it's possible to avoid copying file
data during the update.

Enabling the migration requires two steps
1. Defining LFS_MIGRATE
2. Call lfs_migrate (only available with the above macro)

Each macro multiplies the number of configurations needed to be tested,
so I've been avoiding macro controlled features since there's still work
to be done around testing the single configuration that's already
available. However, here the cost would be too high if we included migration
code in the standard build. We can't use the lfs_migrate function for
link time gc because of a dependency between the allocator and v1 data
structures.

So how does lfs_migrate work? It turned out to be a bit complicated, but
the answer is a multistep process that relies on mounting v1 readonly and
building the metadata skeleton needed by v2.

1. For each directory, create a v2 directory
2. Copy over v1 entries into v2 directory, including the soft-tail entry
3. Move head block of v2 directory into the unused metadata block in v1
   directory. This results in both a v1 and v2 directory sharing the
   same metadata pair.
4. Finally, create a new superblock in the unused metadata block of the
   v1 superblock.

Just like with normal metadata updates, the completion of the write to
the second metadata block marks a succesful migration that can be
mounted with littlefs v2. And all of this can occur atomically, enabling
complete fallback if power is lost of an error occurs.

Note there are several limitations with this solution.

1. While migration doesn't duplicate file data, it does temporarily
   duplicate all metadata. This can cause a device to run out of space if
   storage is tight and the filesystem as many files. If the device was
   created with >~2x the expected storage, it should be fine.

2. The current implementation is not able to recover if the metadata
   pairs develop bad blocks. It may be possilbe to workaround this, but
   it creates the problem that directories may change location during
   the migration. The other solutions I've looked at are complicated and
   require superlinear runtime. Currently I don't think it's worth
   fixing this limitation.

3. Enabling the migration requires additional code size. Currently this
   looks like it's roughly 11% at least on x86.

And, if any failure does occur, no harm is done to the original v1
filesystem on disk.
2019-02-27 19:58:07 -06:00
Christopher Haster
c8a39c4b23 Merge remote-tracking branch 'origin/master' into v2-rebase-part2 2018-10-20 21:02:25 -05:00
Christopher Haster
ec4d8b68ad Changed release script to generate drafts 2018-10-20 12:34:41 -05:00
Christopher Haster
795dd8c7ab Fixed mkdir when inserting into a non-end block
This was an oversight on my part when adding strict ordering to
directories. Unfortunately now we can't take advantage of the atomic
creation of tail+dir entries. Now we need to first create the tail, then
create the actually directory entry. If we lose power, the orphan is
cleaned up like orphans created during remove.

Note that we still take advantage of the atomic tail+dir entries if we
are an end block. This is actually because this corner case is
complicated to _not_ do atomically, needing to update the directory we
just committed to.
2018-10-18 10:00:49 -05:00
Christopher Haster
7af8b81b81 Changed lookahead configuration unit to bytes instead of bits
The fact that the lookahead buffer uses bits instead of bytes is an
internal detail. Poking this through to the user API has caused a decent
amount of confusion. Most buffers are provided as bytes and the
inconsistency here can be surprising.

The use of bytes instead of bits also makes us forward compatible in
the case that we want to change the lookahead internal representation
(hint segment list).

Additionally, we change the configuration name to lookahead_size. This
matches other configurations, such as cache_size and read_size, while
also notifying the user that something important changed at compile time
(by breaking).
2018-10-18 10:00:49 -05:00
Christopher Haster
e4a0d586d5 Added building blocks for dynamic wear-leveling
Initially, littlefs relied entirely on bad-block detection for
wear-leveling. Conceptually, at the end of a devices lifespan, all
blocks would be worn evenly, even if they weren't worn out at the same
time. However, this doesn't work for all devices, rather than causing
corruption during writes, wear reduces a devices "sticking power",
causing bits to flip over time. This means for many devices, true
wear-leveling (dynamic or static) is required.

Fortunately, way back at the beginning, littlefs was designed to do full
dynamic wear-leveling, only dropping it when making the retrospectively
short-sighted realization that bad-block detection is theoretically
sufficient. We can enable dynamic wear-leveling with only a few tweaks
to littlefs. These can be implemented without breaking backwards
compatibility.

1. Evict metadata-pairs after a certain number of writes. Eviction in
   this case is identical to a relocation to recover from a bad block.
   We move our data and stick the old block back into our pool of
   blocks.

   For knowing when to evict, we already have a revision count for each
   metadata-pair which gives us enough information. We add the
   configuration option block_cycles and evict when our revision count
   is a multiple of this value.

2. Now all blocks participate in COW behaviour. However we don't store
   the state of our allocator, so every boot cycle we reuse the first
   blocks on storage. This is very bad on a microcontroller, where we
   may reboot often. We need a way to spread our usage across the disk.

   To pull this off, we can simply randomize which block we start our
   allocator at. But we need a random number generator that is different
   on each boot. Fortunately we have a great source of entropy, our
   filesystem. So we seed our block allocator with a simple hash of the
   CRCs on our metadata-pairs. This can be done for free since we
   already need to scan the metadata-pairs during mount.

What we end up with is a uniform distribution of wear on storage. The
wear is not perfect, if a block is used for metadata it gets more wear,
and the randomization may not be exact. But we can never actually get
perfect wear-leveling, since we're already resigned to dynamic
wear-leveling at the file level.

With the addition of metadata logging, we end up with a really
interesting two-stage wear-leveling algorithm. At the low-level,
metadata is statically wear-leveled. At the high-level, blocks are
dynamically wear-leveled.

---

This specific commit implements the first step, eviction of metadata
pairs. Entertwining this into the already complicated compact logic was
a bit annoying, however we can combine the logic for superblock
expansion with the logic for metadata-pair eviction.
2018-10-18 09:30:45 -05:00
Christopher Haster
6d0a6fc462 Merge remote-tracking branch 'origin/master' into v2-alpha 2018-10-16 11:33:00 -05:00
Christopher Haster
3186e89b14 Changed littlefs-fuse target for testing purposes
This is a downside caused by relying on and external repo for testing,
but also storing the CI configuration inside this repo. Fortunately we
can use a temporary v2-alpha branch in the FUSE repo mirroring the
v2-alpha branch for testing.
2018-10-16 09:42:46 -05:00
Christopher Haster
3cfa08602a Introduced cache_size as alternative to hardware read/write sizes
The introduction of an explicit cache_size configuration allows
customization of the cache buffers independently from the hardware
read/write sizes.

This has been one of littlefs's main handicaps. Without a distinction
between cache units and hardware limitations, littlefs isn't able to
read or program _less_ than the cache size. This leads to the
counter-intuitive case where larger cache sizes can actually be harmful,
since larger read/prog sizes require sending more data over the bus if
we're only accessing a small set of data (for example the CTZ skip-list
traversal).

This is compounded with metadata logging, since a large program size
limits the number of commits we can write out in a single metadata
block. It really doesn't make sense to link program size + cache
size here.

With a separate cache_size configuration, we can be much smarter about
what we actually read/write from disk.

This also simplifies cache handling a bit. Before there were two
possible cache sizes, but these were rarely used. Note that the
cache_size is NOT written to the superblock and can be freely changed
without breaking backwards compatibility.
2018-10-16 08:32:01 -05:00
Christopher Haster
2a8277bd4d Added test coverage for filesystems with no inline files 2018-10-09 23:02:57 -05:00
Christopher Haster
0bb1f7af17 Modified release script to create notes only on minor releases
Before, release notes with a list of changes were created every
patch release. Unfortunately, it looks like this will create a lot of
noise on github, with a notification every patch release, which may be
as often as every time a PR is merged.

Rather than creating all of this noise for relatively uninteresting
changes, the script will now stick to simple tags, and create the
release notes only on minor releases.

I think this is what several of you were originally suggesting,
sorry about the journey, at least I learned a lot.
2018-09-29 12:31:27 -05:00
Christopher Haster
cb62bf2188 Fixed release script issue with fetching recent tags
Fetching all tags was triggering the pagination system inside the github
API. This prevent version tags from being found.

Modified to use the version tag prefix in the ref lookup, however this
still may cause an issue if there are still enough patch releases to trigger
pagination.

Simpleish solution is to grab the link header to jump to the last page,
since pagination results appear to be in sorted order.
2018-09-27 14:46:12 -05:00
Christopher Haster
f5e0539951 Fixed issue with release script non-standard version tags 2018-07-27 15:20:00 -05:00
Christopher Haster
0234c77102 Simplified release process based on feedback
Previously, littlefs had mutable versions. That is, anytime a new commit
landed on master, the bot would update the most recent version to
contain the patch. The idea was that this would make sure users always
had the most recent bug fixes. Immutable snapshots could be accessed
through the git hashes.

However, at this point multiple developers have pointed out that this is
confusing, with mutable versions being non-standard and surprising.

This new release process adopts SemVer in its entirety, with
incrementing patch numbers and immutable versions.

When a new commit lands on master:
1. The major/minor version is taken from lfs.h
2. The most recent patch version is looked up on GitHub and incremented
3. A changelog is built out of the commits to the previous version
4. A new release is created on GitHub

Additionally, any commits that land while CI is still running are
coalesced together. Which means multiple PRs can land in a single
release.
2018-07-25 14:21:58 -05:00
Christopher Haster
5a17fa42e4 Fixed script issue with bash expansion inside makefile parameter
This was causing code sizes to be reported with several of the logging
functions still built in. A useful number, but not the minimum
achievable code size.
2018-07-10 17:18:45 -05:00
Christopher Haster
dbc3cb1798 Fixed Travis rate-limit issue with Github requests
Using credentials avoids rate-limiting based on Travis's IP address
2018-04-08 17:31:09 -05:00
Christopher Haster
155224600a Fixed Travis issue with deploy stage in PRs 2018-03-12 19:57:57 -05:00
Christopher Haster
b2124a5ae5 Fixed multiple deploy steps in Travis 2018-02-20 17:55:30 -06:00
Christopher Haster
67daf9e2c5 Added cross-compile targets for testing
Using gcc cross compilers and qemu:
- make test CC="arm-linux-gnueabi-gcc --static -mthumb" EXEC="qemu-arm"
- make test CC="powerpc-linux-gnu-gcc --static" EXEC="qemu-ppc"
- make test CC="mips-linux-gnu-gcc --static" EXEC="qemu-mips"

Also separated out Travis jobs and added some size reporting
2018-02-19 01:40:28 -06:00
Christopher Haster
fd04ed4f25 Added autogenerated release notes from commits 2018-02-02 02:35:07 -06:00
Christopher Haster
6d8e0e21d0 Moved -Werror flag to CI only
The most useful part of -Werror is preventing code from being
merged that has warnings. However it is annoying for users who may have
different compilers with different warnings. Limiting -Werror to CI only
covers the main concern about warnings without limiting users.
2018-01-29 18:37:48 -06:00
Christopher Haster
5a38d00dde Added deploy step in Travis to push new version as tags 2018-01-29 00:51:43 -06:00
Christopher Haster
2ad435ed63 Added files test to littlefs-fuse tests in Travis 2018-01-20 19:22:38 -06:00
Christopher Haster
425aa3c694 Fixed issue with immediate exhaustion and small unaligned storage
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-12-27 12:59:32 -06:00
Christopher Haster
78c79ecb9e Added QUIET flag to tests so CI is readable 2017-11-16 17:54:44 -06:00
Christopher Haster
f4aeb8331a Fixed issue with aggressively rounding down lookahead configuration
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-10 10:53:30 -06:00
Christopher Haster
ac9766ee39 Added self-hosting fuzz test using littlefs-fuse 2017-10-10 05:05:57 -05:00
Christopher Haster
273cb7c9c8 Fixed problem with lookaheads larger than block device
Simply limiting the lookahead region to the size of
the block device fixes the problem.

Also added logic to limit the allocated region and
floor to nearest word, since the additional memory
couldn't really be used effectively.
2017-09-18 21:20:33 -05:00
Christopher Haster
26dd49aa04 Fixed issue with negative modulo with unaligned lookaheads
When the lookahead buffer wraps around in an unaligned filesystem, it's
possible for blocks at the beginning of the disk to have a negative distance
from the lookahead, but still reside in the lookahead buffer.

Switching to signed modulo doesn't quite work due to how negative modulo
is implemented in C, so the simple solution is to shift the region to be
positive.
2017-09-17 16:51:07 -05:00
Christopher Haster
8795f0e0b7 Added build size output to CI 2017-07-18 01:50:17 -05:00
Christopher Haster
47db7a7370 Added sanity check for compiling example 2017-07-16 12:45:41 -05:00
Christopher Haster
51c8b02336 Updated .travis.yml to test multiple cache sizes
cache = 1 byte and cache = 1 block are imporant corner cases, with
cache = 16 bytes also thrown in as a more common case.
2017-06-28 21:51:09 -05:00
Christopher Haster
390ca3303f Added travis config 2017-03-25 19:23:30 -05:00