You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/04/23 15:31:32 UTC

[incubator-nuttx] branch master updated: fs/littlefs: upgrade littlefs to v2.2.1

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

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


The following commit(s) were added to refs/heads/master by this push:
     new fe0ba38  fs/littlefs: upgrade littlefs to v2.2.1
fe0ba38 is described below

commit fe0ba38580aad3abbe52dd698bd14f1f7606b308
Author: liuhaitao <li...@xiaomi.com>
AuthorDate: Tue Apr 21 15:22:31 2020 +0800

    fs/littlefs: upgrade littlefs to v2.2.1
    
    Since littlefs is in active development, it's not a good idea to use its
    source code files directly. So upgrade littlefs v2.2.1 by using the littlefs
    tar.gz release package instead.
    
    Change-Id: I16d9cf0b6bca700a54ca86ed11d7c8c7f27a898f
    Signed-off-by: liuhaitao <li...@xiaomi.com>
---
 fs/Makefile            |    4 +-
 fs/littlefs/.gitignore |    4 +
 fs/littlefs/DESIGN.md  | 1225 -----------------
 fs/littlefs/Make.defs  |   79 +-
 fs/littlefs/README.md  |  220 ---
 fs/littlefs/SPEC.md    |  370 ------
 fs/littlefs/lfs.c      | 3464 ------------------------------------------------
 fs/littlefs/lfs.h      |  673 ----------
 fs/littlefs/lfs_util.c |   83 --
 fs/littlefs/lfs_util.h |  275 ----
 fs/littlefs/lfs_vfs.c  |  145 +-
 tools/Directories.mk   |    2 +-
 12 files changed, 102 insertions(+), 6442 deletions(-)

diff --git a/fs/Makefile b/fs/Makefile
index 2218aac..6989a74 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -99,6 +99,8 @@ $(COBJS): %$(OBJEXT): %.c
 $(BIN):	$(OBJS)
 	$(call ARCHIVE, $@, $(OBJS))
 
+context::
+
 .depend: Makefile $(SRCS)
 	$(Q) $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
 	$(Q) touch $@
@@ -109,7 +111,7 @@ clean:
 	$(call DELFILE, $(BIN))
 	$(call CLEAN)
 
-distclean: clean
+distclean:: clean
 	$(call DELFILE, Make.dep)
 	$(call DELFILE, .depend)
 
diff --git a/fs/littlefs/.gitignore b/fs/littlefs/.gitignore
new file mode 100644
index 0000000..90a5e6e
--- /dev/null
+++ b/fs/littlefs/.gitignore
@@ -0,0 +1,4 @@
+/.littlefsunpack
+/littlefs
+/*tar.gz
+/*.zip
diff --git a/fs/littlefs/DESIGN.md b/fs/littlefs/DESIGN.md
deleted file mode 100644
index 125a1b0..0000000
--- a/fs/littlefs/DESIGN.md
+++ /dev/null
@@ -1,1225 +0,0 @@
-## The design of the little filesystem
-
-A little fail-safe filesystem designed for embedded systems.
-
-```
-   | | |     .---._____
-  .-----.   |          |
---|o    |---| littlefs |
---|     |---|          |
-  '-----'   '----------'
-   | | |
-```
-
-For a bit of backstory, the littlefs was developed with the goal of learning
-more about filesystem design by tackling the relative unsolved problem of
-managing a robust filesystem resilient to power loss on devices
-with limited RAM and ROM.
-
-The embedded systems the littlefs is targeting are usually 32 bit
-microcontrollers with around 32KB of RAM and 512KB of ROM. These are
-often paired with SPI NOR flash chips with about 4MB of flash storage.
-
-Flash itself is a very interesting piece of technology with quite a bit of
-nuance. Unlike most other forms of storage, writing to flash requires two
-operations: erasing and programming. The programming operation is relatively
-cheap, and can be very granular. For NOR flash specifically, byte-level
-programs are quite common. Erasing, however, requires an expensive operation
-that forces the state of large blocks of memory to reset in a destructive
-reaction that gives flash its name. The [Wikipedia entry](https://en.wikipedia.org/wiki/Flash_memory)
-has more information if you are interested in how this works.
-
-This leaves us with an interesting set of limitations that can be simplified
-to three strong requirements:
-
-1. **Power-loss resilient** - This is the main goal of the littlefs and the
-   focus of this project.
-
-   Embedded systems are usually designed without a shutdown routine and a
-   notable lack of user interface for recovery, so filesystems targeting
-   embedded systems must be prepared to lose power at any given time.
-
-   Despite this state of things, there are very few embedded filesystems that
-   handle power loss in a reasonable manner, and most can become corrupted if
-   the user is unlucky enough.
-
-2. **Wear leveling** - Due to the destructive nature of flash, most flash
-   chips have a limited number of erase cycles, usually in the order of around
-   100,000 erases per block for NOR flash. Filesystems that don't take wear
-   into account can easily burn through blocks used to store frequently updated
-   metadata.
-
-   Consider the [FAT filesystem](https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system),
-   which stores a file allocation table (FAT) at a specific offset from the
-   beginning of disk. Every block allocation will update this table, and after
-   100,000 updates, the block will likely go bad, rendering the filesystem
-   unusable even if there are many more erase cycles available on the storage
-   as a whole.
-
-3. **Bounded RAM/ROM** - Even with the design difficulties presented by the
-   previous two limitations, we have already seen several flash filesystems
-   developed on PCs that handle power loss just fine, such as the
-   logging filesystems. However, these filesystems take advantage of the
-   relatively cheap access to RAM, and use some rather... opportunistic...
-   techniques, such as reconstructing the entire directory structure in RAM.
-   These operations make perfect sense when the filesystem's only concern is
-   erase cycles, but the idea is a bit silly on embedded systems.
-
-   To cater to embedded systems, the littlefs has the simple limitation of
-   using only a bounded amount of RAM and ROM. That is, no matter what is
-   written to the filesystem, and no matter how large the underlying storage
-   is, the littlefs will always use the same amount of RAM and ROM. This
-   presents a very unique challenge, and makes presumably simple operations,
-   such as iterating through the directory tree, surprisingly difficult.
-
-## Existing designs?
-
-There are of course, many different existing filesystem. Here is a very rough
-summary of the general ideas behind some of them.
-
-Most of the existing filesystems fall into the one big category of filesystem
-designed in the early days of spinny magnet disks. While there is a vast amount
-of interesting technology and ideas in this area, the nature of spinny magnet
-disks encourage properties, such as grouping writes near each other, that don't
-make as much sense on recent storage types. For instance, on flash, write
-locality is not important and can actually increase wear.
-
-One of the most popular designs for flash filesystems is called the
-[logging filesystem](https://en.wikipedia.org/wiki/Log-structured_file_system).
-The flash filesystems [jffs](https://en.wikipedia.org/wiki/JFFS)
-and [yaffs](https://en.wikipedia.org/wiki/YAFFS) are good examples. In a
-logging filesystem, data is not stored in a data structure on disk, but instead
-the changes to the files are stored on disk. This has several neat advantages,
-such as the fact that the data is written in a cyclic log format and naturally
-wear levels as a side effect. And, with a bit of error detection, the entire
-filesystem can easily be designed to be resilient to power loss. The
-journaling component of most modern day filesystems is actually a reduced
-form of a logging filesystem. However, logging filesystems have a difficulty
-scaling as the size of storage increases. And most filesystems compensate by
-caching large parts of the filesystem in RAM, a strategy that is inappropriate
-for embedded systems.
-
-Another interesting filesystem design technique is that of [copy-on-write (COW)](https://en.wikipedia.org/wiki/Copy-on-write).
-A good example of this is the [btrfs](https://en.wikipedia.org/wiki/Btrfs)
-filesystem. COW filesystems can easily recover from corrupted blocks and have
-natural protection against power loss. However, if they are not designed with
-wear in mind, a COW filesystem could unintentionally wear down the root block
-where the COW data structures are synchronized.
-
-## Metadata pairs
-
-The core piece of technology that provides the backbone for the littlefs is
-the concept of metadata pairs. The key idea here is that any metadata that
-needs to be updated atomically is stored on a pair of blocks tagged with
-a revision count and checksum. Every update alternates between these two
-pairs, so that at any time there is always a backup containing the previous
-state of the metadata.
-
-Consider a small example where each metadata pair has a revision count,
-a number as data, and the XOR of the block as a quick checksum. If
-we update the data to a value of 9, and then to a value of 5, here is
-what the pair of blocks may look like after each update:
-```
-  block 1   block 2        block 1   block 2        block 1   block 2
-.---------.---------.    .---------.---------.    .---------.---------.
-| rev: 1  | rev: 0  |    | rev: 1  | rev: 2  |    | rev: 3  | rev: 2  |
-| data: 3 | data: 0 | -> | data: 3 | data: 9 | -> | data: 5 | data: 9 |
-| xor: 2  | xor: 0  |    | xor: 2  | xor: 11 |    | xor: 6  | xor: 11 |
-'---------'---------'    '---------'---------'    '---------'---------'
-                 let data = 9             let data = 5
-```
-
-After each update, we can find the most up to date value of data by looking
-at the revision count.
-
-Now consider what the blocks may look like if we suddenly lose power while
-changing the value of data to 5:
-```
-  block 1   block 2        block 1   block 2        block 1   block 2
-.---------.---------.    .---------.---------.    .---------.---------.
-| rev: 1  | rev: 0  |    | rev: 1  | rev: 2  |    | rev: 3  | rev: 2  |
-| data: 3 | data: 0 | -> | data: 3 | data: 9 | -x | data: 3 | data: 9 |
-| xor: 2  | xor: 0  |    | xor: 2  | xor: 11 |    | xor: 2  | xor: 11 |
-'---------'---------'    '---------'---------'    '---------'---------'
-                 let data = 9             let data = 5
-                                          powerloss!!!
-```
-
-In this case, block 1 was partially written with a new revision count, but
-the littlefs hadn't made it to updating the value of data. However, if we
-check our checksum we notice that block 1 was corrupted. So we fall back to
-block 2 and use the value 9.
-
-Using this concept, the littlefs is able to update metadata blocks atomically.
-There are a few other tweaks, such as using a 32 bit CRC and using sequence
-arithmetic to handle revision count overflow, but the basic concept
-is the same. These metadata pairs define the backbone of the littlefs, and the
-rest of the filesystem is built on top of these atomic updates.
-
-## Non-meta data
-
-Now, the metadata pairs do come with some drawbacks. Most notably, each pair
-requires two blocks for each block of data. I'm sure users would be very
-unhappy if their storage was suddenly cut in half! Instead of storing
-everything in these metadata blocks, the littlefs uses a COW data structure
-for files which is in turn pointed to by a metadata block. When
-we update a file, we create copies of any blocks that are modified until
-the metadata blocks are updated with the new copy. Once the metadata block
-points to the new copy, we deallocate the old blocks that are no longer in use.
-
-Here is what updating a one-block file may look like:
-```
-  block 1   block 2        block 1   block 2        block 1   block 2
-.---------.---------.    .---------.---------.    .---------.---------.
-| rev: 1  | rev: 0  |    | rev: 1  | rev: 0  |    | rev: 1  | rev: 2  |
-| file: 4 | file: 0 | -> | file: 4 | file: 0 | -> | file: 4 | file: 5 |
-| xor: 5  | xor: 0  |    | xor: 5  | xor: 0  |    | xor: 5  | xor: 7  |
-'---------'---------'    '---------'---------'    '---------'---------'
-    |                        |                                  |
-    v                        v                                  v
- block 4                  block 4    block 5       block 4    block 5
-.--------.               .--------. .--------.    .--------. .--------.
-| old    |               | old    | | new    |    | old    | | new    |
-| data   |               | data   | | data   |    | data   | | data   |
-|        |               |        | |        |    |        | |        |
-'--------'               '--------' '--------'    '--------' '--------'
-            update data in file        update metadata pair
-```
-
-It doesn't matter if we lose power while writing new data to block 5,
-since the old data remains unmodified in block 4. This example also
-highlights how the atomic updates of the metadata blocks provide a
-synchronization barrier for the rest of the littlefs.
-
-At this point, it may look like we are wasting an awfully large amount
-of space on the metadata. Just looking at that example, we are using
-three blocks to represent a file that fits comfortably in one! So instead
-of giving each file a metadata pair, we actually store the metadata for
-all files contained in a single directory in a single metadata block.
-
-Now we could just leave files here, copying the entire file on write
-provides the synchronization without the duplicated memory requirements
-of the metadata blocks. However, we can do a bit better.
-
-## CTZ skip-lists
-
-There are many different data structures for representing the actual
-files in filesystems. Of these, the littlefs uses a rather unique [COW](https://upload.wikimedia.org/wikipedia/commons/0/0c/Cow_female_black_white.jpg)
-data structure that allows the filesystem to reuse unmodified parts of the
-file without additional metadata pairs.
-
-First lets consider storing files in a simple linked-list. What happens when we
-append a block? We have to change the last block in the linked-list to point
-to this new block, which means we have to copy out the last block, and change
-the second-to-last block, and then the third-to-last, and so on until we've
-copied out the entire file.
-
-```
-Exhibit A: A linked-list
-.--------.  .--------.  .--------.  .--------.  .--------.  .--------.
-| data 0 |->| data 1 |->| data 2 |->| data 4 |->| data 5 |->| data 6 |
-|        |  |        |  |        |  |        |  |        |  |        |
-|        |  |        |  |        |  |        |  |        |  |        |
-'--------'  '--------'  '--------'  '--------'  '--------'  '--------'
-```
-
-To get around this, the littlefs, at its heart, stores files backwards. Each
-block points to its predecessor, with the first block containing no pointers.
-If you think about for a while, it starts to make a bit of sense. Appending
-blocks just point to their predecessor and no other blocks need to be updated.
-If we update a block in the middle, we will need to copy out the blocks that
-follow, but can reuse the blocks before the modified block. Since most file
-operations either reset the file each write or append to files, this design
-avoids copying the file in the most common cases.
-
-```
-Exhibit B: A backwards linked-list
-.--------.  .--------.  .--------.  .--------.  .--------.  .--------.
-| data 0 |<-| data 1 |<-| data 2 |<-| data 4 |<-| data 5 |<-| data 6 |
-|        |  |        |  |        |  |        |  |        |  |        |
-|        |  |        |  |        |  |        |  |        |  |        |
-'--------'  '--------'  '--------'  '--------'  '--------'  '--------'
-```
-
-However, a backwards linked-list does come with a rather glaring problem.
-Iterating over a file _in order_ has a runtime cost of O(n^2). Gah! A quadratic
-runtime to just _read_ a file? That's awful. Keep in mind reading files is
-usually the most common filesystem operation.
-
-To avoid this problem, the littlefs uses a multilayered linked-list. For
-every nth block where n is divisible by 2^x, the block contains a pointer
-to block n-2^x. So each block contains anywhere from 1 to log2(n) pointers
-that skip to various sections of the preceding list. If you're familiar with
-data-structures, you may have recognized that this is a type of deterministic
-skip-list.
-
-The name comes from the use of the
-[count trailing zeros (CTZ)](https://en.wikipedia.org/wiki/Count_trailing_zeros)
-instruction, which allows us to calculate the power-of-two factors efficiently.
-For a given block n, the block contains ctz(n)+1 pointers.
-
-```
-Exhibit C: A backwards CTZ skip-list
-.--------.  .--------.  .--------.  .--------.  .--------.  .--------.
-| data 0 |<-| data 1 |<-| data 2 |<-| data 3 |<-| data 4 |<-| data 5 |
-|        |<-|        |--|        |<-|        |--|        |  |        |
-|        |<-|        |--|        |--|        |--|        |  |        |
-'--------'  '--------'  '--------'  '--------'  '--------'  '--------'
-```
-
-The additional pointers allow us to navigate the data-structure on disk
-much more efficiently than in a singly linked-list.
-
-Taking exhibit C for example, here is the path from data block 5 to data
-block 1. You can see how data block 3 was completely skipped:
-```
-.--------.  .--------.  .--------.  .--------.  .--------.  .--------.
-| data 0 |  | data 1 |<-| data 2 |  | data 3 |  | data 4 |<-| data 5 |
-|        |  |        |  |        |<-|        |--|        |  |        |
-|        |  |        |  |        |  |        |  |        |  |        |
-'--------'  '--------'  '--------'  '--------'  '--------'  '--------'
-```
-
-The path to data block 0 is even more quick, requiring only two jumps:
-```
-.--------.  .--------.  .--------.  .--------.  .--------.  .--------.
-| data 0 |  | data 1 |  | data 2 |  | data 3 |  | data 4 |<-| data 5 |
-|        |  |        |  |        |  |        |  |        |  |        |
-|        |<-|        |--|        |--|        |--|        |  |        |
-'--------'  '--------'  '--------'  '--------'  '--------'  '--------'
-```
-
-We can find the runtime complexity by looking at the path to any block from
-the block containing the most pointers. Every step along the path divides
-the search space for the block in half. This gives us a runtime of O(log n).
-To get to the block with the most pointers, we can perform the same steps
-backwards, which puts the runtime at O(2 log n) = O(log n). The interesting
-part about this data structure is that this optimal path occurs naturally
-if we greedily choose the pointer that covers the most distance without passing
-our target block.
-
-So now we have a representation of files that can be appended trivially with
-a runtime of O(1), and can be read with a worst case runtime of O(n log n).
-Given that the the runtime is also divided by the amount of data we can store
-in a block, this is pretty reasonable.
-
-Unfortunately, the CTZ skip-list comes with a few questions that aren't
-straightforward to answer. What is the overhead? How do we handle more
-pointers than we can store in a block? How do we store the skip-list in
-a directory entry?
-
-One way to find the overhead per block is to look at the data structure as
-multiple layers of linked-lists. Each linked-list skips twice as many blocks
-as the previous linked-list. Another way of looking at it is that each
-linked-list uses half as much storage per block as the previous linked-list.
-As we approach infinity, the number of pointers per block forms a geometric
-series. Solving this geometric series gives us an average of only 2 pointers
-per block.
-
-![overhead_per_block](https://latex.codecogs.com/svg.latex?%5Clim_%7Bn%5Cto%5Cinfty%7D%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi%3D0%7D%5E%7Bn%7D%5Cleft%28%5Ctext%7Bctz%7D%28i%29&plus;1%5Cright%29%20%3D%20%5Csum_%7Bi%3D0%7D%5Cfrac%7B1%7D%7B2%5Ei%7D%20%3D%202)
-
-Finding the maximum number of pointers in a block is a bit more complicated,
-but since our file size is limited by the integer width we use to store the
-size, we can solve for it. Setting the overhead of the maximum pointers equal
-to the block size we get the following equation. Note that a smaller block size
-results in more pointers, and a larger word width results in larger pointers.
-
-![maximum overhead](https://latex.codecogs.com/svg.latex?B%20%3D%20%5Cfrac%7Bw%7D%7B8%7D%5Cleft%5Clceil%5Clog_2%5Cleft%28%5Cfrac%7B2%5Ew%7D%7BB-2%5Cfrac%7Bw%7D%7B8%7D%7D%5Cright%29%5Cright%5Crceil)
-
-where:
-B = block size in bytes
-w = word width in bits
-
-Solving the equation for B gives us the minimum block size for various word
-widths:
-32 bit CTZ skip-list = minimum block size of 104 bytes
-64 bit CTZ skip-list = minimum block size of 448 bytes
-
-Since littlefs uses a 32 bit word size, we are limited to a minimum block
-size of 104 bytes. This is a perfectly reasonable minimum block size, with most
-block sizes starting around 512 bytes. So we can avoid additional logic to
-avoid overflowing our block's capacity in the CTZ skip-list.
-
-So, how do we store the skip-list in a directory entry? A naive approach would
-be to store a pointer to the head of the skip-list, the length of the file
-in bytes, the index of the head block in the skip-list, and the offset in the
-head block in bytes. However this is a lot of information, and we can observe
-that a file size maps to only one block index + offset pair. So it should be
-sufficient to store only the pointer and file size.
-
-But there is one problem, calculating the block index + offset pair from a
-file size doesn't have an obvious implementation.
-
-We can start by just writing down an equation. The first idea that comes to
-mind is to just use a for loop to sum together blocks until we reach our
-file size. We can write this equation as a summation:
-
-![summation1](https://latex.codecogs.com/svg.latex?N%20%3D%20%5Csum_i%5En%5Cleft%5BB-%5Cfrac%7Bw%7D%7B8%7D%5Cleft%28%5Ctext%7Bctz%7D%28i%29&plus;1%5Cright%29%5Cright%5D)
-
-where:
-B = block size in bytes
-w = word width in bits
-n = block index in skip-list
-N = file size in bytes
-
-And this works quite well, but is not trivial to calculate. This equation
-requires O(n) to compute, which brings the entire runtime of reading a file
-to O(n^2 log n). Fortunately, the additional O(n) does not need to touch disk,
-so it is not completely unreasonable. But if we could solve this equation into
-a form that is easily computable, we can avoid a big slowdown.
-
-Unfortunately, the summation of the CTZ instruction presents a big challenge.
-How would you even begin to reason about integrating a bitwise instruction?
-Fortunately, there is a powerful tool I've found useful in these situations:
-The [On-Line Encyclopedia of Integer Sequences (OEIS)](https://oeis.org/).
-If we work out the first couple of values in our summation, we find that CTZ
-maps to [A001511](https://oeis.org/A001511), and its partial summation maps
-to [A005187](https://oeis.org/A005187), and surprisingly, both of these
-sequences have relatively trivial equations! This leads us to a rather
-unintuitive property:
-
-![mindblown](https://latex.codecogs.com/svg.latex?%5Csum_i%5En%5Cleft%28%5Ctext%7Bctz%7D%28i%29&plus;1%5Cright%29%20%3D%202n-%5Ctext%7Bpopcount%7D%28n%29)
-
-where:
-ctz(x) = the number of trailing bits that are 0 in x
-popcount(x) = the number of bits that are 1 in x
-
-It's a bit bewildering that these two seemingly unrelated bitwise instructions
-are related by this property. But if we start to dissect this equation we can
-see that it does hold. As n approaches infinity, we do end up with an average
-overhead of 2 pointers as we find earlier. And popcount seems to handle the
-error from this average as it accumulates in the CTZ skip-list.
-
-Now we can substitute into the original equation to get a trivial equation
-for a file size:
-
-![summation2](https://latex.codecogs.com/svg.latex?N%20%3D%20Bn%20-%20%5Cfrac%7Bw%7D%7B8%7D%5Cleft%282n-%5Ctext%7Bpopcount%7D%28n%29%5Cright%29)
-
-Unfortunately, we're not quite done. The popcount function is non-injective,
-so we can only find the file size from the block index, not the other way
-around. However, we can solve for an n' block index that is greater than n
-with an error bounded by the range of the popcount function. We can then
-repeatedly substitute this n' into the original equation until the error
-is smaller than the integer division. As it turns out, we only need to
-perform this substitution once. Now we directly calculate our block index:
-
-![formulaforn](https://latex.codecogs.com/svg.latex?n%20%3D%20%5Cleft%5Clfloor%5Cfrac%7BN-%5Cfrac%7Bw%7D%7B8%7D%5Cleft%28%5Ctext%7Bpopcount%7D%5Cleft%28%5Cfrac%7BN%7D%7BB-2%5Cfrac%7Bw%7D%7B8%7D%7D-1%5Cright%29&plus;2%5Cright%29%7D%7BB-2%5Cfrac%7Bw%7D%7B8%7D%7D%5Cright%5Crfloor)
-
-Now that we have our block index n, we can just plug it back into the above
-equation to find the offset. However, we do need to rearrange the equation
-a bit to avoid integer overflow:
-
-![formulaforoff](https://latex.codecogs.com/svg.latex?%5Cmathit%7Boff%7D%20%3D%20N%20-%20%5Cleft%28B-2%5Cfrac%7Bw%7D%7B8%7D%5Cright%29n%20-%20%5Cfrac%7Bw%7D%7B8%7D%5Ctext%7Bpopcount%7D%28n%29)
-
-The solution involves quite a bit of math, but computers are very good at math.
-Now we can solve for both the block index and offset from the file size in O(1).
-
-Here is what it might look like to update a file stored with a CTZ skip-list:
-```
-                                      block 1   block 2
-                                    .---------.---------.
-                                    | rev: 1  | rev: 0  |
-                                    | file: 6 | file: 0 |
-                                    | size: 4 | size: 0 |
-                                    | xor: 3  | xor: 0  |
-                                    '---------'---------'
-                                        |
-                                        v
-  block 3     block 4     block 5     block 6
-.--------.  .--------.  .--------.  .--------.
-| data 0 |<-| data 1 |<-| data 2 |<-| data 3 |
-|        |<-|        |--|        |  |        |
-|        |  |        |  |        |  |        |
-'--------'  '--------'  '--------'  '--------'
-
-|  update data in file
-v
-
-                                      block 1   block 2
-                                    .---------.---------.
-                                    | rev: 1  | rev: 0  |
-                                    | file: 6 | file: 0 |
-                                    | size: 4 | size: 0 |
-                                    | xor: 3  | xor: 0  |
-                                    '---------'---------'
-                                        |
-                                        v
-  block 3     block 4     block 5     block 6
-.--------.  .--------.  .--------.  .--------.
-| data 0 |<-| data 1 |<-| old    |<-| old    |
-|        |<-|        |--| data 2 |  | data 3 |
-|        |  |        |  |        |  |        |
-'--------'  '--------'  '--------'  '--------'
-     ^ ^           ^
-     | |           |      block 7     block 8     block 9    block 10
-     | |           |    .--------.  .--------.  .--------.  .--------.
-     | |           '----| new    |<-| new    |<-| new    |<-| new    |
-     | '----------------| data 2 |<-| data 3 |--| data 4 |  | data 5 |
-     '------------------|        |--|        |--|        |  |        |
-                        '--------'  '--------'  '--------'  '--------'
-
-|  update metadata pair
-v
-
-                                                   block 1   block 2
-                                                 .---------.---------.
-                                                 | rev: 1  | rev: 2  |
-                                                 | file: 6 | file: 10|
-                                                 | size: 4 | size: 6 |
-                                                 | xor: 3  | xor: 14 |
-                                                 '---------'---------'
-                                                                |
-                                                                |
-  block 3     block 4     block 5     block 6                   |
-.--------.  .--------.  .--------.  .--------.                  |
-| data 0 |<-| data 1 |<-| old    |<-| old    |                  |
-|        |<-|        |--| data 2 |  | data 3 |                  |
-|        |  |        |  |        |  |        |                  |
-'--------'  '--------'  '--------'  '--------'                  |
-     ^ ^           ^                                            v
-     | |           |      block 7     block 8     block 9    block 10
-     | |           |    .--------.  .--------.  .--------.  .--------.
-     | |           '----| new    |<-| new    |<-| new    |<-| new    |
-     | '----------------| data 2 |<-| data 3 |--| data 4 |  | data 5 |
-     '------------------|        |--|        |--|        |  |        |
-                        '--------'  '--------'  '--------'  '--------'
-```
-
-## Block allocation
-
-So those two ideas provide the grounds for the filesystem. The metadata pairs
-give us directories, and the CTZ skip-lists give us files. But this leaves
-one big [elephant](https://upload.wikimedia.org/wikipedia/commons/3/37/African_Bush_Elephant.jpg)
-of a question. How do we get those blocks in the first place?
-
-One common strategy is to store unallocated blocks in a big free list, and
-initially the littlefs was designed with this in mind. By storing a reference
-to the free list in every single metadata pair, additions to the free list
-could be updated atomically at the same time the replacement blocks were
-stored in the metadata pair. During boot, every metadata pair had to be
-scanned to find the most recent free list, but once the list was found the
-state of all free blocks becomes known.
-
-However, this approach had several issues:
-
-- There was a lot of nuanced logic for adding blocks to the free list without
-  modifying the blocks, since the blocks remain active until the metadata is
-  updated.
-- The free list had to support both additions and removals in FIFO order while
-  minimizing block erases.
-- The free list had to handle the case where the file system completely ran
-  out of blocks and may no longer be able to add blocks to the free list.
-- If we used a revision count to track the most recently updated free list,
-  metadata blocks that were left unmodified were ticking time bombs that would
-  cause the system to go haywire if the revision count overflowed.
-- Every single metadata block wasted space to store these free list references.
-
-Actually, to simplify, this approach had one massive glaring issue: complexity.
-
-> Complexity leads to fallibility.
-> Fallibility leads to unmaintainability.
-> Unmaintainability leads to suffering.
-
-Or at least, complexity leads to increased code size, which is a problem
-for embedded systems.
-
-In the end, the littlefs adopted more of a "drop it on the floor" strategy.
-That is, the littlefs doesn't actually store information about which blocks
-are free on the storage. The littlefs already stores which files _are_ in
-use, so to find a free block, the littlefs just takes all of the blocks that
-exist and subtract the blocks that are in use.
-
-Of course, it's not quite that simple. Most filesystems that adopt this "drop
-it on the floor" strategy either rely on some properties inherent to the
-filesystem, such as the cyclic-buffer structure of logging filesystems,
-or use a bitmap or table stored in RAM to track free blocks, which scales
-with the size of storage and is problematic when you have limited RAM. You
-could iterate through every single block in storage and check it against
-every single block in the filesystem on every single allocation, but that
-would have an abhorrent runtime.
-
-So the littlefs compromises. It doesn't store a bitmap the size of the storage,
-but it does store a little bit-vector that contains a fixed set lookahead
-for block allocations. During a block allocation, the lookahead vector is
-checked for any free blocks. If there are none, the lookahead region jumps
-forward and the entire filesystem is scanned for free blocks.
-
-Here's what it might look like to allocate 4 blocks on a decently busy
-filesystem with a 32bit lookahead and a total of
-128 blocks (512Kbytes of storage if blocks are 4Kbyte):
-```
-boot...         lookahead:
-                fs blocks: fffff9fffffffffeffffffffffff0000
-scanning...     lookahead: fffff9ff
-                fs blocks: fffff9fffffffffeffffffffffff0000
-alloc = 21      lookahead: fffffdff
-                fs blocks: fffffdfffffffffeffffffffffff0000
-alloc = 22      lookahead: ffffffff
-                fs blocks: fffffffffffffffeffffffffffff0000
-scanning...     lookahead:         fffffffe
-                fs blocks: fffffffffffffffeffffffffffff0000
-alloc = 63      lookahead:         ffffffff
-                fs blocks: ffffffffffffffffffffffffffff0000
-scanning...     lookahead:         ffffffff
-                fs blocks: ffffffffffffffffffffffffffff0000
-scanning...     lookahead:                 ffffffff
-                fs blocks: ffffffffffffffffffffffffffff0000
-scanning...     lookahead:                         ffff0000
-                fs blocks: ffffffffffffffffffffffffffff0000
-alloc = 112     lookahead:                         ffff8000
-                fs blocks: ffffffffffffffffffffffffffff8000
-```
-
-While this lookahead approach still has an asymptotic runtime of O(n^2) to
-scan all of storage, the lookahead reduces the practical runtime to a
-reasonable amount. Bit-vectors are surprisingly compact, given only 16 bytes,
-the lookahead could track 128 blocks. For a 4Mbyte flash chip with 4Kbyte
-blocks, the littlefs would only need 8 passes to scan the entire storage.
-
-The real benefit of this approach is just how much it simplified the design
-of the littlefs. Deallocating blocks is as simple as simply forgetting they
-exist, and there is absolutely no concern of bugs in the deallocation code
-causing difficult to detect memory leaks.
-
-## Directories
-
-Now we just need directories to store our files. Since we already have
-metadata blocks that store information about files, lets just use these
-metadata blocks as the directories. Maybe turn the directories into linked
-lists of metadata blocks so it isn't limited by the number of files that fit
-in a single block. Add entries that represent other nested directories.
-Drop "." and ".." entries, cause who needs them. Dust off our hands and
-we now have a directory tree.
-
-```
-            .--------.
-            |root dir|
-            | pair 0 |
-            |        |
-            '--------'
-            .-'    '-------------------------.
-           v                                  v
-      .--------.        .--------.        .--------.
-      | dir A  |------->| dir A  |        | dir B  |
-      | pair 0 |        | pair 1 |        | pair 0 |
-      |        |        |        |        |        |
-      '--------'        '--------'        '--------'
-      .-'    '-.            |             .-'    '-.
-     v          v           v            v          v
-.--------.  .--------.  .--------.  .--------.  .--------.
-| file C |  | file D |  | file E |  | file F |  | file G |
-|        |  |        |  |        |  |        |  |        |
-|        |  |        |  |        |  |        |  |        |
-'--------'  '--------'  '--------'  '--------'  '--------'
-```
-
-Unfortunately it turns out it's not that simple. See, iterating over a
-directory tree isn't actually all that easy, especially when you're trying
-to fit in a bounded amount of RAM, which rules out any recursive solution.
-And since our block allocator involves iterating over the entire filesystem
-tree, possibly multiple times in a single allocation, iteration needs to be
-efficient.
-
-So, as a solution, the littlefs adopted a sort of threaded tree. Each
-directory not only contains pointers to all of its children, but also a
-pointer to the next directory. These pointers create a linked-list that
-is threaded through all of the directories in the filesystem. Since we
-only use this linked list to check for existence, the order doesn't actually
-matter. As an added plus, we can repurpose the pointer for the individual
-directory linked-lists and avoid using any additional space.
-
-```
-            .--------.
-            |root dir|-.
-            | pair 0 | |
-   .--------|        |-'
-   |        '--------'
-   |        .-'    '-------------------------.
-   |       v                                  v
-   |  .--------.        .--------.        .--------.
-   '->| dir A  |------->| dir A  |------->| dir B  |
-      | pair 0 |        | pair 1 |        | pair 0 |
-      |        |        |        |        |        |
-      '--------'        '--------'        '--------'
-      .-'    '-.            |             .-'    '-.
-     v          v           v            v          v
-.--------.  .--------.  .--------.  .--------.  .--------.
-| file C |  | file D |  | file E |  | file F |  | file G |
-|        |  |        |  |        |  |        |  |        |
-|        |  |        |  |        |  |        |  |        |
-'--------'  '--------'  '--------'  '--------'  '--------'
-```
-
-This threaded tree approach does come with a few tradeoffs. Now, anytime we
-want to manipulate the directory tree, we find ourselves having to update two
-pointers instead of one. For anyone familiar with creating atomic data
-structures this should set off a whole bunch of red flags.
-
-But unlike the data structure guys, we can update a whole block atomically! So
-as long as we're really careful (and cheat a little bit), we can still
-manipulate the directory tree in a way that is resilient to power loss.
-
-Consider how we might add a new directory. Since both pointers that reference
-it can come from the same directory, we only need a single atomic update to
-finagle the directory into the filesystem:
-```
-   .--------.
-   |root dir|-.
-   | pair 0 | |
-.--|        |-'
-|  '--------'
-|      |
-|      v
-|  .--------.
-'->| dir A  |
-   | pair 0 |
-   |        |
-   '--------'
-
-|  create the new directory block
-v
-
-               .--------.
-               |root dir|-.
-               | pair 0 | |
-            .--|        |-'
-            |  '--------'
-            |      |
-            |      v
-            |  .--------.
-.--------.  '->| dir A  |
-| dir B  |---->| pair 0 |
-| pair 0 |     |        |
-|        |     '--------'
-'--------'
-
-|  update root to point to directory B
-v
-
-         .--------.
-         |root dir|-.
-         | pair 0 | |
-.--------|        |-'
-|        '--------'
-|        .-'    '-.
-|       v          v
-|  .--------.  .--------.
-'->| dir B  |->| dir A  |
-   | pair 0 |  | pair 0 |
-   |        |  |        |
-   '--------'  '--------'
-```
-
-Note that even though directory B was added after directory A, we insert
-directory B before directory A in the linked-list because it is convenient.
-
-Now how about removal:
-```
-         .--------.        .--------.
-         |root dir|------->|root dir|-.
-         | pair 0 |        | pair 1 | |
-.--------|        |--------|        |-'
-|        '--------'        '--------'
-|        .-'    '-.            |
-|       v          v           v
-|  .--------.  .--------.  .--------.
-'->| dir A  |->| dir B  |->| dir C  |
-   | pair 0 |  | pair 0 |  | pair 0 |
-   |        |  |        |  |        |
-   '--------'  '--------'  '--------'
-
-|  update root to no longer contain directory B
-v
-
-   .--------.              .--------.
-   |root dir|------------->|root dir|-.
-   | pair 0 |              | pair 1 | |
-.--|        |--------------|        |-'
-|  '--------'              '--------'
-|      |                       |
-|      v                       v
-|  .--------.  .--------.  .--------.
-'->| dir A  |->| dir B  |->| dir C  |
-   | pair 0 |  | pair 0 |  | pair 0 |
-   |        |  |        |  |        |
-   '--------'  '--------'  '--------'
-
-|  remove directory B from the linked-list
-v
-
-   .--------.  .--------.
-   |root dir|->|root dir|-.
-   | pair 0 |  | pair 1 | |
-.--|        |--|        |-'
-|  '--------'  '--------'
-|      |           |
-|      v           v
-|  .--------.  .--------.
-'->| dir A  |->| dir C  |
-   | pair 0 |  | pair 0 |
-   |        |  |        |
-   '--------'  '--------'
-```
-
-Wait, wait, wait, that's not atomic at all! If power is lost after removing
-directory B from the root, directory B is still in the linked-list. We've
-just created a memory leak!
-
-And to be honest, I don't have a clever solution for this case. As a
-side-effect of using multiple pointers in the threaded tree, the littlefs
-can end up with orphan blocks that have no parents and should have been
-removed.
-
-To keep these orphan blocks from becoming a problem, the littlefs has a
-deorphan step that simply iterates through every directory in the linked-list
-and checks it against every directory entry in the filesystem to see if it
-has a parent. The deorphan step occurs on the first block allocation after
-boot, so orphans should never cause the littlefs to run out of storage
-prematurely. Note that the deorphan step never needs to run in a read-only
-filesystem.
-
-## The move problem
-
-Now we have a real problem. How do we move things between directories while
-remaining power resilient? Even looking at the problem from a high level,
-it seems impossible. We can update directory blocks atomically, but atomically
-updating two independent directory blocks is not an atomic operation.
-
-Here's the steps the filesystem may go through to move a directory:
-```
-         .--------.
-         |root dir|-.
-         | pair 0 | |
-.--------|        |-'
-|        '--------'
-|        .-'    '-.
-|       v          v
-|  .--------.  .--------.
-'->| dir A  |->| dir B  |
-   | pair 0 |  | pair 0 |
-   |        |  |        |
-   '--------'  '--------'
-
-|  update directory B to point to directory A
-v
-
-         .--------.
-         |root dir|-.
-         | pair 0 | |
-.--------|        |-'
-|        '--------'
-|    .-----'    '-.
-|    |             v
-|    |           .--------.
-|    |        .->| dir B  |
-|    |        |  | pair 0 |
-|    |        |  |        |
-|    |        |  '--------'
-|    |     .-------'
-|    v    v   |
-|  .--------. |
-'->| dir A  |-'
-   | pair 0 |
-   |        |
-   '--------'
-
-|  update root to no longer contain directory A
-v
-     .--------.
-     |root dir|-.
-     | pair 0 | |
-.----|        |-'
-|    '--------'
-|        |
-|        v
-|    .--------.
-| .->| dir B  |
-| |  | pair 0 |
-| '--|        |-.
-|    '--------' |
-|        |      |
-|        v      |
-|    .--------. |
-'--->| dir A  |-'
-     | pair 0 |
-     |        |
-     '--------'
-```
-
-We can leave any orphans up to the deorphan step to collect, but that doesn't
-help the case where dir A has both dir B and the root dir as parents if we
-lose power inconveniently.
-
-Initially, you might think this is fine. Dir A _might_ end up with two parents,
-but the filesystem will still work as intended. But then this raises the
-question of what do we do when the dir A wears out? For other directory blocks
-we can update the parent pointer, but for a dir with two parents we would need
-work out how to update both parents. And the check for multiple parents would
-need to be carried out for every directory, even if the directory has never
-been moved.
-
-It also presents a bad user-experience, since the condition of ending up with
-two parents is rare, it's unlikely user-level code will be prepared. Just think
-about how a user would recover from a multi-parented directory. They can't just
-remove one directory, since remove would report the directory as "not empty".
-
-Other atomic filesystems simple COW the entire directory tree. But this
-introduces a significant bit of complexity, which leads to code size, along
-with a surprisingly expensive runtime cost during what most users assume is
-a single pointer update.
-
-Another option is to update the directory block we're moving from to point
-to the destination with a sort of predicate that we have moved if the
-destination exists. Unfortunately, the omnipresent concern of wear could
-cause any of these directory entries to change blocks, and changing the
-entry size before a move introduces complications if it spills out of
-the current directory block.
-
-So how do we go about moving a directory atomically?
-
-We rely on the improbableness of power loss.
-
-Power loss during a move is certainly possible, but it's actually relatively
-rare. Unless a device is writing to a filesystem constantly, it's unlikely that
-a power loss will occur during filesystem activity. We still need to handle
-the condition, but runtime during a power loss takes a back seat to the runtime
-during normal operations.
-
-So what littlefs does is inelegantly simple. When littlefs moves a file, it
-marks the file as "moving". This is stored as a single bit in the directory
-entry and doesn't take up much space. Then littlefs moves the directory,
-finishing with the complete remove of the "moving" directory entry.
-
-```
-         .--------.
-         |root dir|-.
-         | pair 0 | |
-.--------|        |-'
-|        '--------'
-|        .-'    '-.
-|       v          v
-|  .--------.  .--------.
-'->| dir A  |->| dir B  |
-   | pair 0 |  | pair 0 |
-   |        |  |        |
-   '--------'  '--------'
-
-|  update root directory to mark directory A as moving
-v
-
-        .----------.
-        |root dir  |-.
-        | pair 0   | |
-.-------| moving A!|-'
-|       '----------'
-|        .-'    '-.
-|       v          v
-|  .--------.  .--------.
-'->| dir A  |->| dir B  |
-   | pair 0 |  | pair 0 |
-   |        |  |        |
-   '--------'  '--------'
-
-|  update directory B to point to directory A
-v
-
-        .----------.
-        |root dir  |-.
-        | pair 0   | |
-.-------| moving A!|-'
-|       '----------'
-|    .-----'    '-.
-|    |             v
-|    |           .--------.
-|    |        .->| dir B  |
-|    |        |  | pair 0 |
-|    |        |  |        |
-|    |        |  '--------'
-|    |     .-------'
-|    v    v   |
-|  .--------. |
-'->| dir A  |-'
-   | pair 0 |
-   |        |
-   '--------'
-
-|  update root to no longer contain directory A
-v
-     .--------.
-     |root dir|-.
-     | pair 0 | |
-.----|        |-'
-|    '--------'
-|        |
-|        v
-|    .--------.
-| .->| dir B  |
-| |  | pair 0 |
-| '--|        |-.
-|    '--------' |
-|        |      |
-|        v      |
-|    .--------. |
-'--->| dir A  |-'
-     | pair 0 |
-     |        |
-     '--------'
-```
-
-Now, if we run into a directory entry that has been marked as "moved", one
-of two things is possible. Either the directory entry exists elsewhere in the
-filesystem, or it doesn't. This is a O(n) operation, but only occurs in the
-unlikely case we lost power during a move.
-
-And we can easily fix the "moved" directory entry. Since we're already scanning
-the filesystem during the deorphan step, we can also check for moved entries.
-If we find one, we either remove the "moved" marking or remove the whole entry
-if it exists elsewhere in the filesystem.
-
-## Wear awareness
-
-So now that we have all of the pieces of a filesystem, we can look at a more
-subtle attribute of embedded storage: The wear down of flash blocks.
-
-The first concern for the littlefs, is that perfectly valid blocks can suddenly
-become unusable. As a nice side-effect of using a COW data-structure for files,
-we can simply move on to a different block when a file write fails. All
-modifications to files are performed in copies, so we will only replace the
-old file when we are sure none of the new file has errors. Directories, on
-the other hand, need a different strategy.
-
-The solution to directory corruption in the littlefs relies on the redundant
-nature of the metadata pairs. If an error is detected during a write to one
-of the metadata pairs, we seek out a new block to take its place. Once we find
-a block without errors, we iterate through the directory tree, updating any
-references to the corrupted metadata pair to point to the new metadata block.
-Just like when we remove directories, we can lose power during this operation
-and end up with a desynchronized metadata pair in our filesystem. And just like
-when we remove directories, we leave the possibility of a desynchronized
-metadata pair up to the deorphan step to clean up.
-
-Here's what encountering a directory error may look like with all of
-the directories and directory pointers fully expanded:
-```
-         root dir
-         block 1   block 2
-       .---------.---------.
-       | rev: 1  | rev: 0  |--.
-       |         |         |-.|
-.------|         |         |-|'
-|.-----|         |         |-'
-||     '---------'---------'
-||       |||||'--------------------------------------------------.
-||       ||||'-----------------------------------------.         |
-||       |||'-----------------------------.            |         |
-||       ||'--------------------.         |            |         |
-||       |'-------.             |         |            |         |
-||       v         v            v         v            v         v
-||    dir A                  dir B                  dir C
-||    block 3   block 4      block 5   block 6      block 7   block 8
-||  .---------.---------.  .---------.---------.  .---------.---------.
-|'->| rev: 1  | rev: 0  |->| rev: 1  | rev: 0  |->| rev: 1  | rev: 0  |
-'-->|         |         |->|         |         |->|         |         |
-    |         |         |  |         |         |  |
-    |         |         |  |         |         |  |         |         |
-    '---------'---------'  '---------'---------'  '---------'---------'
-
-|  update directory B
-v
-
-         root dir
-         block 1   block 2
-       .---------.---------.
-       | rev: 1  | rev: 0  |--.
-       |         |         |-.|
-.------|         |         |-|'
-|.-----|         |         |-'
-||     '---------'---------'
-||       |||||'--------------------------------------------------.
-||       ||||'-----------------------------------------.         |
-||       |||'-----------------------------.            |         |
-||       ||'--------------------.         |            |         |
-||       |'-------.             |         |            |         |
-||       v         v            v         v            v         v
-||    dir A                  dir B                  dir C
-||    block 3   block 4      block 5   block 6      block 7   block 8
-||  .---------.---------.  .---------.---------.  .---------.---------.
-|'->| rev: 1  | rev: 0  |->| rev: 1  | rev: 2  |->| rev: 1  | rev: 0  |
-'-->|         |         |->|         | corrupt!|->|         |         |
-    |         |         |  |         | corrupt!|  |         |         |
-    |         |         |  |         | corrupt!|  |         |         |
-    '---------'---------'  '---------'---------'  '---------'---------'
-
-|  oh no! corruption detected
-v  allocate a replacement block
-
-         root dir
-         block 1   block 2
-       .---------.---------.
-       | rev: 1  | rev: 0  |--.
-       |         |         |-.|
-.------|         |         |-|'
-|.-----|         |         |-'
-||     '---------'---------'
-||       |||||'----------------------------------------------------.
-||       ||||'-------------------------------------------.         |
-||       |||'-----------------------------.              |         |
-||       ||'--------------------.         |              |         |
-||       |'-------.             |         |              |         |
-||       v         v            v         v              v         v
-||    dir A                  dir B                    dir C
-||    block 3   block 4      block 5   block 6        block 7   block 8
-||  .---------.---------.  .---------.---------.    .---------.---------.
-|'->| rev: 1  | rev: 0  |->| rev: 1  | rev: 2  |--->| rev: 1  | rev: 0  |
-'-->|         |         |->|         | corrupt!|--->|         |         |
-    |         |         |  |         | corrupt!| .->|         |         |
-    |         |         |  |         | corrupt!| |  |         |         |
-    '---------'---------'  '---------'---------' |  '---------'---------'
-                                       block 9   |
-                                     .---------. |
-                                     | rev: 2  |-'
-                                     |         |
-                                     |         |
-                                     |         |
-                                     '---------'
-
-|  update root directory to contain block 9
-v
-
-        root dir
-        block 1   block 2
-      .---------.---------.
-      | rev: 1  | rev: 2  |--.
-      |         |         |-.|
-.-----|         |         |-|'
-|.----|         |         |-'
-||    '---------'---------'
-||       .--------'||||'----------------------------------------------.
-||       |         |||'-------------------------------------.         |
-||       |         ||'-----------------------.              |         |
-||       |         |'------------.           |              |         |
-||       |         |             |           |              |         |
-||       v         v             v           v              v         v
-||    dir A                   dir B                      dir C
-||    block 3   block 4       block 5     block 9        block 7   block 8
-||  .---------.---------.   .---------. .---------.    .---------.---------.
-|'->| rev: 1  | rev: 0  |-->| rev: 1  |-| rev: 2  |--->| rev: 1  | rev: 0  |
-'-->|         |         |-. |         | |         |--->|         |         |
-    |         |         | | |         | |         | .->|         |         |
-    |         |         | | |         | |         | |  |         |         |
-    '---------'---------' | '---------' '---------' |  '---------'---------'
-                          |               block 6   |
-                          |             .---------. |
-                          '------------>| rev: 2  |-'
-                                        | corrupt!|
-                                        | corrupt!|
-                                        | corrupt!|
-                                        '---------'
-
-|  remove corrupted block from linked-list
-v
-
-        root dir
-        block 1   block 2
-      .---------.---------.
-      | rev: 1  | rev: 2  |--.
-      |         |         |-.|
-.-----|         |         |-|'
-|.----|         |         |-'
-||    '---------'---------'
-||       .--------'||||'-----------------------------------------.
-||       |         |||'--------------------------------.         |
-||       |         ||'--------------------.            |         |
-||       |         |'-----------.         |            |         |
-||       |         |            |         |            |         |
-||       v         v            v         v            v         v
-||    dir A                  dir B                  dir C
-||    block 3   block 4      block 5   block 9      block 7   block 8
-||  .---------.---------.  .---------.---------.  .---------.---------.
-|'->| rev: 1  | rev: 2  |->| rev: 1  | rev: 2  |->| rev: 1  | rev: 0  |
-'-->|         |         |->|         |         |->|         |         |
-    |         |         |  |         |         |  |         |         |
-    |         |         |  |         |         |  |         |         |
-    '---------'---------'  '---------'---------'  '---------'---------'
-```
-
-Also one question I've been getting is, what about the root directory?
-It can't move so wouldn't the filesystem die as soon as the root blocks
-develop errors? And you would be correct. So instead of storing the root
-in the first few blocks of the storage, the root is actually pointed to
-by the superblock. The superblock contains a few bits of static data, but
-outside of when the filesystem is formatted, it is only updated when the root
-develops errors and needs to be moved.
-
-## Wear leveling
-
-The second concern for the littlefs is that blocks in the filesystem may wear
-unevenly. In this situation, a filesystem may meet an early demise where
-there are no more non-corrupted blocks that aren't in use. It's common to
-have files that were written once and left unmodified, wasting the potential
-erase cycles of the blocks it sits on.
-
-Wear leveling is a term that describes distributing block writes evenly to
-avoid the early termination of a flash part. There are typically two levels
-of wear leveling:
-1. Dynamic wear leveling - Wear is distributed evenly across all **dynamic**
-   blocks. Usually this is accomplished by simply choosing the unused block
-   with the lowest amount of wear. Note this does not solve the problem of
-   static data.
-2. Static wear leveling - Wear is distributed evenly across all **dynamic**
-   and **static** blocks. Unmodified blocks may be evicted for new block
-   writes. This does handle the problem of static data but may lead to
-   wear amplification.
-
-In littlefs's case, it's possible to use the revision count on metadata pairs
-to approximate the wear of a metadata block. And combined with the COW nature
-of files, littlefs could provide your usual implementation of dynamic wear
-leveling.
-
-However, the littlefs does not. This is for a few reasons. Most notably, even
-if the littlefs did implement dynamic wear leveling, this would still not
-handle the case of write-once files, and near the end of the lifetime of a
-flash device, you would likely end up with uneven wear on the blocks anyways.
-
-As a flash device reaches the end of its life, the metadata blocks will
-naturally be the first to go since they are updated most often. In this
-situation, the littlefs is designed to simply move on to another set of
-metadata blocks. This travelling means that at the end of a flash device's
-life, the filesystem will have worn the device down nearly as evenly as the
-usual dynamic wear leveling could. More aggressive wear leveling would come
-with a code-size cost for marginal benefit.
-
-
-One important takeaway to note, if your storage stack uses highly sensitive
-storage such as NAND flash, static wear leveling is the only valid solution.
-In most cases you are going to be better off using a full [flash translation layer (FTL)](https://en.wikipedia.org/wiki/Flash_translation_layer).
-NAND flash already has many limitations that make it poorly suited for an
-embedded system: low erase cycles, very large blocks, errors that can develop
-even during reads, errors that can develop during writes of neighboring blocks.
-Managing sensitive storage such as NAND flash is out of scope for the littlefs.
-The littlefs does have some properties that may be beneficial on top of a FTL,
-such as limiting the number of writes where possible, but if you have the
-storage requirements that necessitate the need of NAND flash, you should have
-the RAM to match and just use an FTL or flash filesystem.
-
-## Summary
-
-So, to summarize:
-
-1. The littlefs is composed of directory blocks
-2. Each directory is a linked-list of metadata pairs
-3. These metadata pairs can be updated atomically by alternating which
-   metadata block is active
-4. Directory blocks contain either references to other directories or files
-5. Files are represented by copy-on-write CTZ skip-lists which support O(1)
-   append and O(n log n) reading
-6. Blocks are allocated by scanning the filesystem for used blocks in a
-   fixed-size lookahead region that is stored in a bit-vector
-7. To facilitate scanning the filesystem, all directories are part of a
-   linked-list that is threaded through the entire filesystem
-8. If a block develops an error, the littlefs allocates a new block, and
-   moves the data and references of the old block to the new.
-9. Any case where an atomic operation is not possible, mistakes are resolved
-   by a deorphan step that occurs on the first allocation after boot
-
-That's the little filesystem. Thanks for reading!
diff --git a/fs/littlefs/Make.defs b/fs/littlefs/Make.defs
index d02e529..fb21f06 100644
--- a/fs/littlefs/Make.defs
+++ b/fs/littlefs/Make.defs
@@ -1,55 +1,52 @@
-#############################################################################
+############################################################################
 # fs/littlefs/Make.defs
 #
-# This file is a part of NuttX:
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
 #
-#   Copyright (C) 2019 Gregory Nutt. All rights reserved.
+#   http://www.apache.org/licenses/LICENSE-2.0
 #
-# Ported by:
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
 #
-#   Copyright (C) 2019 Pinecone Inc. All rights reserved.
-#   Author: lihaichen <li...@163.com>
-#
-# This port derives from ARM mbed logic which has a compatible 3-clause
-# BSD license:
-#
-#   Copyright (c) 2017, Arm Limited. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in
-#    the documentation and/or other materials provided with the
-#    distribution.
-# 3. Neither the names ARM, NuttX nor the names of its contributors may be
-#    used to endorse or promote products derived from this software
-#    without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-#############################################################################
+############################################################################
 
 ifeq ($(CONFIG_FS_LITTLEFS),y)
 # Files required for littlefs file system support
 
-CSRCS += lfs.c lfs_util.c lfs_vfs.c
+CSRCS += lfs_vfs.c
 
 DEPPATH += --dep-path littlefs
 VPATH += :littlefs
 
+CSRCS += lfs.c lfs_util.c
+
+DEPPATH += --dep-path littlefs/littlefs
+VPATH += :littlefs/littlefs
+
+LITTLEFS_VERSION ?= 2.2.1
+LITTLEFS_TARBALL = v$(LITTLEFS_VERSION).tar.gz
+
+$(LITTLEFS_TARBALL):
+	$(Q) wget -P littlefs https://github.com/ARMmbed/littlefs/archive/$(LITTLEFS_TARBALL)
+
+.littlefsunpack: $(LITTLEFS_TARBALL)
+	$(Q) tar zxf littlefs/$(LITTLEFS_TARBALL) -C littlefs
+	$(Q) mv littlefs/littlefs-$(LITTLEFS_VERSION) littlefs/littlefs
+	$(Q) touch littlefs/.littlefsunpack
+
+context:: .littlefsunpack
+
+distclean::
+	$(call DELFILE, littlefs/.littlefsunpack)
+	$(call DELFILE, littlefs/$(LITTLEFS_TARBALL))
+	$(call DELDIR, littlefs/littlefs)
+
 endif
diff --git a/fs/littlefs/README.md b/fs/littlefs/README.md
deleted file mode 100644
index 32d3f6e..0000000
--- a/fs/littlefs/README.md
+++ /dev/null
@@ -1,220 +0,0 @@
-## usage
-
-depends on !DISABLE_MOUNTPOINT
-
-1. register_mtddriver("/dev/w25", mtd, 0755, NULL);
-2. mount("/dev/w25", "/w25", "littlefs", 0, NULL);
-
-## need to do
-
-1. no format tool, mount auto format.
-
-
-## The little filesystem
-
-A little fail-safe filesystem designed for embedded systems.
-
-```
-   | | |     .---._____
-  .-----.   |          |
---|o    |---| littlefs |
---|     |---|          |
-  '-----'   '----------'
-   | | |
-```
-
-**Bounded RAM/ROM** - The littlefs is designed to work with a limited amount
-of memory. Recursion is avoided and dynamic memory is limited to configurable
-buffers that can be provided statically.
-
-**Power-loss resilient** - The littlefs is designed for systems that may have
-random power failures. The littlefs has strong copy-on-write guarantees and
-storage on disk is always kept in a valid state.
-
-**Wear leveling** - Since the most common form of embedded storage is erodible
-flash memories, littlefs provides a form of dynamic wear leveling for systems
-that can not fit a full flash translation layer.
-
-## Example
-
-Here's a simple example that updates a file named `boot_count` every time
-main runs. The program can be interrupted at any time without losing track
-of how many times it has been booted and without corrupting the filesystem:
-
-``` c
-#include "lfs.h"
-
-/* variables used by the filesystem */
-
-lfs_t lfs;
-lfs_file_t file;
-
-/* configuration of the filesystem is provided by this struct */
-
-const struct lfs_config cfg =
-{
-  /* block device operations */
-
-  .read  = user_provided_block_device_read,
-  .prog  = user_provided_block_device_prog,
-  .erase = user_provided_block_device_erase,
-  .sync  = user_provided_block_device_sync,
-
-  /* block device configuration */
-
-  .read_size = 16,
-  .prog_size = 16,
-  .block_size = 4096,
-  .block_count = 128,
-  .lookahead = 128,
-};
-
-/* entry point */
-
-int main(void)
-{
-  /* mount the filesystem */
-
-  int err = lfs_mount(&lfs, &cfg);
-
-  /* reformat if we can't mount the filesystem
-   * this should only happen on the first boot
-   */
-
-  if (err)
-    {
-      lfs_format(&lfs, &cfg);
-      lfs_mount(&lfs, &cfg);
-    }
-
-  /* read current count  */
-
-  uint32_t boot_count = 0;
-  lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
-  lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
-
-  /* update boot count */
-
-  boot_count += 1;
-  lfs_file_rewind(&lfs, &file);
-  lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
-
-  /* remember the storage is not updated until the file is closed successfully */
-
-  lfs_file_close(&lfs, &file);
-
-  /* release any resources we were using */
-
-  lfs_unmount(&lfs);
-
-  /* print the boot count */
-
-  printf("boot_count: %d\n", boot_count);
-}
-```
-
-## Usage
-
-Detailed documentation (or at least as much detail as is currently available)
-can be found in the comments in [lfs.h](lfs.h).
-
-As you may have noticed, littlefs takes in a configuration structure that
-defines how the filesystem operates. The configuration struct provides the
-filesystem with the block device operations and dimensions, tweakable
-parameters that tradeoff memory usage for performance, and optional
-static buffers if the user wants to avoid dynamic memory.
-
-The state of the littlefs is stored in the `lfs_t` type which is left up
-to the user to allocate, allowing multiple filesystems to be in use
-simultaneously. With the `lfs_t` and configuration struct, a user can
-format a block device or mount the filesystem.
-
-Once mounted, the littlefs provides a full set of POSIX-like file and
-directory functions, with the deviation that the allocation of filesystem
-structures must be provided by the user.
-
-All POSIX operations, such as remove and rename, are atomic, even in event
-of power-loss. Additionally, no file updates are actually committed to the
-filesystem until sync or close is called on the file.
-
-## Other notes
-
-All littlefs have the potential to return a negative error code. The errors
-can be either one of those found in the `enum lfs_error` in [lfs.h](lfs.h),
-or an error returned by the user's block device operations.
-
-In the configuration struct, the `prog` and `erase` function provided by the
-user may return a `LFS_ERR_CORRUPT` error if the implementation already can
-detect corrupt blocks. However, the wear leveling does not depend on the return
-code of these functions, instead all data is read back and checked for
-integrity.
-
-If your storage caches writes, make sure that the provided `sync` function
-flushes all the data to memory and ensures that the next read fetches the data
-from memory, otherwise data integrity can not be guaranteed. If the `write`
-function does not perform caching, and therefore each `read` or `write` call
-hits the memory, the `sync` function can simply return 0.
-
-## Reference material
-
-[DESIGN.md](DESIGN.md) - DESIGN.md contains a fully detailed dive into how
-littlefs actually works. I would encourage you to read it since the
-solutions and tradeoffs at work here are quite interesting.
-
-[SPEC.md](SPEC.md) - SPEC.md contains the on-disk specification of littlefs
-with all the nitty-gritty details. Can be useful for developing tooling.
-
-## Testing
-
-The littlefs comes with a test suite designed to run on a PC using the
-[emulated block device](emubd/lfs_emubd.h) found in the emubd directory.
-The tests assume a Linux environment and can be started with make:
-
-``` bash
-make test
-```
-
-## License
-
-The littlefs is provided under the [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html)
-license. See [LICENSE.md](LICENSE.md) for more information. Contributions to
-this project are accepted under the same license.
-
-Individual files contain the following tag instead of the full license text.
-
-    SPDX-License-Identifier:    BSD-3-Clause
-
-This enables machine processing of license information based on the SPDX
-License Identifiers that are here available: http://spdx.org/licenses/
-
-## Related projects
-
-[Mbed OS](https://github.com/ARMmbed/mbed-os/tree/master/features/filesystem/littlefs) -
-The easiest way to get started with littlefs is to jump into [Mbed](https://os.mbed.com/),
-which already has block device drivers for most forms of embedded storage. The
-littlefs is available in Mbed OS as the [LittleFileSystem](https://os.mbed.com/docs/latest/reference/littlefilesystem.html)
-class.
-
-[littlefs-fuse](https://github.com/geky/littlefs-fuse) - A [FUSE](https://github.com/libfuse/libfuse)
-wrapper for littlefs. The project allows you to mount littlefs directly on a
-Linux machine. Can be useful for debugging littlefs if you have an SD card
-handy.
-
-[littlefs-js](https://github.com/geky/littlefs-js) - A javascript wrapper for
-littlefs. I'm not sure why you would want this, but it is handy for demos.
-You can see it in action [here](http://littlefs.geky.net/demo.html).
-
-[mklfs](https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src) -
-A command line tool built by the [Lua RTOS](https://github.com/whitecatboard/Lua-RTOS-ESP32)
-guys for making littlefs images from a host PC. Supports Windows, Mac OS,
-and Linux.
-
-[SPIFFS](https://github.com/pellepl/spiffs) - Another excellent embedded
-filesystem for NOR flash. As a more traditional logging filesystem with full
-static wear-leveling, SPIFFS will likely outperform littlefs on small
-memories such as the internal flash on microcontrollers.
-
-[Dhara](https://github.com/dlbeer/dhara) - An interesting NAND flash
-translation layer designed for small MCUs. It offers static wear-leveling and
-power-resilience with only a fixed O(|address|) pointer structure stored on
-each block and in RAM.
diff --git a/fs/littlefs/SPEC.md b/fs/littlefs/SPEC.md
deleted file mode 100644
index 202f50c..0000000
--- a/fs/littlefs/SPEC.md
+++ /dev/null
@@ -1,370 +0,0 @@
-## The little filesystem technical specification
-
-This is the technical specification of the little filesystem. This document
-covers the technical details of how the littlefs is stored on disk for
-introspection and tooling development. This document assumes you are
-familiar with the design of the littlefs, for more info on how littlefs
-works check out [DESIGN.md](DESIGN.md).
-
-```
-   | | |     .---._____
-  .-----.   |          |
---|o    |---| littlefs |
---|     |---|          |
-  '-----'   '----------'
-   | | |
-```
-
-## Some important details
-
-- The littlefs is a block-based filesystem. This is, the disk is divided into
-  an array of evenly sized blocks that are used as the logical unit of storage
-  in littlefs. Block pointers are stored in 32 bits.
-
-- There is no explicit free-list stored on disk, the littlefs only knows what
-  is in use in the filesystem.
-
-- The littlefs uses the value of 0xffffffff to represent a null block-pointer.
-
-- All values in littlefs are stored in little-endian byte order.
-
-## Directories / Metadata pairs
-
-Metadata pairs form the backbone of the littlefs and provide a system for
-atomic updates. Even the superblock is stored in a metadata pair.
-
-As their name suggests, a metadata pair is stored in two blocks, with one block
-acting as a redundant backup in case the other is corrupted. These two blocks
-could be anywhere in the disk and may not be next to each other, so any
-pointers to directory pairs need to be stored as two block pointers.
-
-Here's the layout of metadata blocks on disk:
-
-| offset | size          | description    |
-|--------|---------------|----------------|
-| 0x00   | 32 bits       | revision count |
-| 0x04   | 32 bits       | dir size       |
-| 0x08   | 64 bits       | tail pointer   |
-| 0x10   | size-16 bytes | dir entries    |
-| 0x00+s | 32 bits       | CRC            |
-
-**Revision count** - Incremented every update, only the uncorrupted
-metadata-block with the most recent revision count contains the valid metadata.
-Comparison between revision counts must use sequence comparison since the
-revision counts may overflow.
-
-**Dir size** - Size in bytes of the contents in the current metadata block,
-including the metadata-pair metadata. Additionally, the highest bit of the
-dir size may be set to indicate that the directory's contents continue on the
-next metadata-pair pointed to by the tail pointer.
-
-**Tail pointer** - Pointer to the next metadata-pair in the filesystem.
-A null pair-pointer (0xffffffff, 0xffffffff) indicates the end of the list.
-If the highest bit in the dir size is set, this points to the next
-metadata-pair in the current directory, otherwise it points to an arbitrary
-metadata-pair. Starting with the superblock, the tail-pointers form a
-linked-list containing all metadata-pairs in the filesystem.
-
-**CRC** - 32 bit CRC used to detect corruption from power-lost, from block
-end-of-life, or just from noise on the storage bus. The CRC is appended to
-the end of each metadata-block. The littlefs uses the standard CRC-32, which
-uses a polynomial of 0x04c11db7, initialized with 0xffffffff.
-
-Here's an example of a simple directory stored on disk:
-```
-(32 bits) revision count = 10                    (0x0000000a)
-(32 bits) dir size       = 154 bytes, end of dir (0x0000009a)
-(64 bits) tail pointer   = 37, 36                (0x00000025, 0x00000024)
-(32 bits) CRC            = 0xc86e3106
-
-00000000: 0a 00 00 00 9a 00 00 00 25 00 00 00 24 00 00 00  ........%...$...
-00000010: 22 08 00 03 05 00 00 00 04 00 00 00 74 65 61 22  "...........tea"
-00000020: 08 00 06 07 00 00 00 06 00 00 00 63 6f 66 66 65  ...........coffe
-00000030: 65 22 08 00 04 09 00 00 00 08 00 00 00 73 6f 64  e"...........sod
-00000040: 61 22 08 00 05 1d 00 00 00 1c 00 00 00 6d 69 6c  a"...........mil
-00000050: 6b 31 22 08 00 05 1f 00 00 00 1e 00 00 00 6d 69  k1"...........mi
-00000060: 6c 6b 32 22 08 00 05 21 00 00 00 20 00 00 00 6d  lk2"...!... ...m
-00000070: 69 6c 6b 33 22 08 00 05 23 00 00 00 22 00 00 00  ilk3"...#..."...
-00000080: 6d 69 6c 6b 34 22 08 00 05 25 00 00 00 24 00 00  milk4"...%...$..
-00000090: 00 6d 69 6c 6b 35 06 31 6e c8                    .milk5.1n.
-```
-
-A note about the tail pointer linked-list: Normally, this linked-list is
-threaded through the entire filesystem. However, after power-loss this
-linked-list may become out of sync with the rest of the filesystem.
-- The linked-list may contain a directory that has actually been removed
-- The linked-list may contain a metadata pair that has not been updated after
-  a block in the pair has gone bad.
-
-The threaded linked-list must be checked for these errors before it can be
-used reliably. Fortunately, the threaded linked-list can simply be ignored
-if littlefs is mounted read-only.
-
-## Entries
-
-Each metadata block contains a series of entries that follow a standard
-layout. An entry contains the type of the entry, along with a section for
-entry-specific data, attributes, and a name.
-
-Here's the layout of entries on disk:
-
-| offset  | size                   | description                |
-|---------|------------------------|----------------------------|
-| 0x0     | 8 bits                 | entry type                 |
-| 0x1     | 8 bits                 | entry length               |
-| 0x2     | 8 bits                 | attribute length           |
-| 0x3     | 8 bits                 | name length                |
-| 0x4     | entry length bytes     | entry-specific data        |
-| 0x4+e   | attribute length bytes | system-specific attributes |
-| 0x4+e+a | name length bytes      | entry name                 |
-
-**Entry type** - Type of the entry, currently this is limited to the following:
-- 0x11 - file entry
-- 0x22 - directory entry
-- 0x2e - superblock entry
-
-Additionally, the type is broken into two 4 bit nibbles, with the upper nibble
-specifying the type's data structure used when scanning the filesystem. The
-lower nibble clarifies the type further when multiple entries share the same
-data structure.
-
-The highest bit is reserved for marking the entry as "moved". If an entry
-is marked as "moved", the entry may also exist somewhere else in the
-filesystem. If the entry exists elsewhere, this entry must be treated as
-though it does not exist.
-
-**Entry length** - Length in bytes of the entry-specific data. This does
-not include the entry type size, attributes, or name. The full size in bytes
-of the entry is 4 + entry length + attribute length + name length.
-
-**Attribute length** - Length of system-specific attributes in bytes. Since
-attributes are system specific, there is not much guarantee on the values in
-this section, and systems are expected to work even when it is empty. See the
-[attributes](#entry-attributes) section for more details.
-
-**Name length** - Length of the entry name. Entry names are stored as UTF8,
-although most systems will probably only support ASCII. Entry names can not
-contain '/' and can not be '.' or '..' as these are a part of the syntax of
-filesystem paths.
-
-Here's an example of a simple entry stored on disk:
-```
-(8 bits)   entry type       = file     (0x11)
-(8 bits)   entry length     = 8 bytes  (0x08)
-(8 bits)   attribute length = 0 bytes  (0x00)
-(8 bits)   name length      = 12 bytes (0x0c)
-(8 bytes)  entry data       = 05 00 00 00 20 00 00 00
-(12 bytes) entry name       = smallavacado
-
-00000000: 11 08 00 0c 05 00 00 00 20 00 00 00 73 6d 61 6c  ........ ...smal
-00000010: 6c 61 76 61 63 61 64 6f                          lavacado
-```
-
-## Superblock
-
-The superblock is the anchor for the littlefs. The superblock is stored as
-a metadata pair containing a single superblock entry. It is through the
-superblock that littlefs can access the rest of the filesystem.
-
-The superblock can always be found in blocks 0 and 1, however fetching the
-superblock requires knowing the block size. The block size can be guessed by
-searching the beginning of disk for the string "littlefs", although currently
-the filesystems relies on the user providing the correct block size.
-
-The superblock is the most valuable block in the filesystem. It is updated
-very rarely, only during format or when the root directory must be moved. It
-is encouraged to always write out both superblock pairs even though it is not
-required.
-
-Here's the layout of the superblock entry:
-
-| offset | size                   | description                            |
-|--------|------------------------|----------------------------------------|
-| 0x00   | 8 bits                 | entry type (0x2e for superblock entry) |
-| 0x01   | 8 bits                 | entry length (20 bytes)                |
-| 0x02   | 8 bits                 | attribute length                       |
-| 0x03   | 8 bits                 | name length (8 bytes)                  |
-| 0x04   | 64 bits                | root directory                         |
-| 0x0c   | 32 bits                | block size                             |
-| 0x10   | 32 bits                | block count                            |
-| 0x14   | 32 bits                | version                                |
-| 0x18   | attribute length bytes | system-specific attributes             |
-| 0x18+a | 8 bytes                | magic string ("littlefs")              |
-
-**Root directory** - Pointer to the root directory's metadata pair.
-
-**Block size** - Size of the logical block size used by the filesystem.
-
-**Block count** - Number of blocks in the filesystem.
-
-**Version** - The littlefs version encoded as a 32 bit value. The upper 16 bits
-encodes the major version, which is incremented when a breaking-change is
-introduced in the filesystem specification. The lower 16 bits encodes the
-minor version, which is incremented when a backwards-compatible change is
-introduced. Non-standard Attribute changes do not change the version. This
-specification describes version 1.1 (0x00010001), which is the first version
-of littlefs.
-
-**Magic string** - The magic string "littlefs" takes the place of an entry
-name.
-
-Here's an example of a complete superblock:
-```
-(32 bits) revision count   = 3                    (0x00000003)
-(32 bits) dir size         = 52 bytes, end of dir (0x00000034)
-(64 bits) tail pointer     = 3, 2                 (0x00000003, 0x00000002)
-(8 bits)  entry type       = superblock           (0x2e)
-(8 bits)  entry length     = 20 bytes             (0x14)
-(8 bits)  attribute length = 0 bytes              (0x00)
-(8 bits)  name length      = 8 bytes              (0x08)
-(64 bits) root directory   = 3, 2                 (0x00000003, 0x00000002)
-(32 bits) block size       = 512 bytes            (0x00000200)
-(32 bits) block count      = 1024 blocks          (0x00000400)
-(32 bits) version          = 1.1                  (0x00010001)
-(8 bytes) magic string     = littlefs
-(32 bits) CRC              = 0xc50b74fa
-
-00000000: 03 00 00 00 34 00 00 00 03 00 00 00 02 00 00 00  ....4...........
-00000010: 2e 14 00 08 03 00 00 00 02 00 00 00 00 02 00 00  ................
-00000020: 00 04 00 00 01 00 01 00 6c 69 74 74 6c 65 66 73  ........littlefs
-00000030: fa 74 0b c5                                      .t..
-```
-
-## Directory entries
-
-Directories are stored in entries with a pointer to the first metadata pair
-in the directory. Keep in mind that a directory may be composed of multiple
-metadata pairs connected by the tail pointer when the highest bit in the dir
-size is set.
-
-Here's the layout of a directory entry:
-
-| offset | size                   | description                             |
-|--------|------------------------|-----------------------------------------|
-| 0x0    | 8 bits                 | entry type (0x22 for directory entries) |
-| 0x1    | 8 bits                 | entry length (8 bytes)                  |
-| 0x2    | 8 bits                 | attribute length                        |
-| 0x3    | 8 bits                 | name length                             |
-| 0x4    | 64 bits                | directory pointer                       |
-| 0xc    | attribute length bytes | system-specific attributes              |
-| 0xc+a  | name length bytes      | directory name                          |
-
-**Directory pointer** - Pointer to the first metadata pair in the directory.
-
-Here's an example of a directory entry:
-```
-(8 bits)  entry type        = directory (0x22)
-(8 bits)  entry length      = 8 bytes   (0x08)
-(8 bits)  attribute length  = 0 bytes   (0x00)
-(8 bits)  name length       = 3 bytes   (0x03)
-(64 bits) directory pointer = 5, 4      (0x00000005, 0x00000004)
-(3 bytes) name              = tea
-
-00000000: 22 08 00 03 05 00 00 00 04 00 00 00 74 65 61     "...........tea
-```
-
-## File entries
-
-Files are stored in entries with a pointer to the head of the file and the
-size of the file. This is enough information to determine the state of the
-CTZ skip-list that is being referenced.
-
-How files are actually stored on disk is a bit complicated. The full
-explanation of CTZ skip-lists can be found in [DESIGN.md](DESIGN.md#ctz-skip-lists).
-
-A terribly quick summary: For every nth block where n is divisible by 2^x,
-the block contains a pointer to block n-2^x. These pointers are stored in
-increasing order of x in each block of the file preceding the data in the
-block.
-
-The maximum number of pointers in a block is bounded by the maximum file size
-divided by the block size. With 32 bits for file size, this results in a
-minimum block size of 104 bytes.
-
-Here's the layout of a file entry:
-
-| offset | size                   | description                        |
-|--------|------------------------|------------------------------------|
-| 0x0    | 8 bits                 | entry type (0x11 for file entries) |
-| 0x1    | 8 bits                 | entry length (8 bytes)             |
-| 0x2    | 8 bits                 | attribute length                   |
-| 0x3    | 8 bits                 | name length                        |
-| 0x4    | 32 bits                | file head                          |
-| 0x8    | 32 bits                | file size                          |
-| 0xc    | attribute length bytes | system-specific attributes         |
-| 0xc+a  | name length bytes      | directory name                     |
-
-**File head** - Pointer to the block that is the head of the file's CTZ
-skip-list.
-
-**File size** - Size of file in bytes.
-
-Here's an example of a file entry:
-```
-(8 bits)   entry type       = file     (0x11)
-(8 bits)   entry length     = 8 bytes  (0x08)
-(8 bits)   attribute length = 0 bytes  (0x00)
-(8 bits)   name length      = 12 bytes (0x03)
-(32 bits)  file head        = 543      (0x0000021f)
-(32 bits)  file size        = 256 KB   (0x00040000)
-(12 bytes) name             = largeavacado
-
-00000000: 11 08 00 0c 1f 02 00 00 00 00 04 00 6c 61 72 67  ............large
-00000010: 65 61 76 61 63 61 64 6f                          eavacado
-```
-
-## Entry attributes
-
-Each dir entry can have up to 256 bytes of system-specific attributes. Since
-these attributes are system-specific, they may not be portable between
-different systems. For this reason, all attributes must be optional. A minimal
-littlefs driver must be able to get away with supporting no attributes at all.
-
-For some level of portability, littlefs has a simple scheme for attributes.
-Each attribute is prefixes with an 8-bit type that indicates what the attribute
-is. The length of attributes may also be determined from this type. Attributes
-in an entry should be sorted based on portability, since attribute parsing
-will end when it hits the first attribute it does not understand.
-
-Each system should choose a 4-bit value to prefix all attribute types with to
-avoid conflicts with other systems. Additionally, littlefs drivers that support
-attributes should provide a "ignore attributes" flag to users in case attribute
-conflicts do occur.
-
-Attribute types prefixes with 0x0 and 0xf are currently reserved for future
-standard attributes. Standard attributes will be added to this document in
-that case.
-
-Here's an example of non-standard time attribute:
-```
-(8 bits)  attribute type  = time       (0xc1)
-(72 bits) time in seconds = 1506286115 (0x0059c81a23)
-
-00000000: c1 23 1a c8 59 00                                .#..Y.
-```
-
-Here's an example of non-standard permissions attribute:
-```
-(8 bits)  attribute type  = permissions (0xc2)
-(16 bits) permission bits = rw-rw-r--   (0x01b4)
-
-00000000: c2 b4 01                                         ...
-```
-
-Here's what a dir entry may look like with these attributes:
-```
-(8 bits)   entry type       = file         (0x11)
-(8 bits)   entry length     = 8 bytes      (0x08)
-(8 bits)   attribute length = 9 bytes      (0x09)
-(8 bits)   name length      = 12 bytes     (0x0c)
-(8 bytes)  entry data       = 05 00 00 00 20 00 00 00
-(8 bits)   attribute type   = time         (0xc1)
-(72 bits)  time in seconds  = 1506286115   (0x0059c81a23)
-(8 bits)   attribute type   = permissions  (0xc2)
-(16 bits)  permission bits  = rw-rw-r--    (0x01b4)
-(12 bytes) entry name       = smallavacado
-
-00000000: 11 08 09 0c 05 00 00 00 20 00 00 00 c1 23 1a c8  ........ ....#..
-00000010: 59 00 c2 b4 01 73 6d 61 6c 6c 61 76 61 63 61 64  Y....smallavacad
-00000020: 6f                                               o
-```
diff --git a/fs/littlefs/lfs.c b/fs/littlefs/lfs.c
deleted file mode 100644
index 77d06af..0000000
--- a/fs/littlefs/lfs.c
+++ /dev/null
@@ -1,3464 +0,0 @@
-/****************************************************************************
- * fs/littlefs/lfs.c
- *
- * This file is a part of NuttX:
- *
- *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
- *
- * Ported by:
- *
- *   Copyright (C) 2019 Pinecone Inc. All rights reserved.
- *   Author: lihaichen <li...@163.com>
- *
- * This port derives from ARM mbed logic which has a compatible 3-clause
- * BSD license:
- *
- *   Copyright (c) 2017, Arm Limited. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the names ARM, NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <inttypes.h>
-
-#include "lfs.h"
-#include "lfs_util.h"
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-struct lfs_region_s
-{
-  lfs_off_t oldoff;
-  lfs_size_t oldlen;
-  FAR const void *newdata;
-  lfs_size_t newlen;
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-static int lfs_pred(FAR lfs_t *lfs, FAR const lfs_block_t dir[2],
-                    FAR lfs_dir_t *pdir);
-static int lfs_parent(FAR lfs_t *lfs, FAR const lfs_block_t dir[2],
-                      FAR lfs_dir_t *parent, FAR lfs_entry_t *entry);
-static int lfs_moved(FAR lfs_t *lfs, FAR const void *e);
-static int lfs_relocate(FAR lfs_t *lfs, FAR const lfs_block_t oldpair[2],
-                        FAR const lfs_block_t newpair[2]);
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/* Caching block device operations */
-
-static int lfs_cache_read(FAR lfs_t *lfs, FAR lfs_cache_t *rcache,
-                          FAR const lfs_cache_t *pcache, lfs_block_t block,
-                          lfs_off_t off, FAR void *buffer, lfs_size_t size)
-{
-  FAR uint8_t *data = buffer;
-  LFS_ASSERT(block < lfs->cfg->block_count);
-
-  while (size > 0)
-    {
-      if (pcache && block == pcache->block && off >= pcache->off &&
-          off < pcache->off + lfs->cfg->prog_size)
-        {
-          /* is already in pcache? */
-
-          lfs_size_t diff =
-              lfs_min(size, lfs->cfg->prog_size - (off - pcache->off));
-          memcpy(data, &pcache->buffer[off - pcache->off], diff);
-
-          data += diff;
-          off += diff;
-          size -= diff;
-          continue;
-        }
-
-      if (block == rcache->block && off >= rcache->off &&
-          off < rcache->off + lfs->cfg->read_size)
-        {
-          /* is already in rcache? */
-
-          lfs_size_t diff =
-              lfs_min(size, lfs->cfg->read_size - (off - rcache->off));
-          memcpy(data, &rcache->buffer[off - rcache->off], diff);
-
-          data += diff;
-          off += diff;
-          size -= diff;
-          continue;
-        }
-
-      if (off % lfs->cfg->read_size == 0 && size >= lfs->cfg->read_size)
-        {
-          /* bypass cache? */
-
-          lfs_size_t diff = size - (size % lfs->cfg->read_size);
-          int err = lfs->cfg->read(lfs->cfg, block, off, data, diff);
-          if (err)
-            {
-              return err;
-            }
-
-          data += diff;
-          off += diff;
-          size -= diff;
-          continue;
-        }
-
-      /* load to cache, first condition can no longer fail */
-
-      rcache->block = block;
-      rcache->off = off - (off % lfs->cfg->read_size);
-      int err = lfs->cfg->read(lfs->cfg, rcache->block, rcache->off,
-                               rcache->buffer, lfs->cfg->read_size);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  return 0;
-}
-
-static int lfs_cache_cmp(FAR lfs_t *lfs, FAR lfs_cache_t *rcache,
-                         FAR const lfs_cache_t *pcache, lfs_block_t block,
-                         lfs_off_t off, FAR const void *buffer,
-                         lfs_size_t size)
-{
-  FAR const uint8_t *data = buffer;
-  lfs_off_t i;
-
-  for (i = 0; i < size; i++)
-    {
-      uint8_t c;
-      int err = lfs_cache_read(lfs, rcache, pcache, block, off + i, &c, 1);
-      if (err)
-        {
-          return err;
-        }
-
-      if (c != data[i])
-        {
-          return false;
-        }
-    }
-
-  return true;
-}
-
-static int lfs_cache_crc(FAR lfs_t *lfs, FAR lfs_cache_t *rcache,
-                         FAR const lfs_cache_t *pcache, lfs_block_t block,
-                         lfs_off_t off, lfs_size_t size, FAR uint32_t *crc)
-{
-  lfs_off_t i;
-
-  for (i = 0; i < size; i++)
-    {
-      uint8_t c;
-      int err = lfs_cache_read(lfs, rcache, pcache, block, off + i, &c, 1);
-      if (err)
-        {
-          return err;
-        }
-
-      lfs_crc(crc, &c, 1);
-    }
-
-  return 0;
-}
-
-static inline void lfs_cache_drop(FAR lfs_t *lfs, FAR lfs_cache_t *rcache)
-{
-  /* do not zero, cheaper if cache is readonly or only going to be
-   * written with identical data (during relocates)
-   */
-
-  rcache->block = 0xffffffff;
-}
-
-static inline void lfs_cache_zero(FAR lfs_t *lfs, FAR lfs_cache_t *pcache)
-{
-  /* zero to avoid information leak */
-
-  memset(pcache->buffer, 0xff, lfs->cfg->prog_size);
-  pcache->block = 0xffffffff;
-}
-
-static int lfs_cache_flush(FAR lfs_t *lfs, FAR lfs_cache_t *pcache,
-                           FAR lfs_cache_t *rcache)
-{
-  if (pcache->block != 0xffffffff)
-    {
-      int err = lfs->cfg->prog(lfs->cfg, pcache->block, pcache->off,
-                               pcache->buffer, lfs->cfg->prog_size);
-      if (err)
-        {
-          return err;
-        }
-
-      if (rcache)
-        {
-          int res = lfs_cache_cmp(lfs, rcache, NULL, pcache->block,
-                                  pcache->off, pcache->buffer,
-                                  lfs->cfg->prog_size);
-          if (res < 0)
-            {
-              return res;
-            }
-
-          if (!res)
-            {
-              return LFS_ERR_CORRUPT;
-            }
-        }
-
-      lfs_cache_zero(lfs, pcache);
-    }
-
-  return 0;
-}
-
-static int lfs_cache_prog(FAR lfs_t *lfs, FAR lfs_cache_t *pcache,
-                          FAR lfs_cache_t *rcache, lfs_block_t block,
-                          lfs_off_t off, FAR const void *buffer,
-                          lfs_size_t size)
-{
-  FAR const uint8_t *data = buffer;
-  LFS_ASSERT(block < lfs->cfg->block_count);
-
-  while (size > 0)
-    {
-      if (block == pcache->block && off >= pcache->off &&
-          off < pcache->off + lfs->cfg->prog_size)
-        {
-          /* is already in pcache? */
-
-          lfs_size_t diff =
-              lfs_min(size, lfs->cfg->prog_size - (off - pcache->off));
-          memcpy(&pcache->buffer[off - pcache->off], data, diff);
-
-          data += diff;
-          off += diff;
-          size -= diff;
-
-          if (off % lfs->cfg->prog_size == 0)
-            {
-              /* eagerly flush out pcache if we fill up */
-
-              int err = lfs_cache_flush(lfs, pcache, rcache);
-              if (err)
-                {
-                  return err;
-                }
-            }
-
-          continue;
-        }
-
-      /* pcache must have been flushed, either by programming and
-       * entire block or manually flushing the pcache
-       */
-
-      LFS_ASSERT(pcache->block == 0xffffffff);
-
-      if (off % lfs->cfg->prog_size == 0 && size >= lfs->cfg->prog_size)
-        {
-          /* bypass pcache? */
-
-          lfs_size_t diff = size - (size % lfs->cfg->prog_size);
-          int err = lfs->cfg->prog(lfs->cfg, block, off, data, diff);
-          if (err)
-            {
-              return err;
-            }
-
-          if (rcache)
-            {
-              int res =
-                  lfs_cache_cmp(lfs, rcache, NULL, block, off, data, diff);
-              if (res < 0)
-                {
-                  return res;
-                }
-
-              if (!res)
-                {
-                  return LFS_ERR_CORRUPT;
-                }
-            }
-
-          data += diff;
-          off += diff;
-          size -= diff;
-          continue;
-        }
-
-      /* prepare pcache, first condition can no longer fail */
-
-      pcache->block = block;
-      pcache->off = off - (off % lfs->cfg->prog_size);
-    }
-
-  return 0;
-}
-
-/* General lfs block device operations */
-
-static int lfs_bd_read(FAR lfs_t *lfs, lfs_block_t block, lfs_off_t off,
-                       FAR void *buffer, lfs_size_t size)
-{
-  /* if we ever do more than writes to alternating pairs,
-   * this may need to consider pcache
-   */
-
-  return lfs_cache_read(lfs, &lfs->rcache, NULL, block, off, buffer, size);
-}
-
-static int lfs_bd_prog(FAR lfs_t *lfs, lfs_block_t block, lfs_off_t off,
-                       FAR const void *buffer, lfs_size_t size)
-{
-  return lfs_cache_prog(lfs, &lfs->pcache, NULL, block, off, buffer, size);
-}
-
-static int lfs_bd_cmp(FAR lfs_t *lfs, lfs_block_t block, lfs_off_t off,
-                      FAR const void *buffer, lfs_size_t size)
-{
-  return lfs_cache_cmp(lfs, &lfs->rcache, NULL, block, off, buffer, size);
-}
-
-static int lfs_bd_crc(FAR lfs_t *lfs, lfs_block_t block, lfs_off_t off,
-                      lfs_size_t size, FAR uint32_t *crc)
-{
-  return lfs_cache_crc(lfs, &lfs->rcache, NULL, block, off, size, crc);
-}
-
-static int lfs_bd_erase(FAR lfs_t *lfs, lfs_block_t block)
-{
-  return lfs->cfg->erase(lfs->cfg, block);
-}
-
-static int lfs_bd_sync(FAR lfs_t *lfs)
-{
-  lfs_cache_drop(lfs, &lfs->rcache);
-
-  int err = lfs_cache_flush(lfs, &lfs->pcache, NULL);
-  if (err)
-    {
-      return err;
-    }
-
-  return lfs->cfg->sync(lfs->cfg);
-}
-
-/* Block allocator */
-
-static int lfs_alloc_lookahead(FAR void *p, lfs_block_t block)
-{
-  FAR lfs_t *lfs = p;
-
-  lfs_block_t off =
-      ((block - lfs->free.off) + lfs->cfg->block_count) %
-      lfs->cfg->block_count;
-
-  if (off < lfs->free.size)
-    {
-      lfs->free.buffer[off / 32] |= 1U << (off % 32);
-    }
-
-  return 0;
-}
-
-static int lfs_alloc(FAR lfs_t *lfs, FAR lfs_block_t *block)
-{
-  while (true)
-    {
-      while (lfs->free.i != lfs->free.size)
-        {
-          lfs_block_t off = lfs->free.i;
-          lfs->free.i += 1;
-          lfs->free.ack -= 1;
-
-          if (!(lfs->free.buffer[off / 32] & (1U << (off % 32))))
-            {
-              /* found a free block */
-
-              *block = (lfs->free.off + off) % lfs->cfg->block_count;
-
-              /* eagerly find next off so an alloc ack can
-               * discredit old lookahead blocks
-               */
-
-              while (lfs->free.i != lfs->free.size &&
-                     (lfs->free.buffer[lfs->free.i / 32] &
-                      (1U << (lfs->free.i % 32))))
-                {
-                  lfs->free.i += 1;
-                  lfs->free.ack -= 1;
-                }
-
-              return 0;
-            }
-        }
-
-      /* check if we have looked at all blocks since last ack */
-
-      if (lfs->free.ack == 0)
-        {
-          LFS_WARN("No more free space %" PRIu32,
-                   lfs->free.i + lfs->free.off);
-          return LFS_ERR_NOSPC;
-        }
-
-      lfs->free.off  = (lfs->free.off + lfs->free.size) %
-                       lfs->cfg->block_count;
-      lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->free.ack);
-      lfs->free.i    = 0;
-
-      /* find mask of free blocks from tree */
-
-      memset(lfs->free.buffer, 0, lfs->cfg->lookahead / 8);
-      int err = lfs_traverse(lfs, lfs_alloc_lookahead, lfs);
-      if (err)
-        {
-          return err;
-        }
-    }
-}
-
-static void lfs_alloc_ack(FAR lfs_t *lfs)
-{
-  lfs->free.ack = lfs->cfg->block_count;
-}
-
-/* Endian swapping functions */
-
-static void lfs_dir_fromle32(FAR struct lfs_disk_dir_s *d)
-{
-  d->rev = lfs_fromle32(d->rev);
-  d->size = lfs_fromle32(d->size);
-  d->tail[0] = lfs_fromle32(d->tail[0]);
-  d->tail[1] = lfs_fromle32(d->tail[1]);
-}
-
-static void lfs_dir_tole32(FAR struct lfs_disk_dir_s *d)
-{
-  d->rev = lfs_tole32(d->rev);
-  d->size = lfs_tole32(d->size);
-  d->tail[0] = lfs_tole32(d->tail[0]);
-  d->tail[1] = lfs_tole32(d->tail[1]);
-}
-
-static void lfs_entry_fromle32(FAR struct lfs_disk_entry_s *d)
-{
-  d->u.dir[0] = lfs_fromle32(d->u.dir[0]);
-  d->u.dir[1] = lfs_fromle32(d->u.dir[1]);
-}
-
-static void lfs_entry_tole32(FAR struct lfs_disk_entry_s *d)
-{
-  d->u.dir[0] = lfs_tole32(d->u.dir[0]);
-  d->u.dir[1] = lfs_tole32(d->u.dir[1]);
-}
-
-static void lfs_superblock_fromle32(FAR struct lfs_disk_superblock_s *d)
-{
-  d->root[0] = lfs_fromle32(d->root[0]);
-  d->root[1] = lfs_fromle32(d->root[1]);
-  d->block_size = lfs_fromle32(d->block_size);
-  d->block_count = lfs_fromle32(d->block_count);
-  d->version = lfs_fromle32(d->version);
-}
-
-static void lfs_superblock_tole32(FAR struct lfs_disk_superblock_s *d)
-{
-  d->root[0] = lfs_tole32(d->root[0]);
-  d->root[1] = lfs_tole32(d->root[1]);
-  d->block_size = lfs_tole32(d->block_size);
-  d->block_count = lfs_tole32(d->block_count);
-  d->version = lfs_tole32(d->version);
-}
-
-/* Metadata pair and directory operations */
-
-static inline void lfs_pairswap(FAR lfs_block_t pair[2])
-{
-  lfs_block_t t = pair[0];
-  pair[0] = pair[1];
-  pair[1] = t;
-}
-
-static inline bool lfs_pairisnull(FAR const lfs_block_t pair[2])
-{
-  return pair[0] == 0xffffffff || pair[1] == 0xffffffff;
-}
-
-static inline int lfs_paircmp(FAR const lfs_block_t paira[2],
-                              FAR const lfs_block_t pairb[2])
-{
-  return !(paira[0] == pairb[0] || paira[1] == pairb[1] ||
-           paira[0] == pairb[1] || paira[1] == pairb[0]);
-}
-
-static inline bool lfs_pairsync(FAR const lfs_block_t paira[2],
-                                FAR const lfs_block_t pairb[2])
-{
-  return (paira[0] == pairb[0] && paira[1] == pairb[1]) ||
-         (paira[0] == pairb[1] && paira[1] == pairb[0]);
-}
-
-static inline lfs_size_t lfs_entry_size(FAR const lfs_entry_t *entry)
-{
-  return 4 + entry->d.elen + entry->d.alen + entry->d.nlen;
-}
-
-static int lfs_dir_alloc(FAR lfs_t *lfs, FAR lfs_dir_t *dir)
-{
-  int i;
-
-  /* allocate pair of dir blocks */
-
-  for (i = 0; i < 2; i++)
-    {
-      int err = lfs_alloc(lfs, &dir->pair[i]);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  /* rather than clobbering one of the blocks we just pretend
-   * the revision may be valid
-   */
-
-  int err = lfs_bd_read(lfs, dir->pair[0], 0, &dir->d.rev, 4);
-  if (err && err != LFS_ERR_CORRUPT)
-    {
-      return err;
-    }
-
-  if (err != LFS_ERR_CORRUPT)
-    {
-      dir->d.rev = lfs_fromle32(dir->d.rev);
-    }
-
-  /* set defaults */
-
-  dir->d.rev += 1;
-  dir->d.size = sizeof(dir->d) + 4;
-  dir->d.tail[0] = 0xffffffff;
-  dir->d.tail[1] = 0xffffffff;
-  dir->off = sizeof(dir->d);
-
-  /* don't write out yet, let caller take care of that */
-
-  return 0;
-}
-
-static int lfs_dir_fetch(FAR lfs_t *lfs, FAR lfs_dir_t *dir,
-                         FAR const lfs_block_t pair[2])
-{
-  /* copy out pair, otherwise may be aliasing dir */
-
-  FAR const lfs_block_t tpair[2] =
-  {
-    pair[0], pair[1]
-  };
-
-  bool valid = false;
-  int i;
-
-  /* check both blocks for the most recent revision */
-
-  for (i = 0; i < 2; i++)
-    {
-      struct lfs_disk_dir_s test;
-      uint32_t crc;
-      int err = lfs_bd_read(lfs, tpair[i], 0, &test, sizeof(test));
-      lfs_dir_fromle32(&test);
-      if (err)
-        {
-          if (err == LFS_ERR_CORRUPT)
-            {
-              continue;
-            }
-
-          return err;
-        }
-
-      if (valid && lfs_scmp(test.rev, dir->d.rev) < 0)
-        {
-          continue;
-        }
-
-      if ((0x7fffffff & test.size) < sizeof(test) + 4 ||
-          (0x7fffffff & test.size) > lfs->cfg->block_size)
-        {
-          continue;
-        }
-
-      crc = 0xffffffff;
-      lfs_dir_tole32(&test);
-      lfs_crc(&crc, &test, sizeof(test));
-      lfs_dir_fromle32(&test);
-      err = lfs_bd_crc(lfs, tpair[i], sizeof(test),
-                       (0x7fffffff & test.size) - sizeof(test), &crc);
-      if (err)
-        {
-          if (err == LFS_ERR_CORRUPT)
-            {
-              continue;
-            }
-
-          return err;
-        }
-
-      if (crc != 0)
-        {
-          continue;
-        }
-
-      valid = true;
-
-      /* setup dir in case it's valid */
-
-      dir->pair[0] = tpair[(i + 0) % 2];
-      dir->pair[1] = tpair[(i + 1) % 2];
-      dir->off = sizeof(dir->d);
-      dir->d = test;
-    }
-
-  if (!valid)
-    {
-      LFS_ERROR("Corrupted dir pair at %" PRIu32 " %" PRIu32, tpair[0],
-                tpair[1]);
-      return LFS_ERR_CORRUPT;
-    }
-
-  return 0;
-}
-
-static int lfs_dir_commit(FAR lfs_t *lfs, FAR lfs_dir_t *dir,
-                          FAR const struct lfs_region_s *regions, int count)
-{
-  FAR lfs_dir_t *d;
-  lfs_block_t oldpair[2];
-  bool relocated;
-  int err;
-  int i;
-
-  /* increment revision count */
-
-  dir->d.rev += 1;
-
-  /* keep pairs in order such that pair[0] is most recent */
-
-  lfs_pairswap(dir->pair);
-  for (i = 0; i < count; i++)
-    {
-      dir->d.size += regions[i].newlen - regions[i].oldlen;
-    }
-
-  oldpair[0] = dir->pair[0];
-  oldpair[1] = dir->pair[1];
-  relocated = false;
-
-  while (true)
-    {
-      if (true)
-        {
-          uint32_t crc;
-          err = lfs_bd_erase(lfs, dir->pair[0]);
-          if (err)
-            {
-              if (err == LFS_ERR_CORRUPT)
-                {
-                  goto relocate;
-                }
-
-              return err;
-            }
-
-          crc = 0xffffffff;
-          lfs_dir_tole32(&dir->d);
-          lfs_crc(&crc, &dir->d, sizeof(dir->d));
-          err = lfs_bd_prog(lfs, dir->pair[0], 0, &dir->d, sizeof(dir->d));
-          lfs_dir_fromle32(&dir->d);
-          if (err)
-            {
-              if (err == LFS_ERR_CORRUPT)
-                {
-                  goto relocate;
-                }
-
-              return err;
-            }
-
-          i = 0;
-          lfs_off_t oldoff = sizeof(dir->d);
-          lfs_off_t newoff = sizeof(dir->d);
-          while (newoff < (0x7fffffff & dir->d.size) - 4)
-            {
-              if (i < count && regions[i].oldoff == oldoff)
-                {
-                  lfs_crc(&crc, regions[i].newdata, regions[i].newlen);
-                  err = lfs_bd_prog(lfs, dir->pair[0], newoff,
-                                    regions[i].newdata, regions[i].newlen);
-                  if (err)
-                    {
-                      if (err == LFS_ERR_CORRUPT)
-                        {
-                          goto relocate;
-                        }
-
-                      return err;
-                    }
-
-                  oldoff += regions[i].oldlen;
-                  newoff += regions[i].newlen;
-                  i += 1;
-                }
-              else
-                {
-                  uint8_t data;
-                  err = lfs_bd_read(lfs, oldpair[1], oldoff, &data, 1);
-                  if (err)
-                    {
-                      return err;
-                    }
-
-                  lfs_crc(&crc, &data, 1);
-                  err = lfs_bd_prog(lfs, dir->pair[0], newoff, &data, 1);
-                  if (err)
-                    {
-                      if (err == LFS_ERR_CORRUPT)
-                        {
-                          goto relocate;
-                        }
-
-                      return err;
-                    }
-
-                  oldoff += 1;
-                  newoff += 1;
-                }
-            }
-
-          crc = lfs_tole32(crc);
-          err = lfs_bd_prog(lfs, dir->pair[0], newoff, &crc, 4);
-          crc = lfs_fromle32(crc);
-          if (err)
-            {
-              if (err == LFS_ERR_CORRUPT)
-                {
-                  goto relocate;
-                }
-
-              return err;
-            }
-
-          err = lfs_bd_sync(lfs);
-          if (err)
-            {
-              if (err == LFS_ERR_CORRUPT)
-                {
-                  goto relocate;
-                }
-
-              return err;
-            }
-
-          /* successful commit, check checksum to make sure */
-
-          uint32_t ncrc = 0xffffffff;
-          err = lfs_bd_crc(lfs, dir->pair[0], 0,
-                           (0x7fffffff & dir->d.size) - 4, &ncrc);
-          if (err)
-            {
-              return err;
-            }
-
-          if (ncrc != crc)
-            {
-              goto relocate;
-            }
-        }
-
-      break;
-
-relocate:
-
-      /* Commit was corrupted */
-
-      LFS_DEBUG("Bad block at %" PRIu32, dir->pair[0]);
-
-      /* Drop caches and prepare to relocate block */
-
-      relocated = true;
-      lfs_cache_drop(lfs, &lfs->pcache);
-
-      /* Can't relocate superblock, filesystem is now frozen */
-
-      if (lfs_paircmp(oldpair, (const lfs_block_t[2]){ 0, 1 }) == 0)
-        {
-          LFS_WARN("Superblock %" PRIu32 " has become unwritable",
-                   oldpair[0]);
-          return LFS_ERR_CORRUPT;
-        }
-
-      /* Relocate half of pair */
-
-      err = lfs_alloc(lfs, &dir->pair[0]);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  if (relocated)
-    {
-      /* update references if we relocated */
-
-      LFS_DEBUG("Relocating %" PRIu32 " %" PRIu32 " to %" PRIu32 " %" PRIu32,
-                oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]);
-      err = lfs_relocate(lfs, oldpair, dir->pair);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  /* shift over any directories that are affected */
-
-  for (d = lfs->dirs; d; d = d->next)
-    {
-      if (lfs_paircmp(d->pair, dir->pair) == 0)
-        {
-          d->pair[0] = dir->pair[0];
-          d->pair[1] = dir->pair[1];
-        }
-    }
-
-  return 0;
-}
-
-static int lfs_dir_update(FAR lfs_t *lfs, FAR lfs_dir_t *dir,
-                          FAR lfs_entry_t *entry, FAR const void *data)
-{
-  int err;
-
-  lfs_entry_tole32(&entry->d);
-  err = lfs_dir_commit(
-      lfs, dir,
-      (struct lfs_region_s[])
-      {
-        {
-          entry->off, sizeof(entry->d), &entry->d, sizeof(entry->d)
-        },
-        {
-          entry->off + sizeof(entry->d), entry->d.nlen, data, entry->d.nlen
-        }
-      },
-      data ? 2 : 1);
-  lfs_entry_fromle32(&entry->d);
-  return err;
-}
-
-static int lfs_dir_append(FAR lfs_t *lfs, FAR lfs_dir_t *dir,
-                          FAR lfs_entry_t *entry, FAR const void *data)
-{
-  /* check if we fit, if top bit is set we do not and move on */
-
-  while (true)
-    {
-      if (dir->d.size + lfs_entry_size(entry) <= lfs->cfg->block_size)
-        {
-          entry->off = dir->d.size - 4;
-
-          lfs_entry_tole32(&entry->d);
-          int err =
-              lfs_dir_commit(lfs, dir,
-                             (struct lfs_region_s[])
-                             {
-                               {
-                                 entry->off, 0, &entry->d, sizeof(entry->d)
-                               },
-                               {
-                                 entry->off, 0, data, entry->d.nlen
-                               }
-                             },
-                             2);
-          lfs_entry_fromle32(&entry->d);
-          return err;
-        }
-
-      /* we need to allocate a new dir block */
-
-      if (!(0x80000000 & dir->d.size))
-        {
-          lfs_dir_t olddir = *dir;
-          int err = lfs_dir_alloc(lfs, dir);
-          if (err)
-            {
-              return err;
-            }
-
-          dir->d.tail[0] = olddir.d.tail[0];
-          dir->d.tail[1] = olddir.d.tail[1];
-          entry->off = dir->d.size - 4;
-          lfs_entry_tole32(&entry->d);
-          err = lfs_dir_commit(lfs, dir,
-                               (struct lfs_region_s[])
-                               {
-                                 {
-                                   entry->off, 0, &entry->d, sizeof(entry->d)
-                                 },
-                                 {
-                                   entry->off, 0, data, entry->d.nlen
-                                 }
-                               },
-                               2);
-          lfs_entry_fromle32(&entry->d);
-          if (err)
-            {
-              return err;
-            }
-
-          olddir.d.size |= 0x80000000;
-          olddir.d.tail[0] = dir->pair[0];
-          olddir.d.tail[1] = dir->pair[1];
-          return lfs_dir_commit(lfs, &olddir, NULL, 0);
-        }
-
-      int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
-      if (err)
-        {
-          return err;
-        }
-    }
-}
-
-static int lfs_dir_remove(FAR lfs_t *lfs, FAR lfs_dir_t *dir,
-                          FAR lfs_entry_t *entry)
-{
-  FAR lfs_file_t *f;
-  FAR lfs_dir_t *d;
-  int err;
-
-  /* check if we should just drop the directory block */
-
-  if ((dir->d.size & 0x7fffffff) ==
-      sizeof(dir->d) + 4 + lfs_entry_size(entry))
-    {
-      lfs_dir_t pdir;
-      int res = lfs_pred(lfs, dir->pair, &pdir);
-      if (res < 0)
-        {
-          return res;
-        }
-
-      if (pdir.d.size & 0x80000000)
-        {
-          pdir.d.size &= dir->d.size | 0x7fffffff;
-          pdir.d.tail[0] = dir->d.tail[0];
-          pdir.d.tail[1] = dir->d.tail[1];
-          return lfs_dir_commit(lfs, &pdir, NULL, 0);
-        }
-    }
-
-  /* shift out the entry */
-
-  err = lfs_dir_commit(lfs, dir,
-                       (struct lfs_region_s[])
-                       {
-                         {
-                           entry->off, lfs_entry_size(entry), NULL, 0
-                         },
-                       },
-                       1);
-  if (err)
-    {
-      return err;
-    }
-
-  /* shift over any files/directories that are affected */
-
-  for (f = lfs->files; f; f = f->next)
-    {
-      if (lfs_paircmp(f->pair, dir->pair) == 0)
-        {
-          if (f->poff == entry->off)
-            {
-              f->pair[0] = 0xffffffff;
-              f->pair[1] = 0xffffffff;
-            }
-          else if (f->poff > entry->off)
-            {
-              f->poff -= lfs_entry_size(entry);
-            }
-        }
-    }
-
-  for (d = lfs->dirs; d; d = d->next)
-    {
-      if (lfs_paircmp(d->pair, dir->pair) == 0)
-        {
-          if (d->off > entry->off)
-            {
-              d->off -= lfs_entry_size(entry);
-              d->pos -= lfs_entry_size(entry);
-            }
-        }
-    }
-
-  return 0;
-}
-
-static int lfs_dir_next(FAR lfs_t *lfs, FAR lfs_dir_t *dir,
-                        FAR lfs_entry_t *entry)
-{
-  while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size) - 4)
-    {
-      if (!(0x80000000 & dir->d.size))
-        {
-          entry->off = dir->off;
-          return LFS_ERR_NOENT;
-        }
-
-      int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
-      if (err)
-        {
-          return err;
-        }
-
-      dir->off = sizeof(dir->d);
-      dir->pos += sizeof(dir->d) + 4;
-    }
-
-  int err = lfs_bd_read(lfs, dir->pair[0], dir->off, &entry->d,
-                        sizeof(entry->d));
-  lfs_entry_fromle32(&entry->d);
-  if (err)
-    {
-      return err;
-    }
-
-  entry->off = dir->off;
-  dir->off += lfs_entry_size(entry);
-  dir->pos += lfs_entry_size(entry);
-  return 0;
-}
-
-static int lfs_dir_find(FAR lfs_t *lfs, FAR lfs_dir_t *dir,
-                        FAR lfs_entry_t *entry,
-                        FAR const char **path)
-{
-  FAR const char *pathname = *path;
-  size_t pathlen;
-  entry->d.type = LFS_TYPE_DIR;
-  entry->d.elen = sizeof(entry->d) - 4;
-  entry->d.alen = 0;
-  entry->d.nlen = 0;
-  entry->d.u.dir[0] = lfs->root[0];
-  entry->d.u.dir[1] = lfs->root[1];
-
-  while (true)
-    {
-      FAR const char *suffix;
-      size_t sufflen;
-      int depth;
-
-nextname:
-
-      /* Skip slashes */
-
-      pathname += strspn(pathname, "/");
-      pathlen = strcspn(pathname, "/");
-
-      /* Skip '.' and root '..' */
-
-      if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) ||
-          (pathlen == 2 && memcmp(pathname, "..", 2) == 0))
-        {
-          pathname += pathlen;
-          goto nextname;
-        }
-
-      /* Skip if matched by '..' in name */
-
-      suffix = pathname + pathlen;
-      depth = 1;
-      while (true)
-        {
-          suffix += strspn(suffix, "/");
-          sufflen = strcspn(suffix, "/");
-          if (sufflen == 0)
-            {
-              break;
-            }
-
-          if (sufflen == 2 && memcmp(suffix, "..", 2) == 0)
-            {
-              depth -= 1;
-              if (depth == 0)
-                {
-                  pathname = suffix + sufflen;
-                  goto nextname;
-                }
-            }
-          else
-            {
-              depth += 1;
-            }
-
-          suffix += sufflen;
-        }
-
-      /* found path */
-
-      if (pathname[0] == '\0')
-        {
-          return 0;
-        }
-
-      /* update what we've found */
-
-      *path = pathname;
-
-      /* continue on if we hit a directory */
-
-      if (entry->d.type != LFS_TYPE_DIR)
-        {
-          return LFS_ERR_NOTDIR;
-        }
-
-      int err = lfs_dir_fetch(lfs, dir, entry->d.u.dir);
-      if (err)
-        {
-          return err;
-        }
-
-      /* find entry matching name */
-
-      while (true)
-        {
-          err = lfs_dir_next(lfs, dir, entry);
-          if (err)
-            {
-              return err;
-            }
-
-          if (((0x7f & entry->d.type) != LFS_TYPE_REG &&
-               (0x7f & entry->d.type) != LFS_TYPE_DIR) ||
-              entry->d.nlen != pathlen)
-            {
-              continue;
-            }
-
-          int res = lfs_bd_cmp(lfs, dir->pair[0],
-                               entry->off + 4 + entry->d.elen + entry->d.alen,
-                               pathname, pathlen);
-          if (res < 0)
-            {
-              return res;
-            }
-
-          /* found match */
-
-          if (res)
-            {
-              break;
-            }
-        }
-
-      /* check that entry has not been moved */
-
-      if (!lfs->moving && entry->d.type & 0x80)
-        {
-          int moved = lfs_moved(lfs, &entry->d.u);
-          if (moved < 0 || moved)
-            {
-              return (moved < 0) ? moved : LFS_ERR_NOENT;
-            }
-
-          entry->d.type &= ~0x80;
-        }
-
-      /* to next name */
-
-      pathname += pathlen;
-    }
-}
-
-/* File index list operations */
-
-static int lfs_ctz_index(FAR lfs_t *lfs, FAR lfs_off_t *off)
-{
-  lfs_off_t size = *off;
-  lfs_off_t b = lfs->cfg->block_size - 2 * 4;
-  lfs_off_t i = size / b;
-  if (i == 0)
-    {
-      return 0;
-    }
-
-  i = (size - 4 * (lfs_popc(i - 1) + 2)) / b;
-  *off = size - b * i - 4 * lfs_popc(i);
-  return i;
-}
-
-static int lfs_ctz_find(FAR lfs_t *lfs, FAR lfs_cache_t *rcache,
-                        FAR const lfs_cache_t *pcache, lfs_block_t head,
-                        lfs_size_t size, lfs_size_t pos,
-                        FAR lfs_block_t *block, FAR lfs_off_t *off)
-{
-  if (size == 0)
-    {
-      *block = 0xffffffff;
-      *off = 0;
-      return 0;
-    }
-
-  lfs_off_t current = lfs_ctz_index(lfs, &(lfs_off_t){ size - 1 });
-  lfs_off_t target = lfs_ctz_index(lfs, &pos);
-
-  while (current > target)
-    {
-      int err;
-
-      lfs_size_t skip =
-          lfs_min(lfs_npw2(current - target + 1) - 1, lfs_ctz(current));
-
-      err = lfs_cache_read(lfs, rcache, pcache, head, 4 * skip, &head, 4);
-      head = lfs_fromle32(head);
-      if (err)
-        {
-          return err;
-        }
-
-      LFS_ASSERT(head >= 2 && head <= lfs->cfg->block_count);
-      current -= 1 << skip;
-    }
-
-  *block = head;
-  *off = pos;
-  return 0;
-}
-
-static int lfs_ctz_extend(FAR lfs_t *lfs, FAR lfs_cache_t *rcache,
-                          FAR lfs_cache_t *pcache, lfs_block_t head,
-                          lfs_size_t size, FAR lfs_block_t *block,
-                          FAR lfs_off_t *off)
-{
-  while (true)
-    {
-      lfs_block_t nblock;
-      int err;
-
-      /* go ahead and grab a block */
-
-      err = lfs_alloc(lfs, &nblock);
-      if (err)
-        {
-          return err;
-        }
-
-      LFS_ASSERT(nblock >= 2 && nblock <= lfs->cfg->block_count);
-
-      if (true)
-        {
-          lfs_off_t index;
-          lfs_size_t skips;
-          lfs_off_t i;
-
-          err = lfs_bd_erase(lfs, nblock);
-          if (err)
-            {
-              if (err == LFS_ERR_CORRUPT)
-                {
-                  goto relocate;
-                }
-
-              return err;
-            }
-
-          if (size == 0)
-            {
-              *block = nblock;
-              *off = 0;
-              return 0;
-            }
-
-          size -= 1;
-          index = lfs_ctz_index(lfs, &size);
-          size += 1;
-
-          /* just copy out the last block if it is incomplete */
-
-          if (size != lfs->cfg->block_size)
-            {
-              for (i = 0; i < size; i++)
-                {
-                  uint8_t data;
-                  err = lfs_cache_read(lfs, rcache, NULL, head, i,
-                                       &data, 1);
-                  if (err)
-                    {
-                      return err;
-                    }
-
-                  err = lfs_cache_prog(lfs, pcache, rcache, nblock, i,
-                                       &data, 1);
-                  if (err)
-                    {
-                      if (err == LFS_ERR_CORRUPT)
-                        {
-                          goto relocate;
-                        }
-
-                      return err;
-                    }
-                }
-
-              *block = nblock;
-              *off = size;
-              return 0;
-            }
-
-          /* append block */
-
-          index += 1;
-          skips = lfs_ctz(index) + 1;
-
-          for (i = 0; i < skips; i++)
-            {
-              head = lfs_tole32(head);
-              err = lfs_cache_prog(lfs, pcache, rcache, nblock, 4 * i,
-                                   &head, 4);
-              head = lfs_fromle32(head);
-              if (err)
-                {
-                  if (err == LFS_ERR_CORRUPT)
-                    {
-                      goto relocate;
-                    }
-
-                  return err;
-                }
-
-              if (i != skips - 1)
-                {
-                  err = lfs_cache_read(lfs, rcache, NULL, head, 4 * i,
-                                       &head, 4);
-                  head = lfs_fromle32(head);
-                  if (err)
-                    {
-                      return err;
-                    }
-                }
-
-              LFS_ASSERT(head >= 2 && head <= lfs->cfg->block_count);
-            }
-
-          *block = nblock;
-          *off = 4 * skips;
-          return 0;
-        }
-
-relocate:
-
-      LFS_DEBUG("Bad block at %" PRIu32, nblock);
-
-      /* Just clear cache and try a new block */
-
-      lfs_cache_drop(lfs, &lfs->pcache);
-    }
-}
-
-static int lfs_ctz_traverse(FAR lfs_t *lfs, FAR lfs_cache_t *rcache,
-                            FAR const lfs_cache_t *pcache, lfs_block_t head,
-                            FAR lfs_size_t size,
-                            CODE int (*cb)(FAR void *, lfs_block_t),
-                            FAR void *data)
-{
-  lfs_off_t index;
-
-  if (size == 0)
-    {
-      return 0;
-    }
-
-  index = lfs_ctz_index(lfs, &(lfs_off_t){ size - 1 });
-
-  while (true)
-    {
-      lfs_block_t heads[2];
-      int count;
-      int err;
-      int i;
-
-      err = cb(data, head);
-      if (err)
-        {
-          return err;
-        }
-
-      if (index == 0)
-        {
-          return 0;
-        }
-
-      count = 2 - (index & 1);
-      err = lfs_cache_read(lfs, rcache, pcache, head, 0, &heads, count * 4);
-      heads[0] = lfs_fromle32(heads[0]);
-      heads[1] = lfs_fromle32(heads[1]);
-      if (err)
-        {
-          return err;
-        }
-
-      for (i = 0; i < count - 1; i++)
-        {
-          err = cb(data, heads[i]);
-          if (err)
-            {
-              return err;
-            }
-        }
-
-      head = heads[count - 1];
-      index -= count;
-    }
-}
-
-static int lfs_file_relocate(FAR lfs_t *lfs, FAR lfs_file_t *file)
-{
-  lfs_block_t nblock;
-  lfs_off_t i;
-  int err;
-
-relocate:
-  LFS_DEBUG("Bad block at %" PRIu32, file->block);
-
-  /* just relocate what exists into new block */
-
-  err = lfs_alloc(lfs, &nblock);
-  if (err)
-    {
-      return err;
-    }
-
-  err = lfs_bd_erase(lfs, nblock);
-  if (err)
-    {
-      if (err == LFS_ERR_CORRUPT)
-        {
-          goto relocate;
-        }
-
-      return err;
-    }
-
-  /* either read from dirty cache or disk */
-
-  for (i = 0; i < file->off; i++)
-    {
-      uint8_t data;
-      err = lfs_cache_read(lfs, &lfs->rcache, &file->cache, file->block, i,
-                           &data, 1);
-      if (err)
-        {
-          return err;
-        }
-
-      err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, nblock, i,
-                           &data, 1);
-      if (err)
-        {
-          if (err == LFS_ERR_CORRUPT)
-            {
-              goto relocate;
-            }
-
-          return err;
-        }
-    }
-
-  /* copy over new state of file */
-
-  memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size);
-  file->cache.block = lfs->pcache.block;
-  file->cache.off = lfs->pcache.off;
-  lfs_cache_zero(lfs, &lfs->pcache);
-
-  file->block = nblock;
-  return 0;
-}
-
-static int lfs_file_flush(FAR lfs_t *lfs, FAR lfs_file_t *file)
-{
-  if (file->flags & LFS_F_READING)
-    {
-      /* just drop read cache */
-
-      lfs_cache_drop(lfs, &file->cache);
-      file->flags &= ~LFS_F_READING;
-    }
-
-  if (file->flags & LFS_F_WRITING)
-    {
-      lfs_off_t pos = file->pos;
-
-      /* copy over anything after current branch */
-
-      lfs_file_t orig =
-      {
-        .head  = file->head,
-        .size  = file->size,
-        .flags = LFS_O_RDONLY,
-        .pos   = file->pos,
-        .cache = lfs->rcache,
-      };
-
-      lfs_cache_drop(lfs, &lfs->rcache);
-
-      while (file->pos < file->size)
-        {
-          /* copy over a byte at a time, leave it up to caching
-           * to make this efficient
-           */
-
-          uint8_t data;
-          lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1);
-          if (res < 0)
-            {
-              return res;
-            }
-
-          res = lfs_file_write(lfs, file, &data, 1);
-          if (res < 0)
-            {
-              return res;
-            }
-
-          /* keep our reference to the rcache in sync */
-
-          if (lfs->rcache.block != 0xffffffff)
-            {
-              lfs_cache_drop(lfs, &orig.cache);
-              lfs_cache_drop(lfs, &lfs->rcache);
-            }
-        }
-
-      /* Write out what we have */
-
-      while (true)
-        {
-          int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache);
-          if (err)
-            {
-              if (err == LFS_ERR_CORRUPT)
-                {
-                  goto relocate;
-                }
-
-              return err;
-            }
-
-          break;
-
-relocate:
-
-          err = lfs_file_relocate(lfs, file);
-          if (err)
-            {
-              return err;
-            }
-        }
-
-      /* Actual file updates */
-
-      file->head = file->block;
-      file->size = file->pos;
-      file->flags &= ~LFS_F_WRITING;
-      file->flags |= LFS_F_DIRTY;
-
-      file->pos = pos;
-    }
-
-  return 0;
-}
-
-/* Filesystem operations */
-
-static void lfs_deinit(FAR lfs_t *lfs)
-{
-  /* free allocated memory */
-
-  if (!lfs->cfg->read_buffer)
-    {
-      lfs_free(lfs->rcache.buffer);
-    }
-
-  if (!lfs->cfg->prog_buffer)
-    {
-      lfs_free(lfs->pcache.buffer);
-    }
-
-  if (!lfs->cfg->lookahead_buffer)
-    {
-      lfs_free(lfs->free.buffer);
-    }
-}
-
-static int lfs_init(FAR lfs_t *lfs, FAR const struct lfs_config_s *cfg)
-{
-  lfs->cfg = cfg;
-
-  /* setup read cache */
-
-  if (lfs->cfg->read_buffer)
-    {
-      lfs->rcache.buffer = lfs->cfg->read_buffer;
-    }
-  else
-    {
-      lfs->rcache.buffer = lfs_malloc(lfs->cfg->read_size);
-      if (!lfs->rcache.buffer)
-        {
-          goto cleanup;
-        }
-    }
-
-  /* setup program cache */
-
-  if (lfs->cfg->prog_buffer)
-    {
-      lfs->pcache.buffer = lfs->cfg->prog_buffer;
-    }
-  else
-    {
-      lfs->pcache.buffer = lfs_malloc(lfs->cfg->prog_size);
-      if (!lfs->pcache.buffer)
-        {
-          goto cleanup;
-        }
-    }
-
-  /* zero to avoid information leaks */
-
-  lfs_cache_zero(lfs, &lfs->pcache);
-  lfs_cache_drop(lfs, &lfs->rcache);
-
-  /* setup lookahead, round down to nearest 32-bits */
-
-  LFS_ASSERT(lfs->cfg->lookahead % 32 == 0);
-  LFS_ASSERT(lfs->cfg->lookahead > 0);
-  if (lfs->cfg->lookahead_buffer)
-    {
-      lfs->free.buffer = lfs->cfg->lookahead_buffer;
-    }
-  else
-    {
-      lfs->free.buffer = lfs_malloc(lfs->cfg->lookahead / 8);
-      if (!lfs->free.buffer)
-        {
-          goto cleanup;
-        }
-    }
-
-  /* check that program and read sizes are multiples of the block size */
-
-  LFS_ASSERT(lfs->cfg->prog_size % lfs->cfg->read_size == 0);
-  LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->prog_size == 0);
-
-  /* check that the block size is large enough to fit ctz pointers */
-
-  LFS_ASSERT(4 * lfs_npw2(0xffffffff / (lfs->cfg->block_size - 2 * 4)) <=
-             lfs->cfg->block_size);
-
-  /* setup default state */
-
-  lfs->root[0] = 0xffffffff;
-  lfs->root[1] = 0xffffffff;
-  lfs->files = NULL;
-  lfs->dirs = NULL;
-  lfs->deorphaned = false;
-  lfs->moving = false;
-
-  return 0;
-
-cleanup:
-  lfs_deinit(lfs);
-  return LFS_ERR_NOMEM;
-}
-
-static int lfs_pred(FAR lfs_t *lfs, FAR const lfs_block_t dir[2],
-                    FAR lfs_dir_t *pdir)
-{
-  int err;
-
-  if (lfs_pairisnull(lfs->root))
-    {
-      return 0;
-    }
-
-  /* iterate over all directory directory entries */
-
-  err = lfs_dir_fetch(lfs, pdir, (FAR const lfs_block_t[2]){ 0, 1 });
-  if (err)
-    {
-      return err;
-    }
-
-  while (!lfs_pairisnull(pdir->d.tail))
-    {
-      if (lfs_paircmp(pdir->d.tail, dir) == 0)
-        {
-          return true;
-        }
-
-      err = lfs_dir_fetch(lfs, pdir, pdir->d.tail);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  return false;
-}
-
-static int lfs_parent(FAR lfs_t *lfs, FAR const lfs_block_t dir[2],
-                      FAR lfs_dir_t *parent, FAR lfs_entry_t *entry)
-{
-  if (lfs_pairisnull(lfs->root))
-    {
-      return 0;
-    }
-
-  parent->d.tail[0] = 0;
-  parent->d.tail[1] = 1;
-
-  /* iterate over all directory directory entries */
-
-  while (!lfs_pairisnull(parent->d.tail))
-    {
-      int err = lfs_dir_fetch(lfs, parent, parent->d.tail);
-      if (err)
-        {
-          return err;
-        }
-
-      while (true)
-        {
-          err = lfs_dir_next(lfs, parent, entry);
-          if (err && err != LFS_ERR_NOENT)
-            {
-              return err;
-            }
-
-          if (err == LFS_ERR_NOENT)
-            {
-              break;
-            }
-
-          if (((0x70 & entry->d.type) == (0x70 & LFS_TYPE_DIR)) &&
-              lfs_paircmp(entry->d.u.dir, dir) == 0)
-            {
-              return true;
-            }
-        }
-    }
-
-  return false;
-}
-
-static int lfs_moved(FAR lfs_t *lfs, FAR const void *e)
-{
-  lfs_dir_t cwd;
-  lfs_entry_t entry;
-  int err;
-
-  if (lfs_pairisnull(lfs->root))
-    {
-      return 0;
-    }
-
-  /* skip superblock */
-
-  err = lfs_dir_fetch(lfs, &cwd, (const lfs_block_t[2]){ 0, 1 });
-  if (err)
-    {
-      return err;
-    }
-
-  /* iterate over all directory directory entries */
-
-  while (!lfs_pairisnull(cwd.d.tail))
-    {
-      err = lfs_dir_fetch(lfs, &cwd, cwd.d.tail);
-      if (err)
-        {
-          return err;
-        }
-
-      while (true)
-        {
-          err = lfs_dir_next(lfs, &cwd, &entry);
-          if (err && err != LFS_ERR_NOENT)
-            {
-              return err;
-            }
-
-          if (err == LFS_ERR_NOENT)
-            {
-              break;
-            }
-
-          if (!(0x80 & entry.d.type) &&
-              memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0)
-            {
-              return true;
-            }
-        }
-    }
-
-  return false;
-}
-
-static int lfs_relocate(FAR lfs_t *lfs, FAR const lfs_block_t oldpair[2],
-                        FAR const lfs_block_t newpair[2])
-{
-  lfs_dir_t parent;
-  lfs_entry_t entry;
-  int res;
-
-  /* find parent */
-
-  res = lfs_parent(lfs, oldpair, &parent, &entry);
-  if (res < 0)
-    {
-      return res;
-    }
-
-  if (res)
-    {
-      int err;
-
-      /* update disk, this creates a desync */
-
-      entry.d.u.dir[0] = newpair[0];
-      entry.d.u.dir[1] = newpair[1];
-
-      err = lfs_dir_update(lfs, &parent, &entry, NULL);
-      if (err)
-        {
-          return err;
-        }
-
-      /* update internal root */
-
-      if (lfs_paircmp(oldpair, lfs->root) == 0)
-        {
-          LFS_DEBUG("Relocating root %" PRIu32 " %" PRIu32, newpair[0],
-                    newpair[1]);
-          lfs->root[0] = newpair[0];
-          lfs->root[1] = newpair[1];
-        }
-
-      /* clean up bad block, which should now be a desync */
-
-      return lfs_deorphan(lfs);
-    }
-
-  /* find pred */
-
-  res = lfs_pred(lfs, oldpair, &parent);
-  if (res < 0)
-    {
-      return res;
-    }
-
-  if (res)
-    {
-      /* just replace bad pair, no desync can occur */
-
-      parent.d.tail[0] = newpair[0];
-      parent.d.tail[1] = newpair[1];
-
-      return lfs_dir_commit(lfs, &parent, NULL, 0);
-    }
-
-  /* couldn't find dir, must be new */
-
-  return 0;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/* Top level directory operations */
-
-int lfs_mkdir(FAR lfs_t *lfs, FAR const char *path)
-{
-  lfs_dir_t cwd;
-  lfs_dir_t dir;
-  lfs_entry_t entry;
-  int err;
-
-  /* deorphan if we haven't yet, needed at most once after poweron */
-
-  if (!lfs->deorphaned)
-    {
-      err = lfs_deorphan(lfs);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  /* fetch parent directory */
-
-  err = lfs_dir_find(lfs, &cwd, &entry, &path);
-  if (err != LFS_ERR_NOENT || strchr(path, '/') != NULL)
-    {
-      return err ? err : LFS_ERR_EXIST;
-    }
-
-  /* build up new directory */
-
-  lfs_alloc_ack(lfs);
-
-  err = lfs_dir_alloc(lfs, &dir);
-  if (err)
-    {
-      return err;
-    }
-
-  dir.d.tail[0] = cwd.d.tail[0];
-  dir.d.tail[1] = cwd.d.tail[1];
-
-  err = lfs_dir_commit(lfs, &dir, NULL, 0);
-  if (err)
-    {
-      return err;
-    }
-
-  entry.d.type = LFS_TYPE_DIR;
-  entry.d.elen = sizeof(entry.d) - 4;
-  entry.d.alen = 0;
-  entry.d.nlen = strlen(path);
-  entry.d.u.dir[0] = dir.pair[0];
-  entry.d.u.dir[1] = dir.pair[1];
-
-  cwd.d.tail[0] = dir.pair[0];
-  cwd.d.tail[1] = dir.pair[1];
-
-  err = lfs_dir_append(lfs, &cwd, &entry, path);
-  if (err)
-    {
-      return err;
-    }
-
-  lfs_alloc_ack(lfs);
-  return 0;
-}
-
-int lfs_dir_open(FAR lfs_t *lfs, FAR lfs_dir_t *dir, FAR const char *path)
-{
-  lfs_entry_t entry;
-  int err;
-
-  dir->pair[0] = lfs->root[0];
-  dir->pair[1] = lfs->root[1];
-
-  err = lfs_dir_find(lfs, dir, &entry, &path);
-  if (err)
-    {
-      return err;
-    }
-  else if (entry.d.type != LFS_TYPE_DIR)
-    {
-      return LFS_ERR_NOTDIR;
-    }
-
-  err = lfs_dir_fetch(lfs, dir, entry.d.u.dir);
-  if (err)
-    {
-      return err;
-    }
-
-  /* setup head dir
-   * special offset for '.' and '..'
-   */
-
-  dir->head[0] = dir->pair[0];
-  dir->head[1] = dir->pair[1];
-  dir->pos = sizeof(dir->d) - 2;
-  dir->off = sizeof(dir->d);
-
-  /* add to list of directories */
-
-  dir->next = lfs->dirs;
-  lfs->dirs = dir;
-
-  return 0;
-}
-
-int lfs_dir_close(FAR lfs_t *lfs, FAR lfs_dir_t *dir)
-{
-  FAR lfs_dir_t **p;
-
-  /* remove from list of directories */
-
-  for (p = &lfs->dirs; *p; p = &(*p)->next)
-    {
-      if (*p == dir)
-        {
-          *p = dir->next;
-          break;
-        }
-    }
-
-  return 0;
-}
-
-int lfs_dir_read(FAR lfs_t *lfs, FAR lfs_dir_t *dir,
-                 FAR struct lfs_info_s *info)
-{
-  lfs_entry_t entry;
-
-  memset(info, 0, sizeof(*info));
-
-  /* special offset for '.' and '..' */
-
-  if (dir->pos == sizeof(dir->d) - 2)
-    {
-      info->type = LFS_TYPE_DIR;
-      strcpy(info->name, ".");
-      dir->pos += 1;
-      return 1;
-    }
-  else if (dir->pos == sizeof(dir->d) - 1)
-    {
-      info->type = LFS_TYPE_DIR;
-      strcpy(info->name, "..");
-      dir->pos += 1;
-      return 1;
-    }
-
-  while (true)
-    {
-      int err = lfs_dir_next(lfs, dir, &entry);
-      if (err)
-        {
-          return (err == LFS_ERR_NOENT) ? 0 : err;
-        }
-
-      if ((0x7f & entry.d.type) != LFS_TYPE_REG &&
-          (0x7f & entry.d.type) != LFS_TYPE_DIR)
-        {
-          continue;
-        }
-
-      /* check that entry has not been moved */
-
-      if (entry.d.type & 0x80)
-        {
-          int moved = lfs_moved(lfs, &entry.d.u);
-          if (moved < 0)
-            {
-              return moved;
-            }
-
-          if (moved)
-            {
-              continue;
-            }
-
-          entry.d.type &= ~0x80;
-        }
-
-      break;
-    }
-
-  info->type = entry.d.type;
-  if (info->type == LFS_TYPE_REG)
-    {
-      info->size = entry.d.u.file.size;
-    }
-
-  int err = lfs_bd_read(lfs, dir->pair[0],
-                        entry.off + 4 + entry.d.elen + entry.d.alen,
-                        info->name, entry.d.nlen);
-  if (err)
-    {
-      return err;
-    }
-
-  return 1;
-}
-
-int lfs_dir_seek(FAR lfs_t *lfs, FAR lfs_dir_t *dir, lfs_off_t off)
-{
-  int err;
-
-  /* simply walk from head dir */
-
-  err = lfs_dir_rewind(lfs, dir);
-  if (err)
-    {
-      return err;
-    }
-
-  dir->pos = off;
-
-  while (off > (0x7fffffff & dir->d.size))
-    {
-      off -= 0x7fffffff & dir->d.size;
-      if (!(0x80000000 & dir->d.size))
-        {
-          return LFS_ERR_INVAL;
-        }
-
-      err = lfs_dir_fetch(lfs, dir, dir->d.tail);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  dir->off = off;
-  return 0;
-}
-
-lfs_soff_t lfs_dir_tell(FAR lfs_t *lfs, FAR lfs_dir_t *dir)
-{
-  return dir->pos;
-}
-
-int lfs_dir_rewind(FAR lfs_t *lfs, FAR lfs_dir_t *dir)
-{
-  int err;
-
-  /* reload the head dir */
-
-  err = lfs_dir_fetch(lfs, dir, dir->head);
-  if (err)
-    {
-      return err;
-    }
-
-  dir->pair[0] = dir->head[0];
-  dir->pair[1] = dir->head[1];
-  dir->pos = sizeof(dir->d) - 2;
-  dir->off = sizeof(dir->d);
-  return 0;
-}
-
-/* Top level file operations */
-
-int lfs_file_opencfg(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                     FAR const char *path, int flags,
-                     FAR const struct lfs_file_config_s *cfg)
-{
-  lfs_dir_t cwd;
-  lfs_entry_t entry;
-  int err;
-
-  /* deorphan if we haven't yet, needed at most once after poweron */
-
-  if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned)
-    {
-      err = lfs_deorphan(lfs);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  /* allocate entry for file if it doesn't exist */
-
-  err = lfs_dir_find(lfs, &cwd, &entry, &path);
-  if (err && (err != LFS_ERR_NOENT || strchr(path, '/') != NULL))
-    {
-      return err;
-    }
-
-  if (err == LFS_ERR_NOENT)
-    {
-      if (!(flags & LFS_O_CREAT))
-        {
-          return LFS_ERR_NOENT;
-        }
-
-      /* create entry to remember name */
-
-      entry.d.type = LFS_TYPE_REG;
-      entry.d.elen = sizeof(entry.d) - 4;
-      entry.d.alen = 0;
-      entry.d.nlen = strlen(path);
-      entry.d.u.file.head = 0xffffffff;
-      entry.d.u.file.size = 0;
-      err = lfs_dir_append(lfs, &cwd, &entry, path);
-      if (err)
-        {
-          return err;
-        }
-    }
-  else if (entry.d.type == LFS_TYPE_DIR)
-    {
-      return LFS_ERR_ISDIR;
-    }
-  else if (flags & LFS_O_EXCL)
-    {
-      return LFS_ERR_EXIST;
-    }
-
-  /* setup file struct */
-
-  file->cfg = cfg;
-  file->pair[0] = cwd.pair[0];
-  file->pair[1] = cwd.pair[1];
-  file->poff = entry.off;
-  file->head = entry.d.u.file.head;
-  file->size = entry.d.u.file.size;
-  file->flags = flags;
-  file->pos = 0;
-
-  if (flags & LFS_O_TRUNC)
-    {
-      if (file->size != 0)
-        {
-          file->flags |= LFS_F_DIRTY;
-        }
-
-      file->head = 0xffffffff;
-      file->size = 0;
-    }
-
-  /* allocate buffer if needed */
-
-  file->cache.block = 0xffffffff;
-  if (file->cfg && file->cfg->buffer)
-    {
-      file->cache.buffer = file->cfg->buffer;
-    }
-  else if (lfs->cfg->file_buffer)
-    {
-      if (lfs->files)
-        {
-          /* already in use */
-
-          return LFS_ERR_NOMEM;
-        }
-
-      file->cache.buffer = lfs->cfg->file_buffer;
-    }
-  else if ((file->flags & 3) == LFS_O_RDONLY)
-    {
-      file->cache.buffer = lfs_malloc(lfs->cfg->read_size);
-      if (!file->cache.buffer)
-        {
-          return LFS_ERR_NOMEM;
-        }
-    }
-  else
-    {
-      file->cache.buffer = lfs_malloc(lfs->cfg->prog_size);
-      if (!file->cache.buffer)
-        {
-          return LFS_ERR_NOMEM;
-        }
-    }
-
-  /* zero to avoid information leak */
-
-  lfs_cache_drop(lfs, &file->cache);
-  if ((file->flags & 3) != LFS_O_RDONLY)
-    {
-      lfs_cache_zero(lfs, &file->cache);
-    }
-
-  /* add to list of files */
-
-  file->next = lfs->files;
-  lfs->files = file;
-
-  return 0;
-}
-
-int lfs_file_open(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                  FAR const char *path, int flags)
-{
-  return lfs_file_opencfg(lfs, file, path, flags, NULL);
-}
-
-int lfs_file_close(FAR lfs_t *lfs, FAR lfs_file_t *file)
-{
-  FAR lfs_file_t **p;
-  int err;
-
-  err = lfs_file_sync(lfs, file);
-
-  /* remove from list of files */
-
-  for (p = &lfs->files; *p; p = &(*p)->next)
-    {
-      if (*p == file)
-        {
-          *p = file->next;
-          break;
-        }
-    }
-
-  /* clean up memory */
-
-  if (!(file->cfg && file->cfg->buffer) && !lfs->cfg->file_buffer)
-    {
-      lfs_free(file->cache.buffer);
-    }
-
-  return err;
-}
-
-int lfs_file_sync(FAR lfs_t *lfs, FAR lfs_file_t *file)
-{
-  int err = lfs_file_flush(lfs, file);
-  if (err)
-    {
-      return err;
-    }
-
-  if ((file->flags & LFS_F_DIRTY) && !(file->flags & LFS_F_ERRED) &&
-      !lfs_pairisnull(file->pair))
-    {
-      lfs_dir_t cwd;
-      lfs_entry_t entry =
-      {
-        .off = file->poff
-      };
-
-      /* update dir entry */
-
-      err = lfs_dir_fetch(lfs, &cwd, file->pair);
-      if (err)
-        {
-          return err;
-        }
-
-      err = lfs_bd_read(lfs, cwd.pair[0], entry.off, &entry.d,
-                        sizeof(entry.d));
-      lfs_entry_fromle32(&entry.d);
-      if (err)
-        {
-          return err;
-        }
-
-      LFS_ASSERT(entry.d.type == LFS_TYPE_REG);
-      entry.d.u.file.head = file->head;
-      entry.d.u.file.size = file->size;
-
-      err = lfs_dir_update(lfs, &cwd, &entry, NULL);
-      if (err)
-        {
-          return err;
-        }
-
-      file->flags &= ~LFS_F_DIRTY;
-    }
-
-  return 0;
-}
-
-lfs_ssize_t lfs_file_read(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                          FAR void *buffer, lfs_size_t size)
-{
-  FAR uint8_t *data = buffer;
-  lfs_size_t nsize = size;
-
-  if ((file->flags & 3) == LFS_O_WRONLY)
-    {
-      return LFS_ERR_BADF;
-    }
-
-  if (file->flags & LFS_F_WRITING)
-    {
-      /* flush out any writes */
-
-      int err = lfs_file_flush(lfs, file);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  if (file->pos >= file->size)
-    {
-      /* eof if past end */
-
-      return 0;
-    }
-
-  size = lfs_min(size, file->size - file->pos);
-  nsize = size;
-
-  while (nsize > 0)
-    {
-      /* check if we need a new block */
-
-      if (!(file->flags & LFS_F_READING) || file->off == lfs->cfg->block_size)
-        {
-          int err =
-              lfs_ctz_find(lfs, &file->cache, NULL, file->head, file->size,
-                           file->pos, &file->block, &file->off);
-          if (err)
-            {
-              return err;
-            }
-
-          file->flags |= LFS_F_READING;
-        }
-
-      /* read as much as we can in current block */
-
-      lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off);
-      int err = lfs_cache_read(lfs, &file->cache, NULL, file->block,
-                               file->off, data, diff);
-      if (err)
-        {
-          return err;
-        }
-
-      file->pos += diff;
-      file->off += diff;
-      data += diff;
-      nsize -= diff;
-    }
-
-  return size;
-}
-
-lfs_ssize_t lfs_file_write(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                           FAR const void *buffer, lfs_size_t size)
-{
-  FAR const uint8_t *data = buffer;
-  lfs_size_t nsize = size;
-
-  if ((file->flags & 3) == LFS_O_RDONLY)
-    {
-      return LFS_ERR_BADF;
-    }
-
-  if (file->flags & LFS_F_READING)
-    {
-      /* drop any reads */
-
-      int err = lfs_file_flush(lfs, file);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  if ((file->flags & LFS_O_APPEND) && file->pos < file->size)
-    {
-      file->pos = file->size;
-    }
-
-  if (file->pos + size > LFS_FILE_MAX)
-    {
-      /* larger than file limit? */
-
-      return LFS_ERR_FBIG;
-    }
-
-  if (!(file->flags & LFS_F_WRITING) && file->pos > file->size)
-    {
-      /* fill with zeros */
-
-      lfs_off_t pos = file->pos;
-      file->pos = file->size;
-
-      while (file->pos < pos)
-        {
-          lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){ 0 }, 1);
-          if (res < 0)
-            {
-              return res;
-            }
-        }
-    }
-
-  while (nsize > 0)
-    {
-      lfs_size_t diff;
-
-      /* check if we need a new block */
-
-      if (!(file->flags & LFS_F_WRITING) || file->off == lfs->cfg->block_size)
-        {
-          int err;
-
-          if (!(file->flags & LFS_F_WRITING) && file->pos > 0)
-            {
-              /* find out which block we're extending from */
-
-              err = lfs_ctz_find(lfs, &file->cache, NULL, file->head,
-                                 file->size, file->pos - 1, &file->block,
-                                 &file->off);
-              if (err)
-                {
-                  file->flags |= LFS_F_ERRED;
-                  return err;
-                }
-
-              /* mark cache as dirty since we may have read data into it */
-
-              lfs_cache_zero(lfs, &file->cache);
-            }
-
-          /* extend file with new blocks */
-
-          lfs_alloc_ack(lfs);
-          err = lfs_ctz_extend(lfs, &lfs->rcache, &file->cache, file->block,
-                               file->pos, &file->block, &file->off);
-          if (err)
-            {
-              file->flags |= LFS_F_ERRED;
-              return err;
-            }
-
-          file->flags |= LFS_F_WRITING;
-        }
-
-      /* program as much as we can in current block */
-
-      diff = lfs_min(nsize, lfs->cfg->block_size - file->off);
-      while (true)
-        {
-          int err = lfs_cache_prog(lfs, &file->cache, &lfs->rcache,
-                                   file->block, file->off, data, diff);
-          if (err)
-            {
-              if (err == LFS_ERR_CORRUPT)
-                {
-                  goto relocate;
-                }
-
-              file->flags |= LFS_F_ERRED;
-              return err;
-            }
-
-          break;
-        relocate:
-          err = lfs_file_relocate(lfs, file);
-          if (err)
-            {
-              file->flags |= LFS_F_ERRED;
-              return err;
-            }
-        }
-
-      file->pos += diff;
-      file->off += diff;
-      data += diff;
-      nsize -= diff;
-
-      lfs_alloc_ack(lfs);
-    }
-
-  file->flags &= ~LFS_F_ERRED;
-  return size;
-}
-
-lfs_soff_t lfs_file_seek(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                         lfs_soff_t off, int whence)
-{
-  lfs_soff_t npos;
-  int err;
-
-  /* write out everything beforehand, may be noop if rdonly */
-
-  err = lfs_file_flush(lfs, file);
-  if (err)
-    {
-      return err;
-    }
-
-  /* find new pos */
-
-  npos = file->pos;
-  if (whence == LFS_SEEK_SET)
-    {
-      npos = off;
-    }
-  else if (whence == LFS_SEEK_CUR)
-    {
-      npos = file->pos + off;
-    }
-  else if (whence == LFS_SEEK_END)
-    {
-      npos = file->size + off;
-    }
-
-  if (npos < 0 || npos > LFS_FILE_MAX)
-    {
-      /* file position out of range */
-
-      return LFS_ERR_INVAL;
-    }
-
-  /* update pos */
-
-  file->pos = npos;
-  return npos;
-}
-
-int lfs_file_truncate(FAR lfs_t *lfs, FAR lfs_file_t *file, lfs_off_t size)
-{
-  lfs_off_t oldsize;
-
-  if ((file->flags & 3) == LFS_O_RDONLY)
-    {
-      return LFS_ERR_BADF;
-    }
-
-  oldsize = lfs_file_size(lfs, file);
-  if (size < oldsize)
-    {
-      /* need to flush since directly changing metadata */
-
-      int err = lfs_file_flush(lfs, file);
-      if (err)
-        {
-          return err;
-        }
-
-      /* lookup new head in ctz skip list */
-
-      err = lfs_ctz_find(lfs, &file->cache, NULL, file->head, file->size,
-                         size, &file->head, &(lfs_off_t){ 0 });
-      if (err)
-        {
-          return err;
-        }
-
-      file->size = size;
-      file->flags |= LFS_F_DIRTY;
-    }
-  else if (size > oldsize)
-    {
-      int err;
-
-      lfs_off_t pos = file->pos;
-
-      /* flush+seek if not already at end */
-
-      if (file->pos != oldsize)
-        {
-          err = lfs_file_seek(lfs, file, 0, LFS_SEEK_END);
-          if (err < 0)
-            {
-              return err;
-            }
-        }
-
-      /* fill with zeros */
-
-      while (file->pos < size)
-        {
-          lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){ 0 }, 1);
-          if (res < 0)
-            {
-              return res;
-            }
-        }
-
-      /* restore pos */
-
-      err = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET);
-      if (err < 0)
-        {
-          return err;
-        }
-    }
-
-  return 0;
-}
-
-lfs_soff_t lfs_file_tell(FAR lfs_t *lfs, FAR lfs_file_t *file)
-{
-  return file->pos;
-}
-
-int lfs_file_rewind(FAR lfs_t *lfs, FAR lfs_file_t *file)
-{
-  lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_SET);
-  if (res < 0)
-    {
-      return res;
-    }
-
-  return 0;
-}
-
-lfs_soff_t lfs_file_size(FAR lfs_t *lfs, FAR lfs_file_t *file)
-{
-  if (file->flags & LFS_F_WRITING)
-    {
-      return lfs_max(file->pos, file->size);
-    }
-  else
-    {
-      return file->size;
-    }
-}
-
-/* General fs operations */
-
-int lfs_stat(FAR lfs_t *lfs, FAR const char *path,
-             FAR struct lfs_info_s *info)
-{
-  lfs_dir_t cwd;
-  lfs_entry_t entry;
-  int err = lfs_dir_find(lfs, &cwd, &entry, &path);
-  if (err)
-    {
-      return err;
-    }
-
-  memset(info, 0, sizeof(*info));
-  info->type = entry.d.type;
-  if (info->type == LFS_TYPE_REG)
-    {
-      info->size = entry.d.u.file.size;
-    }
-
-  if (lfs_paircmp(entry.d.u.dir, lfs->root) == 0)
-    {
-      strcpy(info->name, "/");
-    }
-  else
-    {
-      err = lfs_bd_read(lfs, cwd.pair[0],
-                        entry.off + 4 + entry.d.elen + entry.d.alen,
-                        info->name, entry.d.nlen);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  return 0;
-}
-
-int lfs_remove(FAR lfs_t *lfs, FAR const char *path)
-{
-  lfs_dir_t cwd;
-  lfs_entry_t entry;
-  int err;
-
-  /* deorphan if we haven't yet, needed at most once after poweron */
-
-  if (!lfs->deorphaned)
-    {
-      err = lfs_deorphan(lfs);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  err = lfs_dir_find(lfs, &cwd, &entry, &path);
-  if (err)
-    {
-      return err;
-    }
-
-  lfs_dir_t dir;
-  if (entry.d.type == LFS_TYPE_DIR)
-    {
-      /* must be empty before removal, checking size
-       * without masking top bit checks for any case where
-       * dir is not empty
-       */
-
-      err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir);
-      if (err)
-        {
-          return err;
-        }
-      else if (dir.d.size != sizeof(dir.d) + 4)
-        {
-          return LFS_ERR_NOTEMPTY;
-        }
-    }
-
-  /* remove the entry */
-
-  err = lfs_dir_remove(lfs, &cwd, &entry);
-  if (err)
-    {
-      return err;
-    }
-
-  /* if we were a directory, find pred, replace tail */
-
-  if (entry.d.type == LFS_TYPE_DIR)
-    {
-      int res = lfs_pred(lfs, dir.pair, &cwd);
-      if (res < 0)
-        {
-          return res;
-        }
-
-      LFS_ASSERT(res); /* must have pred */
-
-      cwd.d.tail[0] = dir.d.tail[0];
-      cwd.d.tail[1] = dir.d.tail[1];
-
-      err = lfs_dir_commit(lfs, &cwd, NULL, 0);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  return 0;
-}
-
-int lfs_rename(FAR lfs_t *lfs, FAR const char *oldpath,
-               FAR const char *newpath)
-{
-  lfs_dir_t oldcwd;
-  lfs_dir_t newcwd;
-  lfs_dir_t dir;
-  lfs_entry_t oldentry;
-  lfs_entry_t preventry;
-  lfs_entry_t newentry;
-  bool prevexists;
-  int err;
-
-  /* deorphan if we haven't yet, needed at most once after poweron */
-
-  if (!lfs->deorphaned)
-    {
-      err = lfs_deorphan(lfs);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  /* find old entry */
-
-  err = lfs_dir_find(lfs, &oldcwd, &oldentry,
-                     &(FAR const char *){ oldpath });
-  if (err)
-    {
-      return err;
-    }
-
-  /* mark as moving */
-
-  oldentry.d.type |= 0x80;
-  err = lfs_dir_update(lfs, &oldcwd, &oldentry, NULL);
-  if (err)
-    {
-      return err;
-    }
-
-  /* allocate new entry */
-
-  err = lfs_dir_find(lfs, &newcwd, &preventry, &newpath);
-  if (err && (err != LFS_ERR_NOENT || strchr(newpath, '/') != NULL))
-    {
-      return err;
-    }
-
-  /* must have same type */
-
-  prevexists = (err != LFS_ERR_NOENT);
-  if (prevexists && preventry.d.type != (0x7f & oldentry.d.type))
-    {
-      return LFS_ERR_ISDIR;
-    }
-
-  if (prevexists && preventry.d.type == LFS_TYPE_DIR)
-    {
-      /* must be empty before removal, checking size
-       * without masking top bit checks for any case where
-       * dir is not empty
-       */
-
-      err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir);
-      if (err)
-        {
-          return err;
-        }
-      else if (dir.d.size != sizeof(dir.d) + 4)
-        {
-          return LFS_ERR_NOTEMPTY;
-        }
-    }
-
-  /* move to new location */
-
-  newentry = preventry;
-  newentry.d = oldentry.d;
-  newentry.d.type &= ~0x80;
-  newentry.d.nlen = strlen(newpath);
-
-  if (prevexists)
-    {
-      err = lfs_dir_update(lfs, &newcwd, &newentry, newpath);
-      if (err)
-        {
-          return err;
-        }
-    }
-  else
-    {
-      err = lfs_dir_append(lfs, &newcwd, &newentry, newpath);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  /* fetch old pair again in case dir block changed */
-
-  lfs->moving = true;
-  err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath);
-  if (err)
-    {
-      return err;
-    }
-
-  lfs->moving = false;
-
-  /* remove old entry */
-
-  err = lfs_dir_remove(lfs, &oldcwd, &oldentry);
-  if (err)
-    {
-      return err;
-    }
-
-  /* if we were a directory, find pred, replace tail */
-
-  if (prevexists && preventry.d.type == LFS_TYPE_DIR)
-    {
-      int res = lfs_pred(lfs, dir.pair, &newcwd);
-      if (res < 0)
-        {
-          return res;
-        }
-
-      LFS_ASSERT(res); /* must have pred */
-
-      newcwd.d.tail[0] = dir.d.tail[0];
-      newcwd.d.tail[1] = dir.d.tail[1];
-
-      err = lfs_dir_commit(lfs, &newcwd, NULL, 0);
-      if (err)
-        {
-          return err;
-        }
-    }
-
-  return 0;
-}
-
-int lfs_format(FAR lfs_t *lfs, FAR const struct lfs_config_s *cfg)
-{
-  lfs_superblock_t superblock;
-  bool valid;
-  int err = 0;
-
-  if (true)
-    {
-      lfs_dir_t superdir;
-      lfs_dir_t root;
-      int i;
-
-      err = lfs_init(lfs, cfg);
-      if (err)
-        {
-          return err;
-        }
-
-      /* create free lookahead */
-
-      memset(lfs->free.buffer, 0, lfs->cfg->lookahead / 8);
-      lfs->free.off = 0;
-      lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
-      lfs->free.i = 0;
-      lfs_alloc_ack(lfs);
-
-      /* create superblock dir */
-
-      err = lfs_dir_alloc(lfs, &superdir);
-      if (err)
-        {
-          goto cleanup;
-        }
-
-      /* write root directory */
-
-      err = lfs_dir_alloc(lfs, &root);
-      if (err)
-        {
-          goto cleanup;
-        }
-
-      err = lfs_dir_commit(lfs, &root, NULL, 0);
-      if (err)
-        {
-          goto cleanup;
-        }
-
-      lfs->root[0] = root.pair[0];
-      lfs->root[1] = root.pair[1];
-
-      /* write superblocks */
-
-      superblock.off           = sizeof(superdir.d);
-      superblock.d.type        = LFS_TYPE_SUPERBLOCK;
-      superblock.d.elen        = sizeof(superblock.d) -
-                                 sizeof(superblock.d.magic) - 4;
-      superblock.d.nlen        = sizeof(superblock.d.magic);
-      superblock.d.version     = LFS_DISK_VERSION;
-      superblock.d.block_size  = lfs->cfg->block_size;
-      superblock.d.block_count = lfs->cfg->block_count;
-      superblock.d.root[0]     = lfs->root[0];
-      superblock.d.root[1]     = lfs->root[1];
-
-      memcpy(superblock.d.magic, "littlefs", 8);
-
-      superdir.d.tail[0]       = root.pair[0];
-      superdir.d.tail[1]       = root.pair[1];
-      superdir.d.size          = sizeof(superdir.d) +
-                                 sizeof(superblock.d) + 4;
-
-      /* write both pairs to be safe */
-
-      lfs_superblock_tole32(&superblock.d);
-      valid = false;
-      for (i = 0; i < 2; i++)
-        {
-          err = lfs_dir_commit(
-              lfs, &superdir,
-              (struct lfs_region_s[])
-              {
-                {
-                  sizeof(superdir.d), sizeof(superblock.d),
-                  &superblock.d, sizeof(superblock.d)
-                }
-              },
-              1);
-
-          if (err && err != LFS_ERR_CORRUPT)
-            {
-              goto cleanup;
-            }
-
-          valid = valid || !err;
-        }
-
-      if (!valid)
-        {
-          err = LFS_ERR_CORRUPT;
-          goto cleanup;
-        }
-
-      /* sanity check that fetch works */
-
-      err = lfs_dir_fetch(lfs, &superdir,
-                         (FAR const lfs_block_t[2]){0, 1});
-      if (err)
-        {
-          goto cleanup;
-        }
-
-      lfs_alloc_ack(lfs);
-    }
-
-cleanup:
-  lfs_deinit(lfs);
-  return err;
-}
-
-int lfs_mount(FAR lfs_t *lfs, FAR const struct lfs_config_s *cfg)
-{
-  int err = 0;
-  if (true)
-    {
-      lfs_dir_t dir;
-      lfs_superblock_t superblock;
-      uint16_t major_version;
-      uint16_t minor_version;
-
-      err = lfs_init(lfs, cfg);
-      if (err)
-        {
-          return err;
-        }
-
-      /* setup free lookahead */
-
-      lfs->free.off = 0;
-      lfs->free.size = 0;
-      lfs->free.i = 0;
-      lfs_alloc_ack(lfs);
-
-      /* load superblock */
-
-      err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){ 0, 1 });
-      if (err && err != LFS_ERR_CORRUPT)
-        {
-          goto cleanup;
-        }
-
-      if (!err)
-        {
-          err = lfs_bd_read(lfs, dir.pair[0], sizeof(dir.d), &superblock.d,
-                            sizeof(superblock.d));
-          lfs_superblock_fromle32(&superblock.d);
-          if (err)
-            {
-              goto cleanup;
-            }
-
-          lfs->root[0] = superblock.d.root[0];
-          lfs->root[1] = superblock.d.root[1];
-        }
-
-      if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0)
-        {
-          LFS_ERROR("Invalid superblock at %d %d", 0, 1);
-          err = LFS_ERR_CORRUPT;
-          goto cleanup;
-        }
-
-      major_version = (0xffff & (superblock.d.version >> 16));
-      minor_version = (0xffff & (superblock.d.version >> 0));
-      if ((major_version != LFS_DISK_VERSION_MAJOR ||
-           minor_version > LFS_DISK_VERSION_MINOR))
-        {
-          LFS_ERROR("Invalid version %d.%d", major_version, minor_version);
-          err = LFS_ERR_INVAL;
-          goto cleanup;
-        }
-
-      return 0;
-    }
-
-cleanup:
-
-  lfs_deinit(lfs);
-  return err;
-}
-
-int lfs_unmount(FAR lfs_t *lfs)
-{
-  lfs_deinit(lfs);
-  return 0;
-}
-
-/* Littlefs specific operations */
-
-int lfs_traverse(FAR lfs_t *lfs, CODE int (*cb)(void *, lfs_block_t),
-                 FAR void *data)
-{
-  lfs_dir_t dir;
-  lfs_entry_t entry;
-  lfs_block_t cwd[2] =
-  {
-    0, 1
-  };
-
-  FAR lfs_file_t *f;
-
-  if (lfs_pairisnull(lfs->root))
-    {
-      return 0;
-    }
-
-  /* iterate over metadata pairs */
-
-  while (true)
-    {
-      int err;
-      int i;
-
-      for (i = 0; i < 2; i++)
-        {
-          err = cb(data, cwd[i]);
-          if (err)
-            {
-              return err;
-            }
-        }
-
-      err = lfs_dir_fetch(lfs, &dir, cwd);
-      if (err)
-        {
-          return err;
-        }
-
-      /* iterate over contents */
-
-      while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size) - 4)
-        {
-          err = lfs_bd_read(lfs, dir.pair[0], dir.off, &entry.d,
-                            sizeof(entry.d));
-          lfs_entry_fromle32(&entry.d);
-          if (err)
-            {
-              return err;
-            }
-
-          dir.off += lfs_entry_size(&entry);
-          if ((0x70 & entry.d.type) == (0x70 & LFS_TYPE_REG))
-            {
-              err = lfs_ctz_traverse(lfs, &lfs->rcache, NULL,
-                                     entry.d.u.file.head,
-                                     entry.d.u.file.size, cb, data);
-              if (err)
-                {
-                  return err;
-                }
-            }
-        }
-
-      cwd[0] = dir.d.tail[0];
-      cwd[1] = dir.d.tail[1];
-
-      if (lfs_pairisnull(cwd))
-        {
-          break;
-        }
-    }
-
-  /* iterate over any open files */
-
-  for (f = lfs->files; f; f = f->next)
-    {
-      if (f->flags & LFS_F_DIRTY)
-        {
-          int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache, f->head,
-                                     f->size, cb, data);
-          if (err)
-            {
-              return err;
-            }
-        }
-
-      if (f->flags & LFS_F_WRITING)
-        {
-          int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache, f->block,
-                                     f->pos, cb, data);
-          if (err)
-            {
-              return err;
-            }
-        }
-    }
-
-  return 0;
-}
-
-int lfs_deorphan(FAR lfs_t *lfs)
-{
-  lfs_dir_t pdir =
-  {
-    .d.size = 0x80000000
-  };
-
-  lfs_dir_t cwd =
-  {
-    .d.tail[0] = 0,
-    .d.tail[1] = 1
-  };
-
-  lfs_size_t i;
-  int err;
-
-  lfs->deorphaned = true;
-
-  if (lfs_pairisnull(lfs->root))
-    {
-      return 0;
-    }
-
-  /* iterate over all directory directory entries */
-
-  for (i = 0; i < lfs->cfg->block_count; i++)
-    {
-      lfs_entry_t entry;
-
-      if (lfs_pairisnull(cwd.d.tail))
-        {
-          return 0;
-        }
-
-      err = lfs_dir_fetch(lfs, &cwd, cwd.d.tail);
-      if (err)
-        {
-          return err;
-        }
-
-      /* check head blocks for orphans */
-
-      if (!(0x80000000 & pdir.d.size))
-        {
-          lfs_dir_t parent;
-          int res;
-
-          /* check if we have a parent */
-
-          res = lfs_parent(lfs, pdir.d.tail, &parent, &entry);
-          if (res < 0)
-            {
-              return res;
-            }
-
-          if (!res)
-            {
-              /* we are an orphan */
-
-              LFS_DEBUG("Found orphan %" PRIu32 " %" PRIu32, pdir.d.tail[0],
-                        pdir.d.tail[1]);
-
-              pdir.d.tail[0] = cwd.d.tail[0];
-              pdir.d.tail[1] = cwd.d.tail[1];
-
-              err = lfs_dir_commit(lfs, &pdir, NULL, 0);
-              if (err)
-                {
-                  return err;
-                }
-
-              return 0;
-            }
-
-          if (!lfs_pairsync(entry.d.u.dir, pdir.d.tail))
-            {
-              /* we have desynced */
-
-              LFS_DEBUG("Found desync %" PRIu32 " %" PRIu32, entry.d.u.dir[0],
-                        entry.d.u.dir[1]);
-
-              pdir.d.tail[0] = entry.d.u.dir[0];
-              pdir.d.tail[1] = entry.d.u.dir[1];
-
-              err = lfs_dir_commit(lfs, &pdir, NULL, 0);
-              if (err)
-                {
-                  return err;
-                }
-
-              return 0;
-            }
-        }
-
-      /* check entries for moves */
-
-      while (true)
-        {
-          err = lfs_dir_next(lfs, &cwd, &entry);
-          if (err && err != LFS_ERR_NOENT)
-            {
-              return err;
-            }
-
-          if (err == LFS_ERR_NOENT)
-            {
-              break;
-            }
-
-          /* found moved entry */
-
-          if (entry.d.type & 0x80)
-            {
-              int moved = lfs_moved(lfs, &entry.d.u);
-              if (moved < 0)
-                {
-                  return moved;
-                }
-
-              if (moved)
-                {
-                  LFS_DEBUG("Found move %" PRIu32 " %" PRIu32,
-                            entry.d.u.dir[0], entry.d.u.dir[1]);
-
-                  err = lfs_dir_remove(lfs, &cwd, &entry);
-                  if (err)
-                    {
-                      return err;
-                    }
-                }
-              else
-                {
-                  LFS_DEBUG("Found partial move %" PRIu32 " %" PRIu32,
-                            entry.d.u.dir[0], entry.d.u.dir[1]);
-
-                  entry.d.type &= ~0x80;
-                  err = lfs_dir_update(lfs, &cwd, &entry, NULL);
-                  if (err)
-                    {
-                      return err;
-                    }
-                }
-            }
-        }
-
-      memcpy(&pdir, &cwd, sizeof(pdir));
-    }
-
-  /* If we reached here, we have more directory pairs than blocks in the
-   * filesystem... So something must be horribly wrong
-   */
-
-  return LFS_ERR_CORRUPT;
-}
diff --git a/fs/littlefs/lfs.h b/fs/littlefs/lfs.h
deleted file mode 100644
index a597593..0000000
--- a/fs/littlefs/lfs.h
+++ /dev/null
@@ -1,673 +0,0 @@
-/****************************************************************************
- * fs/littlefs/lfs.h
- *
- * This file is a part of NuttX:
- *
- *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
- *
- * Ported by:
- *
- *   Copyright (C) 2019 Pinecone Inc. All rights reserved.
- *   Author: lihaichen <li...@163.com>
- *
- * This port derives from ARM mbed logic which has a compatible 3-clause
- * BSD license:
- *
- *   Copyright (c) 2017, Arm Limited. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the names ARM, NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-#ifndef __FS_LITTLEFS_LFS_H
-#define __FS_LITTLEFS_LFS_H
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <stdint.h>
-#include <stdbool.h>
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/* Version info */
-
-/* Software library version
- * Major (top-nibble), incremented on backwards incompatible changes
- * Minor (bottom-nibble), incremented on feature additions
- */
-
-#define LFS_VERSION 0x00010007
-#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
-#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >>  0))
-
-/* Version of On-disk data structures
- * Major (top-nibble), incremented on backwards incompatible changes
- * Minor (bottom-nibble), incremented on feature additions
- */
-
-#define LFS_DISK_VERSION 0x00010001
-#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16))
-#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >>  0))
-
-/* Max name size in bytes */
-
-#ifndef LFS_NAME_MAX
-#  define LFS_NAME_MAX NAME_MAX
-#endif
-
-/* Max file size in bytes */
-
-#ifndef LFS_FILE_MAX
-#  define LFS_FILE_MAX 2147483647
-#endif
-
-/****************************************************************************
- * Public Types
- ****************************************************************************/
-
-typedef uint32_t lfs_size_t;
-typedef uint32_t lfs_off_t;
-
-typedef int32_t  lfs_ssize_t;
-typedef int32_t  lfs_soff_t;
-
-typedef uint32_t lfs_block_t;
-
-/* Possible error codes, these are negative to allow
- * valid positive return values
- */
-
-enum lfs_error_e
-{
-  LFS_ERR_OK       = 0,    /* No error */
-  LFS_ERR_IO       = -5,   /* Error during device operation */
-  LFS_ERR_CORRUPT  = -52,  /* Corrupted */
-  LFS_ERR_NOENT    = -2,   /* No directory entry */
-  LFS_ERR_EXIST    = -17,  /* Entry already exists */
-  LFS_ERR_NOTDIR   = -20,  /* Entry is not a dir */
-  LFS_ERR_ISDIR    = -21,  /* Entry is a dir */
-  LFS_ERR_NOTEMPTY = -39,  /* Dir is not empty */
-  LFS_ERR_BADF     = -9,   /* Bad file number */
-  LFS_ERR_FBIG     = -27,  /* File too large */
-  LFS_ERR_INVAL    = -22,  /* Invalid parameter */
-  LFS_ERR_NOSPC    = -28,  /* No space left on device */
-  LFS_ERR_NOMEM    = -12,  /* No more memory available */
-};
-
-/* File types */
-
-enum lfs_type_e
-{
-  LFS_TYPE_REG        = 0x11,
-  LFS_TYPE_DIR        = 0x22,
-  LFS_TYPE_SUPERBLOCK = 0x2e,
-};
-
-/* File open flags */
-
-enum lfs_open_flags_e
-{
-  /* open flags */
-
-  LFS_O_RDONLY = 1,        /* Open a file as read only */
-  LFS_O_WRONLY = 2,        /* Open a file as write only */
-  LFS_O_RDWR   = 3,        /* Open a file as read and write */
-  LFS_O_CREAT  = 0x0100,   /* Create a file if it does not exist */
-  LFS_O_EXCL   = 0x0200,   /* Fail if a file already exists */
-  LFS_O_TRUNC  = 0x0400,   /* Truncate the existing file to zero size */
-  LFS_O_APPEND = 0x0800,   /* Move to end of file on every write */
-
-  /* internally used flags */
-
-  LFS_F_DIRTY   = 0x10000, /* File does not match storage */
-  LFS_F_WRITING = 0x20000, /* File has been written since last flush */
-  LFS_F_READING = 0x40000, /* File has been read since last flush */
-  LFS_F_ERRED   = 0x80000, /* An error occurred during write */
-};
-
-/* File seek flags */
-
-enum lfs_whence_flags_e
-{
-  LFS_SEEK_SET = 0,   /* Seek relative to an absolute position */
-  LFS_SEEK_CUR = 1,   /* Seek relative to the current file position */
-  LFS_SEEK_END = 2,   /* Seek relative to the end of the file */
-};
-
-/* Configuration provided during initialization of the littlefs */
-
-struct lfs_config_s
-{
-  /* Opaque user provided context that can be used to pass
-   * information to the block device operations
-   */
-
-  FAR void *context;
-
-  /* Read a region in a block. Negative error codes are propagated
-   * to the user.
-   */
-
-  CODE int (*read)(FAR const struct lfs_config_s *c, lfs_block_t block,
-                   lfs_off_t off, FAR void *buffer, lfs_size_t size);
-
-  /* Program a region in a block. The block must have previously
-   * been erased. Negative error codes are propagated to the user.
-   * May return LFS_ERR_CORRUPT if the block should be considered bad.
-   */
-
-  CODE int (*prog)(FAR const struct lfs_config_s *c, lfs_block_t block,
-                   lfs_off_t off, const void *buffer, lfs_size_t size);
-
-  /* Erase a block. A block must be erased before being programmed.
-   * The state of an erased block is undefined. Negative error codes
-   * are propagated to the user.
-   * May return LFS_ERR_CORRUPT if the block should be considered bad.
-   */
-
-  CODE int (*erase)(FAR const struct lfs_config_s *c, lfs_block_t block);
-
-  /* Sync the state of the underlying block device. Negative error codes
-   * are propagated to the user.
-   */
-
-  CODE int (*sync)(FAR const struct lfs_config_s *c);
-
-  /* Minimum size of a block read. This determines the size of read buffers.
-   * This may be larger than the physical read size to improve performance
-   * by caching more of the block device.
-   */
-
-  lfs_size_t read_size;
-
-  /* Minimum size of a block program. This determines the size of program
-   * buffers. This may be larger than the physical program size to improve
-   * performance by caching more of the block device.
-   * Must be a multiple of the read size.
-   */
-
-  lfs_size_t prog_size;
-
-  /* Size of an erasable block. This does not impact ram consumption and
-   * may be larger than the physical erase size. However, this should be
-   * kept small as each file currently takes up an entire block.
-   * Must be a multiple of the program size.
-   */
-
-  lfs_size_t block_size;
-
-  /* Number of erasable blocks on the device. */
-
-  lfs_size_t block_count;
-
-  /* Number of blocks to lookahead during block allocation. A larger
-   * lookahead reduces the number of passes required to allocate a block.
-   * The lookahead buffer requires only 1 bit per block so it can be quite
-   * large with little ram impact. Should be a multiple of 32.
-   */
-
-  lfs_size_t lookahead;
-
-  /* Optional, statically allocated read buffer. Must be read sized. */
-
-  FAR void *read_buffer;
-
-  /* Optional, statically allocated program buffer. Must be program sized. */
-
-  FAR void *prog_buffer;
-
-  /* Optional, statically allocated lookahead buffer. Must be 1 bit per
-   * lookahead block.
-   */
-
-  FAR void *lookahead_buffer;
-
-  /* Optional, statically allocated buffer for files. Must be program sized.
-   * If enabled, only one file may be opened at a time.
-   */
-
-  FAR void *file_buffer;
-};
-
-/* Optional configuration provided during lfs_file_opencfg */
-
-struct lfs_file_config_s
-{
-  /* Optional, statically allocated buffer for files. Must be program sized.
-   * If NULL, malloc will be used by default.
-   */
-
-  FAR void *buffer;
-};
-
-/* File info structure */
-
-struct lfs_info_s
-{
-  /* Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR */
-
-  uint8_t type;
-
-  /* Size of the file, only valid for REG files */
-
-  lfs_size_t size;
-
-  /* Name of the file stored as a null-terminated string */
-
-  char name[LFS_NAME_MAX + 1];
-};
-
-/* littlefs data structures */
-
-typedef struct lfs_entry_s
-{
-  lfs_off_t off;
-
-  struct lfs_disk_entry_s
-  {
-    uint8_t type;
-    uint8_t elen;
-    uint8_t alen;
-    uint8_t nlen;
-    union
-    {
-      struct
-      {
-        lfs_block_t head;
-        lfs_size_t size;
-      } file;
-      lfs_block_t dir[2];
-    } u;
-  } d;
-} lfs_entry_t;
-
-typedef struct lfs_cache_s
-{
-  lfs_block_t block;
-  lfs_off_t off;
-  FAR uint8_t *buffer;
-} lfs_cache_t;
-
-typedef struct lfs_file_s
-{
-  FAR struct lfs_file_s *next;
-  lfs_block_t pair[2];
-  lfs_off_t poff;
-
-  lfs_block_t head;
-  lfs_size_t size;
-
-  FAR const struct lfs_file_config_s *cfg;
-  uint32_t flags;
-  lfs_off_t pos;
-  lfs_block_t block;
-  lfs_off_t off;
-  lfs_cache_t cache;
-} lfs_file_t;
-
-typedef struct lfs_dir_s
-{
-  FAR struct lfs_dir_s *next;
-  lfs_block_t pair[2];
-  lfs_off_t off;
-
-  lfs_block_t head[2];
-  lfs_off_t pos;
-
-  struct lfs_disk_dir_s
-  {
-    uint32_t rev;
-    lfs_size_t size;
-    lfs_block_t tail[2];
-  } d;
-} lfs_dir_t;
-
-typedef struct lfs_superblock_s
-{
-  lfs_off_t off;
-
-  struct lfs_disk_superblock_s
-  {
-    uint8_t type;
-    uint8_t elen;
-    uint8_t alen;
-    uint8_t nlen;
-    lfs_block_t root[2];
-    uint32_t block_size;
-    uint32_t block_count;
-    uint32_t version;
-    char magic[8];
-  } d;
-} lfs_superblock_t;
-
-typedef struct lfs_free_s
-{
-  lfs_block_t off;
-  lfs_block_t size;
-  lfs_block_t i;
-  lfs_block_t ack;
-  FAR uint32_t *buffer;
-} lfs_free_t;
-
-/* The littlefs type */
-
-typedef struct lfs_s
-{
-  FAR const struct lfs_config_s *cfg;
-
-  lfs_block_t root[2];
-  FAR lfs_file_t *files;
-  lfs_dir_t *dirs;
-
-  lfs_cache_t rcache;
-  lfs_cache_t pcache;
-
-  lfs_free_t free;
-  bool deorphaned;
-  bool moving;
-} lfs_t;
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/****************************************************************************
- * Public Function Prototypes
- ****************************************************************************/
-
-/* Filesystem functions */
-
-/* Format a block device with the littlefs
- *
- * Requires a littlefs object and config struct. This clobbers the littlefs
- * object, and does not leave the filesystem mounted. The config struct must
- * be zeroed for defaults and backwards compatibility.
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_format(FAR lfs_t *lfs, FAR const struct lfs_config_s *config);
-
-/* Mounts a littlefs
- *
- * Requires a littlefs object and config struct. Multiple filesystems
- * may be mounted simultaneously with multiple littlefs objects. Both
- * lfs and config must be allocated while mounted. The config struct must
- * be zeroed for defaults and backwards compatibility.
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_mount(FAR lfs_t *lfs, FAR const struct lfs_config_s *config);
-
-/* Unmounts a littlefs
- *
- * Does nothing besides releasing any allocated resources.
- * Returns a negative error code on failure.
- */
-
-int lfs_unmount(FAR lfs_t *lfs);
-
-/* General operations */
-
-/* Removes a file or directory
- *
- * If removing a directory, the directory must be empty.
- * Returns a negative error code on failure.
- */
-
-int lfs_remove(FAR lfs_t *lfs, FAR const char *path);
-
-/* Rename or move a file or directory
- *
- * If the destination exists, it must match the source in type.
- * If the destination is a directory, the directory must be empty.
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_rename(FAR lfs_t *lfs, FAR const char *oldpath, FAR
-               const char *newpath);
-
-/* Find info about a file or directory
- *
- * Fills out the info structure, based on the specified file or directory.
- * Returns a negative error code on failure.
- */
-
-int lfs_stat(FAR lfs_t *lfs, FAR const char *path,
-             FAR struct lfs_info_s *info);
-
-/* File operations */
-
-/* Open a file
- *
- * The mode that the file is opened in is determined by the flags, which
- * are values from the enum lfs_open_flags that are bitwise-ored together.
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_file_open(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                  FAR const char *path, int flags);
-
-/* Open a file with extra configuration
- *
- * The mode that the file is opened in is determined by the flags, which
- * are values from the enum lfs_open_flags that are bitwise-ored together.
- *
- * The config struct provides additional config options per file as described
- * above. The config struct must be allocated while the file is open, and the
- * config struct must be zeroed for defaults and backwards compatibility.
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_file_opencfg(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                     FAR const char *path, int flags,
-                     FAR const struct lfs_file_config_s *config);
-
-/* Close a file
- *
- * Any pending writes are written out to storage as though
- * sync had been called and releases any allocated resources.
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_file_close(FAR lfs_t *lfs, FAR lfs_file_t *file);
-
-/* Synchronize a file on storage
- *
- * Any pending writes are written out to storage.
- * Returns a negative error code on failure.
- */
-
-int lfs_file_sync(FAR lfs_t *lfs, FAR lfs_file_t *file);
-
-/* Read data from file
- *
- * Takes a buffer and size indicating where to store the read data.
- * Returns the number of bytes read, or a negative error code on failure.
- */
-
-lfs_ssize_t lfs_file_read(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                          FAR void *buffer, lfs_size_t size);
-
-/* Write data to file
- *
- * Takes a buffer and size indicating the data to write. The file will not
- * actually be updated on the storage until either sync or close is called.
- *
- * Returns the number of bytes written, or a negative error code on failure.
- */
-
-lfs_ssize_t lfs_file_write(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                           FAR const void *buffer, lfs_size_t size);
-
-/* Change the position of the file
- *
- * The change in position is determined by the offset and whence flag.
- * Returns the old position of the file, or a negative error code on failure.
- */
-
-lfs_soff_t lfs_file_seek(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                         lfs_soff_t off, int whence);
-
-/* Truncates the size of the file to the specified size
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_file_truncate(FAR lfs_t *lfs, FAR lfs_file_t *file,
-                      lfs_off_t size);
-
-/* Return the position of the file
- *
- * Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
- * Returns the position of the file, or a negative error code on failure.
- */
-
-lfs_soff_t lfs_file_tell(FAR lfs_t *lfs, FAR lfs_file_t *file);
-
-/* Change the position of the file to the beginning of the file
- *
- * Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
- * Returns a negative error code on failure.
- */
-
-int lfs_file_rewind(FAR lfs_t *lfs, FAR lfs_file_t *file);
-
-/* Return the size of the file
- *
- * Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END)
- * Returns the size of the file, or a negative error code on failure.
- */
-
-lfs_soff_t lfs_file_size(FAR lfs_t *lfs, FAR lfs_file_t *file);
-
-/* Directory operations */
-
-/* Create a directory
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_mkdir(FAR lfs_t *lfs, FAR const char *path);
-
-/* Open a directory
- *
- * Once open a directory can be used with read to iterate over files.
- * Returns a negative error code on failure.
- */
-
-int lfs_dir_open(FAR lfs_t *lfs, FAR lfs_dir_t *dir, FAR const char *path);
-
-/* Close a directory
- *
- * Releases any allocated resources.
- * Returns a negative error code on failure.
- */
-
-int lfs_dir_close(FAR lfs_t *lfs, FAR lfs_dir_t *dir);
-
-/* Read an entry in the directory
- *
- * Fills out the info structure, based on the specified file or directory.
- * Returns a negative error code on failure.
- */
-
-int lfs_dir_read(FAR lfs_t *lfs, FAR lfs_dir_t *dir,
-                 FAR struct lfs_info_s *info);
-
-/* Change the position of the directory
- *
- * The new off must be a value previous returned from tell and specifies
- * an absolute offset in the directory seek.
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_dir_seek(FAR lfs_t *lfs, FAR lfs_dir_t *dir, lfs_off_t off);
-
-/* Return the position of the directory
- *
- * The returned offset is only meant to be consumed by seek and may not make
- * sense, but does indicate the current position in the directory iteration.
- *
- * Returns the position of the directory, or a negative error code on failure
- */
-
-lfs_soff_t lfs_dir_tell(FAR lfs_t *lfs, FAR lfs_dir_t *dir);
-
-/* Change the position of the directory to the beginning of the directory
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_dir_rewind(FAR lfs_t *lfs, FAR lfs_dir_t *dir);
-
-/* Miscellaneous littlefs specific operations */
-
-/* Traverse through all blocks in use by the filesystem
- *
- * The provided callback will be called with each block address that is
- * currently in use by the filesystem. This can be used to determine which
- * blocks are in use or how much of the storage is available.
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_traverse(FAR lfs_t *lfs, CODE int (*cb)(FAR void *, lfs_block_t),
-                 FAR void *data);
-
-/* Prunes any recoverable errors that may have occurred in the filesystem
- *
- * Not needed to be called by user unless an operation is interrupted
- * but the filesystem is still mounted. This is already called on first
- * allocation.
- *
- * Returns a negative error code on failure.
- */
-
-int lfs_deorphan(FAR lfs_t *lfs);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __FS_LITTLEFS_LFS_H */
diff --git a/fs/littlefs/lfs_util.c b/fs/littlefs/lfs_util.c
deleted file mode 100644
index b558ff6..0000000
--- a/fs/littlefs/lfs_util.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
- * fs/littlefs/lfs_util.c
- *
- * This file is a part of NuttX:
- *
- *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
- *
- * Ported by:
- *
- *   Copyright (C) 2019 Pinecone Inc. All rights reserved.
- *   Author: lihaichen <li...@163.com>
- *
- * This port derives from ARM mbed logic which has a compatible 3-clause
- * BSD license:
- *
- *   Copyright (c) 2017, Arm Limited. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the names ARM, NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include "lfs.h"
-#include "lfs_util.h"
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/* Only compile if user does not provide custom config */
-
-#ifndef LFS_CONFIG
-
-/* Software CRC implementation with small lookup table */
-
-void lfs_crc(FAR uint32_t *crc, FAR const void *buffer, size_t size)
-{
-  static const uint32_t rtable[16] =
-  {
-    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4,
-    0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
-    0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
-  };
-
-  FAR const uint8_t *data = buffer;
-  size_t i;
-
-  for (i = 0; i < size; i++)
-    {
-      *crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 0)) & 0xf];
-      *crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 4)) & 0xf];
-    }
-}
-
-#endif
diff --git a/fs/littlefs/lfs_util.h b/fs/littlefs/lfs_util.h
deleted file mode 100644
index 46c72be..0000000
--- a/fs/littlefs/lfs_util.h
+++ /dev/null
@@ -1,275 +0,0 @@
-/****************************************************************************
- * fs/littlefs/lfs_util.h
- *
- * This file is a part of NuttX:
- *
- *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
- *
- * Ported by:
- *
- *   Copyright (C) 2019 Pinecone Inc. All rights reserved.
- *   Author: lihaichen <li...@163.com>
- *
- * This port derives from ARM mbed logic which has a compatible 3-clause
- * BSD license:
- *
- *   Copyright (c) 2017, Arm Limited. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the names ARM, NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-#ifndef __FS_LITTLEFS_LFS_UTIL_H
-#define __FS_LITTLEFS_LFS_UTIL_H
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-/* Users can override lfs_util.h with their own configuration by defining
- * LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
- *
- * If LFS_CONFIG is used, none of the default utils will be emitted and must be
- * provided by the config file. To start I would suggest copying lfs_util.h and
- * modifying as needed.
- */
-
-#ifdef LFS_CONFIG
-#  define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
-#  define LFS_STRINGIZE2(x) #x
-#  include LFS_STRINGIZE(LFS_CONFIG)
-#else
-
-/* System includes */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-
-#ifndef LFS_NO_MALLOC
-#  include <nuttx/kmalloc.h>
-#endif
-#ifndef LFS_NO_ASSERT
-#  include <assert.h>
-#endif
-#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR)
-#  include <debug.h>
-#endif
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/* Macros, may be replaced by system specific wrappers. Arguments to these
- * macros must not have side-effects as the macros can be removed for a smaller
- * code footprint
- */
-
-/* Logging functions */
-
-#ifndef LFS_NO_DEBUG
-#  define LFS_DEBUG(fmt, ...) \
-    finfo("lfs debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
-#else
-#  define LFS_DEBUG(fmt, ...)
-#endif
-
-#ifndef LFS_NO_WARN
-#  define LFS_WARN(fmt, ...) \
-    fwarn("lfs warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
-#else
-#  define LFS_WARN(fmt, ...)
-#endif
-
-#ifndef LFS_NO_ERROR
-#  define LFS_ERROR(fmt, ...) \
-    ferr("lfs error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
-#else
-#  define LFS_ERROR(fmt, ...)
-#endif
-
-/* Runtime assertions */
-
-#ifndef LFS_NO_ASSERT
-#  define LFS_ASSERT(test) DEBUGASSERT(test)
-#else
-#  define LFS_ASSERT(test)
-#endif
-
-/****************************************************************************
- * Public Types
- ****************************************************************************/
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/****************************************************************************
- * Inline Functions
- ****************************************************************************/
-
-/* Builtin functions, these may be replaced by more efficient
- * toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
- * expensive basic C implementation for debugging purposes
- */
-
-/* Min/max functions for unsigned 32-bit numbers */
-
-static inline uint32_t lfs_max(uint32_t a, uint32_t b)
-{
-  return (a > b) ? a : b;
-}
-
-static inline uint32_t lfs_min(uint32_t a, uint32_t b)
-{
-  return (a < b) ? a : b;
-}
-
-/* Find the next smallest power of 2 less than or equal to a */
-
-static inline uint32_t lfs_npw2(uint32_t a)
-{
-#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
-  return 32 - __builtin_clz(a - 1);
-#else
-  uint32_t r = 0;
-  uint32_t s;
-  a -= 1;
-  s = (a > 0xffff) << 4;
-  a >>= s;
-  r |= s;
-  s = (a > 0xff) << 3;
-  a >>= s;
-  r |= s;
-  s = (a > 0xf) << 2;
-  a >>= s;
-  r |= s;
-  s = (a > 0x3) << 1;
-  a >>= s;
-  r |= s;
-  return (r | (a >> 1)) + 1;
-#endif
-}
-
-/* Count the number of trailing binary zeros in a
- * lfs_ctz(0) may be undefined
- */
-
-static inline uint32_t lfs_ctz(uint32_t a)
-{
-#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
-  return __builtin_ctz(a);
-#else
-  return lfs_npw2((a & -a) + 1) - 1;
-#endif
-}
-
-/* Count the number of binary ones in a */
-
-static inline uint32_t lfs_popc(uint32_t a)
-{
-#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
-  return __builtin_popcount(a);
-#else
-  a = a - ((a >> 1) & 0x55555555);
-  a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
-  return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
-#endif
-}
-
-/* Find the sequence comparison of a and b, this is the distance
- * between a and b ignoring overflow
- */
-
-static inline int lfs_scmp(uint32_t a, uint32_t b)
-{
-  return (int)(unsigned)(a - b);
-}
-
-/* Convert from 32-bit little-endian to native order */
-
-static inline uint32_t lfs_fromle32(uint32_t a)
-{
-#if !defined(CONFIG_ENDIAN_BIG)
-  return a;
-#elif !defined(LFS_NO_INTRINSICS)
-  return __builtin_bswap32(a);
-#else
-  return (((uint8_t *)&a)[0] << 0) | (((uint8_t *)&a)[1] << 8) |
-         (((uint8_t *)&a)[2] << 16) | (((uint8_t *)&a)[3] << 24);
-#endif
-}
-
-/* Convert to 32-bit little-endian from native order */
-
-static inline uint32_t lfs_tole32(uint32_t a)
-{
-  return lfs_fromle32(a);
-}
-
-/* Allocate memory, only used if buffers are not provided to littlefs */
-
-static inline void *lfs_malloc(size_t size)
-{
-#ifndef LFS_NO_MALLOC
-  return kmm_malloc(size);
-#else
-  return NULL;
-#endif
-}
-
-/* Deallocate memory, only used if buffers are not provided to littlefs */
-
-static inline void lfs_free(FAR void *p)
-{
-#ifndef LFS_NO_MALLOC
-  kmm_free(p);
-#else
-  (void)p;
-#endif
-}
-
-/****************************************************************************
- * Public Function Prototypes
- ****************************************************************************/
-
- /* Calculate CRC-32 with polynomial = 0x04c11db7 */
-
-void lfs_crc(uint32_t *crc, const void *buffer, size_t size);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif
-#endif /* __FS_LITTLEFS_LFS_UTIL_H */
diff --git a/fs/littlefs/lfs_vfs.c b/fs/littlefs/lfs_vfs.c
index eeea1e2..85ff7b4 100644
--- a/fs/littlefs/lfs_vfs.c
+++ b/fs/littlefs/lfs_vfs.c
@@ -1,46 +1,20 @@
 /****************************************************************************
  * fs/littlefs/lfs_vfs.c
  *
- * This file is a part of NuttX:
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
  *
- *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Ported by:
- *
- *   Copyright (C) 2019 Pinecone Inc. All rights reserved.
- *   Author: lihaichen <li...@163.com>
- *
- * This port derives from ARM mbed logic which has a compatible 3-clause
- * BSD license:
- *
- *   Copyright (c) 2017, Arm Limited. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the names ARM, NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
  *
  ****************************************************************************/
 
@@ -56,14 +30,15 @@
 
 #include <nuttx/fs/dirent.h>
 #include <nuttx/fs/fs.h>
+#include <nuttx/kmalloc.h>
 #include <nuttx/mtd/mtd.h>
 #include <nuttx/semaphore.h>
 
 #include <sys/stat.h>
 #include <sys/statfs.h>
 
-#include "lfs.h"
-#include "lfs_util.h"
+#include "littlefs/lfs.h"
+#include "littlefs/lfs_util.h"
 
 /****************************************************************************
  * Private Types
@@ -79,7 +54,7 @@ struct littlefs_mountpt_s
   sem_t                 sem;
   FAR struct inode     *drv;
   struct mtd_geometry_s geo;
-  struct lfs_config_s   cfg;
+  struct lfs_config     cfg;
   lfs_t                 lfs;
 };
 
@@ -249,7 +224,7 @@ static int littlefs_open(FAR struct file *filep, FAR const char *relpath,
                          int oflags, mode_t mode)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_file_s *priv;
+  FAR struct lfs_file *priv;
   FAR struct inode *inode;
   int ret;
 
@@ -327,7 +302,7 @@ errsem:
 static int littlefs_close(FAR struct file *filep)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_file_s *priv;
+  FAR struct lfs_file *priv;
   FAR struct inode *inode;
   int ret;
 
@@ -363,7 +338,7 @@ static ssize_t littlefs_read(FAR struct file *filep, FAR char *buffer,
                              size_t buflen)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_file_s *priv;
+  FAR struct lfs_file *priv;
   FAR struct inode *inode;
   ssize_t ret;
   int semret;
@@ -401,7 +376,7 @@ static ssize_t littlefs_write(FAR struct file *filep, const char *buffer,
                               size_t buflen)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_file_s *priv;
+  FAR struct lfs_file *priv;
   FAR struct inode *inode;
   ssize_t ret;
   int semret;
@@ -438,7 +413,7 @@ static ssize_t littlefs_write(FAR struct file *filep, const char *buffer,
 static off_t littlefs_seek(FAR struct file *filep, off_t offset, int whence)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_file_s *priv;
+  FAR struct lfs_file *priv;
   FAR struct inode *inode;
   off_t ret;
   int semret;
@@ -505,7 +480,7 @@ static int littlefs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
 static int littlefs_sync(FAR struct file *filep)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_file_s *priv;
+  FAR struct lfs_file *priv;
   FAR struct inode *inode;
   int ret;
 
@@ -551,7 +526,7 @@ static int littlefs_dup(FAR const struct file *oldp, FAR struct file *newp)
 static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_file_s *priv;
+  FAR struct lfs_file *priv;
   FAR struct inode *inode;
   int ret;
 
@@ -598,7 +573,7 @@ static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf)
 static int littlefs_truncate(FAR struct file *filep, off_t length)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_file_s *priv;
+  FAR struct lfs_file *priv;
   FAR struct inode *inode;
   int ret;
 
@@ -634,7 +609,7 @@ static int littlefs_opendir(FAR struct inode *mountpt,
                             FAR struct fs_dirent_s *dir)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_dir_s *priv;
+  FAR struct lfs_dir *priv;
   int ret;
 
   /* Recover our private data from the inode instance */
@@ -689,7 +664,7 @@ static int littlefs_closedir(FAR struct inode *mountpt,
                              FAR struct fs_dirent_s *dir)
 {
   struct littlefs_mountpt_s *fs;
-  FAR struct lfs_dir_s *priv;
+  FAR struct lfs_dir *priv;
   int ret;
 
   /* Recover our private data from the inode instance */
@@ -724,8 +699,8 @@ static int littlefs_readdir(FAR struct inode *mountpt,
                             FAR struct fs_dirent_s *dir)
 {
   FAR struct littlefs_mountpt_s *fs;
-  FAR struct lfs_dir_s *priv;
-  struct lfs_info_s info;
+  FAR struct lfs_dir *priv;
+  struct lfs_info info;
   int ret;
 
   /* Recover our private data from the inode instance */
@@ -777,7 +752,7 @@ static int littlefs_rewinddir(FAR struct inode *mountpt,
                               FAR struct fs_dirent_s *dir)
 {
   struct littlefs_mountpt_s *fs;
-  FAR struct lfs_dir_s *priv;
+  FAR struct lfs_dir *priv;
   int ret;
 
   /* Recover our private data from the inode instance */
@@ -815,7 +790,7 @@ static int littlefs_rewinddir(FAR struct inode *mountpt,
  *
  ****************************************************************************/
 
-static int littlefs_read_block(FAR const struct lfs_config_s *c,
+static int littlefs_read_block(FAR const struct lfs_config *c,
                                lfs_block_t block, lfs_off_t off,
                                FAR void *buffer, lfs_size_t size)
 {
@@ -843,7 +818,7 @@ static int littlefs_read_block(FAR const struct lfs_config_s *c,
  * Name: littlefs_write_block
  ****************************************************************************/
 
-static int littlefs_write_block(FAR const struct lfs_config_s *c,
+static int littlefs_write_block(FAR const struct lfs_config *c,
                                 lfs_block_t block, lfs_off_t off,
                                 FAR const void *buffer, lfs_size_t size)
 {
@@ -871,7 +846,7 @@ static int littlefs_write_block(FAR const struct lfs_config_s *c,
  * Name: littlefs_erase_block
  ****************************************************************************/
 
-static int littlefs_erase_block(FAR const struct lfs_config_s *c,
+static int littlefs_erase_block(FAR const struct lfs_config *c,
                                 lfs_block_t block)
 {
   FAR struct littlefs_mountpt_s *fs = c->context;
@@ -894,7 +869,7 @@ static int littlefs_erase_block(FAR const struct lfs_config_s *c,
  * Name: littlefs_sync_block
  ****************************************************************************/
 
-static int littlefs_sync_block(FAR const struct lfs_config_s *c)
+static int littlefs_sync_block(FAR const struct lfs_config *c)
 {
   FAR struct littlefs_mountpt_s *fs = c->context;
   FAR struct inode *drv = fs->drv;
@@ -988,21 +963,19 @@ static int littlefs_bind(FAR struct inode *driver, FAR const void *data,
 
   /* Initialize lfs_config structure */
 
-  fs->cfg.context     = fs;
-  fs->cfg.read        = littlefs_read_block;
-  fs->cfg.prog        = littlefs_write_block;
-  fs->cfg.erase       = littlefs_erase_block;
-  fs->cfg.sync        = littlefs_sync_block;
-  fs->cfg.read_size   = fs->geo.blocksize;
-  fs->cfg.prog_size   = fs->geo.blocksize;
-  fs->cfg.block_size  = fs->geo.erasesize;
-  fs->cfg.block_count = fs->geo.neraseblocks;
-  fs->cfg.lookahead   = 32 * ((fs->cfg.block_count + 31) / 32);
-
-  if (fs->cfg.lookahead > 32 * fs->cfg.read_size)
-    {
-      fs->cfg.lookahead = 32 * fs->cfg.read_size;
-    }
+  fs->cfg.context        = fs;
+  fs->cfg.read           = littlefs_read_block;
+  fs->cfg.prog           = littlefs_write_block;
+  fs->cfg.erase          = littlefs_erase_block;
+  fs->cfg.sync           = littlefs_sync_block;
+  fs->cfg.read_size      = fs->geo.blocksize;
+  fs->cfg.prog_size      = fs->geo.blocksize;
+  fs->cfg.block_size     = fs->geo.erasesize;
+  fs->cfg.block_count    = fs->geo.neraseblocks;
+  fs->cfg.block_cycles   = 500;
+  fs->cfg.cache_size     = fs->geo.blocksize;
+  fs->cfg.lookahead_size = lfs_min(lfs_alignup(fs->cfg.block_count / 8, 8),
+                                   fs->cfg.read_size);
 
   /* Then get information about the littlefs filesystem on the devices
    * managed by this driver.
@@ -1117,20 +1090,6 @@ static int littlefs_unbind(FAR void *handle, FAR struct inode **driver,
 }
 
 /****************************************************************************
- * Name: littlefs_used_block
- ****************************************************************************/
-
-static int littlefs_used_block(void *arg, lfs_block_t block)
-{
-  FAR struct statfs *buf = arg;
-
-  buf->f_bfree--;
-  buf->f_bavail--;
-
-  return 0;
-}
-
-/****************************************************************************
  * Name: littlefs_statfs
  *
  * Description: Return filesystem statistics
@@ -1162,7 +1121,15 @@ static int littlefs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
       return ret;
     }
 
-  ret = lfs_traverse(&fs->lfs, littlefs_used_block, buf);
+  ret = lfs_fs_size(&fs->lfs);
+  if (ret > 0)
+    {
+      buf->f_bfree -= ret;
+      buf->f_bavail -= ret;
+
+      ret = 0;
+    }
+
   littlefs_semgive(fs);
 
   return ret;
@@ -1285,7 +1252,7 @@ static int littlefs_stat(FAR struct inode *mountpt, FAR const char *relpath,
                          FAR struct stat *buf)
 {
   FAR struct littlefs_mountpt_s *fs;
-  struct lfs_info_s info;
+  struct lfs_info info;
   int ret;
 
   memset(buf, 0, sizeof(*buf));
diff --git a/tools/Directories.mk b/tools/Directories.mk
index 9f6a437..70a07ab 100644
--- a/tools/Directories.mk
+++ b/tools/Directories.mk
@@ -74,7 +74,7 @@ endif
 
 KERNDEPDIRS += sched drivers boards $(ARCH_SRC)
 KERNDEPDIRS += fs binfmt
-CONTEXTDIRS = boards $(APPDIR)
+CONTEXTDIRS = boards fs $(APPDIR)
 CLEANDIRS += pass1
 
 ifeq ($(CONFIG_BUILD_FLAT),y)