Initial remote commit
This commit is contained in:
85
test/build_merged.py
Normal file
85
test/build_merged.py
Normal file
@@ -0,0 +1,85 @@
|
||||
import struct
|
||||
|
||||
CHUNK = 128*512
|
||||
LV_START = 5120000*512
|
||||
BSIZE = 4096
|
||||
BPG = 32768
|
||||
GDT_ENTRY = 64
|
||||
NUM_GROUPS = 35728
|
||||
|
||||
def is_meta(virt_byte):
|
||||
in_group = virt_byte % (5*CHUNK)
|
||||
return (in_group // CHUNK) == 4
|
||||
|
||||
def raw_read(virt_offset, length):
|
||||
result = bytearray(length)
|
||||
pos = virt_offset
|
||||
remaining = length
|
||||
with open('/dev/md0','rb') as f:
|
||||
while remaining > 0:
|
||||
group = pos // (5*CHUNK)
|
||||
in_group = pos % (5*CHUNK)
|
||||
chunk_idx = in_group // CHUNK
|
||||
intra = in_group % CHUNK
|
||||
seg_len = min(CHUNK-intra, remaining)
|
||||
dst_off = pos - virt_offset
|
||||
if chunk_idx != 4:
|
||||
phys = LV_START + group*4*CHUNK + chunk_idx*CHUNK + intra
|
||||
f.seek(phys)
|
||||
data = f.read(seg_len)
|
||||
result[dst_off:dst_off+len(data)] = data
|
||||
pos += seg_len
|
||||
remaining -= seg_len
|
||||
return bytes(result)
|
||||
|
||||
# Build merged GDT: for each group, use whichever of primary/backup
|
||||
# is NOT in a metadata chunk
|
||||
print('Building merged GDT...')
|
||||
primary_start = BSIZE # block 1
|
||||
backup_start = (1*BPG + 1) * BSIZE # group 1 backup
|
||||
|
||||
# Read both GDTs in full
|
||||
primary_gdt = raw_read(primary_start, NUM_GROUPS * GDT_ENTRY)
|
||||
backup_gdt = raw_read(backup_start, NUM_GROUPS * GDT_ENTRY)
|
||||
|
||||
merged = bytearray(NUM_GROUPS * GDT_ENTRY)
|
||||
primary_used = 0
|
||||
backup_used = 0
|
||||
neither = 0
|
||||
|
||||
for g in range(NUM_GROUPS):
|
||||
prim_byte = primary_start + g * GDT_ENTRY
|
||||
backup_byte = backup_start + g * GDT_ENTRY
|
||||
src_off = g * GDT_ENTRY
|
||||
|
||||
if not is_meta(prim_byte):
|
||||
# Primary is valid - use it
|
||||
merged[src_off:src_off+GDT_ENTRY] = primary_gdt[src_off:src_off+GDT_ENTRY]
|
||||
primary_used += 1
|
||||
elif not is_meta(backup_byte):
|
||||
# Primary is in metadata chunk - use backup
|
||||
merged[src_off:src_off+GDT_ENTRY] = backup_gdt[src_off:src_off+GDT_ENTRY]
|
||||
backup_used += 1
|
||||
else:
|
||||
# Both bad - shouldn't happen given our analysis
|
||||
neither += 1
|
||||
|
||||
print(f'From primary GDT: {primary_used}')
|
||||
print(f'From backup GDT: {backup_used}')
|
||||
print(f'Neither (error): {neither}')
|
||||
assert neither == 0, 'Unexpected gap in coverage!'
|
||||
|
||||
# Verify merged GDT looks sane
|
||||
print()
|
||||
print('Sample entries:')
|
||||
for g in [0, 1, 100, 1000, 32699, 35000, 35727]:
|
||||
e = merged[g*GDT_ENTRY:(g+1)*GDT_ENTRY]
|
||||
bb = struct.unpack_from('<I',e,0)[0]
|
||||
ib = struct.unpack_from('<I',e,4)[0]
|
||||
it = struct.unpack_from('<I',e,8)[0]
|
||||
cs = struct.unpack_from('<H',e,30)[0]
|
||||
print(f' Group {g:6d}: bb={bb:8d} ib={ib:8d} it={it:10d} csum=0x{cs:04x}')
|
||||
|
||||
with open('/tmp/merged_gdt.bin','wb') as f:
|
||||
f.write(merged)
|
||||
print(f'Saved /tmp/merged_gdt.bin ({len(merged)//1024}KB)')
|
||||
Reference in New Issue
Block a user