mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-10-16 23:07:55 +08:00
Merge branch 'devel' into ci-revamp
Needed to bring in new "error-asserts" configuration
This commit is contained in:
17
.github/workflows/release.yml
vendored
17
.github/workflows/release.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
|||||||
| capture("Code size is (?<result>[0-9]+)").result' \
|
| capture("Code size is (?<result>[0-9]+)").result' \
|
||||||
prev-results.json || echo 0)"
|
prev-results.json || echo 0)"
|
||||||
./scripts/code.py -u results/code-thumb-readonly.csv -s | awk '
|
./scripts/code.py -u results/code-thumb-readonly.csv -s | awk '
|
||||||
NR==2 {printf "Code size (readonly),%d B",$2}
|
NR==2 {printf "Code size<br/>(readonly),%d B",$2}
|
||||||
NR==2 && ENVIRON["PREV"]+0 != 0 {
|
NR==2 && ENVIRON["PREV"]+0 != 0 {
|
||||||
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
|
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
|
||||||
NR==2 {printf "\n"}' \
|
NR==2 {printf "\n"}' \
|
||||||
@@ -107,7 +107,7 @@ jobs:
|
|||||||
| capture("Code size is (?<result>[0-9]+)").result' \
|
| capture("Code size is (?<result>[0-9]+)").result' \
|
||||||
prev-results.json || echo 0)"
|
prev-results.json || echo 0)"
|
||||||
./scripts/code.py -u results/code-thumb-threadsafe.csv -s | awk '
|
./scripts/code.py -u results/code-thumb-threadsafe.csv -s | awk '
|
||||||
NR==2 {printf "Code size (threadsafe),%d B",$2}
|
NR==2 {printf "Code size<br/>(threadsafe),%d B",$2}
|
||||||
NR==2 && ENVIRON["PREV"]+0 != 0 {
|
NR==2 && ENVIRON["PREV"]+0 != 0 {
|
||||||
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
|
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
|
||||||
NR==2 {printf "\n"}' \
|
NR==2 {printf "\n"}' \
|
||||||
@@ -118,7 +118,18 @@ jobs:
|
|||||||
| capture("Code size is (?<result>[0-9]+)").result' \
|
| capture("Code size is (?<result>[0-9]+)").result' \
|
||||||
prev-results.json || echo 0)"
|
prev-results.json || echo 0)"
|
||||||
./scripts/code.py -u results/code-thumb-migrate.csv -s | awk '
|
./scripts/code.py -u results/code-thumb-migrate.csv -s | awk '
|
||||||
NR==2 {printf "Code size (migrate),%d B",$2}
|
NR==2 {printf "Code size<br/>(migrate),%d B",$2}
|
||||||
|
NR==2 && ENVIRON["PREV"]+0 != 0 {
|
||||||
|
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
|
||||||
|
NR==2 {printf "\n"}' \
|
||||||
|
>> results.csv)
|
||||||
|
[ -e results/code-thumb-error-asserts.csv ] && ( \
|
||||||
|
export PREV="$(jq -re '
|
||||||
|
select(.context == "results / code (error-asserts)").description
|
||||||
|
| capture("Code size is (?<result>[0-9]+)").result' \
|
||||||
|
prev-results.json || echo 0)"
|
||||||
|
./scripts/code.py -u results/code-thumb-error-asserts.csv -s | awk '
|
||||||
|
NR==2 {printf "Code size<br/>(error-asserts),%d B",$2}
|
||||||
NR==2 && ENVIRON["PREV"]+0 != 0 {
|
NR==2 && ENVIRON["PREV"]+0 != 0 {
|
||||||
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
|
printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/ENVIRON["PREV"]}
|
||||||
NR==2 {printf "\n"}' \
|
NR==2 {printf "\n"}' \
|
||||||
|
11
.github/workflows/test.yml
vendored
11
.github/workflows/test.yml
vendored
@@ -195,6 +195,17 @@ jobs:
|
|||||||
-DLFS_NO_ERROR \
|
-DLFS_NO_ERROR \
|
||||||
-DLFS_MIGRATE" \
|
-DLFS_MIGRATE" \
|
||||||
CODEFLAGS+="-o results/code-${{matrix.arch}}-migrate.csv"
|
CODEFLAGS+="-o results/code-${{matrix.arch}}-migrate.csv"
|
||||||
|
- name: results-code-error-asserts
|
||||||
|
run: |
|
||||||
|
mkdir -p results
|
||||||
|
make clean
|
||||||
|
make code \
|
||||||
|
CFLAGS+=" \
|
||||||
|
-DLFS_NO_DEBUG \
|
||||||
|
-DLFS_NO_WARN \
|
||||||
|
-DLFS_NO_ERROR \
|
||||||
|
-D'LFS_ASSERT(test)=do {if(!(test)) {return -1;}} while(0)'" \
|
||||||
|
CODEFLAGS+="-o results/code-${{matrix.arch}}-error-asserts.csv"
|
||||||
- name: upload-results
|
- name: upload-results
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
|
116
lfs.c
116
lfs.c
@@ -425,7 +425,8 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) {
|
|||||||
superblock->attr_max = lfs_tole32(superblock->attr_max);
|
superblock->attr_max = lfs_tole32(superblock->attr_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool lfs_mlist_isopen(struct lfs_mlist *head,
|
#ifndef LFS_NO_ASSERT
|
||||||
|
static bool lfs_mlist_isopen(struct lfs_mlist *head,
|
||||||
struct lfs_mlist *node) {
|
struct lfs_mlist *node) {
|
||||||
for (struct lfs_mlist **p = &head; *p; p = &(*p)->next) {
|
for (struct lfs_mlist **p = &head; *p; p = &(*p)->next) {
|
||||||
if (*p == (struct lfs_mlist*)node) {
|
if (*p == (struct lfs_mlist*)node) {
|
||||||
@@ -435,8 +436,9 @@ static inline bool lfs_mlist_isopen(struct lfs_mlist *head,
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) {
|
static void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) {
|
||||||
for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) {
|
for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) {
|
||||||
if (*p == mlist) {
|
if (*p == mlist) {
|
||||||
*p = (*p)->next;
|
*p = (*p)->next;
|
||||||
@@ -445,7 +447,7 @@ static inline void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lfs_mlist_append(lfs_t *lfs, struct lfs_mlist *mlist) {
|
static void lfs_mlist_append(lfs_t *lfs, struct lfs_mlist *mlist) {
|
||||||
mlist->next = lfs->mlist;
|
mlist->next = lfs->mlist;
|
||||||
lfs->mlist = mlist;
|
lfs->mlist = mlist;
|
||||||
}
|
}
|
||||||
@@ -465,7 +467,7 @@ static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file);
|
|||||||
static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file);
|
static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file);
|
||||||
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file);
|
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file);
|
||||||
|
|
||||||
static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans);
|
static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans);
|
||||||
static void lfs_fs_prepmove(lfs_t *lfs,
|
static void lfs_fs_prepmove(lfs_t *lfs,
|
||||||
uint16_t id, const lfs_block_t pair[2]);
|
uint16_t id, const lfs_block_t pair[2]);
|
||||||
static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2],
|
static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2],
|
||||||
@@ -1589,7 +1591,8 @@ static int lfs_dir_compact(lfs_t *lfs,
|
|||||||
// for metadata updates.
|
// for metadata updates.
|
||||||
if (end - begin < 0xff &&
|
if (end - begin < 0xff &&
|
||||||
size <= lfs_min(lfs->cfg->block_size - 36,
|
size <= lfs_min(lfs->cfg->block_size - 36,
|
||||||
lfs_alignup(lfs->cfg->block_size/2,
|
lfs_alignup((lfs->cfg->metadata_max ?
|
||||||
|
lfs->cfg->metadata_max : lfs->cfg->block_size)/2,
|
||||||
lfs->cfg->prog_size))) {
|
lfs->cfg->prog_size))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1674,7 +1677,8 @@ static int lfs_dir_compact(lfs_t *lfs,
|
|||||||
.crc = 0xffffffff,
|
.crc = 0xffffffff,
|
||||||
|
|
||||||
.begin = 0,
|
.begin = 0,
|
||||||
.end = lfs->cfg->block_size - 8,
|
.end = (lfs->cfg->metadata_max ?
|
||||||
|
lfs->cfg->metadata_max : lfs->cfg->block_size) - 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
// erase block to write to
|
// erase block to write to
|
||||||
@@ -1884,7 +1888,8 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
|
|||||||
.crc = 0xffffffff,
|
.crc = 0xffffffff,
|
||||||
|
|
||||||
.begin = dir->off,
|
.begin = dir->off,
|
||||||
.end = lfs->cfg->block_size - 8,
|
.end = (lfs->cfg->metadata_max ?
|
||||||
|
lfs->cfg->metadata_max : lfs->cfg->block_size) - 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
// traverse attrs that need to be written out
|
// traverse attrs that need to be written out
|
||||||
@@ -2061,7 +2066,10 @@ static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
|
|||||||
// current block end of list?
|
// current block end of list?
|
||||||
if (cwd.m.split) {
|
if (cwd.m.split) {
|
||||||
// update tails, this creates a desync
|
// update tails, this creates a desync
|
||||||
lfs_fs_preporphans(lfs, +1);
|
err = lfs_fs_preporphans(lfs, +1);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
// it's possible our predecessor has to be relocated, and if
|
// it's possible our predecessor has to be relocated, and if
|
||||||
// our parent is our predecessor's predecessor, this could have
|
// our parent is our predecessor's predecessor, this could have
|
||||||
@@ -2081,7 +2089,10 @@ static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lfs->mlist = cwd.next;
|
lfs->mlist = cwd.next;
|
||||||
lfs_fs_preporphans(lfs, -1);
|
err = lfs_fs_preporphans(lfs, -1);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now insert into our parent block
|
// now insert into our parent block
|
||||||
@@ -2966,7 +2977,9 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
|||||||
if ((file->flags & LFS_F_INLINE) &&
|
if ((file->flags & LFS_F_INLINE) &&
|
||||||
lfs_max(file->pos+nsize, file->ctz.size) >
|
lfs_max(file->pos+nsize, file->ctz.size) >
|
||||||
lfs_min(0x3fe, lfs_min(
|
lfs_min(0x3fe, lfs_min(
|
||||||
lfs->cfg->cache_size, lfs->cfg->block_size/8))) {
|
lfs->cfg->cache_size,
|
||||||
|
(lfs->cfg->metadata_max ?
|
||||||
|
lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) {
|
||||||
// inline file doesn't fit anymore
|
// inline file doesn't fit anymore
|
||||||
int err = lfs_file_outline(lfs, file);
|
int err = lfs_file_outline(lfs, file);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -3048,14 +3061,6 @@ relocate:
|
|||||||
|
|
||||||
static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
||||||
lfs_soff_t off, int whence) {
|
lfs_soff_t off, int whence) {
|
||||||
#ifndef LFS_READONLY
|
|
||||||
// write out everything beforehand, may be noop if rdonly
|
|
||||||
int err = lfs_file_flush(lfs, file);
|
|
||||||
if (err) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// find new pos
|
// find new pos
|
||||||
lfs_off_t npos = file->pos;
|
lfs_off_t npos = file->pos;
|
||||||
if (whence == LFS_SEEK_SET) {
|
if (whence == LFS_SEEK_SET) {
|
||||||
@@ -3063,7 +3068,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
|||||||
} else if (whence == LFS_SEEK_CUR) {
|
} else if (whence == LFS_SEEK_CUR) {
|
||||||
npos = file->pos + off;
|
npos = file->pos + off;
|
||||||
} else if (whence == LFS_SEEK_END) {
|
} else if (whence == LFS_SEEK_END) {
|
||||||
npos = file->ctz.size + off;
|
npos = lfs_file_rawsize(lfs, file) + off;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (npos > lfs->file_max) {
|
if (npos > lfs->file_max) {
|
||||||
@@ -3071,6 +3076,19 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
|||||||
return LFS_ERR_INVAL;
|
return LFS_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file->pos == npos) {
|
||||||
|
// noop - position has not changed
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef LFS_READONLY
|
||||||
|
// write out everything beforehand, may be noop if rdonly
|
||||||
|
int err = lfs_file_flush(lfs, file);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// update pos
|
// update pos
|
||||||
file->pos = npos;
|
file->pos = npos;
|
||||||
return npos;
|
return npos;
|
||||||
@@ -3101,21 +3119,22 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// need to set pos/block/off consistently so seeking back to
|
||||||
|
// the old position does not get confused
|
||||||
|
file->pos = size;
|
||||||
file->ctz.head = file->block;
|
file->ctz.head = file->block;
|
||||||
file->ctz.size = size;
|
file->ctz.size = size;
|
||||||
file->flags |= LFS_F_DIRTY | LFS_F_READING;
|
file->flags |= LFS_F_DIRTY | LFS_F_READING;
|
||||||
} else if (size > oldsize) {
|
} else if (size > oldsize) {
|
||||||
// flush+seek if not already at end
|
// flush+seek if not already at end
|
||||||
if (file->pos != oldsize) {
|
|
||||||
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END);
|
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return (int)res;
|
return (int)res;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// fill with zeros
|
// fill with zeros
|
||||||
while (file->pos < size) {
|
while (file->pos < size) {
|
||||||
lfs_ssize_t res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1);
|
res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return (int)res;
|
return (int)res;
|
||||||
}
|
}
|
||||||
@@ -3206,7 +3225,10 @@ static int lfs_rawremove(lfs_t *lfs, const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mark fs as orphaned
|
// mark fs as orphaned
|
||||||
lfs_fs_preporphans(lfs, +1);
|
err = lfs_fs_preporphans(lfs, +1);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
// I know it's crazy but yes, dir can be changed by our parent's
|
// I know it's crazy but yes, dir can be changed by our parent's
|
||||||
// commit (if predecessor is child)
|
// commit (if predecessor is child)
|
||||||
@@ -3226,7 +3248,10 @@ static int lfs_rawremove(lfs_t *lfs, const char *path) {
|
|||||||
lfs->mlist = dir.next;
|
lfs->mlist = dir.next;
|
||||||
if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
|
if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
|
||||||
// fix orphan
|
// fix orphan
|
||||||
lfs_fs_preporphans(lfs, -1);
|
err = lfs_fs_preporphans(lfs, -1);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = lfs_fs_pred(lfs, dir.m.pair, &cwd);
|
err = lfs_fs_pred(lfs, dir.m.pair, &cwd);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -3312,7 +3337,10 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mark fs as orphaned
|
// mark fs as orphaned
|
||||||
lfs_fs_preporphans(lfs, +1);
|
err = lfs_fs_preporphans(lfs, +1);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
// I know it's crazy but yes, dir can be changed by our parent's
|
// I know it's crazy but yes, dir can be changed by our parent's
|
||||||
// commit (if predecessor is child)
|
// commit (if predecessor is child)
|
||||||
@@ -3355,7 +3383,10 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|||||||
lfs->mlist = prevdir.next;
|
lfs->mlist = prevdir.next;
|
||||||
if (prevtag != LFS_ERR_NOENT && lfs_tag_type3(prevtag) == LFS_TYPE_DIR) {
|
if (prevtag != LFS_ERR_NOENT && lfs_tag_type3(prevtag) == LFS_TYPE_DIR) {
|
||||||
// fix orphan
|
// fix orphan
|
||||||
lfs_fs_preporphans(lfs, -1);
|
err = lfs_fs_preporphans(lfs, -1);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = lfs_fs_pred(lfs, prevdir.m.pair, &newcwd);
|
err = lfs_fs_pred(lfs, prevdir.m.pair, &newcwd);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -3536,6 +3567,8 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
lfs->attr_max = LFS_ATTR_MAX;
|
lfs->attr_max = LFS_ATTR_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LFS_ASSERT(lfs->cfg->metadata_max <= lfs->cfg->block_size);
|
||||||
|
|
||||||
// setup default state
|
// setup default state
|
||||||
lfs->root[0] = LFS_BLOCK_NULL;
|
lfs->root[0] = LFS_BLOCK_NULL;
|
||||||
lfs->root[1] = LFS_BLOCK_NULL;
|
lfs->root[1] = LFS_BLOCK_NULL;
|
||||||
@@ -3616,12 +3649,6 @@ static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sanity check that fetch works
|
|
||||||
err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1});
|
|
||||||
if (err) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
// force compaction to prevent accidentally mounting any
|
// force compaction to prevent accidentally mounting any
|
||||||
// older version of littlefs that may live on disk
|
// older version of littlefs that may live on disk
|
||||||
root.erased = false;
|
root.erased = false;
|
||||||
@@ -3629,6 +3656,12 @@ static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sanity check that fetch works
|
||||||
|
err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1});
|
||||||
|
if (err) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@@ -3986,7 +4019,10 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|||||||
|
|
||||||
if (tag != LFS_ERR_NOENT) {
|
if (tag != LFS_ERR_NOENT) {
|
||||||
// update disk, this creates a desync
|
// update disk, this creates a desync
|
||||||
lfs_fs_preporphans(lfs, +1);
|
int err = lfs_fs_preporphans(lfs, +1);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
// fix pending move in this pair? this looks like an optimization but
|
// fix pending move in this pair? this looks like an optimization but
|
||||||
// is in fact _required_ since relocating may outdate the move.
|
// is in fact _required_ since relocating may outdate the move.
|
||||||
@@ -4003,7 +4039,7 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
lfs_pair_tole32(newpair);
|
lfs_pair_tole32(newpair);
|
||||||
int err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS(
|
err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS(
|
||||||
{LFS_MKTAG_IF(moveid != 0x3ff,
|
{LFS_MKTAG_IF(moveid != 0x3ff,
|
||||||
LFS_TYPE_DELETE, moveid, 0), NULL},
|
LFS_TYPE_DELETE, moveid, 0), NULL},
|
||||||
{tag, newpair}));
|
{tag, newpair}));
|
||||||
@@ -4013,7 +4049,10 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// next step, clean up orphans
|
// next step, clean up orphans
|
||||||
lfs_fs_preporphans(lfs, -1);
|
err = lfs_fs_preporphans(lfs, -1);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// find pred
|
// find pred
|
||||||
@@ -4052,11 +4091,13 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) {
|
static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) {
|
||||||
LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0 || orphans >= 0);
|
LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0 || orphans >= 0);
|
||||||
lfs->gstate.tag += orphans;
|
lfs->gstate.tag += orphans;
|
||||||
lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x800, 0, 0)) |
|
lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x800, 0, 0)) |
|
||||||
((uint32_t)lfs_gstate_hasorphans(&lfs->gstate) << 31));
|
((uint32_t)lfs_gstate_hasorphans(&lfs->gstate) << 31));
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -4173,8 +4214,7 @@ static int lfs_fs_deorphan(lfs_t *lfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mark orphans as fixed
|
// mark orphans as fixed
|
||||||
lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate));
|
return lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
6
lfs.h
6
lfs.h
@@ -256,6 +256,12 @@ struct lfs_config {
|
|||||||
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
|
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
|
||||||
// LFS_ATTR_MAX when zero.
|
// LFS_ATTR_MAX when zero.
|
||||||
lfs_size_t attr_max;
|
lfs_size_t attr_max;
|
||||||
|
|
||||||
|
// Optional upper limit on total space given to metadata pairs in bytes. On
|
||||||
|
// devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB)
|
||||||
|
// can help bound the metadata compaction time. Must be <= block_size.
|
||||||
|
// Defaults to block_size when zero.
|
||||||
|
lfs_size_t metadata_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
// File info structure
|
// File info structure
|
||||||
|
@@ -812,9 +812,9 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument('test_paths', nargs='*', default=[TEST_PATHS],
|
parser.add_argument('test_paths', nargs='*', default=[TEST_PATHS],
|
||||||
help="Description of test(s) to run. By default, this is all tests \
|
help="Description of test(s) to run. By default, this is all tests \
|
||||||
found in the \"{0}\" directory. Here, you can specify a different \
|
found in the \"{0}\" directory. Here, you can specify a different \
|
||||||
directory of tests, a specific file, a suite by name, and even a \
|
directory of tests, a specific file, a suite by name, and even \
|
||||||
specific test case by adding brackets. For example \
|
specific test cases and permutations. For example \
|
||||||
\"test_dirs[0]\" or \"{0}/test_dirs.toml[0]\".".format(TEST_PATHS))
|
\"test_dirs#1\" or \"{0}/test_dirs.toml#1#1\".".format(TEST_PATHS))
|
||||||
parser.add_argument('-D', action='append', default=[],
|
parser.add_argument('-D', action='append', default=[],
|
||||||
help="Overriding parameter definitions.")
|
help="Overriding parameter definitions.")
|
||||||
parser.add_argument('-v', '--verbose', action='store_true',
|
parser.add_argument('-v', '--verbose', action='store_true',
|
||||||
|
@@ -392,3 +392,48 @@ code = '''
|
|||||||
|
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
[[case]] # noop truncate
|
||||||
|
define.MEDIUMSIZE = [32, 2048]
|
||||||
|
code = '''
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &file, "baldynoop",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT) => 0;
|
||||||
|
|
||||||
|
strcpy((char*)buffer, "hair");
|
||||||
|
size = strlen((char*)buffer);
|
||||||
|
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||||
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||||
|
|
||||||
|
// this truncate should do nothing
|
||||||
|
lfs_file_truncate(&lfs, &file, j+size) => 0;
|
||||||
|
}
|
||||||
|
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||||
|
|
||||||
|
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
|
||||||
|
// should do nothing again
|
||||||
|
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
|
||||||
|
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||||
|
|
||||||
|
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||||
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||||
|
memcmp(buffer, "hair", size) => 0;
|
||||||
|
}
|
||||||
|
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||||
|
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// still there after reboot?
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
|
||||||
|
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||||
|
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||||
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||||
|
memcmp(buffer, "hair", size) => 0;
|
||||||
|
}
|
||||||
|
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
Reference in New Issue
Block a user