gc: Made CKMETA/CKDATA progressable, added lfsr_gc_unck
LFS_GC_CKMETA and LFS_GC_CKDATA are a bit unique in that their work is
never really done.
Where LFS_GC_MKCONSISTENT/COMPACT can prove things about the system,
LFS_GC_CKMETA/CKDATA can't, because it's always possible for new
bit-errors to develop. Even _during_ an LFS_GC_CKMETA/CKDATA traversal.
But while this is technically true, it's not a very useful state of
things for our lfsr_gc API...
---
What we really want is some way to know if ckmeta/ckdata has completed
"recently" (for some definition of recently), and to let users indicate
when they need another ckmeta/ckdata scan.
To try to solve this:
1. Added LFS_I_CANCKMETA and LFS_I_CANCKDATA to indicate when lfsr_gc
has not checked metadata/data.
These are set during mount (unless mounting with
LFS_M_CKMETA/CKDATA), and cleared when either lfsr_gc completes or
lfsr_fs_ckmeta/data is called. Once cleared, littlefs will not reset
them on its own.
2. Added lfsr_gc_unck to allow users to explicitly reset LFS_I_CKMETA
and/or LFS_I_CKDATA, which will tell lfsr_gc to check metadata/data
again on the next call.
There is some subtlety around clobbering ongoing traversals, but a
mask and some tests should prevent this from being a problem.
Currently, lfsr_gc_unck also allows clearing of other gc flags, but
I'm not sure there's any real use-case for this...
Note that you can still get the previous behavior if you just call
lfsr_gc_unck after every lfsr_gc call.
This also changes info flag behavior slightly in default mode, with
LFS_I_CANCKMETA/CANCKDATA telling you if metadata/data has been checked
since mount. Which does seem useful? Maybe these flags deserve a better
name?
Code changes:
code stack ctx
default before: 37796 (+0.0%) 2608 (+0.0%) 620 (+0.0%)
default after: 37792 (+0.0%) 2608 (+0.0%) 620 (+0.0%)
gc before: 37896 2608 768
gc after: 37938 (+0.1%) 2608 (+0.0%) 768 (+0.0.%)
This commit is contained in:
@@ -1045,6 +1045,305 @@ code = '''
|
||||
done:;
|
||||
'''
|
||||
|
||||
# test we can detect fully clobbered blocks after a ck pass, if we call
|
||||
# lfsr_gc_unck
|
||||
[cases.test_gc_ckmeta_unck]
|
||||
# AFTER=0 => after running lfsr_gc once
|
||||
# AFTER=1 => after running lfsr_gc to completion
|
||||
# AFTER=2 => after lfsr_fs_ckmeta
|
||||
# AFTER=3 => after remounting with LFS_M_CKMETA
|
||||
defines.AFTER = [0, 1, 2, 3]
|
||||
defines.GC_FLAGS = 'LFS_GC_CKMETA'
|
||||
defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000]
|
||||
defines.N = [1, 2, 4, 8, 16, 32, 64]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
'FILE_BUFFER_SIZE/2',
|
||||
'2*FILE_BUFFER_SIZE',
|
||||
'BLOCK_SIZE/2',
|
||||
'BLOCK_SIZE',
|
||||
'2*BLOCK_SIZE',
|
||||
'8*BLOCK_SIZE',
|
||||
]
|
||||
if = '(SIZE*N)/BLOCK_SIZE <= 32'
|
||||
ifdef = 'LFS_GC'
|
||||
code = '''
|
||||
lfs_block_t i = 0;
|
||||
while (true) {
|
||||
// a bit hacky, but this catches infinite loops
|
||||
assert(i < 2*BLOCK_COUNT);
|
||||
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||
|
||||
// create an interesting filesystem
|
||||
uint32_t prng = 42;
|
||||
for (lfs_size_t i = 0; i < N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "squid%03x", i);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
||||
}
|
||||
|
||||
lfsr_file_t file;
|
||||
lfsr_file_open(&lfs, &file, name,
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||
lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE;
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
|
||||
// run lfsr_gc before clobbering, this should not find anything
|
||||
|
||||
// run lfsr_gc once
|
||||
if (AFTER == 0) {
|
||||
lfsr_gc(&lfs) => 0;
|
||||
|
||||
// run lfsr_gc to completion
|
||||
} else if (AFTER == 1) {
|
||||
while (true) {
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfsr_fs_stat(&lfs, &fsinfo) => 0;
|
||||
if (!(fsinfo.flags & LFS_I_CANCKMETA)) {
|
||||
break;
|
||||
}
|
||||
|
||||
lfsr_gc(&lfs) => 0;
|
||||
}
|
||||
|
||||
// run lfsr_fs_ckmeta
|
||||
} else if (AFTER == 2) {
|
||||
lfsr_fs_ckmeta(&lfs) => 0;
|
||||
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfsr_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(!(fsinfo.flags & LFS_I_CANCKMETA));
|
||||
|
||||
// remount with LFS_M_CKMETA
|
||||
} else if (AFTER == 3) {
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKMETA, CFG) => 0;
|
||||
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfsr_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(!(fsinfo.flags & LFS_I_CANCKMETA));
|
||||
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// traverse to find blocks
|
||||
lfsr_traversal_t t;
|
||||
lfsr_traversal_open(&lfs, &t, 0) => 0;
|
||||
lfs_block_t k = 0;
|
||||
for (lfs_block_t j = 0;; j++) {
|
||||
assert(j < 2*BLOCK_COUNT);
|
||||
|
||||
struct lfs_tinfo tinfo;
|
||||
int err = lfsr_traversal_read(&lfs, &t, &tinfo);
|
||||
assert(!err || err == LFS_ERR_NOENT);
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
lfsr_traversal_close(&lfs, &t) => 0;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// this gets a bit tricky be cause we need to clobber both
|
||||
// blocks in mdir pairs
|
||||
if (tinfo.btype == LFS_BTYPE_MDIR
|
||||
|| tinfo.btype == LFS_BTYPE_BTREE) {
|
||||
if (k == i || k == i+1) {
|
||||
// clobber this block
|
||||
printf("clobbering 0x%x\n", tinfo.block);
|
||||
uint8_t clobber_buf[BLOCK_SIZE];
|
||||
memset(clobber_buf, 0xcc, BLOCK_SIZE);
|
||||
CFG->erase(CFG, tinfo.block) => 0;
|
||||
CFG->prog(CFG, tinfo.block, 0,
|
||||
clobber_buf, BLOCK_SIZE) => 0;
|
||||
if (tinfo.btype != LFS_BTYPE_MDIR || k == i+1) {
|
||||
i += (tinfo.btype == LFS_BTYPE_MDIR) ? 2 : 1;
|
||||
lfsr_traversal_close(&lfs, &t) => 0;
|
||||
goto clobbered;
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
|
||||
clobbered:;
|
||||
// clear relevant ck flags
|
||||
lfsr_gc_unck(&lfs, LFS_I_CANCKMETA) => 0;
|
||||
|
||||
// running lfsr_gc should eventually find the clobbered block
|
||||
for (lfs_block_t i = 0;; i++) {
|
||||
// a bit hacky, but this catches infinite loops
|
||||
LFS_ASSERT(i < 2*BLOCK_COUNT);
|
||||
|
||||
int err = lfsr_gc(&lfs);
|
||||
assert(!err || err == LFS_ERR_CORRUPT);
|
||||
// found it
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
}
|
||||
done:;
|
||||
'''
|
||||
|
||||
[cases.test_gc_ckdata_unck]
|
||||
# AFTER=0 => after running lfsr_gc once
|
||||
# AFTER=1 => after running lfsr_gc to completion
|
||||
# AFTER=2 => after lfsr_fs_ckdata
|
||||
# AFTER=3 => after remounting with LFS_M_CKDATA
|
||||
defines.AFTER = [0, 1, 2]
|
||||
defines.GC_FLAGS = 'LFS_GC_CKDATA'
|
||||
defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000]
|
||||
defines.N = [1, 2, 4, 8, 16, 32, 64]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
'FILE_BUFFER_SIZE/2',
|
||||
'2*FILE_BUFFER_SIZE',
|
||||
'BLOCK_SIZE/2',
|
||||
'BLOCK_SIZE',
|
||||
'2*BLOCK_SIZE',
|
||||
'8*BLOCK_SIZE',
|
||||
]
|
||||
if = '(SIZE*N)/BLOCK_SIZE <= 32'
|
||||
ifdef = 'LFS_GC'
|
||||
code = '''
|
||||
lfs_block_t i = 0;
|
||||
while (true) {
|
||||
// a bit hacky, but this catches infinite loops
|
||||
assert(i < 2*BLOCK_COUNT);
|
||||
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||
|
||||
// create an interesting filesystem
|
||||
uint32_t prng = 42;
|
||||
for (lfs_size_t i = 0; i < N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "squid%03x", i);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
||||
}
|
||||
|
||||
lfsr_file_t file;
|
||||
lfsr_file_open(&lfs, &file, name,
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||
lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE;
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
|
||||
// run lfsr_gc before clobbering, this should not find anything
|
||||
|
||||
// run lfsr_gc once
|
||||
if (AFTER == 0) {
|
||||
lfsr_gc(&lfs) => 0;
|
||||
|
||||
// run lfsr_gc to completion
|
||||
} else if (AFTER == 1) {
|
||||
while (true) {
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfsr_fs_stat(&lfs, &fsinfo) => 0;
|
||||
if (!(fsinfo.flags & LFS_I_CANCKDATA)) {
|
||||
break;
|
||||
}
|
||||
|
||||
lfsr_gc(&lfs) => 0;
|
||||
}
|
||||
|
||||
// run lfsr_fs_ckdata
|
||||
} else if (AFTER == 2) {
|
||||
lfsr_fs_ckdata(&lfs) => 0;
|
||||
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfsr_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(!(fsinfo.flags & LFS_I_CANCKDATA));
|
||||
|
||||
// remount with LFS_M_CKDATA
|
||||
} else if (AFTER == 3) {
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKDATA, CFG) => 0;
|
||||
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfsr_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(!(fsinfo.flags & LFS_I_CANCKDATA));
|
||||
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// traverse to find blocks
|
||||
lfsr_traversal_t t;
|
||||
lfsr_traversal_open(&lfs, &t, 0) => 0;
|
||||
lfs_block_t k = 0;
|
||||
for (lfs_block_t j = 0;; j++) {
|
||||
assert(j < 2*BLOCK_COUNT);
|
||||
|
||||
struct lfs_tinfo tinfo;
|
||||
int err = lfsr_traversal_read(&lfs, &t, &tinfo);
|
||||
assert(!err || err == LFS_ERR_NOENT);
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
lfsr_traversal_close(&lfs, &t) => 0;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// this gets a bit tricky be cause we need to clobber both
|
||||
// blocks in mdir pairs
|
||||
if (tinfo.btype == LFS_BTYPE_MDIR
|
||||
|| tinfo.btype == LFS_BTYPE_BTREE
|
||||
|| tinfo.btype == LFS_BTYPE_DATA) {
|
||||
if (k == i || k == i+1) {
|
||||
// clobber this block
|
||||
printf("clobbering 0x%x\n", tinfo.block);
|
||||
uint8_t clobber_buf[BLOCK_SIZE];
|
||||
memset(clobber_buf, 0xcc, BLOCK_SIZE);
|
||||
CFG->erase(CFG, tinfo.block) => 0;
|
||||
CFG->prog(CFG, tinfo.block, 0,
|
||||
clobber_buf, BLOCK_SIZE) => 0;
|
||||
if (tinfo.btype != LFS_BTYPE_MDIR || k == i+1) {
|
||||
i += (tinfo.btype == LFS_BTYPE_MDIR) ? 2 : 1;
|
||||
lfsr_traversal_close(&lfs, &t) => 0;
|
||||
goto clobbered;
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
|
||||
clobbered:;
|
||||
// clear relevant ck flags
|
||||
lfsr_gc_unck(&lfs, LFS_I_CANCKDATA) => 0;
|
||||
|
||||
// running lfsr_gc should eventually find the clobbered block
|
||||
//
|
||||
// note LFS_GC_CKDATA implies LFS_GC_CKMETA
|
||||
for (lfs_block_t i = 0;; i++) {
|
||||
// a bit hacky, but this catches infinite loops
|
||||
LFS_ASSERT(i < 2*BLOCK_COUNT);
|
||||
|
||||
int err = lfsr_gc(&lfs);
|
||||
assert(!err || err == LFS_ERR_CORRUPT);
|
||||
// found it
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
}
|
||||
done:;
|
||||
'''
|
||||
|
||||
|
||||
# pseudo-fuzz test that dirtying still works with the GC API
|
||||
[cases.test_gc_mutation]
|
||||
@@ -1115,6 +1414,79 @@ code = '''
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# pseudo-fuzz test that spamming lfsr_gc_unck doesn't break anything
|
||||
[cases.test_gc_mutation_unck]
|
||||
defines.N = 100
|
||||
defines.MKCONSISTENT = [false, true]
|
||||
defines.LOOKAHEAD = [false, true]
|
||||
defines.COMPACT = [false, true]
|
||||
defines.CKMETA = [false, true]
|
||||
defines.CKDATA = [false, true]
|
||||
defines.GC_FLAGS = '''
|
||||
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
|
||||
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
|
||||
| ((COMPACT) ? LFS_GC_COMPACT : 0)
|
||||
| ((CKMETA) ? LFS_GC_CKMETA : 0)
|
||||
| ((CKDATA) ? LFS_GC_CKDATA : 0)
|
||||
'''
|
||||
defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000]
|
||||
# set compact thresh to minimum
|
||||
defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2'
|
||||
defines.SIZE = [
|
||||
'FILE_BUFFER_SIZE/2',
|
||||
'2*FILE_BUFFER_SIZE',
|
||||
'BLOCK_SIZE/2',
|
||||
'BLOCK_SIZE',
|
||||
'2*BLOCK_SIZE',
|
||||
'8*BLOCK_SIZE',
|
||||
]
|
||||
ifdef = 'LFS_GC'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||
|
||||
uint32_t prng = 42;
|
||||
|
||||
// create a file
|
||||
lfsr_file_t file;
|
||||
lfsr_file_open(&lfs, &file, "spider",
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 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;
|
||||
|
||||
for (uint32_t i = 0; i < N; i++) {
|
||||
// rewrite the file every gc cycle
|
||||
lfsr_file_open(&lfs, &file, "spider",
|
||||
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
|
||||
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;
|
||||
|
||||
// choose a random set of flags to unck every cycle
|
||||
uint32_t flags = GC_FLAGS & TEST_PRNG(&prng);
|
||||
lfsr_gc_unck(&lfs, flags) => 0;
|
||||
|
||||
// gc!
|
||||
lfsr_gc(&lfs) => 0;
|
||||
}
|
||||
|
||||
// check the file contents
|
||||
lfsr_file_open(&lfs, &file, "spider", LFS_O_RDONLY) => 0;
|
||||
uint8_t rbuf[SIZE];
|
||||
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
|
||||
|
||||
# many/fuzz tests mixed with GC
|
||||
@@ -1126,6 +1498,7 @@ defines.LOOKAHEAD = [false, true]
|
||||
defines.COMPACT = [false, true]
|
||||
defines.CKMETA = [false, true]
|
||||
defines.CKDATA = [false, true]
|
||||
defines.UNCK = [false, true]
|
||||
defines.GC_FLAGS = '''
|
||||
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
|
||||
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
|
||||
@@ -1153,6 +1526,11 @@ code = '''
|
||||
|
||||
// gc!
|
||||
lfsr_gc(&lfs) => 0;
|
||||
|
||||
// unck to keep things interesting?
|
||||
if (UNCK) {
|
||||
lfsr_gc_unck(&lfs, LFS_I_CANCKMETA | LFS_I_CANCKDATA) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
@@ -1224,6 +1602,7 @@ defines.LOOKAHEAD = [false, true]
|
||||
defines.COMPACT = [false, true]
|
||||
defines.CKMETA = [false, true]
|
||||
defines.CKDATA = [false, true]
|
||||
defines.UNCK = [false, true]
|
||||
defines.GC_FLAGS = '''
|
||||
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
|
||||
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
|
||||
@@ -1334,6 +1713,11 @@ code = '''
|
||||
|
||||
// gc!
|
||||
lfsr_gc(&lfs) => 0;
|
||||
|
||||
// unck to keep things interesting?
|
||||
if (UNCK) {
|
||||
lfsr_gc_unck(&lfs, LFS_I_CANCKMETA | LFS_I_CANCKDATA) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
@@ -1393,6 +1777,7 @@ defines.LOOKAHEAD = [false, true]
|
||||
defines.COMPACT = [false, true]
|
||||
defines.CKMETA = [false, true]
|
||||
defines.CKDATA = [false, true]
|
||||
defines.UNCK = [false, true]
|
||||
defines.GC_FLAGS = '''
|
||||
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
|
||||
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
|
||||
@@ -1440,6 +1825,11 @@ code = '''
|
||||
|
||||
// gc!
|
||||
lfsr_gc(&lfs) => 0;
|
||||
|
||||
// unck to keep things interesting?
|
||||
if (UNCK) {
|
||||
lfsr_gc_unck(&lfs, LFS_I_CANCKMETA | LFS_I_CANCKDATA) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
@@ -1485,6 +1875,7 @@ defines.LOOKAHEAD = [false, true]
|
||||
defines.COMPACT = [false, true]
|
||||
defines.CKMETA = [false, true]
|
||||
defines.CKDATA = [false, true]
|
||||
defines.UNCK = [false, true]
|
||||
defines.GC_FLAGS = '''
|
||||
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
|
||||
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
|
||||
@@ -1642,6 +2033,11 @@ code = '''
|
||||
|
||||
// gc!
|
||||
lfsr_gc(&lfs) => 0;
|
||||
|
||||
// unck to keep things interesting?
|
||||
if (UNCK) {
|
||||
lfsr_gc_unck(&lfs, LFS_I_CANCKMETA | LFS_I_CANCKDATA) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
@@ -1716,6 +2112,7 @@ defines.LOOKAHEAD = [false, true]
|
||||
defines.COMPACT = [false, true]
|
||||
defines.CKMETA = [false, true]
|
||||
defines.CKDATA = [false, true]
|
||||
defines.UNCK = [false, true]
|
||||
defines.GC_FLAGS = '''
|
||||
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
|
||||
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
|
||||
@@ -1809,6 +2206,11 @@ code = '''
|
||||
|
||||
// gc!
|
||||
lfsr_gc(&lfs) => 0;
|
||||
|
||||
// unck to keep things interesting?
|
||||
if (UNCK) {
|
||||
lfsr_gc_unck(&lfs, LFS_I_CANCKMETA | LFS_I_CANCKDATA) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
@@ -1867,6 +2269,7 @@ defines.LOOKAHEAD = [false, true]
|
||||
defines.COMPACT = [false, true]
|
||||
defines.CKMETA = [false, true]
|
||||
defines.CKDATA = [false, true]
|
||||
defines.UNCK = [false, true]
|
||||
defines.GC_FLAGS = '''
|
||||
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
|
||||
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
|
||||
@@ -2142,6 +2545,11 @@ code = '''
|
||||
|
||||
// gc!
|
||||
lfsr_gc(&lfs) => 0;
|
||||
|
||||
// unck to keep things interesting?
|
||||
if (UNCK) {
|
||||
lfsr_gc_unck(&lfs, LFS_I_CANCKMETA | LFS_I_CANCKDATA) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check that disk matches our simulation
|
||||
@@ -2226,6 +2634,7 @@ defines.LOOKAHEAD = [false, true]
|
||||
defines.COMPACT = [false, true]
|
||||
defines.CKMETA = [false, true]
|
||||
defines.CKDATA = [false, true]
|
||||
defines.UNCK = [false, true]
|
||||
defines.GC_FLAGS = '''
|
||||
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
|
||||
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
|
||||
@@ -2563,6 +2972,11 @@ code = '''
|
||||
|
||||
// gc!
|
||||
lfsr_gc(&lfs) => 0;
|
||||
|
||||
// unck to keep things interesting?
|
||||
if (UNCK) {
|
||||
lfsr_gc_unck(&lfs, LFS_I_CANCKMETA | LFS_I_CANCKDATA) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check that disk matches our simulation
|
||||
|
||||
Reference in New Issue
Block a user