Wiping MicroSD cards quickly
To Begin With…
So I’m cleaning up some old Raspberry Pis (3s and 4s) that I had been running some services on at my house. I want to do something useful with them after the fact, so I’m wiping the SD cards in them before I donate/sell/re-purpose/etc. them. But I quickly realized that, while I know dd syntax okay, I was getting really poor performance out of the writing. Some of this came down to back block sizes and mis-matched count settings.
What do you do when you’re having trouble with the math and want things to just match up better? You write a sript!
The Script
#!/usr/bin/env bash
set -eo pipefail
unset -v device
match='/dev/sd[a-z]*'
KBBLKSIZE=64
usage() {
echo "Usage: $0 [-d] [-s] [-m] [-h]"
echo "Options:"
echo "-d The device we want to overwrite (required)"
echo "-m Match against the path of devices (optional, default ${match})"
echo "-s Size (in KB) of individual block writes (optional, default ${KBBLKSIZE})"
echo "-h This message"
}
# Parse options using getopts
while getopts ":d:m:s:" option; do
case "${option}" in
d) device="${OPTARG}" ;;
m) match="${OPTARG}" ;;
s) KBBLKSIZE="${OPTARG}" ;;
h) # Help option
usage
exit 0
;;
\?) # Invalid option
echo "Invalid option: -${option}"
usage
exit 1
;;
: ) # invalid value
echo "Invalid input: ${option} requires an argument"
usage
exit 1
;;
esac
done
set -u
if [[ ! "${device}" =~ ${match} ]]; then
printf "Please format the device correctly!\n%s doesn't match our pattern (/dev/*)" "${device}"
exit 1
fi
size=$(lsblk -Jb "${device}" | jq -r '.blockdevices[0].size')
kb_size=$(( size / 1024 ))
count=$(( kb_size / KBBLKSIZE ))
blksize=$(( KBBLKSIZE * 1024 ))
echo "Writing ${count} chunks of random data to ${device} with block size ${blksize}..."
sudo dd if=/dev/urandom of="${device}" bs="${blksize}" count="${count}" status=progress
Pretty straight forward, but to quickly run through it:
- Find the device we’re going to wipe
- Using
lsblkget the exact size (in bytes) of the device - Math up the block size vs. the device size to determine what to use for
count - Run
dd
Results
Beyond the (in retrospect, obvious) discovery that different SD cards performed at different rates, I found that using a block size of 64k seemed to be faster than other block sizes:
- 64k ~> 73 minutes
- 128k ~> 77 minutes
- 32k ~> 75 minutes
$ bash zero-disk.sh -d /dev/sda -s 64
Writing 488448 chunks of random data to /dev/sda with block size 65536...
[sudo] password :
32006930432 bytes (32 GB, 30 GiB) copied, 3778 s, 8.5 MB/s
488448+0 records in
488448+0 records out
32010928128 bytes (32 GB, 30 GiB) copied, 4404.76 s, 7.3 MB/s
$ bash zero-disk.sh -d /dev/sda -s 128
Writing 244224 chunks of random data to /dev/sda with block size 131072...
[sudo] password :
32009355264 bytes (32 GB, 30 GiB) copied, 4004 s, 8.0 MB/s
244224+0 records in
244224+0 records out
32010928128 bytes (32 GB, 30 GiB) copied, 4670.65 s, 6.9 MB/s
$ bash zero-disk.sh -d /dev/sda -s 32
Writing 976896 chunks of random data to /dev/sda with block size 32768...
[sudo] password :
32009682944 bytes (32 GB, 30 GiB) copied, 3811 s, 8.4 MB/s
976896+0 records in
976896+0 records out
32010928128 bytes (32 GB, 30 GiB) copied, 4522.26 s, 7.1 MB/s
Also, faster SD cards can write random data faster!
$ bash zero-disk.sh -d /dev/sda -s 128
Writing 243492 chunks of random data to /dev/sda with block size 131072...
[sudo] password :
31904628736 bytes (32 GB, 30 GiB) copied, 2064 s, 15.5 MB/sst
243492+0 records in
243492+0 records out
31914983424 bytes (32 GB, 30 GiB) copied, 2443.99 s, 13.1 MB/s
Note 1: The second line of dd “copied” output is after the filesystem finishes flushing.
Note 2: Obviously these are very “rough” esitmates. I: only performed one run per block size, didn’t ensure a cold cache, didn’t verify the health of the cards before runs, and didn’t let the SD adapter cool between runs. So this is mostly just interesting.