mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	This implements the second step of full dynamic wear-leveling, block allocation randomization. This is the key part the uniformly distributes wear across the filesystem, even through reboots. The entropy actually comes from the filesystem itself, by xoring together all of the CRCs in the metadata-pairs on the filesystem. While this sounds like a ridiculous operation, it's easy to do when we already scan the metadata-pairs at mount time. This gives us a random number we can use for block allocation. Unfortunately it's not a great general purpose random generator as the output only changes every filesystem write. Fortunately that's exactly when we need our allocator. --- Additionally, the randomization created a mess for the testing framework. Fortunately, this method of randomization is deterministic. A very useful property for reproducing bugs.
		
			
				
	
	
		
			119 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/bash
 | |
| set -eu
 | |
| 
 | |
| echo "=== Corrupt tests ==="
 | |
| 
 | |
| NAMEMULT=64
 | |
| FILEMULT=1
 | |
| 
 | |
| lfs_mktree() {
 | |
| tests/test.py ${1:-} << TEST
 | |
|     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[0], (char*)buffer,
 | |
|                 LFS_O_WRONLY | LFS_O_CREAT) => 0;
 | |
|         
 | |
|         size = $NAMEMULT;
 | |
|         for (int j = 0; j < i*$FILEMULT; j++) {
 | |
|             lfs_file_write(&lfs, &file[0], buffer, size) => size;
 | |
|         }
 | |
| 
 | |
|         lfs_file_close(&lfs, &file[0]) => 0;
 | |
|     }
 | |
|     lfs_unmount(&lfs) => 0;
 | |
| TEST
 | |
| }
 | |
| 
 | |
| lfs_chktree() {
 | |
| tests/test.py ${1:-} << TEST
 | |
|     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[0], (char*)buffer, LFS_O_RDONLY) => 0;
 | |
|         
 | |
|         size = $NAMEMULT;
 | |
|         for (int j = 0; j < i*$FILEMULT; j++) {
 | |
|             lfs_file_read(&lfs, &file[0], rbuffer, size) => size;
 | |
|             memcmp(buffer, rbuffer, size) => 0;
 | |
|         }
 | |
| 
 | |
|         lfs_file_close(&lfs, &file[0]) => 0;
 | |
|     }
 | |
|     lfs_unmount(&lfs) => 0;
 | |
| TEST
 | |
| }
 | |
| 
 | |
| echo "--- Sanity check ---"
 | |
| rm -rf blocks
 | |
| lfs_mktree
 | |
| lfs_chktree
 | |
| BLOCKS="$(ls blocks | grep -vw '[01]')"
 | |
| 
 | |
| echo "--- Block corruption ---"
 | |
| for b in $BLOCKS
 | |
| do 
 | |
|     rm -rf blocks
 | |
|     mkdir blocks
 | |
|     ln -s /dev/zero blocks/$b
 | |
|     lfs_mktree
 | |
|     lfs_chktree
 | |
| done
 | |
| 
 | |
| echo "--- Block persistance ---"
 | |
| for b in $BLOCKS
 | |
| do 
 | |
|     rm -rf blocks
 | |
|     mkdir blocks
 | |
|     lfs_mktree
 | |
|     chmod a-w blocks/$b
 | |
|     lfs_mktree
 | |
|     lfs_chktree
 | |
| done
 | |
| 
 | |
| echo "--- Big region corruption ---"
 | |
| rm -rf blocks
 | |
| mkdir blocks
 | |
| for i in {2..512}
 | |
| do
 | |
|     ln -s /dev/zero blocks/$(printf '%x' $i)
 | |
| done
 | |
| lfs_mktree
 | |
| lfs_chktree
 | |
| 
 | |
| echo "--- Alternating corruption ---"
 | |
| rm -rf blocks
 | |
| mkdir blocks
 | |
| for i in {2..1024..2}
 | |
| do
 | |
|     ln -s /dev/zero blocks/$(printf '%x' $i)
 | |
| done
 | |
| lfs_mktree
 | |
| lfs_chktree
 | |
| 
 | |
| echo "--- Results ---"
 | |
| tests/stats.py
 |