Added better handling of large program sizes (> 1024)

The issue here is how commits handle padding to the nearest program
size. This is done by exploiting the size field of the LFS_TYPE_CRC
tag that completes the commit. Unfortunately, during developement, the
size field shrank in size to make room for more type information,
limiting the size field to 1024.

Normally this isn't a problem, as very rarely do program sizes exceed
1024 bytes. However, using a simulated block device, user earlephilhower
found that exceeding 1024 caused littlefs to crash.

To make this corner case behave in a more user friendly manner, I've
modified this situtation to treat >1024 program sizes as small commits
that don't match the prog size. As a part of this, littlefs also needed
to understand that non-matching commits indicate an "unerased" dir
block, which would be needed for portability (something which notably
lacks testing).

This raises the question of if the tag size field size needs to be
reconsidered, but to change that at this point would need a new major
version.

found by earlephilhower
This commit is contained in:
Christopher Haster
2019-04-09 16:06:43 -05:00
parent a32be1d875
commit 0b76635f10

8
lfs.c
View File

@@ -827,7 +827,8 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
// next commit not yet programmed or we're not in valid range // next commit not yet programmed or we're not in valid range
if (!lfs_tag_isvalid(tag) || if (!lfs_tag_isvalid(tag) ||
off + lfs_tag_dsize(tag) > lfs->cfg->block_size) { off + lfs_tag_dsize(tag) > lfs->cfg->block_size) {
dir->erased = (lfs_tag_type1(ptag) == LFS_TYPE_CRC); dir->erased = (lfs_tag_type1(ptag) == LFS_TYPE_CRC &&
dir->off % lfs->cfg->prog_size == 0);
break; break;
} }
@@ -1596,7 +1597,7 @@ static int lfs_dir_compact(lfs_t *lfs,
dir->count = end - begin; dir->count = end - begin;
dir->off = commit.off; dir->off = commit.off;
dir->etag = commit.ptag; dir->etag = commit.ptag;
dir->erased = true; dir->erased = (dir->off % lfs->cfg->prog_size == 0);
// note we able to have already handled move here // note we able to have already handled move here
if (lfs_gstate_hasmovehere(&lfs->gpending, dir->pair)) { if (lfs_gstate_hasmovehere(&lfs->gpending, dir->pair)) {
lfs_gstate_xormove(&lfs->gpending, lfs_gstate_xormove(&lfs->gpending,
@@ -2381,7 +2382,8 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
if (file->ctz.size > 0) { if (file->ctz.size > 0) {
lfs_stag_t res = lfs_dir_get(lfs, &file->m, lfs_stag_t res = lfs_dir_get(lfs, &file->m,
LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, file->id, file->cache.size), LFS_MKTAG(LFS_TYPE_STRUCT, file->id,
lfs_min(file->cache.size, 0x3fe)),
file->cache.buffer); file->cache.buffer);
if (res < 0) { if (res < 0) {
err = res; err = res;