Implemented ckcksums
Since we already need all the machinery to track ck info for ckparity, I
figured we might as well implement a full ckcksums option as well.
Ckcksums closes the checksum-read-hole by reading enough data to check a
relevant checksum on ever read, even if this ends up being significantly
more data than the initial request. This should always detect detectable
bit-errors, even if they occur between consecutive reads.
If this sounds naive, that's because it is. Performance will be awful.
To be clear, ckcksums should probably never be used in production. I
can't think of a use case that isn't better handled by either ECC in the
block device or the future-planned ckredund feature. Just look at the
runtime complexities:
small-reads rbyd-lookup rbyd-compaction
ckcksums: O(b^2) O(b log b) O(b^2 log b)
ckredund*: O(log_b(n) + xb) O(log b) O(b log b)
eccbd*: O(b) O(log b) O(b log b)
* theoretical
We've already seen that O(b^2) compactions turns a performance problem
into a tractability problem, so I think O(b^2 log b) compactions will be
a bit too much for most applications.
We can already seen this in our test_ck_ckcksums_* tests (which do pass
by the way!). Compare to test_ck_ckprogs_*, which is basically the same
set of tests:
test_ck_ckprogs_*: 6.08s
test_ck_ckcksums_*: 64.88s
Or consider test_rbyd with/without ckcksums:
test_rbyd: 12.21s
test_rbyd+ckcksums: 389.94s
Still, ckcksums is an interesting proof-of-concept, and does manage to
close the checksum-read-hole.
---
Like ckprogs/ckfetches/ckparity/etc, ckcksums is an opt-in feature,
requiring both 1. defining LFS_CKCKSUMS and 2. passing LFS_M_CKCKSUMS at
mount time.
Like ckparity, ckcksums requires a significant code and stack increase
to track ck info in lfsr_data_t:
code stack
before: 36416 2616
yes-ckcksums: 38872 (+6.7%) 3176 (+21.4%)
no-ckcksums: 36416 (+0.0%) 2616 (+0.0%)
It's interesting to note how this compares to all of the current
ck-modes, though each has their own set of tradeoffs:
code stack
default: 36416 2616
ckprogs: 36468 (+0.1%) 2616 (+0.0%)
ckfetches: 36666 (+0.7%) 2648 (+1.2%)
ckparity: 37996 (+4.3%) 3040 (+16.2%)
ckcksums: 38872 (+6.7%) 3176 (+21.4%)
---
Note that even though ckcksums is opt-in, it may still be worth removing
from the codebase in the future, for a couple reasons:
- Every feature, even if unused, adds developer/maintenance burden.
- Ck info is particularly messy with how it interacts with all
lfsr_data_t APIs. Though getting rid of ck info would also require
getting rid of ckparity.
- It's possible for a user to see ckcksums in the codebase,
misunderstand its tradeoffs, enable it, and get the impression that
littlefs itself is just unusably slow.
This commit is contained in:
@@ -162,6 +162,9 @@ enum lfs_type {
|
||||
#ifdef LFS_CKPARITY
|
||||
#define LFS_F_CKPARITY 0x00400000 // Check tag parity bits on reads
|
||||
#endif
|
||||
#ifdef LFS_CKCKSUMS
|
||||
#define LFS_F_CKCKSUMS 0x00800000 // Check checksums on reads (expensive!)
|
||||
#endif
|
||||
|
||||
#define LFS_F_MTREEONLY 0x00000800 // Only traverse the mtree
|
||||
#define LFS_F_COMPACT 0x00008000 // Compact metadata logs
|
||||
@@ -182,6 +185,9 @@ enum lfs_type {
|
||||
#ifdef LFS_CKPARITY
|
||||
#define LFS_M_CKPARITY 0x00400000 // Check tag parity bits on reads
|
||||
#endif
|
||||
#ifdef LFS_CKCKSUMS
|
||||
#define LFS_M_CKCKSUMS 0x00800000 // Check checksums on reads (expensive!)
|
||||
#endif
|
||||
|
||||
#define LFS_M_MTREEONLY 0x00000800 // Only traverse the mtree
|
||||
#define LFS_M_MKCONSISTENT \
|
||||
@@ -204,6 +210,9 @@ enum lfs_type {
|
||||
#ifdef LFS_CKPARITY
|
||||
#define LFS_I_CKPARITY 0x00400000 // Filesystem mounted with LFS_M_CKPARITY
|
||||
#endif
|
||||
#ifdef LFS_CKCKSUMS
|
||||
#define LFS_I_CKCKSUMS 0x00800000 // Filesystem mounted with LFS_M_CKCKSUMS
|
||||
#endif
|
||||
|
||||
#define LFS_I_INCONSISTENT \
|
||||
0x01000000 // Filesystem needs mkconsistent to write
|
||||
@@ -559,7 +568,7 @@ typedef struct lfsr_omdir {
|
||||
// lfs_block_t tail[2];
|
||||
//} lfs_mdir_t;
|
||||
|
||||
#ifdef LFS_CKPARITY
|
||||
#if defined(LFS_CKPARITY) || defined(LFS_CKCKSUMS)
|
||||
// context for validating data
|
||||
typedef struct lfsr_ck {
|
||||
// sign(cksize)=0 => cksum check
|
||||
@@ -583,7 +592,7 @@ typedef struct lfsr_data {
|
||||
struct {
|
||||
lfs_block_t block;
|
||||
lfs_size_t off;
|
||||
#ifdef LFS_CKPARITY
|
||||
#if defined(LFS_CKPARITY) || defined(LFS_CKCKSUMS)
|
||||
lfsr_ck_t ck;
|
||||
#endif
|
||||
} disk;
|
||||
@@ -758,11 +767,11 @@ typedef struct lfsr_grm {
|
||||
lfsr_smid_t mids[2];
|
||||
} lfsr_grm_t;
|
||||
|
||||
#ifdef LFS_CKPARITY
|
||||
#if defined(LFS_CKPARITY) || defined(LFS_CKCKSUMS)
|
||||
typedef struct lfsr_tailck {
|
||||
lfs_block_t ckblock;
|
||||
// sign(ckoff) => tail parity
|
||||
lfs_size_t ckoff;
|
||||
uint32_t cksum;
|
||||
} lfsr_tailck_t;
|
||||
#endif
|
||||
|
||||
@@ -798,7 +807,7 @@ typedef struct lfs {
|
||||
uint8_t *buffer;
|
||||
} pcache;
|
||||
|
||||
#ifdef LFS_CKPARITY
|
||||
#if defined(LFS_CKPARITY) || defined(LFS_CKCKSUMS)
|
||||
lfsr_tailck_t tailck;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -156,6 +156,12 @@ extern "C"
|
||||
#define LFS_IFDEF_CKPARITY(a, b) (b)
|
||||
#endif
|
||||
|
||||
#ifdef LFS_CKCKSUMS
|
||||
#define LFS_IFDEF_CKCKSUMS(a, b) (a)
|
||||
#else
|
||||
#define LFS_IFDEF_CKCKSUMS(a, b) (b)
|
||||
#endif
|
||||
|
||||
|
||||
// Builtin functions, these may be replaced by more efficient
|
||||
// toolchain-specific implementations. LFS_NO_BUILTINS falls back to a more
|
||||
|
||||
+436
-22
@@ -1095,7 +1095,7 @@ code = '''
|
||||
# will make them more useful.
|
||||
#
|
||||
|
||||
# test every single-bit error in block 0/1
|
||||
# test some single-bit errors in block 0/1
|
||||
[cases.test_ck_ckparity_mroot]
|
||||
defines.BADBLOCK = [0, 1]
|
||||
defines.BADBIT = -1
|
||||
@@ -1208,7 +1208,7 @@ code = '''
|
||||
}
|
||||
'''
|
||||
|
||||
# test every single-bit error in a file's btree node
|
||||
# test some single-bit errors in a file's btree node
|
||||
[cases.test_ck_ckparity_btree]
|
||||
defines.BADBIT = -1
|
||||
defines.BADBLOCK_BEHAVIOR = [
|
||||
@@ -1346,6 +1346,386 @@ code = '''
|
||||
|
||||
|
||||
|
||||
# Some simple ckcksums tests
|
||||
|
||||
# test every single-bit error in block 0/1
|
||||
[cases.test_ck_ckcksums_mroot]
|
||||
defines.BADBLOCK = [0, 1]
|
||||
defines.BADBIT = -1
|
||||
defines.BADBLOCK_BEHAVIOR = [
|
||||
'LFS_EMUBD_BADBLOCK_PROGFLIP',
|
||||
'LFS_EMUBD_BADBLOCK_READFLIP',
|
||||
]
|
||||
# this should stay inlined
|
||||
defines.SIZE = 'BLOCK_SIZE/16'
|
||||
ifdef = 'LFS_CKCKSUMS'
|
||||
code = '''
|
||||
// test all bad bits in the mroot
|
||||
for (lfs_size_t i = 0;
|
||||
i < ((BADBIT == -1) ? 8*BLOCK_SIZE : 1);
|
||||
i++) {
|
||||
lfs_size_t badbit = (BADBIT == -1) ? i : BADBIT;
|
||||
|
||||
// reset the bd prng every run for reproducibility
|
||||
lfs_emubd_seed(CFG, 42);
|
||||
printf("--- badblock: 0x%x.%x, badbit: 0x%x (0x%x+%x) ---\n",
|
||||
(lfs_size_t)BADBLOCK, badbit/8, badbit, badbit/8, badbit%8);
|
||||
|
||||
// mark our badbit as bad
|
||||
lfs_emubd_markbadbit(CFG, BADBLOCK, badbit) => 0;
|
||||
|
||||
// With metastability, basically any filesystem operation can
|
||||
// return LFS_ERR_CORRUPT. This is ok, what we're really testing
|
||||
// for is no internal/external asserts failing.
|
||||
|
||||
// format
|
||||
lfs_t lfs;
|
||||
int err = lfsr_format(&lfs, LFS_M_RDWR | LFS_M_CKCKSUMS, CFG);
|
||||
assert(!err || err == LFS_ERR_CORRUPT);
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto corrupt;
|
||||
}
|
||||
err = lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKCKSUMS, CFG);
|
||||
assert(!err || err == LFS_ERR_CORRUPT);
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto corrupt;
|
||||
}
|
||||
|
||||
{
|
||||
// create a file
|
||||
lfsr_file_t file;
|
||||
err = lfsr_file_open(&lfs, &file, "bathykorus",
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL);
|
||||
assert(!err || err == LFS_ERR_CORRUPT);
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
uint32_t prng = 42;
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
||||
}
|
||||
lfs_ssize_t res = lfsr_file_write(&lfs, &file, wbuf, SIZE);
|
||||
assert(res == SIZE || res == LFS_ERR_CORRUPT);
|
||||
if (res == LFS_ERR_CORRUPT) {
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
err = lfsr_file_close(&lfs, &file);
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
|
||||
// try to read our file
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
// remount?
|
||||
if (remount) {
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
err = lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKCKSUMS, CFG);
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto corrupt;
|
||||
}
|
||||
}
|
||||
|
||||
// yes reads can fail here
|
||||
err = lfsr_file_open(&lfs, &file, "bathykorus", LFS_O_RDONLY);
|
||||
assert(!err
|
||||
|| err == LFS_ERR_CORRUPT
|
||||
// bit errors can also cause our fs state to "rollback",
|
||||
// which is not great but we can't solve this with ckreads
|
||||
// alone
|
||||
|| err == LFS_ERR_NOENT);
|
||||
if (err == LFS_ERR_CORRUPT || err == LFS_ERR_NOENT) {
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
uint8_t rbuf[SIZE];
|
||||
lfs_ssize_t res = lfsr_file_read(&lfs, &file, rbuf, SIZE);
|
||||
assert(res == SIZE || res == LFS_ERR_CORRUPT);
|
||||
if (res == LFS_ERR_CORRUPT) {
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
corrupt_mounted:;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
|
||||
corrupt:;
|
||||
// reset badbit
|
||||
lfs_emubd_markgood(CFG, BADBLOCK) => 0;
|
||||
}
|
||||
'''
|
||||
|
||||
# test every single-bit error in a file's data block
|
||||
[cases.test_ck_ckcksums_data]
|
||||
defines.BADBIT = -1
|
||||
defines.BADBLOCK_BEHAVIOR = [
|
||||
'LFS_EMUBD_BADBLOCK_PROGFLIP',
|
||||
'LFS_EMUBD_BADBLOCK_READFLIP',
|
||||
]
|
||||
# this should create a single block file
|
||||
defines.SIZE = 'BLOCK_SIZE'
|
||||
ifdef = 'LFS_CKCKSUMS'
|
||||
code = '''
|
||||
// first we need to figure out where the data block will actually
|
||||
// end up, fortunately our block randomization is intentionally
|
||||
// consistent
|
||||
|
||||
// format
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKCKSUMS, CFG) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKCKSUMS, CFG) => 0;
|
||||
|
||||
// create a file
|
||||
lfsr_file_t file;
|
||||
lfsr_file_open(&lfs, &file, "bathykorus",
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||
uint32_t prng = 42;
|
||||
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;
|
||||
|
||||
// find the data block
|
||||
lfsr_traversal_t t;
|
||||
lfsr_traversal_open(&lfs, &t, 0) => 0;
|
||||
lfs_block_t badblock;
|
||||
while (true) {
|
||||
struct lfs_tinfo tinfo;
|
||||
lfsr_traversal_read(&lfs, &t, &tinfo) => 0;
|
||||
if (tinfo.btype == LFS_BTYPE_DATA) {
|
||||
badblock = tinfo.block;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lfsr_traversal_close(&lfs, &t) => 0;
|
||||
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
|
||||
// now test all bad bits in the data block
|
||||
for (lfs_size_t i = 0;
|
||||
i < ((BADBIT == -1) ? 8*BLOCK_SIZE : 1);
|
||||
i++) {
|
||||
lfs_size_t badbit = (BADBIT == -1) ? i : BADBIT;
|
||||
|
||||
// reset the bd prng every run for reproducibility
|
||||
lfs_emubd_seed(CFG, 42);
|
||||
printf("--- badblock: 0x%x.%x, badbit: 0x%x (0x%x+%x) ---\n",
|
||||
badblock, badbit/8, badbit, badbit/8, badbit%8);
|
||||
|
||||
// mark our badbit as bad
|
||||
lfs_emubd_markbadbit(CFG, badblock, badbit) => 0;
|
||||
|
||||
// With metastability, basically any filesystem operation can
|
||||
// return LFS_ERR_CORRUPT. This is ok, what we're really testing
|
||||
// for is no internal/external asserts failing.
|
||||
|
||||
// format
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKCKSUMS, CFG) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKCKSUMS, CFG) => 0;
|
||||
|
||||
{
|
||||
// create a file
|
||||
lfsr_file_t file;
|
||||
lfsr_file_open(&lfs, &file, "bathykorus",
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||
uint32_t prng = 42;
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
||||
}
|
||||
lfs_ssize_t res = lfsr_file_write(&lfs, &file, wbuf, SIZE);
|
||||
assert(res == SIZE || res == LFS_ERR_CORRUPT);
|
||||
if (res == LFS_ERR_CORRUPT) {
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
int err = lfsr_file_close(&lfs, &file);
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
|
||||
// try to read our file
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
// remount?
|
||||
if (remount) {
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKCKSUMS, CFG) => 0;
|
||||
}
|
||||
|
||||
// yes reads can fail here
|
||||
err = lfsr_file_open(&lfs, &file, "bathykorus", LFS_O_RDONLY);
|
||||
assert(!err
|
||||
|| err == LFS_ERR_CORRUPT
|
||||
// bit errors can also cause our fs state to "rollback",
|
||||
// which is not great but we can't solve this with ckreads
|
||||
// alone
|
||||
|| err == LFS_ERR_NOENT);
|
||||
if (err == LFS_ERR_CORRUPT || err == LFS_ERR_NOENT) {
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
uint8_t rbuf[SIZE];
|
||||
lfs_ssize_t res = lfsr_file_read(&lfs, &file, rbuf, SIZE);
|
||||
assert(res == SIZE || res == LFS_ERR_CORRUPT);
|
||||
if (res == LFS_ERR_CORRUPT) {
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
corrupt_mounted:;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
|
||||
// reset badbit
|
||||
lfs_emubd_markgood(CFG, badblock) => 0;
|
||||
}
|
||||
'''
|
||||
|
||||
# test every single-bit error in a file's btree node
|
||||
[cases.test_ck_ckcksums_btree]
|
||||
defines.BADBIT = -1
|
||||
defines.BADBLOCK_BEHAVIOR = [
|
||||
'LFS_EMUBD_BADBLOCK_PROGFLIP',
|
||||
'LFS_EMUBD_BADBLOCK_READFLIP',
|
||||
]
|
||||
# force the file to create a btree
|
||||
defines.INLINE_SIZE = 0
|
||||
defines.CRYSTAL_THRESH = -1
|
||||
defines.FRAGMENT_SIZE = 'BLOCK_SIZE/8'
|
||||
defines.SIZE = '2*FRAGMENT_SIZE'
|
||||
ifdef = 'LFS_CKCKSUMS'
|
||||
code = '''
|
||||
// first we need to figure out where the btree block will actually
|
||||
// end up, fortunately our block randomization is intentionally
|
||||
// consistent
|
||||
|
||||
// format
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKCKSUMS, CFG) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKCKSUMS, CFG) => 0;
|
||||
|
||||
// create a file
|
||||
lfsr_file_t file;
|
||||
lfsr_file_open(&lfs, &file, "bathykorus",
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||
uint32_t prng = 42;
|
||||
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;
|
||||
|
||||
// find the btree block
|
||||
lfsr_traversal_t t;
|
||||
lfsr_traversal_open(&lfs, &t, 0) => 0;
|
||||
lfs_block_t badblock;
|
||||
while (true) {
|
||||
struct lfs_tinfo tinfo;
|
||||
lfsr_traversal_read(&lfs, &t, &tinfo) => 0;
|
||||
if (tinfo.btype == LFS_BTYPE_BTREE) {
|
||||
badblock = tinfo.block;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lfsr_traversal_close(&lfs, &t) => 0;
|
||||
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
|
||||
// now test all bad bits in the btree block
|
||||
for (lfs_size_t i = 0;
|
||||
i < ((BADBIT == -1) ? 8*BLOCK_SIZE : 1);
|
||||
i++) {
|
||||
lfs_size_t badbit = (BADBIT == -1) ? i : BADBIT;
|
||||
|
||||
// reset the bd prng every run for reproducibility
|
||||
lfs_emubd_seed(CFG, 42);
|
||||
printf("--- badblock: 0x%x.%x, badbit: 0x%x (0x%x+%x) ---\n",
|
||||
badblock, badbit/8, badbit, badbit/8, badbit%8);
|
||||
|
||||
// mark our badbit as bad
|
||||
lfs_emubd_markbadbit(CFG, badblock, badbit) => 0;
|
||||
|
||||
// With metastability, basically any filesystem operation can
|
||||
// return LFS_ERR_CORRUPT. This is ok, what we're really testing
|
||||
// for is no internal/external asserts failing.
|
||||
|
||||
// format
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKCKSUMS, CFG) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKCKSUMS, CFG) => 0;
|
||||
|
||||
{
|
||||
// create a file
|
||||
lfsr_file_t file;
|
||||
lfsr_file_open(&lfs, &file, "bathykorus",
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||
uint32_t prng = 42;
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
||||
}
|
||||
lfs_ssize_t res = lfsr_file_write(&lfs, &file, wbuf, SIZE);
|
||||
assert(res == SIZE || res == LFS_ERR_CORRUPT);
|
||||
if (res == LFS_ERR_CORRUPT) {
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
int err = lfsr_file_close(&lfs, &file);
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
|
||||
// try to read our file
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
// remount?
|
||||
if (remount) {
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKCKSUMS, CFG) => 0;
|
||||
}
|
||||
|
||||
// yes reads can fail here
|
||||
err = lfsr_file_open(&lfs, &file, "bathykorus", LFS_O_RDONLY);
|
||||
assert(!err
|
||||
|| err == LFS_ERR_CORRUPT
|
||||
// bit errors can also cause our fs state to "rollback",
|
||||
// which is not great but we can't solve this with ckreads
|
||||
// alone
|
||||
|| err == LFS_ERR_NOENT);
|
||||
if (err == LFS_ERR_CORRUPT || err == LFS_ERR_NOENT) {
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
uint8_t rbuf[SIZE];
|
||||
lfs_ssize_t res = lfsr_file_read(&lfs, &file, rbuf, SIZE);
|
||||
assert(res == SIZE || res == LFS_ERR_CORRUPT);
|
||||
if (res == LFS_ERR_CORRUPT) {
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
goto corrupt_mounted;
|
||||
}
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
corrupt_mounted:;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
|
||||
// reset badbit
|
||||
lfs_emubd_markgood(CFG, badblock) => 0;
|
||||
}
|
||||
'''
|
||||
|
||||
|
||||
|
||||
|
||||
## High-level error spam tests
|
||||
#
|
||||
@@ -1360,6 +1740,7 @@ code = '''
|
||||
# METHOD=0 => ckprogs
|
||||
# METHOD=1 => ckfetches
|
||||
# METHOD=2 => ckparity
|
||||
# METHOD=3 => ckcksums
|
||||
defines.METHOD = [0]
|
||||
defines.PERIOD = 10
|
||||
defines.PROTECTED_MROOTANCHOR = [false, true]
|
||||
@@ -1367,6 +1748,7 @@ defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP'
|
||||
defines.CKPROGS = 'METHOD == 0'
|
||||
defines.CKFETCHES = 'METHOD == 1'
|
||||
defines.CKPARITY = 'METHOD == 2'
|
||||
defines.CKCKSUMS = 'METHOD == 3'
|
||||
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256]
|
||||
defines.SEED = 'range(10)'
|
||||
fuzz = 'SEED'
|
||||
@@ -1374,6 +1756,7 @@ if = [
|
||||
'LFS_IFDEF_CKPROGS(true, !CKPROGS)',
|
||||
'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)',
|
||||
'LFS_IFDEF_CKPARITY(true, !CKPARITY)',
|
||||
'LFS_IFDEF_CKCKSUMS(true, !CKCKSUMS)',
|
||||
]
|
||||
code = '''
|
||||
// seed our block device with our seed so we have different error
|
||||
@@ -1394,13 +1777,15 @@ code = '''
|
||||
LFS_F_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_F_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
lfsr_mount(&lfs,
|
||||
LFS_M_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_M_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
|
||||
// set up a simulation to compare against
|
||||
@@ -1421,8 +1806,8 @@ code = '''
|
||||
// types of errors, so we implement errors for each one a
|
||||
// bit differently
|
||||
|
||||
// ckprogs? ckparity?
|
||||
if (METHOD == 0 || METHOD == 2) {
|
||||
// ckprogs? ckparity? ckcksums?
|
||||
if (METHOD == 0 || METHOD == 2 || METHOD == 3) {
|
||||
// mark our badblock as bad
|
||||
lfs_emubd_markbad(CFG, badblock) => 0;
|
||||
|
||||
@@ -1543,6 +1928,9 @@ code = '''
|
||||
: 0)
|
||||
| ((CKPARITY)
|
||||
? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1)
|
||||
: 0)
|
||||
| ((CKCKSUMS)
|
||||
? LFS_IFDEF_CKCKSUMS(LFS_M_CKCKSUMS, -1)
|
||||
: 0),
|
||||
CFG) => 0;
|
||||
}
|
||||
@@ -1601,6 +1989,7 @@ corrupt_mounted:;
|
||||
# METHOD=0 => ckprogs
|
||||
# METHOD=1 => ckfetches
|
||||
# METHOD=2 => ckparity
|
||||
# METHOD=3 => ckcksums
|
||||
defines.METHOD = [0]
|
||||
defines.PERIOD = 10
|
||||
defines.PROTECTED_MROOTANCHOR = [false, true]
|
||||
@@ -1608,6 +1997,7 @@ defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP'
|
||||
defines.CKPROGS = 'METHOD == 0'
|
||||
defines.CKFETCHES = 'METHOD == 1'
|
||||
defines.CKPARITY = 'METHOD == 2'
|
||||
defines.CKCKSUMS = 'METHOD == 3'
|
||||
defines.N = [1, 2, 4, 8, 16, 32, 64]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
@@ -1624,6 +2014,7 @@ if = [
|
||||
'LFS_IFDEF_CKPROGS(true, !CKPROGS)',
|
||||
'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)',
|
||||
'LFS_IFDEF_CKPARITY(true, !CKPARITY)',
|
||||
'LFS_IFDEF_CKCKSUMS(true, !CKCKSUMS)',
|
||||
'(SIZE*N)/BLOCK_SIZE <= 16',
|
||||
]
|
||||
code = '''
|
||||
@@ -1645,13 +2036,15 @@ code = '''
|
||||
LFS_F_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_F_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
lfsr_mount(&lfs,
|
||||
LFS_M_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_M_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
|
||||
// set up a simulation to compare against
|
||||
@@ -1673,8 +2066,8 @@ code = '''
|
||||
// types of errors, so we implement errors for each one a
|
||||
// bit differently
|
||||
|
||||
// ckprogs? ckparity?
|
||||
if (METHOD == 0 || METHOD == 2) {
|
||||
// ckprogs? ckparity? ckcksums?
|
||||
if (METHOD == 0 || METHOD == 2 || METHOD == 3) {
|
||||
// mark our badblock as bad
|
||||
lfs_emubd_markbad(CFG, badblock) => 0;
|
||||
|
||||
@@ -1841,6 +2234,9 @@ code = '''
|
||||
: 0)
|
||||
| ((CKPARITY)
|
||||
? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1)
|
||||
: 0)
|
||||
| ((CKCKSUMS)
|
||||
? LFS_IFDEF_CKCKSUMS(LFS_M_CKCKSUMS, -1)
|
||||
: 0),
|
||||
CFG) => 0;
|
||||
}
|
||||
@@ -1914,6 +2310,7 @@ corrupt_mounted:;
|
||||
# METHOD=0 => ckprogs
|
||||
# METHOD=1 => ckfetches
|
||||
# METHOD=2 => ckparity
|
||||
# METHOD=3 => ckcksums
|
||||
defines.METHOD = [0]
|
||||
defines.PERIOD = 10
|
||||
defines.PROTECTED_MROOTANCHOR = [false, true]
|
||||
@@ -1921,6 +2318,7 @@ defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP'
|
||||
defines.CKPROGS = 'METHOD == 0'
|
||||
defines.CKFETCHES = 'METHOD == 1'
|
||||
defines.CKPARITY = 'METHOD == 2'
|
||||
defines.CKCKSUMS = 'METHOD == 3'
|
||||
defines.SIZE = [
|
||||
'FILE_BUFFER_SIZE/2',
|
||||
'2*FILE_BUFFER_SIZE',
|
||||
@@ -1942,6 +2340,7 @@ if = [
|
||||
'LFS_IFDEF_CKPROGS(true, !CKPROGS)',
|
||||
'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)',
|
||||
'LFS_IFDEF_CKPARITY(true, !CKPARITY)',
|
||||
'LFS_IFDEF_CKCKSUMS(true, !CKCKSUMS)',
|
||||
'CHUNK <= SIZE',
|
||||
# this just saves testing time
|
||||
'SIZE <= 4*1024*FRAGMENT_SIZE',
|
||||
@@ -1965,13 +2364,15 @@ code = '''
|
||||
LFS_F_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_F_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
lfsr_mount(&lfs,
|
||||
LFS_M_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_M_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
|
||||
// create a file
|
||||
@@ -2015,8 +2416,8 @@ code = '''
|
||||
// types of errors, so we implement errors for each one a
|
||||
// bit differently
|
||||
|
||||
// ckprogs? ckparity?
|
||||
if (METHOD == 0 || METHOD == 2) {
|
||||
// ckprogs? ckparity? ckcksums?
|
||||
if (METHOD == 0 || METHOD == 2 || METHOD == 3) {
|
||||
// mark our badblock as bad
|
||||
lfs_emubd_markbad(CFG, badblock) => 0;
|
||||
|
||||
@@ -2083,6 +2484,9 @@ code = '''
|
||||
: 0)
|
||||
| ((CKPARITY)
|
||||
? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1)
|
||||
: 0)
|
||||
| ((CKCKSUMS)
|
||||
? LFS_IFDEF_CKCKSUMS(LFS_M_CKCKSUMS, -1)
|
||||
: 0),
|
||||
CFG) => 0;
|
||||
}
|
||||
@@ -2142,6 +2546,7 @@ defines.BADBLOCK = -1
|
||||
# METHOD=0 => ckprogs
|
||||
# METHOD=1 => ckfetches
|
||||
# METHOD=2 => ckparity
|
||||
# METHOD=3 => ckcksums
|
||||
defines.METHOD = [0]
|
||||
defines.PERIOD = 10
|
||||
defines.PROTECTED_MROOTANCHOR = [false, true]
|
||||
@@ -2149,6 +2554,7 @@ defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP'
|
||||
defines.CKPROGS = 'METHOD == 0'
|
||||
defines.CKFETCHES = 'METHOD == 1'
|
||||
defines.CKPARITY = 'METHOD == 2'
|
||||
defines.CKCKSUMS = 'METHOD == 3'
|
||||
defines.N = [1, 2, 4, 8, 16, 32, 64]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
@@ -2165,6 +2571,7 @@ if = [
|
||||
'LFS_IFDEF_CKPROGS(true, !CKPROGS)',
|
||||
'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)',
|
||||
'LFS_IFDEF_CKPARITY(true, !CKPARITY)',
|
||||
'LFS_IFDEF_CKCKSUMS(true, !CKCKSUMS)',
|
||||
'(SIZE*N)/BLOCK_SIZE <= 16',
|
||||
]
|
||||
code = '''
|
||||
@@ -2186,13 +2593,15 @@ code = '''
|
||||
LFS_F_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_F_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
lfsr_mount(&lfs,
|
||||
LFS_M_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_M_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
|
||||
// set up a simulation to compare against
|
||||
@@ -2224,8 +2633,8 @@ code = '''
|
||||
// types of errors, so we implement errors for each one a
|
||||
// bit differently
|
||||
|
||||
// ckprogs? ckparity?
|
||||
if (METHOD == 0 || METHOD == 2) {
|
||||
// ckprogs? ckparity? ckcksums?
|
||||
if (METHOD == 0 || METHOD == 2 || METHOD == 3) {
|
||||
// mark our badblock as bad
|
||||
lfs_emubd_markbad(CFG, badblock) => 0;
|
||||
|
||||
@@ -2576,6 +2985,7 @@ corrupt_mounted:;
|
||||
# METHOD=0 => ckprogs
|
||||
# METHOD=1 => ckfetches
|
||||
# METHOD=2 => ckparity
|
||||
# METHOD=3 => ckcksums
|
||||
defines.METHOD = [0]
|
||||
defines.PERIOD = 10
|
||||
defines.PROTECTED_MROOTANCHOR = [false, true]
|
||||
@@ -2583,6 +2993,7 @@ defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP'
|
||||
defines.CKPROGS = 'METHOD == 0'
|
||||
defines.CKFETCHES = 'METHOD == 1'
|
||||
defines.CKPARITY = 'METHOD == 2'
|
||||
defines.CKCKSUMS = 'METHOD == 3'
|
||||
defines.N = [1, 2, 4, 8, 16, 32, 64]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
@@ -2599,6 +3010,7 @@ if = [
|
||||
'LFS_IFDEF_CKPROGS(true, !CKPROGS)',
|
||||
'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)',
|
||||
'LFS_IFDEF_CKPARITY(true, !CKPARITY)',
|
||||
'LFS_IFDEF_CKCKSUMS(true, !CKCKSUMS)',
|
||||
'(SIZE*N)/BLOCK_SIZE <= 16',
|
||||
]
|
||||
code = '''
|
||||
@@ -2620,13 +3032,15 @@ code = '''
|
||||
LFS_F_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_F_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
lfsr_mount(&lfs,
|
||||
LFS_M_RDWR
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0),
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_M_CKCKSUMS, -1) : 0),
|
||||
CFG) => 0;
|
||||
|
||||
// set up a simulation to compare against
|
||||
@@ -2659,8 +3073,8 @@ code = '''
|
||||
// types of errors, so we implement errors for each one a
|
||||
// bit differently
|
||||
|
||||
// ckprogs? ckparity?
|
||||
if (METHOD == 0 || METHOD == 2) {
|
||||
// ckprogs? ckparity? ckcksums?
|
||||
if (METHOD == 0 || METHOD == 2 || METHOD == 3) {
|
||||
// mark our badblock as bad
|
||||
lfs_emubd_markbad(CFG, badblock) => 0;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ defines.SYNC = [false, true]
|
||||
defines.CKPROGS = [false, true]
|
||||
defines.CKFETCHES = [false, true]
|
||||
defines.CKPARITY = [false, true]
|
||||
defines.CKCKSUMS = [false, true]
|
||||
defines.MTREEONLY = [false, true]
|
||||
defines.MKCONSISTENT = [false, true]
|
||||
defines.LOOKAHEAD = [false, true]
|
||||
@@ -30,6 +31,7 @@ if = [
|
||||
'LFS_IFDEF_CKPROGS(true, !CKPROGS)',
|
||||
'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)',
|
||||
'LFS_IFDEF_CKPARITY(true, !CKPARITY)',
|
||||
'LFS_IFDEF_CKCKSUMS(true, !CKCKSUMS)',
|
||||
'!RDONLY || !MKCONSISTENT',
|
||||
'!RDONLY || !LOOKAHEAD',
|
||||
'!RDONLY || !COMPACT',
|
||||
@@ -46,6 +48,7 @@ code = '''
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_M_CKCKSUMS, -1) : 0)
|
||||
| ((MTREEONLY) ? LFS_M_MTREEONLY : 0)
|
||||
| ((MKCONSISTENT) ? LFS_M_MKCONSISTENT : 0)
|
||||
| ((LOOKAHEAD) ? LFS_M_LOOKAHEAD : 0)
|
||||
@@ -64,6 +67,7 @@ code = '''
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_I_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_I_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_I_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_I_CKCKSUMS, -1) : 0)
|
||||
| ((!LOOKAHEAD) ? LFS_I_CANLOOKAHEAD : 0)
|
||||
| ((!COMPACT) ? LFS_I_UNCOMPACTED : 0)));
|
||||
|
||||
@@ -77,6 +81,7 @@ code = '''
|
||||
defines.CKPROGS = [false, true]
|
||||
defines.CKFETCHES = [false, true]
|
||||
defines.CKPARITY = [false, true]
|
||||
defines.CKCKSUMS = [false, true]
|
||||
defines.MTREEONLY = [false, true]
|
||||
defines.COMPACT = [false, true]
|
||||
defines.CKMETA = [false, true]
|
||||
@@ -85,6 +90,7 @@ if = [
|
||||
'LFS_IFDEF_CKPROGS(true, !CKPROGS)',
|
||||
'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)',
|
||||
'LFS_IFDEF_CKPARITY(true, !CKPARITY)',
|
||||
'LFS_IFDEF_CKCKSUMS(true, !CKCKSUMS)',
|
||||
'!MTREEONLY || !CKDATA',
|
||||
]
|
||||
code = '''
|
||||
@@ -94,6 +100,7 @@ code = '''
|
||||
| ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0)
|
||||
| ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0)
|
||||
| ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0)
|
||||
| ((CKCKSUMS) ? LFS_IFDEF_CKCKSUMS(LFS_F_CKCKSUMS, -1) : 0)
|
||||
| ((MTREEONLY) ? LFS_M_MTREEONLY : 0)
|
||||
| ((COMPACT) ? LFS_M_COMPACT : 0)
|
||||
| ((CKMETA) ? LFS_M_CKMETA : 0)
|
||||
|
||||
Reference in New Issue
Block a user