mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	WIP Added/fixed tests for noop writes (where bd error can't be trusted)
This commit is contained in:
		| @@ -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) { | ||||
|     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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										6
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -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); | ||||
|         } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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