Цитата(makc @ Jun 14 2018, 08:05)

Поэтому повторные частичные записи (новые записи журнала) в один и тот же блок (страницу) для NAND крайне не рекомендованы, т.к. могут повредить ранее записанные данные. К тому же с учетом вышеуказанных проблем не понятно, как гарантировать атомарность модификации самого журнала. PkUnzip.zip.
Я же написал как - использовать очередь из страниц FLASH.
И зачем тут "повторные частичные записи в одну и ту же страницу"? Я разве где-то предлагал такое? Да, если будет такая возможность, то будет лучше, но и без этого можно обойтись. Посредством очереди страниц. И размер блока стирания тоже не очень важен (к тому же в служебной области блок стирания (как и страница) может быть меньшего размера, чем в области данных - это думаю несложно сделать технологически).
Предположим что:
В служебной области SD страница == N байт, в блоке == K страниц. Создаём очередь из M блоков (M>=2). (где: "страница" - минимальный записываемый элемент данных; "блок" - минимальный стираемый элемент данных). Стёртое состояние: содержит все биты ==0. Страница содержащая все 0 - "чистая", хотя бы в одном байте не 0 - "грязная".
Работаем с очередью так, чтобы:
1) внутри неё всегда был как минимум один стёртый блок;
2) запись страниц шла в порядке увеличения их номеров.
Тогда при вкл.питания ищем первую чистую страницу с шагом K от начала очереди (поиск должен учитывать кольцевой характер очереди). Далее от найденной страницы ищем в сторону уменьшения номеров (опять - по кольцу) первую "грязную" страницу. Найденная страница - "голова очереди".
Каждая грязная страница содержит заголовок определённого формата и CRC всего содержимого. Заголовок обязательно содержит байты != 0.
Теперь, когда нужно добавить запись журнала в такую очередь, разбиваем тело записи на страницы, каждую страницу снабжаем заголовком и CRC. В заголовке первой страницы записи журнала указываем ID="первая_в_записи", в заголовках остальных=="тело_записи". Пишем в очередь эти страницы начиная с конца ("первая_в_записи" будет записана последней в очередь).
При записи страниц в очередь не забываем держать перед "головой очереди" дырку из как минимум одного стёртого блока! (т.е. - если хотим добавить очередную страницу в очередь, а перед ней всего K чистых страниц, то сперва стираем следующий блок и только потом пишем эту страницу).
Здесь создание записи журнала завершено и можно выполнять опасные операции с секторами SD, описанные в данной записи.
По завершении опасных операций удаляем запись журнала. Делаем это записью в очередь страницы с заголовком ID="удалено" (тело данных пустое). Таким образом с этого момента запись журнала в очереди считается удалённой.
Теперь, при вкл.питания, сначала ищется дырка из как минимум K стёртых страниц и последняя грязная страница (как описано выше). Потом считываются страницы начиная с неё. Если в результате обнаружена последовательность из страниц: ID=="первая_в_записи" и потом ID=="тело_записи" и у всех структура заголовка валидна и CRC валидно, значит у нас есть запись журнала. Выполняем её. Затем стираем (пишем в очередь страницу с ID="удалено").
С таким алгоритмом нам почти не важны конкретные значения N, M, K. А также нам не нужна возможность записи "поверх". Также нам не страшны случаи когда запись страницы (или стирание блока) прерывается сбоем питания (т.к. каждая "грязная" страница имеет заголовок определённой структуры и CRC). Конечно запись страниц в журнал будет задерживаться в моменты когда происходит увеличение дырки из стёртых страниц (как минимум K штук), но это время можно уменьшить, разместив блоки в разных физических регионах с независимым стиранием/записью, сделав чередование блоков в очереди и увеличив размер дырки до 2-х блоков - будет идти параллельное стирание и запись страницы.
Цитата(makc @ Jun 14 2018, 08:05)

Есть, если посмотреть значения AU_SIZE на современных картах (регистр SD Status), то там мегабайты. Цитата из вышеуказанной статьи с linaro.org:
Как я показал выше - это не страшно, просто очередь будет немного больше (в байтах), так как она должна занимать целое число блоков (M) и M>=2.
Цитата(makc @ Jun 14 2018, 08:05)

а запись журнала на SD приведет к ее скоропостижной гибели.
Помещение записи журнала внутрь очереди блоков этого не допустит как видно из вышеизложенного.
Я организовывал хранение журналов событий в своих устройствах описанным выше способом (немного сложнее в реальности). Не для wear leveling конечно, для других целей.
Цитата(makc @ Jun 14 2018, 08:05)

Формально Вы правы, но доступные описания механизмов Wear Leveling на SD/MMC говорят о другом.
Тут конечно мне судить трудно как именно там делают. Я только говорю о том, что вполне возможно сделать атомарную устойчивую к сбоям модификацию SD даже имея в своём распоряжении только NAND.
А как именно делают в конкретных реализациях - вполне допускаю что гораздо кривее. К сожалению в современной реальности быдлокодеров гораздо больше чем нормальных программистов. Даже в серьёзных конторах.

Цитата(makc @ Jun 14 2018, 08:05)

Времени на это при включении нет, т.к. у карт жестки временные требования по доступности к чтению/записи.
Опять же - не могу знать как там в картах, но у меня на Cortex-M процесс монтирования такой службы занимал несколько сотен мкс насколько помню (dual SPI-flash 30МГц через DMA параллельно с анализом считанных данных CPU). Если подобрать другие значения N,K,M и с аппаратным ускорением то думаю и в несколько десятков мкс уложиться можно.
Цитата(mantech @ Jun 14 2018, 08:15)

Можете шутить сколь угодно, но ИБП реально помогает, проверял на практике по кол-ву сбоев ФС при записи... А вот насколько эффективно ваше журналирование при внезапных сбросах - эт еще можно поспорить, а вот в несколько раз быстрее убить карту памяти - так это сколь угодно. И второе, внезапные сбросы - эт уже не программная проблема, а, как правило, "плохая" аппаратка.
Во-первых: я и не спорил что "может помогать". Но это очень дорогое решение и такой ИБП может быть дороже чем всё устройство в целом.
Во-вторых: я реализовывал на практике системы с устойчивой к сбоям модификацией данных во FLASH. Да, сперва мы тоже делали расчёт на монитор питания, чтобы по его сигналу корректно закрывать все записи. Так вот - в реале это работает очень плохо! Уже не говоря о том, что сама реализация источника с гарантированным временем удержания питания после аварии очень сложная и дорогая (жёсткие требования по большому диапазону допустимых питающих напряжений). Так ещё и выяснилось, что могут быть сбросы как по срабатыванию супервизора питания, WDT и пр. Так и всякие сбои из-за программных ошибок (а Вы пишете абсолютно безглючный код? и вся ваша команда так пишет? все несколько МБ исходников?

И дальше - а как собственно отлаживаться и писать ПО (в процессе написания которого будет дофига сбоев) если при каждом таком сбое рушится вся система хранения данных и данные теряются потому, что весь расчёт - на монитор питания???)
И что значит ""плохая" аппаратка"? То что Вы предлагаете, требует чтобы устройство соответствовало классу функционирования A по ГОСТу помехоустойчивости. А это очень жёсткое требование, труднодостижимое. Использование моего алгоритма снижает требования к аппаратной части до класса B.
Так что в результате отказались от монитора питания как от дорогой и неудобной вещи. А бессбойное хранение сделали подобно тому как я описал выше (в реале там всё сложнее). Сделали один раз и потом голова больше не болела ни при отладке ни испытаниях ни при опытной эскплуатации. И сейчас эти устройства уже несколько лет продаются по несколько тыс.шт в месяц и данные в них не теряются! Хотя питание в них отключается непредсказуемо.
Конечно там не SD, а просто несколько шт. SPI-flash, но это роли не играет.