спроектирована Samsung под геометрию NAND flash — почему обычная ФС на SSD платит скрытый налог, которого F2FS старается избежатьdesigned by Samsung around NAND flash geometry — why an ordinary filesystem on an SSD pays a hidden tax that F2FS tries to avoid

F2FS: структуры на диске и алгоритмы работыF2FS: on-disk structures and working algorithms

F2FS (Flash-Friendly File System) — файловая система, которую Samsung в 2012 году спроектировала и передала в Linux специально под физику flash-накопителей, а не адаптировала под неё уже существующую ФС. NAND flash не умеет перезаписывать данные на месте — только стирать целыми крупными блоками и писать последовательно; ext4 и большинство классических ФС были спроектированы под жёсткие диски, где перезапись на месте — базовая операция. F2FS использует подход log-structured filesystem — пишет только последовательно, добавляя новые данные в конец лога, а не переписывая старые — и решает при этом классическую проблему таких систем (wandering tree), из-за которой более ранние реализации log-structured FS плохо масштабировались.F2FS (Flash-Friendly File System) is a filesystem Samsung designed from scratch and contributed to Linux in 2012 specifically around the physics of flash storage, rather than adapting an existing filesystem to it. NAND flash can't overwrite data in place — it can only erase in large blocks and write sequentially; ext4 and most classic filesystems were designed around hard disks, where in-place overwriting is a basic operation. F2FS uses a log-structured filesystem approach — writing only sequentially, appending new data to the end of a log rather than overwriting old data — while solving the classic problem (the wandering tree) that made earlier log-structured filesystem implementations scale poorly.

Что этоWhat it is

Ключевая физическая особенность NAND flash: читать и писать можно постранично (обычно 4 КиБ), но стирать — только целыми блоками (block/erase unit), которые намного крупнее страницы и включают в себя много страниц сразу. Изменить один байт в уже записанной странице напрямую нельзя — необходимо стереть весь блок целиком и записать его заново. Обычная файловая система, спроектированная под диск с произвольной перезаписью (ext4, XFS), не знает об этом ограничении и рассеивает мелкие обновления по всему устройству — контроллер SSD (FTL, flash translation layer) вынужден скрыто перекладывать данные, чтобы освободить блок для стирания. Это и есть write amplification: реальный объём физической записи на flash оказывается больше объёма, который запросило приложение, что сокращает ресурс накопителя и снижает производительность. F2FS решает эту проблему не на уровне контроллера, а на уровне самой файловой системы — организуя запись так, чтобы она изначально была последовательной и группировала данные по ожидаемой частоте обновления.The key physical trait of NAND flash: reading and writing can happen per-page (usually 4 KiB), but erasing only works on whole blocks (the block/erase unit), which are much larger than a page and contain many pages at once. A single byte in an already-written page can't be changed directly — the entire block has to be erased and rewritten. An ordinary filesystem designed around a disk with arbitrary in-place overwrites (ext4, XFS) doesn't know about this constraint and scatters small updates across the whole device — the SSD's controller (the FTL, flash translation layer) is then forced to shuffle data around behind the scenes to free up a block for erasing. That's write amplification: the actual amount of physical flash writes ends up larger than what the application requested, which shortens the drive's lifespan and hurts performance. F2FS solves this problem not at the controller level but at the filesystem level itself — organizing writes so they're sequential from the start and grouping data by expected update frequency.

параметрparameterext4F2FS
модель записиwrite modelперезапись на месте (in-place), спроектирована под HDDin-place overwrite, designed for HDDsтолько последовательное добавление в конец лога (log-structured), спроектирована под flashsequential append-only logging (log-structured), designed for flash
знание о геометрии устройстваawareness of device geometryнет — переносит write amplification на FTL контроллераnone — offloads write amplification onto the controller's FTLда — размер сегмента/секции настраивается под геометрию конкретного устройства при mkfsyes — segment/section size is tuned to the specific device's geometry at mkfs time
разделение горячих/холодных данныхhot/cold data separationнетnoда — данные и метаданные записываются в разные потоки логов по ожидаемой частоте обновленияyes — data and metadata are written into separate log streams based on expected update frequency
типичное применениеtypical use caseуниверсальный десктоп/сервер, любой тип накопителяgeneral-purpose desktop/server, any storage typeAndroid (основная ФС для /data с версии 9), embedded с eMMC/UFS/SD, отчасти десктопные SSDAndroid (the primary /data filesystem since version 9), embedded with eMMC/UFS/SD, some desktop SSDs

Как это устроено внутриHow it's built internally

Весь том F2FS делится на четыре уровня физической организации, вложенные друг в друга, а не только на «блоки» как в ext4 — это прямое отражение многослойной геометрии самого flash-накопителя (страница → блок стирания → плоскость → устройство):An entire F2FS volume is split into four levels of physical organization, nested inside each other, not just "blocks" like ext4 — a direct reflection of the flash device's own layered geometry (page → erase block → plane → device):

block 4 КиБ ×512 segment 2 МиБ, фиксирован ×N section 1+ сегментов подряд ×M zone 1+ секций том целиком делится на шесть областей (кроме суперблока — все состоят из сегментов): superblock checkpoint SIT valid blocks NAT node addr. table SSA summary area Main Area сами данные и node-блоки начало checkpoint выравнивается по границе сегмента, начало Main Area — по границе zone (F2FS резервирует под это несколько сегментов SSA) — выравнивание физической записи под границы стирания flash
Блок (4 КиБ) — минимальная единица записи; 512 блоков образуют фиксированный сегмент (2 МиБ); секция — один или несколько сегментов подряд; зона — одна или несколько секций. По умолчанию секция и зона равны размеру одного сегмента, но mkfs.f2fs позволяет увеличить их под реальный размер блока стирания конкретного flash-устройства. Весь том, кроме суперблока, состоит из областей метаданных (checkpoint, SIT, NAT, SSA) и Main Area с данными.A block (4 KiB) is the minimum write unit; 512 blocks form a fixed segment (2 MiB); a section is one or more consecutive segments; a zone is one or more sections. By default a section and a zone equal one segment's size, but mkfs.f2fs lets them be enlarged to match a specific flash device's real erase-block size. The whole volume, aside from the superblock, is made of metadata areas (checkpoint, SIT, NAT, SSA) and the Main Area holding the data.

Log-structured файловые системы существовали и до F2FS, но классическая реализация страдала от так называемой проблемы wandering tree: если файл адресуется деревом указателей (inode → indirect block → data block), а запись всегда идёт в новое место, то изменение одного блока данных требует переписать указывающий на него indirect-блок в новое место, что требует переписать указывающий уже на него блок ещё выше — изменение одного листа лавинообразно «расползается» вверх до самого корня дерева при каждой записи:Log-structured filesystems existed before F2FS, but the classic implementation suffered from the so-called wandering tree problem: if a file is addressed by a tree of pointers (inode → indirect block → data block), and writes always go to a new location, then changing one data block requires rewriting the indirect block pointing to it at a new location, which requires rewriting the block pointing to that one — a single leaf change snowballs upward all the way to the tree's root on every single write:

без решения (классический log-structured FS) root / inode переписать indirect node переписать data block ← изменяется один этот блок F2FS: только NAT обновляется root / inode ← не переписывается indirect node ← не переписывается data block (новый) NAT: physical addr ← только эта запись меняется
В классическом решении новый физический адрес блока данных нужно записать в indirect-узел, который сам физически перемещается при записи, что требует обновить указывающий на него узел выше — цепная реакция до корня на каждую запись. F2FS вместо этого хранит физический адрес каждого node-блока в отдельной Node Address Table (NAT) — обновляется одна запись в NAT, а сами узлы дерева файла (inode, indirect node) остаются на месте и не переписываются вовсе.In the classic approach, a data block's new physical address has to be written into the indirect node, which itself physically moves on write, which requires updating the node pointing to it above — a chain reaction to the root on every write. F2FS instead stores every node block's physical address in a separate Node Address Table (NAT) — one NAT entry gets updated, while the file tree's own nodes (the inode, indirect nodes) stay put and aren't rewritten at all.

Второе ключевое решение F2FS — разделение данных по «температуре» прямо в момент записи (logging time), а не постфактум. Файловая система ведёт несколько параллельных активных логов одновременно (multi-head logging — возможно именно потому, что у SSD нет механической головки чтения/записи, как у HDD, и параллельная запись в разные места не создаёт задержек на позиционирование) и статически делит и данные, и node-блоки на три уровня «температуры»:F2FS's second key decision is separating data by "temperature" right at write time (logging time), not after the fact. The filesystem maintains several parallel active logs at once (multi-head logging — possible precisely because an SSD has no mechanical read/write head like an HDD, so writing to different locations in parallel doesn't incur seek delays) and statically splits both data and node blocks into three temperature levels:

уровеньlevelчто туда попадаетwhat goes there
hotданные и node-блоки, которые обновляются чаще всего — например, direct node-блоки (указывают прямо на данные) обновляются заметно чаще, чем indirect (указывают на другие node-блоки)data and node blocks updated most often — direct node blocks (pointing straight at data), for instance, are updated noticeably more often than indirect ones (pointing at other node blocks)
warmданные со средней частотой обновления — типичный каталог, обновляемый время от времениdata with medium update frequency — a typical directory, updated occasionally
coldредко изменяемые данные — уже записанные и не трогаемые файлы, indirect node-блокиrarely changed data — already-written, untouched files, indirect node blocks

Практический смысл разделения: блоки с похожей «температурой» физически оказываются рядом в одном и том же сегменте. Когда позже наступает сборка мусора (garbage collection — flash не может освободить частично занятый сегмент иначе, чем скопировав ещё живые блоки в новое место и стерев старый целиком), сегмент с однородно «холодными» данными либо весь ещё жив (копировать нечего, можно оставить), либо весь уже мёртв (можно стереть без копирования вообще). Смешение горячих и холодных данных в одном сегменте — худший случай: почти всегда найдётся несколько ещё живых блоков вперемешку с мёртвыми, и каждая сборка мусора вынуждена их копировать. Для выбора сегмента-жертвы при сборке мусора F2FS хранит в SIT (Segment Information Table) битовую карту и счётчик валидных блоков для каждого сегмента, и поддерживает два алгоритма выбора — greedy (сегмент с наименьшим числом валидных блоков) и cost-benefit (учитывает ещё и «возраст» сегмента).The practical point of this separation: blocks with similar "temperature" physically end up next to each other in the same segment. When garbage collection later happens (flash can't free a partially occupied segment except by copying the still-live blocks elsewhere and erasing the old one entirely), a segment with uniformly "cold" data is either entirely still live (nothing to copy, leave it) or entirely dead (erase with no copying at all). Mixing hot and cold data in one segment is the worst case — there will almost always be a few still-live blocks mixed with dead ones, and every garbage collection cycle is forced to copy them. To pick a victim segment for garbage collection, F2FS keeps a valid-block bitmap and count for every segment in the SIT (Segment Information Table), and supports two selection algorithms — greedy (the segment with the fewest valid blocks) and cost-benefit (which also factors in a segment's "age").

Восстановление после сбоя устроено проще, чем журналирование ext4 или CoW-дерево Btrfs/XFS: F2FS периодически (и явно, по запросу) создаёт checkpoint — снимок состояния файловой системы, содержащий её общую информацию, битовые карты валидности текущих наборов NAT/SIT, список inode-сирот и сводку активных сегментов. Хранятся ровно две копии checkpoint по схеме shadow copy (одна из двух всегда валидна и актуальна), и та же схема применяется к NAT и SIT — каждый checkpoint явно указывает, какая из двух копий NAT/SIT актуальна на момент его создания. При сбое питания система откатывается к последнему валидному checkpoint, отбрасывая всё, что было записано после него.Crash recovery is simpler than ext4's journaling or Btrfs/XFS's CoW tree: F2FS periodically (and explicitly, on request) creates a checkpoint — a snapshot of the filesystem's state containing its overall info, validity bitmaps for the current NAT/SIT sets, an orphan inode list, and a summary of active segments. Exactly two checkpoint copies are kept using a shadow-copy scheme (one of the two is always valid and current), and the same scheme applies to the NAT and SIT — every checkpoint explicitly records which of the two NAT/SIT copies was current when it was made. On a power failure, the system rolls back to the last valid checkpoint, discarding everything written after it.

Как этим пользуются на практикеHow it's used in practice

командаcommandчто происходитwhat happens
mkfs.f2fs -l data /dev/sdX1создаёт раздел F2FS; по умолчанию mkfs сам пытается определить геометрию устройства (через ioctl) и подобрать под неё размер секции/зоны — ручная настройка нужна редкоcreates an F2FS partition; by default mkfs tries to detect the device's geometry itself (via ioctl) and pick a matching section/zone size — manual tuning is rarely needed
mount -o discard /dev/sdX1 /mntвключает передачу TRIM/discard устройству сразу при удалении файлов — сообщает SSD, какие блоки реально свободны, что помогает его собственному контроллеру эффективнее готовить их к следующей записиenables TRIM/discard being issued to the device immediately on file deletion — tells the SSD which blocks are actually free, helping its own controller prepare them more efficiently for the next write
f2fs_io fsync /path/to/fileотладочный инструмент из пакета f2fs-tools — вызывает fsync и позволяет наблюдать за реальным поведением записи на конкретном файлеa debugging tool from the f2fs-tools package — calls fsync and lets you observe the real write behavior on a specific file
cat /sys/fs/f2fs/<dev>/gc_urgentуправляет режимом принудительной сборки мусора через sysfs — на практике используется, когда устройство простаивает и есть время заранее расчистить сегменты, не мешая обычной нагрузкеcontrols the forced garbage collection mode via sysfs — used in practice when the device is idle and there's time to clean up segments in advance, without interfering with ordinary load
fsck.f2fs -f /dev/sdX1офлайн-проверка и восстановление файловой системы — используется, если оба checkpoint повреждены одновременно (крайне маловероятный, но не исключённый сценарий) и автоматический откат к последнему валидному checkpoint при монтировании невозможенan offline filesystem check and repair — used if both checkpoints are corrupted simultaneously (an extremely unlikely but not impossible scenario) and an automatic rollback to the last valid checkpoint on mount isn't possible

Грабли и мифыGotchas & myths

F2FS не универсально быстрее ext4 — выигрыш зависит от накопителя и нагрузкиF2FS isn't universally faster than ext4 — the win depends on the drive and workload

Преимущество log-structured подхода наиболее заметно на недорогих flash-накопителях со слабым собственным FTL-контроллером (типичный embedded eMMC, дешёвые SD-карты) — именно там классическая ФС с большим количеством случайной перезаписи создаёт реальные проблемы. На качественном NVMe SSD с продвинутым контроллером и большим объёмом собственного DRAM-кэша разница с ext4 в обычных пользовательских сценариях зачастую в пределах погрешности измерения.the log-structured approach's advantage is most visible on cheap flash storage with a weak onboard FTL controller (typical embedded eMMC, cheap SD cards) — that's exactly where a classic filesystem's heavy random-overwrite pattern creates real problems. On a quality NVMe SSD with an advanced controller and a large onboard DRAM cache, the difference from ext4 in ordinary user workloads is often within measurement noise.

на «почти заполненном» томе garbage collection может начать заметно мешатьon a "nearly full" volume, garbage collection can start noticeably getting in the way

Чем меньше на устройстве действительно свободных сегментов, тем чаще и агрессивнее приходится запускать сборку мусора именно в момент записи (foreground GC вместо фонового), а не заранее в простое — это заметно на телефонах с почти заполненным хранилищем, где внезапно «тормозит» именно запись новых файлов. Это не поломка, а прямое физическое следствие того, как работает log-structured дизайн на пространстве без запаса.the fewer genuinely free segments a device has, the more often and aggressively garbage collection has to run right at write time (foreground GC instead of background) rather than ahead of time during idle periods — this shows up as noticeable "stutter" specifically on new file writes on phones with nearly full storage. It's not a malfunction — it's a direct physical consequence of how a log-structured design behaves with no slack space.

F2FS — не замена TRIM/wear leveling контроллера, а дополнение к нимF2FS isn't a replacement for the controller's TRIM/wear leveling — it complements them

F2FS снижает write amplification на уровне файловой системы, но не отменяет необходимость собственного wear leveling контроллера SSD и передачи TRIM — это независимые, дополняющие друг друга механизмы на разных уровнях стека. Файловая система, дружественная к flash, и накопитель с хорошим контроллером решают одну и ту же проблему с разных сторон, а не конкурируют.F2FS reduces write amplification at the filesystem level, but doesn't remove the need for the SSD controller's own wear leveling and TRIM passthrough — these are independent, complementary mechanisms at different levels of the stack. A flash-friendly filesystem and a drive with a good controller solve the same problem from different angles, not compete for the same role.

ТерминыTerms

write amplification
разница между объёмом данных, которые приложение реально попросило записать, и объёмом, который физически пишется на flash из-за необходимости стирать и переписывать целые блоки — сокращает ресурс накопителя и снижает производительность.the gap between the data volume an application actually requested to write and the volume physically written to flash due to needing to erase and rewrite whole blocks — shortens drive lifespan and hurts performance.
segment / section / zone
три вложенных уровня физической организации тома F2FS выше блока: фиксированный сегмент (2 МиБ) → секция (один или несколько сегментов) → зона (одна или несколько секций); настраиваются при mkfs под геометрию конкретного flash-устройства.three nested levels of F2FS volume organization above the block: a fixed segment (2 MiB) → a section (one or more segments) → a zone (one or more sections); tuned at mkfs time to a specific flash device's geometry.
wandering tree problem
проблема ранних log-structured файловых систем: изменение одного блока данных вынуждает переписать указывающий на него узел, что вынуждает переписать узел ещё выше — цепная реакция до корня дерева на каждую запись.an early log-structured filesystem problem: changing one data block forces the node pointing to it to be rewritten, which forces the node above that to be rewritten — a chain reaction to the tree's root on every write.
NAT (Node Address Table)
таблица физических адресов всех node-блоков тома — решение wandering tree в F2FS: при перемещении node-блока обновляется одна запись в NAT, а не цепочка узлов дерева файла выше по иерархии.a table of physical addresses for every node block in the volume — F2FS's fix for the wandering tree: moving a node block updates one NAT entry, not a chain of file-tree nodes further up the hierarchy.
SIT (Segment Information Table)
таблица с битовой картой валидности блоков и счётчиком валидных блоков для каждого сегмента — основной источник данных для выбора сегмента-жертвы при сборке мусора.a table with a block-validity bitmap and valid-block count for every segment — the primary data source for choosing a victim segment during garbage collection.
hot / warm / cold data separation
разделение данных и node-блоков по ожидаемой частоте обновления прямо во время записи, через несколько параллельных активных логов — снижает вероятность, что мусор и ещё живые данные окажутся смешаны в одном сегменте.splitting data and node blocks by expected update frequency right at write time, via several parallel active logs — reduces the chance that garbage and still-live data end up mixed in the same segment.
garbage collection (GC) / victim segment
процесс переноса ещё живых блоков из частично занятого сегмента в новое место с последующим стиранием старого сегмента целиком; сегмент-жертва выбирается алгоритмом greedy (меньше всего валидных блоков) или cost-benefit (учитывает и возраст сегмента).the process of moving still-live blocks out of a partially occupied segment to a new location, then erasing the old segment entirely; a victim segment is chosen by a greedy (fewest valid blocks) or cost-benefit (also factoring in segment age) algorithm.
checkpoint (F2FS)
периодический снимок состояния файловой системы (общая информация, битовые карты NAT/SIT, список inode-сирот, сводка активных сегментов), хранящийся в двух копиях по схеме shadow copy — восстановление после сбоя откатывается к последнему валидному checkpoint.a periodic snapshot of filesystem state (general info, NAT/SIT bitmaps, an orphan inode list, active-segment summary), kept in two copies under a shadow-copy scheme — crash recovery rolls back to the last valid checkpoint.