Initial remote commit
This commit is contained in:
100
misc_tools/checkfifth.py
Normal file
100
misc_tools/checkfifth.py
Normal file
@@ -0,0 +1,100 @@
|
||||
CHUNK = 128*512
|
||||
LV_START = 5120000*512
|
||||
BSIZE = 4096
|
||||
|
||||
# We know block 9262 is the root directory data block
|
||||
# and it reads correctly. Let's find its chunk position.
|
||||
known_virt = 9262 * BSIZE
|
||||
group = known_virt // (5*CHUNK)
|
||||
in_group = known_virt % (5*CHUNK)
|
||||
chunk_idx = in_group // CHUNK
|
||||
intra = in_group % CHUNK
|
||||
|
||||
print(f'Root dir block 9262: chunk_group={group} chunk_idx={chunk_idx}')
|
||||
|
||||
# Now check the 5th chunk in the SAME group
|
||||
meta_virt = group * 5 * CHUNK + 4 * CHUNK
|
||||
print(f'5th chunk in same group at phys byte: {LV_START + meta_virt}')
|
||||
|
||||
# Read 512 bytes from the 5th chunk
|
||||
with open('/dev/md0','rb') as f:
|
||||
f.seek(LV_START + meta_virt)
|
||||
data = f.read(512)
|
||||
print(f'First 64 bytes: {data[:64].hex()}')
|
||||
print()
|
||||
|
||||
# Compare with what we read from the PERC metadata chunk earlier
|
||||
# istat showed volumes dir data at block 5251104 (chunk_idx=4)
|
||||
# Let's check if that block's data might actually be at a different
|
||||
# physical location - maybe the PERC remapped it
|
||||
|
||||
# What if for chunk_idx=4, the data is stored in a DIFFERENT disk's
|
||||
# corresponding chunk? i.e. the PERC uses the 5th physical chunk
|
||||
# on a different disk?
|
||||
|
||||
# Our disk order: sda(0) sde(1) sdd(2) sdc(3)
|
||||
# In RAID0: chunk N goes to disk N%4
|
||||
# For a group of 5 virtual chunks:
|
||||
# virtual chunk 0 -> disk 0
|
||||
# virtual chunk 1 -> disk 1
|
||||
# virtual chunk 2 -> disk 2
|
||||
# virtual chunk 3 -> disk 3
|
||||
# virtual chunk 4 -> ??? (metadata chunk - no disk?)
|
||||
|
||||
# BUT: if the physical layout has 5 chunks per group across 4 disks
|
||||
# maybe it's: disk0 gets chunks 0,4 / disk1 gets chunk1 / etc?
|
||||
# Or maybe all 5 chunks exist on disk but chunk 4 is PERC metadata
|
||||
# that happens to occupy the same space as filesystem data?
|
||||
|
||||
# The PERC sector-level metadata we found earlier:
|
||||
# Each 64KB metadata chunk stores 512 bytes per sector of the adjacent data
|
||||
# That's 128 sectors * 512 bytes = 64KB of per-sector checksums/metadata
|
||||
# So the 5th chunk IS pure PERC internal data, not filesystem data
|
||||
|
||||
# This means: filesystem block 5251104 maps to virtual chunk_idx=4
|
||||
# BUT the actual filesystem data for that block must be stored differently
|
||||
# OR the block number in the inode is a VIRTUAL block number
|
||||
# that the PERC translates differently than we think
|
||||
|
||||
# Let's check: what if block numbers in inodes are PERC virtual block numbers?
|
||||
# PERC virtual block 5251104:
|
||||
# In PERC virtual space (5 chunks per group):
|
||||
# group = 5251104*4096 // (5*CHUNK) = ?
|
||||
perc_virt_byte = 5251104 * BSIZE
|
||||
perc_group = perc_virt_byte // (5*CHUNK)
|
||||
perc_in_group = perc_virt_byte % (5*CHUNK)
|
||||
perc_chunk_idx = perc_in_group // CHUNK
|
||||
perc_intra = perc_in_group % CHUNK
|
||||
|
||||
print(f'If block 5251104 is PERC virtual:')
|
||||
print(f' PERC group={perc_group} chunk_idx={perc_chunk_idx} intra={perc_intra}')
|
||||
|
||||
# And the physical location would be:
|
||||
# physical = LV_START + perc_group*4*CHUNK + perc_chunk_idx*CHUNK + perc_intra
|
||||
if perc_chunk_idx != 4:
|
||||
phys = LV_START + perc_group*4*CHUNK + perc_chunk_idx*CHUNK + perc_intra
|
||||
print(f' Physical byte: {phys}')
|
||||
with open('/dev/md0','rb') as f:
|
||||
f.seek(phys)
|
||||
data = f.read(BSIZE)
|
||||
nonzero = sum(1 for b in data if b != 0)
|
||||
print(f' Nonzero: {nonzero}/4096')
|
||||
print(f' First 32: {data[:32].hex()}')
|
||||
|
||||
# Try to parse as directory
|
||||
import struct
|
||||
off = 0
|
||||
print(' Directory entries:')
|
||||
while off < BSIZE-8:
|
||||
ino = struct.unpack_from('<I', data, off)[0]
|
||||
rec_len = struct.unpack_from('<H', data, off+4)[0]
|
||||
name_len= data[off+6]
|
||||
ftype = data[off+7]
|
||||
if rec_len < 8: break
|
||||
if ino > 0 and name_len > 0:
|
||||
name = data[off+8:off+8+name_len].decode('utf-8',errors='replace')
|
||||
tname = {1:'file',2:'dir',7:'link'}.get(ftype,'?')
|
||||
print(f' {tname} inode={ino} {name!r}')
|
||||
off += rec_len
|
||||
else:
|
||||
print(f' Still in metadata chunk!')
|
||||
Reference in New Issue
Block a user