спроектирована 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 (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.
Ключевая физическая особенность 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.
| параметрparameter | ext4 | F2FS |
|---|---|---|
| модель записи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 type | Android (основная ФС для /data с версии 9), embedded с eMMC/UFS/SD, отчасти десктопные SSDAndroid (the primary /data filesystem since version 9), embedded with eMMC/UFS/SD, some desktop SSDs |
Весь том 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):
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:
Второе ключевое решение 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.
| команда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 |
Преимущество 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.
Чем меньше на устройстве действительно свободных сегментов, тем чаще и агрессивнее приходится запускать сборку мусора именно в момент записи (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 снижает 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.