Added atomic move using dirty tag in entry type

The "move problem" has been present in littlefs for a while, but I haven't
come across a solution worth implementing for various reasons.

The problem is simple: how do we move directory entries across
directories atomically? Since multiple directory entries are involved,
we can't rely entirely on the atomic block updates. It ends up being
a bit of a puzzle.

To make the problem more complicated, any directory block update can
fail due to wear, and cause the directory block to need to be relocated.
This happens rarely, but brings a large number of corner cases.

---

The solution in this patch is simple:
1. Mark source as "moving"
2. Copy source to destination
3. Remove source

If littlefs ever runs into a "moving" entry, that means a power loss
occured during a move. Either the destination entry exists or it
doesn't. In this case we just search the entire filesystem for the
destination entry.

This is expensive, however the chance of a power loss during a move
is relatively low.
This commit is contained in:
Christopher Haster
2017-10-07 09:19:08 -05:00
parent ac9766ee39
commit 2936514b5e
4 changed files with 438 additions and 38 deletions

6
lfs.h
View File

@@ -46,7 +46,7 @@ enum lfs_error {
enum lfs_type {
LFS_TYPE_REG = 0x11,
LFS_TYPE_DIR = 0x22,
LFS_TYPE_SUPERBLOCK = 0xe2,
LFS_TYPE_SUPERBLOCK = 0x2e,
};
// File open flags
@@ -244,6 +244,7 @@ typedef struct lfs {
lfs_free_t free;
bool deorphaned;
bool deduplicated;
} lfs_t;
@@ -434,5 +435,8 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
// Returns a negative error code on failure.
int lfs_deorphan(lfs_t *lfs);
// TODO doc
int lfs_deduplicate(lfs_t *lfs);
#endif