Compare commits

..

1 Commits

Author SHA1 Message Date
Christopher Haster
041e90a1ca Added handling for corrupt as initial state of blocks
Before this, littlefs incorrectly assumed corrupt blocks were only the result
of our own modification. This would be fine for most cases of freshly
erased storage, but for storage with block-level ECC this wasn't always
true.

Fortunately, it's quite easy for littlefs to handle this case correctly,
as long as corrupt storage always reports that it is corrupt, which for
most forms of ECC is the case unless we perform a write on the storage.

found by rojer
2018-07-16 15:33:52 -05:00
2 changed files with 21 additions and 44 deletions

31
lfs.c
View File

@@ -417,11 +417,14 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) {
// 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);
dir->d.rev = lfs_fromle32(dir->d.rev);
if (err) {
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;
@@ -445,6 +448,9 @@ static int lfs_dir_fetch(lfs_t *lfs,
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;
}
@@ -464,6 +470,9 @@ static int lfs_dir_fetch(lfs_t *lfs,
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;
}
@@ -1282,9 +1291,8 @@ static int lfs_ctz_traverse(lfs_t *lfs,
/// Top level file operations ///
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags,
const struct lfs_file_config *cfg) {
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags) {
// deorphan if we haven't yet, needed at most once after poweron
if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned) {
int err = lfs_deorphan(lfs);
@@ -1324,7 +1332,6 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
}
// setup file struct
file->cfg = cfg;
file->pair[0] = cwd.pair[0];
file->pair[1] = cwd.pair[1];
file->poff = entry.off;
@@ -1342,10 +1349,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
}
// 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->cfg->file_buffer) {
if (lfs->files) {
// already in use
return LFS_ERR_NOMEM;
@@ -1373,11 +1377,6 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
return 0;
}
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags) {
return lfs_file_opencfg(lfs, file, path, flags, NULL);
}
int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
int err = lfs_file_sync(lfs, file);
@@ -1390,7 +1389,7 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
}
// clean up memory
if (!(file->cfg && file->cfg->buffer) && !lfs->cfg->file_buffer) {
if (!lfs->cfg->file_buffer) {
lfs_free(file->cache.buffer);
}

34
lfs.h
View File

@@ -21,7 +21,7 @@ extern "C"
// Software library version
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS_VERSION 0x00010005
#define LFS_VERSION 0x00010004
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
@@ -167,12 +167,6 @@ struct lfs_config {
void *file_buffer;
};
// Optional configuration provided during lfs_file_opencfg
struct lfs_file_config {
// Optional, statically allocated buffer for files. Must be program sized.
// If NULL, malloc will be used by default.
void *buffer;
};
// File info structure
struct lfs_info {
@@ -220,7 +214,6 @@ typedef struct lfs_file {
lfs_block_t head;
lfs_size_t size;
const struct lfs_file_config *cfg;
uint32_t flags;
lfs_off_t pos;
lfs_block_t block;
@@ -288,8 +281,7 @@ typedef struct lfs {
// 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.
// object, and does not leave the filesystem mounted.
//
// Returns a negative error code on failure.
int lfs_format(lfs_t *lfs, const struct lfs_config *config);
@@ -298,8 +290,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config);
//
// 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.
// lfs and config must be allocated while mounted.
//
// Returns a negative error code on failure.
int lfs_mount(lfs_t *lfs, const struct lfs_config *config);
@@ -337,27 +328,14 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
// 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.
// 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(lfs_t *lfs, lfs_file_t *file,
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(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags,
const struct lfs_file_config *config);
// Close a file
//
// Any pending writes are written out to storage as though