mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Added allocation randomization for dynamic wear-leveling
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.
This commit is contained in:
		
							
								
								
									
										98
									
								
								tests/debug.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										98
									
								
								tests/debug.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| #!/usr/bin/env python2 | ||||
|  | ||||
| import struct | ||||
| import binascii | ||||
|  | ||||
| TYPES = { | ||||
|     (0x1ff, 0x001): 'reg', | ||||
|     (0x1ff, 0x002): 'dir', | ||||
|     (0x1ff, 0x011): 'superblock', | ||||
|     (0x1ff, 0x012): 'root', | ||||
|     (0x1ff, 0x030): 'delete', | ||||
|     (0x1f0, 0x080): 'globals', | ||||
|     (0x1ff, 0x0c0): 'tail soft', | ||||
|     (0x1ff, 0x0c1): 'tail hard', | ||||
|     (0x1ff, 0x0f0): 'crc', | ||||
|     (0x1ff, 0x040): 'struct dir', | ||||
|     (0x1ff, 0x041): 'struct inline', | ||||
|     (0x1ff, 0x042): 'struct ctz', | ||||
|     (0x100, 0x100): 'attr', | ||||
| } | ||||
|  | ||||
| def typeof(type): | ||||
|     for prefix in range(9): | ||||
|         mask = 0x1ff & ~((1 << prefix)-1) | ||||
|         if (mask, type & mask) in TYPES: | ||||
|             return TYPES[mask, type & mask] + ( | ||||
|                 ' [%0*x]' % (prefix/4, type & ((1 << prefix)-1)) | ||||
|                 if prefix else '') | ||||
|     else: | ||||
|         return '[%02x]' % type | ||||
|  | ||||
| def main(*blocks): | ||||
|     # find most recent block | ||||
|     file = None | ||||
|     rev = None | ||||
|     crc = None | ||||
|     versions = [] | ||||
|  | ||||
|     for block in blocks: | ||||
|         try: | ||||
|             nfile = open(block, 'rb') | ||||
|             ndata = nfile.read(4) | ||||
|             ncrc = binascii.crc32(ndata) | ||||
|             nrev, = struct.unpack('<I', ndata) | ||||
|  | ||||
|             assert rev != nrev | ||||
|             if not file or ((rev - nrev) & 0x80000000): | ||||
|                 file = nfile | ||||
|                 rev = nrev | ||||
|                 crc = ncrc | ||||
|  | ||||
|             versions.append((nrev, '%s (rev %d)' % (block, nrev))) | ||||
|         except IOError: | ||||
|             pass | ||||
|  | ||||
|     print "--- %s ---" % ', '.join(v for _,v in sorted(versions, reverse=True)) | ||||
|  | ||||
|     # go through each tag, print useful information | ||||
|     print "%-4s  %-8s  %-14s  %3s  %3s  %s" % ( | ||||
|         'off', 'tag', 'type', 'id', 'len', 'dump') | ||||
|  | ||||
|     tag = 0 | ||||
|     off = 4 | ||||
|     while True: | ||||
|         try: | ||||
|             data = file.read(4) | ||||
|             crc = binascii.crc32(data, crc) | ||||
|             ntag, = struct.unpack('<I', data) | ||||
|         except struct.error: | ||||
|             break | ||||
|  | ||||
|         tag ^= ntag | ||||
|         off += 4 | ||||
|  | ||||
|         type = (tag & 0x7fc00000) >> 22 | ||||
|         id   = (tag & 0x003ff000) >> 12 | ||||
|         size = (tag & 0x00000fff) >> 0 | ||||
|  | ||||
|         data = file.read(size) | ||||
|         if type == 0x0f0: | ||||
|             crc = binascii.crc32(data[:4], crc) | ||||
|         else: | ||||
|             crc = binascii.crc32(data, crc) | ||||
|  | ||||
|         print '%04x: %08x  %-14s  %3s  %3d  %-23s  %-8s' % ( | ||||
|             off, tag, | ||||
|             typeof(type) + (' bad!' if type == 0x0f0 and ~crc else ''), | ||||
|             id if id != 0x3ff else '.', size, | ||||
|             ' '.join('%02x' % ord(c) for c in data[:8]), | ||||
|             ''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8])) | ||||
|  | ||||
|         off += tag & 0xfff | ||||
|         if type == 0x0f0: | ||||
|             crc = 0 | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     import sys | ||||
|     main(*sys.argv[1:]) | ||||
		Reference in New Issue
	
	Block a user