An SSD accepts 4 KB writes to any LBA, forever, like a very fast disk. The physics underneath permits none of that: NAND flash cannot overwrite a written page — it must be erased first — and erasure only happens in blocks of hundreds of pages, each surviving a finite number of erase cycles. Between the interface and the physics sits a full embedded computer (multi-core controller, DRAM, firmware) running the flash translation layer, and every strange SSD behavior — the performance cliff when full, the need for TRIM, drives dying by warranty math — is FTL bookkeeping showing through.

The Constraint Set

text
  read:   per page (~4-16 KB)      fast (~50-100 µs)
  write:  per page, blank only     slower (~200+ µs... and see below)
  erase:  per BLOCK (~256+ pages)  slow (~ms), and each block endures
                                   only ~1-3k cycles (TLC/QLC era)

Overwrite-in-place under these rules would mean: read the whole block, erase it (milliseconds), write it all back — and burn one of your few thousand cycles per 4 KB update. No.

The FTL’s Answer: Never Overwrite, Always Remap

The FTL keeps a mapping table (LBA → physical page, gigabytes of DRAM on big drives) and turns every write into an append: incoming data goes to a fresh page in a currently-open block, the map is updated, and the old page is merely marked stale. Sound familiar? Your SSD is an LSM-ish log-structured store, and like every such design it owes a garbage-collection debt: eventually the drive must reclaim stale pages by picking victim blocks, copying their still-live pages elsewhere, and erasing. Those internal copies are writes you didn’t issue — write amplification (WA): host writes 1 GB, NAND absorbs 2–4 GB, endurance and performance both divide by that factor.

WA is workload-shaped, and the shape rules are worth memorizing: sequential writes fill blocks that die together (WA→1); small random writes across a full drive scatter live/stale pages evenly so every victim block is half-alive (WA→high); and free space is the GC’s working room — which is the real explanation of the famous cliff. A drive at 50% full finds nearly-dead victim blocks easily; at 95%, every collection copies mostly-live data to reclaim slivers. Steady- state random-write throughput can drop 3–10× between an empty and a full drive — enterprise drives ship 10–28% hidden over-provisioning precisely to floor this, and you can add more by simply leaving a partition short.

This is also why TRIM matters: without it, the FTL doesn’t know deleted-file pages are dead (the filesystem just edited its own metadata) and dutifully GC-copies garbage. fstrim.timer weekly is the Linux default for a reason. And wear leveling is the FTL’s third job: rotating erase load across blocks (including moving cold data off healthy blocks so they can take heat), tracked publicly in SMART — smartctl -a shows percentage-used/wear-level counters, and endurance is sold as TBW/DWPD numbers that are just (cycles × capacity ÷ WA) arithmetic.

The Performance Personality

Two more internals explain the benchmarks that confuse people. SLC caching: TLC/QLC cells are slow to program, so consumer drives write incoming data in fast 1-bit-per-cell mode into a dynamic cache region, folding it to dense storage later — hence the pattern where a drive writes at 5 GB/s for 30 seconds and then drops to 500 MB/s (cache exhausted, now folding while ingesting). Sustained-write workloads should be benchmarked past the cache. Parallelism is the whole speed story: a big SSD is 8–16 channels × multiple dies, and peak IOPS exist only at high queue depth (QD1 4K random read latency ~60–80 µs is physics; the million-IOPS spec sheet number is QD32+ across many jobs — fio with iodepth=1 vs 32 shows both truths). Meanwhile NVMe removed the software bottleneck (64k queues, MSI-X per queue, no SATA AHCI single-queue chokepoint), which is why the protocol switch mattered as much as the flash.

The through-line for systems people: databases and filesystems built their own log-structured layers on top (WAL, LSM trees, F2FS), so a modern write path is often logs stacked on logs, each with its own GC — and the tuning literature (align writes, batch small writes, leave headroom, TRIM) is the same advice at every layer because it’s the same design underneath.

Takeaways

  • Flash forbids overwrite and erases by block; the FTL converts your writes into an internal append-log with mapping + GC + wear leveling.
  • Write amplification is the tax: sequential ≈1, small-random-when-full worst; endurance and steady-state speed both divide by it.
  • Free space is GC headroom — the full-drive cliff is real; over- provision (or under-partition) and run fstrim.
  • SLC caches make burst ≠ sustained; parallelism makes QD1 ≠ spec-sheet IOPS — benchmark the case you actually run.
  • Your storage stack is logs-on-logs; the same batching/headroom advice applies at every layer because it’s the same architecture.