Skip to content

Instantly share code, notes, and snippets.

@lesterlo
Last active August 1, 2025 12:47
Show Gist options
  • Save lesterlo/bff0286bfbfd90c5dafecc34df245488 to your computer and use it in GitHub Desktop.
Save lesterlo/bff0286bfbfd90c5dafecc34df245488 to your computer and use it in GitHub Desktop.
Evaluate eMMC block integrity
#!/bin/bash
# Changable Variables
DEV="/dev/mmcblk1"
TEST_PATTERN_FILENAME="test_pattern.bin"
BLOCKS_PER_CHUNK=$((2** 13)) # Increase this will make the test go faster. The value should be a multiple of power of 2. Value 15 is the MAX, value >= 13 didn't have a big impact on speed.
# Calculate total blocks based on block size
TOTAL_BYTES=$(blockdev --getsize64 "$DEV")
#TOTAL_BYTES=$((50 * 1024 * 1024)) # Test
LOGICAL_BLOCK_SIZE=$(blockdev --getbsz "$DEV")
CHUNK_SIZE=$((LOGICAL_BLOCK_SIZE * BLOCKS_PER_CHUNK))
TOTAL_BLOCKS=$((TOTAL_BYTES / LOGICAL_BLOCK_SIZE))
TOTAL_CHUNKS=$((TOTAL_BLOCKS / BLOCKS_PER_CHUNK))
TEST_PATTERN="/tmp/$TEST_PATTERN_FILENAME"
echo " "
gen_test_pattern() {
local gen_size=$1
echo "[INFO] Generating test pattern file: $TEST_PATTERN with size $gen_size bytes"
head -c $gen_size /dev/urandom > "$TEST_PATTERN"
}
# Generate the Block pattern file
gen_test_pattern $CHUNK_SIZE
# Get total size in bytes
echo "---------- Test Info -------------"
echo "[INFO] Choosing Device: $DEV"
echo "[INFO] Device Size: $(echo "scale=2; $TOTAL_BYTES/ 1024 / 1024 " | bc) MB"
echo "[INFO] Logical Block size: $LOGICAL_BLOCK_SIZE bytes"
echo "[INFO] Total blocks on dev: $TOTAL_BLOCKS"
echo "[INFO] Chunk size on test: $(echo "scale=2; $CHUNK_SIZE / 1024 / 1024 " | bc) MB"
echo "[INFO] Total chunk to test: $TOTAL_CHUNKS"
echo "---------- Test Running ----------"
fail_flag=0
total_write_time=0
total_read_time=0
successful_chunks=0
success_remaining_blocks=0
for ((i=0; i<TOTAL_CHUNKS; i++)); do
# Write pattern to block i
write_start=$(date +%s.%N)
dd if="$TEST_PATTERN" of="$DEV" bs=$CHUNK_SIZE seek=$i count=1 oflag=direct status=none
write_end=$(date +%s.%N)
write_time=$(echo "$write_end - $write_start" | bc)
write_speed=$(echo "scale=2; $CHUNK_SIZE / 1024 / 1024 / $write_time" | bc)
total_write_time=$(echo "$total_write_time + $write_time" | bc)
# Read back and compare
read_start=$(date +%s.%N)
dd if="$DEV" bs=$CHUNK_SIZE skip=$i count=1 iflag=direct status=none | cmp -s "$TEST_PATTERN"
read_result=$?
read_end=$(date +%s.%N)
read_time=$(echo "$read_end - $read_start" | bc)
read_speed=$(echo "scale=2; $CHUNK_SIZE / 1024 / 1024 / $read_time" | bc)
total_read_time=$(echo "$total_read_time + $read_time" | bc)
# Print progress
echo -ne "\r[INFO] Testing block $i / $TOTAL_CHUNKS... Write: ${write_speed} MB/s, Read: ${read_speed} MB/s"
if [ $read_result -ne 0 ]; then
echo -e "\n[FAIL] Mismatch at block $i"
fail_flag=1
else
successful_chunks=$((successful_chunks + 1))
success_blocks=$((success_blocks+BLOCKS_PER_CHUNK))
fi
done
# Process remaining blocks if any
REMAINING_BLOCKS=$(( TOTAL_BLOCKS - TOTAL_CHUNKS * BLOCKS_PER_CHUNK ))
REMAINING_BYTES=$(( REMAINING_BLOCKS * LOGICAL_BLOCK_SIZE ))
echo " "
echo "[INFO] Remaining block to test: $REMAINING_BLOCKS"
if [ "$REMAINING_BYTES" -gt 0 ]; then
gen_test_pattern $REMAINING_BYTES
echo "[INFO] Testing last partial chunk..."
seek_block=$((TOTAL_CHUNKS * BLOCKS_PER_CHUNK))
dd if="$TEST_PATTERN" of="$DEV" bs=$LOGICAL_BLOCK_SIZE seek=$seek_block count=$REMAINING_BLOCKS oflag=direct conv=notrunc status=none
dd if="$DEV" bs=$LOGICAL_BLOCK_SIZE skip=$seek_block count=$REMAINING_BLOCKS iflag=direct status=none | cmp -s "$TEST_PATTERN"
if [ $? -ne 0 ]; then
echo "[FAIL] Mismatch in final partial chunk"
fail_flag=1
else
success_remaining_blocks=$REMAINING_BLOCKS
fi
fi
echo -e "\n[INFO] Testing complete."
# --- Calculation ---
total_success_bytes=$((successful_chunks * CHUNK_SIZE + success_remaining_blocks * LOGICAL_BLOCK_SIZE))
total_mb=$(echo "scale=2; $total_success_bytes / 1024 / 1024" | bc)
avg_write_speed=$(echo "scale=2; $total_mb / $total_write_time" | bc)
avg_read_speed=$(echo "scale=2; $total_mb / $total_read_time" | bc)
# Print summary
echo "---------- Full Test Summary ----------"
echo "eMMC extcid: $(cat /sys/kernel/debug/mmc1/mmc1:0001/ext_csd)"
echo "---------- Summary --------------------"
echo "Success Rate : $(echo "scale=2; $total_success_bytes / $TOTAL_BYTES * 100" | bc)%"
echo "Success Block : $((successful_chunks * BLOCKS_PER_CHUNK + success_remaining_blocks))/$TOTAL_BLOCKS"
echo "Tested Chunk size : $(echo "scale=2; $CHUNK_SIZE / 1024 " | bc) KB"
echo "Total data tested : $total_mb MB"
echo "Avg Write Speed : $avg_write_speed MB/s"
echo "Avg Read Speed : $avg_read_speed MB/s"
if [ $fail_flag -ne 0 ]; then
echo -e "\n[ERROR] Some blocks failed verification."
exit 1
else
echo -e "\n[SUCCESS] All blocks passed verification."
exit 0
fi
#------------ Notes ---------------
# Manual Check for first 1 M
# dd if=/dev/mmcblk1 bs=4096 count=2 | hexdump -C | head
#Manual fill, contaminate block 10
#yes '2' | tr -d '\n' | head -c $((1 * 1024)) | dd of="/dev/mmcblk1" bs=4096 seek=10 status=progress oflag=direct
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment