Fixed lfsr_fs_fixorphans not fixing orphans
Turns out things get a bit tricky when mdirs are dropped while iterating
over the mtree.
This was actually broken quite a bit before traversal-related changes,
probably during some mtree refactor, but went unnoticed since no test
actually checked that lfsr_fs_fixorphans did what it said it did.
At least the new test_forphans_cleanup* tests should prevent this from
regressing again in the future.
Code changes:
code stack
before: 35472 2680
after: 35480 (+0.0%) 2680 (+0.0%)
This commit is contained in:
@@ -12752,9 +12752,8 @@ static int lfsr_fs_fixorphans(lfs_t *lfs) {
|
|||||||
//
|
//
|
||||||
// note this never takes longer than lfsr_mount
|
// note this never takes longer than lfsr_mount
|
||||||
//
|
//
|
||||||
for (lfsr_mid_t mid = 0;
|
lfsr_mid_t mid = 0;
|
||||||
mid < lfsr_mtree_weight(lfs);
|
while (mid < lfsr_mtree_weight(lfs)) {
|
||||||
mid += (1 << lfs->mdir_bits)) {
|
|
||||||
lfsr_mdir_t mdir;
|
lfsr_mdir_t mdir;
|
||||||
int err = lfsr_mtree_lookup(lfs, mid,
|
int err = lfsr_mtree_lookup(lfs, mid,
|
||||||
&mdir);
|
&mdir);
|
||||||
@@ -12763,10 +12762,16 @@ static int lfsr_fs_fixorphans(lfs_t *lfs) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clean up orphans
|
||||||
err = lfsr_mdir_fixorphans(lfs, &mdir);
|
err = lfsr_mdir_fixorphans(lfs, &mdir);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// incremend mid unless we dropped the mdir
|
||||||
|
if (mdir.rbyd.weight > 0) {
|
||||||
|
mid += 1 << lfs->mdir_bits;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// done, no more orphans
|
// done, no more orphans
|
||||||
|
|||||||
@@ -4610,6 +4610,438 @@ code = '''
|
|||||||
lfsr_unmount(&lfs) => 0;
|
lfsr_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
# test that we actually cleanup orphans correctly
|
||||||
|
[cases.test_forphans_cleanup]
|
||||||
|
defines.SIZE = [
|
||||||
|
'FILE_BUFFER_SIZE/2',
|
||||||
|
'2*FILE_BUFFER_SIZE',
|
||||||
|
'BLOCK_SIZE/2',
|
||||||
|
'BLOCK_SIZE',
|
||||||
|
'2*BLOCK_SIZE',
|
||||||
|
'4*BLOCK_SIZE',
|
||||||
|
]
|
||||||
|
# <=2 => grm-able
|
||||||
|
# >2 => requires orphans
|
||||||
|
defines.N = [0, 1, 2, 3, 10, 100]
|
||||||
|
defines.REMOUNT = [false, true]
|
||||||
|
defines.BOOKENDS = [0x0, 0x1, 0x2, 0x3]
|
||||||
|
if = '(SIZE*N)/BLOCK_SIZE <= 32'
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, CFG) => 0;
|
||||||
|
lfsr_mount(&lfs, CFG) => 0;
|
||||||
|
|
||||||
|
uint32_t prng = 42;
|
||||||
|
|
||||||
|
// create some unrelated files to make sure cleaning up orphans doesn't
|
||||||
|
// break other filesystem things
|
||||||
|
uint32_t bookend_prngs[2] = {0, 0};
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "aatman",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
bookend_prngs[0] = TEST_PRNG(&prng);
|
||||||
|
uint32_t prng_ = bookend_prngs[0];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE;
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "catman",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
bookend_prngs[1] = TEST_PRNG(&prng);
|
||||||
|
uint32_t prng_ = bookend_prngs[1];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE;
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create this many orphaned files
|
||||||
|
//
|
||||||
|
// anytime we close a not-yet-created desync file, we create an
|
||||||
|
// orphan, but note we need these to be different files, and we need
|
||||||
|
// to close them after all open calls, otherwise we just end up with
|
||||||
|
// one orphan (littlefs is eager to clean up orphans)
|
||||||
|
//
|
||||||
|
lfsr_file_t files[N];
|
||||||
|
for (lfs_size_t i = 0; i < N; i++) {
|
||||||
|
char name[256];
|
||||||
|
sprintf(name, "batman%03x", i);
|
||||||
|
lfsr_file_open(&lfs, &files[i], name,
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
||||||
|
}
|
||||||
|
lfsr_file_write(&lfs, &files[i], wbuf, SIZE) => SIZE;
|
||||||
|
}
|
||||||
|
for (lfs_size_t i = 0; i < N; i++) {
|
||||||
|
lfsr_file_close(&lfs, &files[i]) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remount? this has no effect on orphans
|
||||||
|
if (REMOUNT) {
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
lfsr_mount(&lfs, CFG) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calling lfsr_fs_mkconsistent should clean things up
|
||||||
|
lfsr_fs_mkconsistent(&lfs) => 0;
|
||||||
|
|
||||||
|
// we should have cleaned up all grms/orphans
|
||||||
|
assert(lfs.grm.mids[0] == -1);
|
||||||
|
assert(lfs.grm.mids[1] == -1);
|
||||||
|
assert(lfs.hasorphans == false);
|
||||||
|
|
||||||
|
// double check the actual disk state, it's easy for littlefs to
|
||||||
|
// lie here
|
||||||
|
assert(lfsr_mtree_weight(&lfs)
|
||||||
|
<= ((1+lfs_popc(BOOKENDS)) << lfs.mdir_bits));
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_mtree_lookup(&lfs, 0, &mdir) => 0;
|
||||||
|
assert(mdir.rbyd.weight <= 1+lfs_popc(BOOKENDS));
|
||||||
|
|
||||||
|
// check that other files are unaffected
|
||||||
|
for (int remount = 0; remount < 2; remount++) {
|
||||||
|
if (remount) {
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
lfsr_mount(&lfs, CFG) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "aatman", LFS_O_RDONLY) => 0;
|
||||||
|
uint32_t prng_ = bookend_prngs[0];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
uint8_t rbuf[SIZE];
|
||||||
|
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
|
||||||
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||||
|
lfsr_file_close(&lfs, &file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "catman", LFS_O_RDONLY) => 0;
|
||||||
|
uint32_t prng_ = bookend_prngs[1];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
uint8_t rbuf[SIZE];
|
||||||
|
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
|
||||||
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||||
|
lfsr_file_close(&lfs, &file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_forphans_cleanup_opened]
|
||||||
|
defines.SIZE = [
|
||||||
|
'FILE_BUFFER_SIZE/2',
|
||||||
|
'2*FILE_BUFFER_SIZE',
|
||||||
|
'BLOCK_SIZE/2',
|
||||||
|
'BLOCK_SIZE',
|
||||||
|
'2*BLOCK_SIZE',
|
||||||
|
'4*BLOCK_SIZE',
|
||||||
|
]
|
||||||
|
# <=2 => grm-able
|
||||||
|
# >2 => requires orphans
|
||||||
|
defines.N = [0, 1, 2, 3, 10, 100]
|
||||||
|
defines.BOOKENDS = [0x0, 0x1, 0x2, 0x3]
|
||||||
|
if = '(SIZE*N)/BLOCK_SIZE <= 32'
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, CFG) => 0;
|
||||||
|
lfsr_mount(&lfs, CFG) => 0;
|
||||||
|
|
||||||
|
uint32_t prng = 42;
|
||||||
|
|
||||||
|
// create some unrelated files to make sure cleaning up orphans doesn't
|
||||||
|
// break other filesystem things
|
||||||
|
lfsr_file_t bookend_files[2];
|
||||||
|
uint32_t bookend_prngs[2] = {0, 0};
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_open(&lfs, &bookend_files[0], "aatman",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
bookend_prngs[0] = TEST_PRNG(&prng);
|
||||||
|
uint32_t prng_ = bookend_prngs[0];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
lfsr_file_write(&lfs, &bookend_files[0], wbuf, SIZE) => SIZE;
|
||||||
|
lfsr_file_sync(&lfs, &bookend_files[0]) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_open(&lfs, &bookend_files[1], "catman",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
bookend_prngs[1] = TEST_PRNG(&prng);
|
||||||
|
uint32_t prng_ = bookend_prngs[1];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
lfsr_file_write(&lfs, &bookend_files[1], wbuf, SIZE) => SIZE;
|
||||||
|
lfsr_file_sync(&lfs, &bookend_files[1]) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create this many orphaned files
|
||||||
|
//
|
||||||
|
// anytime we close a not-yet-created desync file, we create an
|
||||||
|
// orphan, but note we need these to be different files, and we need
|
||||||
|
// to close them after all open calls, otherwise we just end up with
|
||||||
|
// one orphan (littlefs is eager to clean up orphans)
|
||||||
|
//
|
||||||
|
lfsr_file_t files[N];
|
||||||
|
for (lfs_size_t i = 0; i < N; i++) {
|
||||||
|
char name[256];
|
||||||
|
sprintf(name, "batman%03x", i);
|
||||||
|
lfsr_file_open(&lfs, &files[i], name,
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
||||||
|
}
|
||||||
|
lfsr_file_write(&lfs, &files[i], wbuf, SIZE) => SIZE;
|
||||||
|
}
|
||||||
|
for (lfs_size_t i = 0; i < N; i++) {
|
||||||
|
lfsr_file_close(&lfs, &files[i]) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calling lfsr_fs_mkconsistent should clean things up
|
||||||
|
lfsr_fs_mkconsistent(&lfs) => 0;
|
||||||
|
|
||||||
|
// we should have cleaned up all grms/orphans
|
||||||
|
assert(lfs.grm.mids[0] == -1);
|
||||||
|
assert(lfs.grm.mids[1] == -1);
|
||||||
|
assert(lfs.hasorphans == false);
|
||||||
|
|
||||||
|
// double check the actual disk state, it's easy for littlefs to
|
||||||
|
// lie here
|
||||||
|
assert(lfsr_mtree_weight(&lfs)
|
||||||
|
<= ((1+lfs_popc(BOOKENDS)) << lfs.mdir_bits));
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_mtree_lookup(&lfs, 0, &mdir) => 0;
|
||||||
|
assert(mdir.rbyd.weight <= 1+lfs_popc(BOOKENDS));
|
||||||
|
|
||||||
|
// check that other files are unaffected
|
||||||
|
for (int remount = 0; remount < 2; remount++) {
|
||||||
|
if (remount) {
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_close(&lfs, &bookend_files[0]) => 0;
|
||||||
|
}
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_close(&lfs, &bookend_files[1]) => 0;
|
||||||
|
}
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
lfsr_mount(&lfs, CFG) => 0;
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_open(&lfs, &bookend_files[0], "aatman",
|
||||||
|
LFS_O_RDONLY) => 0;
|
||||||
|
}
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_open(&lfs, &bookend_files[1], "catman",
|
||||||
|
LFS_O_RDONLY) => 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_rewind(&lfs, &bookend_files[0]) => 0;
|
||||||
|
uint32_t prng_ = bookend_prngs[0];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
uint8_t rbuf[SIZE];
|
||||||
|
lfsr_file_read(&lfs, &bookend_files[0], rbuf, SIZE) => SIZE;
|
||||||
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_rewind(&lfs, &bookend_files[1]) => 0;
|
||||||
|
uint32_t prng_ = bookend_prngs[1];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
uint8_t rbuf[SIZE];
|
||||||
|
lfsr_file_read(&lfs, &bookend_files[1], rbuf, SIZE) => SIZE;
|
||||||
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_close(&lfs, &bookend_files[0]);
|
||||||
|
}
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_close(&lfs, &bookend_files[1]);
|
||||||
|
}
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_forphans_cleanup_orphaned]
|
||||||
|
defines.SIZE = [
|
||||||
|
'FILE_BUFFER_SIZE/2',
|
||||||
|
'2*FILE_BUFFER_SIZE',
|
||||||
|
'BLOCK_SIZE/2',
|
||||||
|
'BLOCK_SIZE',
|
||||||
|
'2*BLOCK_SIZE',
|
||||||
|
'4*BLOCK_SIZE',
|
||||||
|
]
|
||||||
|
# <=2 => grm-able
|
||||||
|
# >2 => requires orphans
|
||||||
|
defines.N = [0, 1, 2, 3, 10, 100]
|
||||||
|
defines.BOOKENDS = [0x0, 0x1, 0x2, 0x3]
|
||||||
|
if = '(SIZE*N)/BLOCK_SIZE <= 32'
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, CFG) => 0;
|
||||||
|
lfsr_mount(&lfs, CFG) => 0;
|
||||||
|
|
||||||
|
uint32_t prng = 42;
|
||||||
|
|
||||||
|
// create some unrelated files to make sure cleaning up orphans doesn't
|
||||||
|
// break other filesystem things
|
||||||
|
lfsr_file_t bookend_files[2];
|
||||||
|
uint32_t bookend_prngs[2] = {0, 0};
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_open(&lfs, &bookend_files[0], "aatman",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
bookend_prngs[0] = TEST_PRNG(&prng);
|
||||||
|
uint32_t prng_ = bookend_prngs[0];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
lfsr_file_write(&lfs, &bookend_files[0], wbuf, SIZE) => SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_open(&lfs, &bookend_files[1], "catman",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
bookend_prngs[1] = TEST_PRNG(&prng);
|
||||||
|
uint32_t prng_ = bookend_prngs[1];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
lfsr_file_write(&lfs, &bookend_files[1], wbuf, SIZE) => SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create this many orphaned files
|
||||||
|
//
|
||||||
|
// anytime we close a not-yet-created desync file, we create an
|
||||||
|
// orphan, but note we need these to be different files, and we need
|
||||||
|
// to close them after all open calls, otherwise we just end up with
|
||||||
|
// one orphan (littlefs is eager to clean up orphans)
|
||||||
|
//
|
||||||
|
lfsr_file_t files[N];
|
||||||
|
for (lfs_size_t i = 0; i < N; i++) {
|
||||||
|
char name[256];
|
||||||
|
sprintf(name, "batman%03x", i);
|
||||||
|
lfsr_file_open(&lfs, &files[i], name,
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
||||||
|
}
|
||||||
|
lfsr_file_write(&lfs, &files[i], wbuf, SIZE) => SIZE;
|
||||||
|
}
|
||||||
|
for (lfs_size_t i = 0; i < N; i++) {
|
||||||
|
lfsr_file_close(&lfs, &files[i]) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calling lfsr_fs_mkconsistent should clean things up
|
||||||
|
lfsr_fs_mkconsistent(&lfs) => 0;
|
||||||
|
|
||||||
|
// we should have cleaned up all grms/orphans
|
||||||
|
assert(lfs.grm.mids[0] == -1);
|
||||||
|
assert(lfs.grm.mids[1] == -1);
|
||||||
|
assert(lfs.hasorphans == false);
|
||||||
|
|
||||||
|
// double check the actual disk state, it's easy for littlefs to
|
||||||
|
// lie here
|
||||||
|
assert(lfsr_mtree_weight(&lfs)
|
||||||
|
<= ((1+lfs_popc(BOOKENDS)) << lfs.mdir_bits));
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_mtree_lookup(&lfs, 0, &mdir) => 0;
|
||||||
|
assert(mdir.rbyd.weight <= 1+lfs_popc(BOOKENDS));
|
||||||
|
|
||||||
|
// check that other files are unaffected
|
||||||
|
for (int remount = 0; remount < 2; remount++) {
|
||||||
|
if (remount) {
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_close(&lfs, &bookend_files[0]) => 0;
|
||||||
|
}
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_close(&lfs, &bookend_files[1]) => 0;
|
||||||
|
}
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
lfsr_mount(&lfs, CFG) => 0;
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_open(&lfs, &bookend_files[0], "aatman",
|
||||||
|
LFS_O_RDONLY) => 0;
|
||||||
|
}
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_open(&lfs, &bookend_files[1], "catman",
|
||||||
|
LFS_O_RDONLY) => 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_rewind(&lfs, &bookend_files[0]) => 0;
|
||||||
|
uint32_t prng_ = bookend_prngs[0];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
uint8_t rbuf[SIZE];
|
||||||
|
lfsr_file_read(&lfs, &bookend_files[0], rbuf, SIZE) => SIZE;
|
||||||
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_rewind(&lfs, &bookend_files[1]) => 0;
|
||||||
|
uint32_t prng_ = bookend_prngs[1];
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
uint8_t rbuf[SIZE];
|
||||||
|
lfsr_file_read(&lfs, &bookend_files[1], rbuf, SIZE) => SIZE;
|
||||||
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOKENDS & 0x1) {
|
||||||
|
lfsr_file_close(&lfs, &bookend_files[0]);
|
||||||
|
}
|
||||||
|
if (BOOKENDS & 0x2) {
|
||||||
|
lfsr_file_close(&lfs, &bookend_files[1]);
|
||||||
|
}
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# these doesn't really involve scratch files, but we might as well test
|
# these doesn't really involve scratch files, but we might as well test
|
||||||
# them here
|
# them here
|
||||||
[cases.test_forphans_mv]
|
[cases.test_forphans_mv]
|
||||||
|
|||||||
Reference in New Issue
Block a user