Портировал недавно PH7 PHP engine на ESP32. И обнаружил, что engine умеет не просто скрипты загружать в память и исполнять, а исполнять их без загрузки (на манер XIP). Но нужна поддержка mmap(). Которая есть в Линуксе, а вот в ESP32 - нету.
Сел писать свою ФС со свистелками, под это дело. Чтобы mmap() поддерживался. Дмуал - напишу за день-два (чо там писать, примеры, вон , лежат), в одном файлике. Провозился три недели, в результате.
Файловая система только для чтения. Чуть более POSIX, чем то, что есть на ESP32.
Надеюсь, спортировать ее когда-нибудь на STM32. Пока она работает на ESP32 и в режиме разработчика
на Windows/CYGWIN.
А, самое главное-то забыл сказать: образ файловой системы - это TAR архив. Соответственно, поддерживаются symlinks/hardlinks. Для создания образа файловой системы нужна лишь утилита tar.
Образ можно скачать\исправить\залить обратно, например.
Погоняю еще недельку (глюки половлю) и выложу в общий доступ. Может в основное дерево ESP-IDF удастся пролезть ;0)
README для любителей читать простыни.
TARFS — Read-only mmap-oriented filesystem over TAR images for firmware assets and runtime resources
1. Введение
TARFS — простая и быстрая файловая система только для чтения, разработанная специально для встраиваемых систем.
В качестве образа фаловой системы используется файл в формате TAR, который создает утилита GNU tar.
Вместо реализации полноценной файловой системы с поддержкой записи, TARFS предоставляет прямой zero-copy
доступ к стандартным POSIX TAR-архивам, расположенным в отображённой (memory-mapped) Flash-памяти.
Это позволяет использовать файлы любого размера практически без расхода оперативной памяти, сохраняя
совместимость с привычными POSIX-интерфейсами и стандартными инструментами для работы с TAR.
Большинство файлов в прошивке никогда не изменяются после компиляции. HTML-страницы, CSS, JavaScript,
изображения, сертификаты, шрифты, словари, таблицы, модели ML и другие ресурсы обычно создаются на этапе
сборки прошивки и затем только читаются. Использование полноценной файловой системы с поддержкой записи
для хранения таких данных зачастую избыточно.
2. Зачем нужна еще одна файловая система?
-
Для хранения и быстрого доступа к неизменяемым данным в условиях ограниченной памяти при больщом количестве файлов. Например - к иконкам и прочим ассетам
вашего firmware / UI, или к html страницам вашего embedded HTTP сервера. TARFS ориентирована на большое количество неизменяемых файлов и максимальную скорость доступа. -
Как porting layer для приложений, портируемых с Linux, которые ожидают “более-менее POSIX файловую систему”:
например PH7 PHP Engine для ESP32 использует mmap() для выполнения скриптов PHP. Наличие mmap() позволяет нам работать с файлами любого размера не смотря на то, что RAM - ограниченный ресурс. -
Для повышения выживаемости и восстановления работоспособности (мы всегда сможем сделать mount()) после
повреждений файловой системы (для устройств в “поле”) -
Для контроля целостности каждого файла внутри файловой системы
3. Что такого особенного она умеет?
-
Особенного - ничего. Просто реализует более-менее POSIX файловую систему (POSIX в смысле
интерфейса доступа). Разработана для микроконтроллеров с поддержкой адресуемой FLASH памяти, легко
портируется (один платформо-зависимый файл), написана на языке Си. Примеры платформ, куда потенциально
можно портировать TARFS:STM32, ESP32, SAMD21/SAMD51, RP2040, nRF52, RA4M1 (Arduino UNO R4), LPC17xx/LPC55xx и многие другие, которые
поддерживают отображение flash памяти в адресное пространство.Файловая система может находится на флешке, или быть встроенной в бинарник прошивки (средствами линкера
или прямым включением бинарных файлов в проект) -
Требования к памяти:
TARFS написана для использования на микроконтроллерах, в условиях ограниченной памяти.
Для своей работы TARFS использует 24 байта на файл\каталог. Файловая система с тысячей файлов будет
занимать чуть меньше 24Кбайт памяти.Ограничения на количество активных mmap() - нет, т.к. mmap() в TARFS не аллокирует никаких ресурсов, а
всего лишь возвращает указатель.
При создании файлового индекса используются прямые указатели на имена хранящиеся в TAR файле,
дополнительная память (RAM) под имена не выделяется. При работе файловой системы в обычном режиме
никаких аллокаций\освобождений памяти не производится (за исключением операций mount()/unmount(),
которые выделяют и освобождают память)Не фрагментирует память при работе (в большинстве случаев), т.к. совершает всего 2 (две) аллокации
памяти при монтировании и не аллокирует память вовсе при нормальной работе. -
Более полная совместимость с POSIX, чем у существующих файловых систем в ESP-IDF:
Поддержка mmap()/zero-copy: Файлы из файловой системы можно отобразить на память стандартной функцией mmap(). RAM при этом
не используется, а файл становится доступен, как если бы это был байтовый массив.помимо mmap() поддерживаются readlink(): symlinks и hardlinks (и directory junctions, если архив создавался
на хосте под управлением Windows). Поддерживаются UTF-8 в именах каталогов, файлов и ссылок. open() может
открывать каталог, поддерживается POSIXный dirfd(). -
Контроль целостности файлов внутри файловой системы (CRC64/ECMA-182):
Контроль целостности файлов достигается встройкой специальной контрольной суммы в каждую запись TAR архива таким образом, чтобы это не влияло на
сам архив: TAR файлы с контрольными суммами файлов все так же будут открываться обычными утилитами, предназначенными для работы с TAR архивами.
Контрольные суммы встраиваются в неиспользуемые поля TAR заголовков, для “прошивки” контрольных сумм в
любой TAR архив используется утилитаtarsum.c: утилита считает контрольные суммы всех файлов входящих
в архив (не только файлов но и прочих записей имеющих ненулевой размер) и записывает эти суммы в
неиспользуемое пространство TAR файла. -
Устойчивость к повреждениям:
Файловая система не имеет никакого центрального суперблока, поэтому повредить ее так, чтобы она
совсем не работала - крайне сложно: повреждение отдельных записей TAR-архива не приводит к отказу
файловой системы в целом. TARFS пропускает поврежденные записи и продолжает анализ архива, сохраняя
доступ к неповрежденным данным.Устойчивость к “забытым” mmap() (когда забыли вызвать munmap() после окончания пользования файлом):
прошивка НЕ может съесть память или ресурсы ксли нерадивый программист “забыл” сделать munmap(). -
Скорость и предсказуемость:
TARFS не использует объекты синхронизации, за исключением операций mount/unmount: весь код написан
без блокировок, lockless (конечно, не без races, но они довольно специфичны и задокументированы).Для поиска inodes используется бинарный поиск по хэшу имени. Для readdir() & friends все inodes
отсортированы и по хэшу и по алфавитуОперация : Время : Примечание
----------------------------------:------------:--------------------------
mount() : O(3N)+O(k) : 3N==> три прохода по архиву + O(k) link resolution step
open(), opendir() : O(log N) : бинарный поиск
readlink() : O(k) : k - количество ссылок в файловой системе (hard+sym)
read()/mmap()/close()/seek()/ итд : O(1) : чтение по готовому казателю
telldir()/readdir()/ итд : O(1) : чтение по готовому казателю