FTL

Flash Translation Layer & Logical-to-Physical Mapping (Basic/Flat L2P)

A conceptual introduction to the FTL and the logical-to-physical (L2P) table it's built around, focused on the flat/direct-mapped scheme typical of enterprise SSDs with a full DRAM budget — as opposed to the tiered/hierarchical L2P schemes client and DRAM-less drives use to get by on much less memory (a topic for a follow-on doc). This is the conceptual layer underneath the controller/FTL stage and DRAM stage in ssd-controller-architecture §2–3.


1. Why the FTL Exists

A host operating system expects to talk to a drive the way it's talked to storage for decades: a flat address space of logical block addresses (LBAs), each of which can be read, written, and overwritten in place, as many times as needed, in any order.

NAND flash physically cannot do that. As covered in nand §6, NAND has an asymmetric operation model — pages are programmed and read individually, but an entire block must be bulk-erased before any of its pages can be programmed again, and a page can't be reprogrammed in place without that intervening erase. If the host's LBA space were pinned directly to fixed physical NAND locations, every overwrite would stall on an erase, and small updates would force erasing (and rewriting) far more data than actually changed.

The flash translation layer (FTL) is the firmware layer that resolves this mismatch. It presents the host with the familiar illusion of a normal, freely-rewritable block device, while underneath it is free to write every update to a fresh, already-erased physical location and simply remember where it put it. The data structure that remembers this — the address indirection itself — is the logical-to-physical (L2P) table: an index from "LBA the host asked for" to "physical NAND location that data currently lives at."

Because updates never land back on their old physical location, the old copy doesn't disappear — it just becomes stale (invalid) data still occupying a page until that page's block is erased. Reclaiming those stale pages is garbage collection (GC), and the extra NAND writes GC generates to do so are the origin of write amplification (WAF) — covered in ssd-controller-architecture §8. The L2P table and garbage collection are two sides of the same coin: the table is what makes it possible to relocate data freely; GC is the process that has to happen because data keeps getting relocated.


2. What a Basic (Flat) L2P Table Is

In the simplest and most common enterprise scheme, the L2P table is a flat, direct-mapped array: one entry per logical block (typically a 4KB LBA), indexed directly by LBA number, holding the physical address (channel / die / plane / block / page, sometimes packed as a single flash address) where that LBA's data currently lives.

Key properties of this "basic" (non-tiered) design:

  • Fully resident in DRAM. The entire table — every LBA's mapping — is kept in the controller's onboard DRAM at all times. A common sizing rule of thumb is roughly 1 GB of DRAM per 1 TB of NAND capacity (≈4 bytes per 4KB-mapped entry, plus overhead), which is exactly the BW_DRAM / mapping-table sizing referenced in ssd-controller-architecture §3.
  • O(1), single-hop lookups. Because the table is flat and fully resident, translating any LBA to its physical location is a direct array index — no secondary index, no cache miss, no extra NAND read to find the mapping itself. This is a major reason enterprise/data-center drives with a full DRAM budget can sustain very high, consistent random IOPS: every I/O's address translation costs the same one DRAM access, regardless of access pattern.
  • Durability matters as much as speed. Since the table is the only record of where data actually lives, losing it is equivalent to losing the data itself. It has to be checkpointed to NAND periodically and reconstructed/replayed cleanly after an unexpected power loss — see power-loss-protection for how the drive protects in-flight table updates.

This is distinct from the tiered (hierarchical) L2P schemes used in many client and DRAM-less drives, where only a working set of "hot" mapping entries is cached in limited SRAM/DRAM, and the full table lives out in NAND itself, paged in on demand — trading lookup latency (and worst-case IOPS consistency) for a much smaller memory footprint. That tiered design is worth its own write-up; this document only covers the flat case.


3. The Parking Garage Analogy

A useful mental model for the whole system:

Analogy FTL/NAND concept
The parking garage The SSD
A floor of the garage A NAND block (the erase unit)
A numbered parking space A NAND page (the program/read unit)
A car A chunk of host data (one LBA's worth)
The attendant The FTL/controller
The attendant's notebook The L2P table

Parking a car (a host write). A car pulls up and the attendant doesn't force it into a specific pre-assigned space — she parks it in the next open space on whatever floor currently has room, then writes an entry in the notebook: plate "LBA 1000" → Floor 3, Space 47. The driver never needs to know or care which floor or space was used.

Retrieving a car (a host read). The owner comes back and asks for plate "LBA 1000." The attendant doesn't search the whole garage — she flips straight to that entry in the notebook, reads "Floor 3, Space 47," and walks directly there. That direct notebook lookup is exactly what makes the flat L2P table fast: one lookup, no searching.

Updating a car (overwriting an LBA). If the data for "LBA 1000" changes, the attendant doesn't walk back to Floor 3, Space 47 and repaint the car in place — she can't; that space's floor can only be cleared by sweeping the whole floor at once. Instead she parks the new version in a fresh open space somewhere else — say Floor 6, Space 12 — updates the notebook entry to point there, and marks the old Space 47 as stale: car gone, but the space hasn't been swept yet. That "stale but not yet reclaimed" space is exactly an invalid NAND page: it holds no useful data anymore, but nothing has erased it.

Cleaning a floor (garbage collection). Over time, floors fill up with a mix of cars that are still valid and spaces marked stale from cars long since relocated elsewhere. Periodically, the attendant has to reclaim space by picking a floor, driving the still-valid cars off it and packing them as tightly as possible onto another floor that has room, then sweeping the vacated floor completely clean (an erase) so it can be reopened as fresh, available parking.

Where write amplification comes from. Notice that relocating those still-valid cars is work the attendant has to do that wasn't triggered by a new car showing up at the gate — it's pure overhead generated by the need to free space. If the attendant picks a floor that's 90% stale and only 10% still-valid, she moves very few cars to free almost an entire floor — cheap. If she's forced to pick a floor that's 60% still-valid, she has to relocate a lot of cars to free the same amount of space — expensive. That ratio of "total parking moves the attendant makes" to "moves the customers actually asked for" is exactly the WAF ratio in ssd-controller-architecture §8 (WAF = total NAND bytes written / host bytes written), and it's why garbage collection algorithms specifically hunt for the floors (blocks) with the least remaining valid data to clean first — that's the cheapest space to reclaim.


4. Why This Matters for Enterprise SSDs

The flat, fully-resident L2P design is what lets enterprise/data-center drives deliver flat, predictable random-IOPS performance under sustained load — every lookup costs the same, so latency doesn't have a long tail from occasional cache misses the way it can with a tiered client-drive scheme. The tradeoff is DRAM cost and power: a full 1GB-per-1TB table is a real bill-of-materials line item, which is exactly why client and cost-sensitive drives move to the tiered/cached approach instead.

The write-amplification behavior driven by garbage collection (§3 above) is the other half of the enterprise story: over-provisioning, workload sequentiality, and GC scheduling policy all exist specifically to keep the "how many still-valid cars am I forced to relocate" ratio as low as possible, since WAF directly divides down the sustainable write throughput in the bottleneck model (BW_host_sustainable = BW_media / WAF).


5. Designing the L2P Table for Power-Loss Survival

The L2P table lives in DRAM, which is volatile — pull power and it's gone. But it's the drive's only record of where every LBA's data actually lives, so losing it without a way to reconstruct it is equivalent to losing the data itself. At the same time, it changes on essentially every host write, so whatever scheme keeps it durable has to be cheap enough to run continuously, not just occasionally.

The naive fix — rewrite the entire table to NAND every time an entry changes — is a nonstarter: at multi-GB scale, re-snapshotting the whole table for every single 4KB write would blow the write-amplification and latency budget many times over. So real designs split the problem into layers that cooperate, rather than one big periodic dump:

  • Checkpointing (the periodic photocopy). Instead of snapshotting the whole table at once, it's typically broken into fixed-size chunks (e.g., one "L2P table page" covering a contiguous LBA range), and only the chunks that have actually changed — dirty chunks — get written out to NAND, on a schedule (time-based, or after enough updates accumulate). This is the same dirty-page-writeback idea an OS page cache uses. One checkpoint is also always taken as the last step of an orderly power-loss shutdown, using the energy held in the PLP hold-up capacitor bank (power-loss-protection §5–6) to finish that flush before the rails actually collapse.
  • Journaling (the sticky notes). Between checkpoints, individual mapping updates ("LBA 1000 now lives at physical address X") are appended to a small, fast, sequentially-written log region rather than touching the bulky table itself — cheap, because it's purely an append. On a clean or PLP-assisted shutdown the journal gets fully flushed and a checkpoint taken, resetting it to empty. On recovery from an unclean power loss, the FTL loads the last valid checkpoint and replays the journal entries written since then, in order, to bring the in-DRAM table back to exactly its state the instant before power was lost. This log-structured update pattern is the piece some drives lean on heavily — appending small journal records is far cheaper than repeatedly touching the full table.
  • Multiple layers tied together with sequence numbers. This is the "multiple layers that have to be periodically saved" shape: the live table in DRAM, a checkpoint on NAND, and a journal on NAND, and correctness hinges entirely on the FTL knowing, on every boot, exactly which journal entries are newer than the checkpoint it just loaded. That's handled with a monotonically increasing sequence/generation number stamped on every checkpoint and every journal entry — recovery loads the highest-numbered valid checkpoint, then replays only the journal entries whose sequence number is greater than that checkpoint's.
  • Never overwrite the only copy. A checkpoint write can itself be interrupted by a power event mid-write, so checkpoints — and the small pointer that says "which checkpoint is current" (often called a superblock) — are written to alternating regions (A/B, or a small ring of slots) rather than in place. A torn checkpoint write then just leaves the previous, still-intact checkpoint as the valid fallback, instead of corrupting the drive's only record of itself.
  • Self-describing pages: the backstop of last resort. Underneath all of that, most designs also tag every NAND page's out-of-band (OOB)/spare area with the LBA (and often a sequence number) it holds at the moment it's written. This doesn't replace checkpoint-plus-journal — it's a fallback: if the journal or checkpoint region is itself found corrupted at boot, the FTL can fall back to scanning the raw media and rebuilding the entire L2P table purely from what's tagged on each page. Slow — a full-media scan can take minutes on a large drive — but it's the guaranteed-correct backstop, which is why it earns its keep even in a design that normally never has to reach for it.

Extending the analogy: the attendant's live notebook (DRAM) is what she works out of day to day, but she also periodically photocopies its pages into a fireproof filing cabinet (a checkpoint), and between photocopies she jots each new move on a sticky note pinned to a corkboard (the journal) rather than re-copying the whole notebook every time a single car moves. If the power goes out, whoever takes over pulls the latest photocopy from the cabinet and works through the sticky notes in order — newest first, stopping once they run out — to bring a fresh working notebook back up to date. And as a genuine last resort, every car has its plate number and a timestamp taped to the windshield — so even if the cabinet burned down and the corkboard blew away, a new attendant could walk every floor, read every windshield, and rebuild the whole notebook from scratch. Slow, but it always works.


6. Valid Maps: What Garbage Collection Actually Needs Beyond the L2P Table

The L2P table only answers one direction of question: given an LBA, where does its current data live? Garbage collection needs the opposite question answered, and the L2P table alone doesn't answer it efficiently: given a physical block, how much of what's in it is still current, and which LBAs does that current data belong to?

Why the L2P table alone isn't enough. In principle you could test whether one physical page is still valid by reading the LBA tag out of its OOB metadata, looking up L2P[that LBA], and checking whether it still points back to this exact physical page. That's a correct test — but doing it one page at a time, for every page in every candidate block, just to decide whether a block is worth cleaning, is far too slow to run as a routine background task across the whole drive.

The valid page bitmap. So the FTL keeps a second structure, maintained alongside the L2P table rather than instead of it: one bit per physical page, marking it valid (still the current home of some LBA) or invalid (stale — a later write moved that LBA elsewhere). Every time the FTL updates L2P[LBA] to point at a new physical page, it does two things as part of that same atomic update: set the valid bit at the new location, and clear the valid bit at the old one. In garage terms, this is exactly the attendant marking a space "occupied" the instant she parks a car there, and marking the old space "cleared for sweeping" the instant she repoints the notebook entry — it's a byproduct of the same notebook edit from §3, not a separate bookkeeping task.

The valid page count. A full bitmap is fine for checking one page, but GC's actual job is choosing which block to clean, and for that most designs also keep a much smaller per-block valid-page count (or equivalently, an invalid/stale count) that's incremented/decremented in lockstep with the bitmap. Victim selection then just scans this small per-block table for the lowest valid count — the mostly-stale floor from the §3 cleaning example — instead of scanning full-resolution bitmaps across the entire drive.

The reverse-lookup problem. Choosing a victim block only tells GC that some pages in it are still valid — actually relocating them requires knowing which LBA each valid page belongs to, so GC can write the data elsewhere and repoint L2P[LBA] there. This is the OOB tag from §5 again, doing double duty: rather than maintaining a separate, large physical-to-logical (P2L) table that mirrors the L2P table in reverse — more DRAM, and one more structure that has to stay perfectly in sync — most designs just read the LBA identifier straight out of the page's own OOB metadata at GC time.

Keeping the valid map itself durable. The valid bitmap/count is derived data: in principle it can always be rebuilt after any L2P recovery by scanning OOB tags against the recovered L2P table — the same "naive test" described above, just run once at boot instead of continuously. In practice, most designs checkpoint the compact per-block valid counts alongside the L2P checkpoint anyway, purely to avoid paying for that full-media scan on every boot, and only fall back to a real rebuild-from-scan if the checkpointed valid-count data itself doesn't check out.


Open Follow-Ons (for future sections/docs)

  • Tiered/hierarchical L2P (client, DRAM-less/HMB-based drives) — the cached-working-set version of this same idea.
  • Wear leveling — how the attendant decides which open floor/space to use so no single floor wears out faster than the others.
  • GC victim-selection policy in more depth — greedy (lowest valid count) vs. cost-benefit models that also weigh how "cold" (rarely rewritten) a block's data is.
  • Page-level vs. block-level mapping granularity tradeoffs.

Sources

Contact

Have an Idea?
Let's Build It.

Whether you're a startup with a hardware concept, an established company needing deep design help, or an enthusiast with a wild project — we want to hear about it.

LocationBoulder, Colorado