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:

  1. Find the device we’re going to wipe
  2. Using lsblk get the exact size (in bytes) of the device
  3. Math up the block size vs. the device size to determine what to use for count
  4. 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.