Deleting a file on Linux is cheap for a reason that used to not matter, and now matters a great deal: the filesystem only updates its own bookkeeping (the directory entry and the free-space bitmap), it doesn’t actually erase the underlying sectors. On a spinning hard disk that’s a harmless optimization. On flash storage it creates a hidden cost. This lesson, part of our free linux device drivers course and free embedded linux course series, explains why, and shows how the discard/TRIM mechanism fixes it.
What You Will Learn
- Why deleting a file doesn’t actually free space at the flash chip level
- How the discard/TRIM mechanism closes that gap between filesystem and flash controller
- How to check whether your storage device and driver support discard
- The difference between mount-time discard and periodic
fstrim - Common pitfalls when enabling discard on embedded products
Prerequisites
- This lesson builds directly on Flash Filesystem Selection Guide — read that first if you haven’t
- Comfort running commands as root and reading
/sysfiles
The Stale Data Problem
When you delete a file on any filesystem, the operating system removes the directory entry and marks the data blocks as free in its own metadata. It does not, as a rule, overwrite the sectors that used to hold the file’s contents — there’s no need to, since nothing will read them again through the filesystem.
On a plain hard disk, that’s the end of the story. On managed flash, it isn’t, because the flash translation layer (FTL) inside the eMMC or SSD controller has no visibility into filesystem metadata. From the controller’s point of view, those sectors still contain valid data, because nobody told it otherwise. The FTL will happily keep relocating and garbage-collecting that stale data during wear leveling — real work spent preserving bytes nobody wants anymore.
Enter discard / TRIM
The fix is a small addition to the storage command set that lets the OS explicitly tell the controller “these sectors no longer matter, you don’t need to preserve their contents.” The exact command name depends on the storage interface:
| Interface | Command name | Linux term |
|---|---|---|
| SATA | TRIM | discard |
| SCSI | UNMAP | discard |
| MMC/eMMC | ERASE | discard |
| NVMe | Deallocate | discard |
Linux exposes all of these under one umbrella name: discard. Once the filesystem sends a discard request for a range of sectors, the controller is free to skip them entirely during garbage collection, or even zero them out immediately, depending on the device.
Checking Whether Your Device Supports Discard
Support for discard isn’t universal, and it isn’t automatic just because the chip is flash-based — the device firmware and the kernel block driver both have to cooperate. You can check the block layer’s queue parameters directly under /sys:
$ grep -s "" /sys/block/mmcblk1/queue/discard_*
/sys/block/mmcblk1/queue/discard_granularity:524288
/sys/block/mmcblk1/queue/discard_max_bytes:4294967295
/sys/block/mmcblk1/queue/discard_zeroes_data:0
Three fields matter here:
- discard_granularity — the smallest chunk the device can discard in one operation. Note it lines up closely with the erase block size we measured with Flashbench in the previous lesson — that’s not a coincidence.
- discard_max_bytes — the largest single discard request the device will accept.
- discard_zeroes_data — if set to 1, discarded sectors are guaranteed to read back as zero; if 0, their contents are undefined until overwritten.
If a device or its driver doesn’t support discard at all, every one of these fields reads back as zero.
Two Ways To Trigger Discard
1. Mount-time discard
Both ext4 and F2FS accept a mount option that sends a discard request synchronously, as part of every delete or overwrite operation:
# mount -t ext4 -o discard /dev/mmcblk1p2 /mnt/data
This keeps the flash controller’s view of free space up to date in real time, but it does add a small amount of latency to every write path, since each delete now triggers an extra command to the device.
2. Periodic fstrim
The alternative is to mount normally (without -o discard) and instead run the fstrim command on a schedule — typically via a systemd timer or a cron job once a day or once a week. fstrim operates on an already-mounted filesystem and walks its free-space map, discarding everything that’s currently unused in one batch:
$ sudo fstrim -v /mnt/data
/mnt/data: 512983040 bytes were trimmed
The -v flag reports how many bytes were freed at the device level — a useful number to log if you’re debugging why a product’s flash appears to be wearing out faster than expected.
A Minimal Discard-Aware Maintenance Script
Here’s an original example of a small maintenance script suitable for a systemd timer on an embedded board, discarding all mounted flash filesystems that support it:
#!/bin/sh
# ep_trim_flash.sh — trim every mounted filesystem that supports discard
for mnt in $(awk '$3 == "ext4" || $3 == "f2fs" {print $2}' /proc/mounts); do
dev=$(findmnt -n -o SOURCE --target "$mnt")
gran=$(cat /sys/class/block/$(basename "$dev")/queue/discard_granularity 2>/dev/null || echo 0)
if [ "$gran" != "0" ]; then
echo "Trimming $mnt ($dev, granularity ${gran} bytes)"
fstrim -v "$mnt"
else
echo "Skipping $mnt ($dev) — discard not supported"
fi
done
$ sudo ./ep_trim_flash.sh
Trimming / (/dev/mmcblk1p2, granularity 524288 bytes)
/: 512983040 bytes were trimmed
Skipping /mnt/usb (/dev/sda1) — discard not supported
Common Mistakes And Troubleshooting
- Enabling
-o discardwithout checking support first. The mount option is accepted silently even on devices that don’t support discard — it just becomes a no-op, but you lose the opportunity to catch a misconfigured board early. Always checkdiscard_granularityfirst. - Assuming discard implies secure erase. Unless
discard_zeroes_datais 1, a discarded sector’s old contents may still be recoverable until overwritten — don’t rely on discard alone for wiping sensitive data. - Running
fstrimon a busy production system during peak load. A full-filesystem trim can briefly compete with application I/O; schedule it for an idle period. - Forgetting removable media.
fstrimand mount-time discard only help the filesystems you actually enable them on — a vfat-formatted SD card used for data logging gets none of this benefit.
Best Practices
- Prefer periodic
fstrimover mount-time-o discardon latency-sensitive embedded workloads, since it batches the cost into a maintenance window. - Log the bytes-trimmed output over the product’s lifetime — a sudden drop can indicate the filesystem is filling up in a way discard can’t help with.
- Verify discard support on every new eMMC part number, not just once per product line.
Security Considerations
If your product handles sensitive data and relies on deletion for compliance, don’t treat discard as secure erase. Check discard_zeroes_data, and where guaranteed erasure matters, use a dedicated secure-erase command supported by your storage device instead of assuming a plain discard is sufficient.
Summary / Key Takeaways
- Deleting a file only updates filesystem metadata — the flash controller doesn’t know the space is free unless it’s told.
- Linux’s
discardmechanism maps onto TRIM/UNMAP/ERASE/Deallocate depending on the underlying interface. - Check
/sys/block/<device>/queue/discard_*before relying on discard support. - Use mount-time
-o discardfor real-time cleanup or periodicfstrimfor batched, lower-latency maintenance.
Conclusion
Discard support is one of those features that costs almost nothing to enable correctly and quietly extends the useful life of your product’s flash storage. The key is checking support before assuming it, and picking the trigger mechanism — mount-time or periodic — that matches your workload’s latency budget. Next in this chapter, we’ll put this all together and walk through building and mounting an ext4 filesystem tuned for flash from scratch.
FAQ
What is the difference between discard and TRIM?
TRIM is the SATA-specific command name; Linux uses “discard” as a generic term covering TRIM, SCSI UNMAP, MMC ERASE, and NVMe Deallocate.
Does enabling discard slow down my embedded product?
Mount-time discard adds a small latency cost to every delete/overwrite. Periodic fstrim avoids that by batching the work into a scheduled maintenance window instead.
How do I know if my eMMC chip supports discard?
Check /sys/block/<device>/queue/discard_granularity — if it reads 0, the device or driver doesn’t support it.
Is discard the same as securely wiping data?
Not unless discard_zeroes_data is 1. Otherwise the old data may still be recoverable from the chip until it’s physically overwritten.
Which filesystems support the discard mount option?
Both ext4 and F2FS support -o discard, along with several other Linux filesystems designed with flash or SSD storage in mind.
Should I use fstrim or mount-time discard on an embedded board?
For most embedded workloads, periodic fstrim via a systemd timer is the safer default since it keeps discard cost off the hot write path.
Keep Learning Embedded Linux Storage
This lesson is part of a free, complete embedded Linux and kernel development course.
Browse the Free Course Next Lesson: Ext4 For Flash Storage
2 Comments