WIP Added/fixed tests for noop writes (where bd error can't be trusted)
This commit is contained in:
+21
-10
@@ -47,7 +47,7 @@ int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path,
|
||||
|
||||
memset(bd->wear, 0, sizeof(lfs_testbd_wear_t) * cfg->block_count);
|
||||
}
|
||||
|
||||
|
||||
// create underlying block device
|
||||
if (bd->persist) {
|
||||
bd->u.file.cfg = (struct lfs_filebd_config){
|
||||
@@ -155,9 +155,8 @@ int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block,
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
|
||||
// block bad?
|
||||
if (bd->cfg->erase_cycles &&
|
||||
bd->cfg->badblock_behavior == LFS_TESTBD_BADBLOCK_NOREAD &&
|
||||
bd->wear[block] >= bd->cfg->erase_cycles) {
|
||||
if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles &&
|
||||
bd->cfg->badblock_behavior == LFS_TESTBD_BADBLOCK_READERROR) {
|
||||
LFS_TRACE("lfs_testbd_read -> %d", LFS_ERR_CORRUPT);
|
||||
return LFS_ERR_CORRUPT;
|
||||
}
|
||||
@@ -180,11 +179,18 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block,
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
|
||||
// block bad?
|
||||
if (bd->cfg->erase_cycles &&
|
||||
bd->cfg->badblock_behavior == LFS_TESTBD_BADBLOCK_NOPROG &&
|
||||
bd->wear[block] >= bd->cfg->erase_cycles) {
|
||||
LFS_TRACE("lfs_testbd_prog -> %d", LFS_ERR_CORRUPT);
|
||||
return LFS_ERR_CORRUPT;
|
||||
if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles) {
|
||||
if (bd->cfg->badblock_behavior ==
|
||||
LFS_TESTBD_BADBLOCK_PROGERROR) {
|
||||
LFS_TRACE("lfs_testbd_prog -> %d", LFS_ERR_CORRUPT);
|
||||
return LFS_ERR_CORRUPT;
|
||||
} else if (bd->cfg->badblock_behavior ==
|
||||
LFS_TESTBD_BADBLOCK_PROGNOOP ||
|
||||
bd->cfg->badblock_behavior ==
|
||||
LFS_TESTBD_BADBLOCK_ERASENOOP) {
|
||||
LFS_TRACE("lfs_testbd_prog -> %d", 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// prog
|
||||
@@ -219,9 +225,14 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
// block bad?
|
||||
if (bd->cfg->erase_cycles) {
|
||||
if (bd->wear[block] >= bd->cfg->erase_cycles) {
|
||||
if (bd->cfg->badblock_behavior == LFS_TESTBD_BADBLOCK_NOERASE) {
|
||||
if (bd->cfg->badblock_behavior ==
|
||||
LFS_TESTBD_BADBLOCK_ERASEERROR) {
|
||||
LFS_TRACE("lfs_testbd_erase -> %d", LFS_ERR_CORRUPT);
|
||||
return LFS_ERR_CORRUPT;
|
||||
} else if (bd->cfg->badblock_behavior ==
|
||||
LFS_TESTBD_BADBLOCK_ERASENOOP) {
|
||||
LFS_TRACE("lfs_testbd_erase -> %d", 0);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// mark wear
|
||||
|
||||
+12
-8
@@ -19,14 +19,18 @@ extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
// Mode determining how "bad blocks" behave during testing. This
|
||||
// simulates some real-world circumstances such as writes not
|
||||
// going through (noprog), erases not sticking (noerase), and ECC
|
||||
// failures (noread).
|
||||
// Mode determining how "bad blocks" behave during testing. This simulates
|
||||
// some real-world circumstances such as progs not sticking (prog-noop),
|
||||
// a readonly disk (erase-noop), and ECC failures (read-error).
|
||||
//
|
||||
// Not that read-noop is not allowed. Read _must_ return a consistent (but
|
||||
// may be arbitrary) value on every read.
|
||||
enum lfs_testbd_badblock_behavior {
|
||||
LFS_TESTBD_BADBLOCK_NOPROG = 0,
|
||||
LFS_TESTBD_BADBLOCK_NOERASE = 1,
|
||||
LFS_TESTBD_BADBLOCK_NOREAD = 2,
|
||||
LFS_TESTBD_BADBLOCK_PROGERROR,
|
||||
LFS_TESTBD_BADBLOCK_ERASEERROR,
|
||||
LFS_TESTBD_BADBLOCK_READERROR,
|
||||
LFS_TESTBD_BADBLOCK_PROGNOOP,
|
||||
LFS_TESTBD_BADBLOCK_ERASENOOP,
|
||||
};
|
||||
|
||||
// Type for measuring wear
|
||||
@@ -82,7 +86,7 @@ typedef struct lfs_testbd {
|
||||
/// Block device API ///
|
||||
|
||||
// Create a test block device using the geometry in lfs_config
|
||||
//
|
||||
//
|
||||
// Note that filebd is used if a path is provided, if path is NULL
|
||||
// testbd will use rambd which can be much faster.
|
||||
int lfs_testbd_create(const struct lfs_config *cfg, const char *path);
|
||||
|
||||
@@ -1300,9 +1300,9 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
|
||||
// check against written crc to detect if block is readonly
|
||||
// (we may pick up old commits)
|
||||
// TODO rm me?
|
||||
// if (i == noff && crc != ncrc) {
|
||||
// return LFS_ERR_CORRUPT;
|
||||
// }
|
||||
if (i == noff && crc != ncrc) {
|
||||
return LFS_ERR_CORRUPT;
|
||||
}
|
||||
|
||||
crc = lfs_crc(crc, &dat, 1);
|
||||
}
|
||||
|
||||
+1
-5
@@ -52,7 +52,7 @@ DEFINES = {
|
||||
'LFS_LOOKAHEAD_SIZE': 16,
|
||||
'LFS_ERASE_VALUE': 0xff,
|
||||
'LFS_ERASE_CYCLES': 0,
|
||||
'LFS_BADBLOCK_BEHAVIOR': 'LFS_TESTBD_BADBLOCK_NOPROG',
|
||||
'LFS_BADBLOCK_BEHAVIOR': 'LFS_TESTBD_BADBLOCK_PROGERROR',
|
||||
}
|
||||
PROLOGUE = """
|
||||
// prologue
|
||||
@@ -183,12 +183,10 @@ class TestCase:
|
||||
return False
|
||||
elif self.if_ is not None:
|
||||
if_ = self.if_
|
||||
print(if_)
|
||||
while True:
|
||||
for k, v in self.defines.items():
|
||||
if k in if_:
|
||||
if_ = if_.replace(k, '(%s)' % v)
|
||||
print(if_)
|
||||
break
|
||||
else:
|
||||
break
|
||||
@@ -196,8 +194,6 @@ class TestCase:
|
||||
re.sub('(\&\&|\?)', ' and ',
|
||||
re.sub('(\|\||:)', ' or ',
|
||||
re.sub('!(?!=)', ' not ', if_))))
|
||||
print(if_)
|
||||
print('---', eval(if_), '---')
|
||||
return eval(if_)
|
||||
else:
|
||||
return True
|
||||
|
||||
+29
-142
@@ -1,6 +1,14 @@
|
||||
[[case]] # single bad blocks
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
||||
define.LFS_ERASE_CYCLES = 0xffffffff
|
||||
define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_NOPROG'
|
||||
define.LFS_ERASE_VALUE = [0x00, 0xff, -1]
|
||||
define.LFS_BADBLOCK_BEHAVIOR = [
|
||||
'LFS_TESTBD_BADBLOCK_PROGERROR',
|
||||
'LFS_TESTBD_BADBLOCK_ERASEERROR',
|
||||
'LFS_TESTBD_BADBLOCK_READERROR',
|
||||
'LFS_TESTBD_BADBLOCK_PROGNOOP',
|
||||
'LFS_TESTBD_BADBLOCK_ERASENOOP',
|
||||
]
|
||||
define.NAMEMULT = 64
|
||||
define.FILEMULT = 1
|
||||
code = '''
|
||||
@@ -64,144 +72,16 @@ code = '''
|
||||
}
|
||||
'''
|
||||
|
||||
[[case]] # single persistent blocks (can't erase)
|
||||
define.LFS_ERASE_CYCLES = 0xffffffff
|
||||
define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_NOERASE'
|
||||
define.NAMEMULT = 64
|
||||
define.FILEMULT = 1
|
||||
code = '''
|
||||
for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) {
|
||||
lfs_testbd_setwear(&cfg, badblock-1, 0) => 0;
|
||||
lfs_testbd_setwear(&cfg, badblock, 0xffffffff) => 0;
|
||||
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
for (int i = 1; i < 10; i++) {
|
||||
for (int j = 0; j < NAMEMULT; j++) {
|
||||
buffer[j] = '0'+i;
|
||||
}
|
||||
buffer[NAMEMULT] = '\0';
|
||||
lfs_mkdir(&lfs, (char*)buffer) => 0;
|
||||
|
||||
buffer[NAMEMULT] = '/';
|
||||
for (int j = 0; j < NAMEMULT; j++) {
|
||||
buffer[j+NAMEMULT+1] = '0'+i;
|
||||
}
|
||||
buffer[2*NAMEMULT+1] = '\0';
|
||||
lfs_file_open(&lfs, &file, (char*)buffer,
|
||||
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
||||
|
||||
size = NAMEMULT;
|
||||
for (int j = 0; j < i*FILEMULT; j++) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
}
|
||||
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
for (int i = 1; i < 10; i++) {
|
||||
for (int j = 0; j < NAMEMULT; j++) {
|
||||
buffer[j] = '0'+i;
|
||||
}
|
||||
buffer[NAMEMULT] = '\0';
|
||||
lfs_stat(&lfs, (char*)buffer, &info) => 0;
|
||||
info.type => LFS_TYPE_DIR;
|
||||
|
||||
buffer[NAMEMULT] = '/';
|
||||
for (int j = 0; j < NAMEMULT; j++) {
|
||||
buffer[j+NAMEMULT+1] = '0'+i;
|
||||
}
|
||||
buffer[2*NAMEMULT+1] = '\0';
|
||||
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
|
||||
|
||||
size = NAMEMULT;
|
||||
for (int j = 0; j < i*FILEMULT; j++) {
|
||||
uint8_t rbuffer[1024];
|
||||
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
||||
memcmp(buffer, rbuffer, size) => 0;
|
||||
}
|
||||
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
}
|
||||
'''
|
||||
|
||||
[[case]] # single unreadable blocks (can't read)
|
||||
define.LFS_ERASE_CYCLES = 0xffffffff
|
||||
define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_NOREAD'
|
||||
define.NAMEMULT = 64
|
||||
define.FILEMULT = 1
|
||||
code = '''
|
||||
for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT/2; badblock++) {
|
||||
lfs_testbd_setwear(&cfg, badblock-1, 0) => 0;
|
||||
lfs_testbd_setwear(&cfg, badblock, 0xffffffff) => 0;
|
||||
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
for (int i = 1; i < 10; i++) {
|
||||
for (int j = 0; j < NAMEMULT; j++) {
|
||||
buffer[j] = '0'+i;
|
||||
}
|
||||
buffer[NAMEMULT] = '\0';
|
||||
lfs_mkdir(&lfs, (char*)buffer) => 0;
|
||||
|
||||
buffer[NAMEMULT] = '/';
|
||||
for (int j = 0; j < NAMEMULT; j++) {
|
||||
buffer[j+NAMEMULT+1] = '0'+i;
|
||||
}
|
||||
buffer[2*NAMEMULT+1] = '\0';
|
||||
lfs_file_open(&lfs, &file, (char*)buffer,
|
||||
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
||||
|
||||
size = NAMEMULT;
|
||||
for (int j = 0; j < i*FILEMULT; j++) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
}
|
||||
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
for (int i = 1; i < 10; i++) {
|
||||
for (int j = 0; j < NAMEMULT; j++) {
|
||||
buffer[j] = '0'+i;
|
||||
}
|
||||
buffer[NAMEMULT] = '\0';
|
||||
lfs_stat(&lfs, (char*)buffer, &info) => 0;
|
||||
info.type => LFS_TYPE_DIR;
|
||||
|
||||
buffer[NAMEMULT] = '/';
|
||||
for (int j = 0; j < NAMEMULT; j++) {
|
||||
buffer[j+NAMEMULT+1] = '0'+i;
|
||||
}
|
||||
buffer[2*NAMEMULT+1] = '\0';
|
||||
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
|
||||
|
||||
size = NAMEMULT;
|
||||
for (int j = 0; j < i*FILEMULT; j++) {
|
||||
uint8_t rbuffer[1024];
|
||||
lfs_file_read(&lfs, &file, rbuffer, size) => size;
|
||||
memcmp(buffer, rbuffer, size) => 0;
|
||||
}
|
||||
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
}
|
||||
'''
|
||||
|
||||
[[case]] # region corruption (causes cascading failures)
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
||||
define.LFS_ERASE_CYCLES = 0xffffffff
|
||||
define.LFS_ERASE_VALUE = [0x00, 0xff, -1]
|
||||
define.LFS_BADBLOCK_BEHAVIOR = [
|
||||
'LFS_TESTBD_BADBLOCK_NOPROG',
|
||||
'LFS_TESTBD_BADBLOCK_NOERASE',
|
||||
'LFS_TESTBD_BADBLOCK_NOREAD',
|
||||
'LFS_TESTBD_BADBLOCK_PROGERROR',
|
||||
'LFS_TESTBD_BADBLOCK_ERASEERROR',
|
||||
'LFS_TESTBD_BADBLOCK_READERROR',
|
||||
'LFS_TESTBD_BADBLOCK_PROGNOOP',
|
||||
'LFS_TESTBD_BADBLOCK_ERASENOOP',
|
||||
]
|
||||
define.NAMEMULT = 64
|
||||
define.FILEMULT = 1
|
||||
@@ -266,11 +146,15 @@ code = '''
|
||||
'''
|
||||
|
||||
[[case]] # alternating corruption (causes cascading failures)
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
||||
define.LFS_ERASE_CYCLES = 0xffffffff
|
||||
define.LFS_ERASE_VALUE = [0x00, 0xff, -1]
|
||||
define.LFS_BADBLOCK_BEHAVIOR = [
|
||||
'LFS_TESTBD_BADBLOCK_NOPROG',
|
||||
'LFS_TESTBD_BADBLOCK_NOERASE',
|
||||
'LFS_TESTBD_BADBLOCK_NOREAD',
|
||||
'LFS_TESTBD_BADBLOCK_PROGERROR',
|
||||
'LFS_TESTBD_BADBLOCK_ERASEERROR',
|
||||
'LFS_TESTBD_BADBLOCK_READERROR',
|
||||
'LFS_TESTBD_BADBLOCK_PROGNOOP',
|
||||
'LFS_TESTBD_BADBLOCK_ERASENOOP',
|
||||
]
|
||||
define.NAMEMULT = 64
|
||||
define.FILEMULT = 1
|
||||
@@ -337,10 +221,13 @@ code = '''
|
||||
# other corner cases
|
||||
[[case]] # bad superblocks (corrupt 1 or 0)
|
||||
define.LFS_ERASE_CYCLES = 0xffffffff
|
||||
define.LFS_ERASE_VALUE = [0x00, 0xff, -1]
|
||||
define.LFS_BADBLOCK_BEHAVIOR = [
|
||||
'LFS_TESTBD_BADBLOCK_NOPROG',
|
||||
'LFS_TESTBD_BADBLOCK_NOERASE',
|
||||
'LFS_TESTBD_BADBLOCK_NOREAD',
|
||||
'LFS_TESTBD_BADBLOCK_PROGERROR',
|
||||
'LFS_TESTBD_BADBLOCK_ERASEERROR',
|
||||
'LFS_TESTBD_BADBLOCK_READERROR',
|
||||
'LFS_TESTBD_BADBLOCK_PROGNOOP',
|
||||
'LFS_TESTBD_BADBLOCK_ERASENOOP',
|
||||
]
|
||||
code = '''
|
||||
lfs_testbd_setwear(&cfg, 0, 0xffffffff) => 0;
|
||||
|
||||
+14
-20
@@ -1,11 +1,13 @@
|
||||
[[case]] # test running a filesystem to exhaustion
|
||||
define.LFS_ERASE_CYCLES = 10
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so it runs faster
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
||||
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
|
||||
define.LFS_BADBLOCK_BEHAVIOR = [
|
||||
'LFS_TESTBD_BADBLOCK_NOPROG',
|
||||
'LFS_TESTBD_BADBLOCK_NOERASE',
|
||||
'LFS_TESTBD_BADBLOCK_NOREAD',
|
||||
'LFS_TESTBD_BADBLOCK_PROGERROR',
|
||||
'LFS_TESTBD_BADBLOCK_ERASEERROR',
|
||||
'LFS_TESTBD_BADBLOCK_READERROR',
|
||||
'LFS_TESTBD_BADBLOCK_PROGNOOP',
|
||||
'LFS_TESTBD_BADBLOCK_ERASENOOP',
|
||||
]
|
||||
define.FILES = 10
|
||||
code = '''
|
||||
@@ -79,12 +81,14 @@ exhausted:
|
||||
[[case]] # test running a filesystem to exhaustion
|
||||
# which also requires expanding superblocks
|
||||
define.LFS_ERASE_CYCLES = 10
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so it runs faster
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
||||
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
|
||||
define.LFS_BADBLOCK_BEHAVIOR = [
|
||||
'LFS_TESTBD_BADBLOCK_NOPROG',
|
||||
'LFS_TESTBD_BADBLOCK_NOERASE',
|
||||
'LFS_TESTBD_BADBLOCK_NOREAD',
|
||||
'LFS_TESTBD_BADBLOCK_PROGERROR',
|
||||
'LFS_TESTBD_BADBLOCK_ERASEERROR',
|
||||
'LFS_TESTBD_BADBLOCK_READERROR',
|
||||
'LFS_TESTBD_BADBLOCK_PROGNOOP',
|
||||
'LFS_TESTBD_BADBLOCK_ERASENOOP',
|
||||
]
|
||||
define.FILES = 10
|
||||
code = '''
|
||||
@@ -159,13 +163,8 @@ exhausted:
|
||||
|
||||
[[case]] # wear-level test running a filesystem to exhaustion
|
||||
define.LFS_ERASE_CYCLES = 20
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so it runs faster
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
||||
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
|
||||
define.LFS_BADBLOCK_BEHAVIOR = [
|
||||
'LFS_TESTBD_BADBLOCK_NOPROG',
|
||||
'LFS_TESTBD_BADBLOCK_NOERASE',
|
||||
'LFS_TESTBD_BADBLOCK_NOREAD',
|
||||
]
|
||||
define.FILES = 10
|
||||
code = '''
|
||||
uint32_t run_cycles[2];
|
||||
@@ -252,13 +251,8 @@ exhausted:
|
||||
|
||||
[[case]] # wear-level test + expanding superblock
|
||||
define.LFS_ERASE_CYCLES = 20
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so it runs faster
|
||||
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
||||
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
|
||||
define.LFS_BADBLOCK_BEHAVIOR = [
|
||||
'LFS_TESTBD_BADBLOCK_NOPROG',
|
||||
'LFS_TESTBD_BADBLOCK_NOERASE',
|
||||
'LFS_TESTBD_BADBLOCK_NOREAD',
|
||||
]
|
||||
define.FILES = 10
|
||||
code = '''
|
||||
uint32_t run_cycles[2];
|
||||
|
||||
Reference in New Issue
Block a user