Как избежать повреждения SD-карты при записи больших объемов данных?

Хорошо, сначала немного предыстории, чтобы прояснить мой вопрос:

Я работаю над устройством, которое собирает определенные данные с датчиков и отправляет их на сервер с помощью модема GSM. Поскольку соединение GSM не на 100% надежно, оно будет содержать механизм регистрации, который будет записывать неотправленные данные на SD-карту.

Мы используем модуль FatFs Чана для предоставления нам файловой системы, поскольку мы хотим, чтобы log для чтения на ПК.

Сейчас тестирую систему FAT на граничные условия, т.е. пытаюсь залить карту полностью.

При первом запуске я открыл файл и установил код, чтобы продолжать писать строку до тех пор, пока диск не будет заполнен. Программа будет синхронизироваться после каждой записи.

Я оставил код работать на ночь.

На следующий день осмотрел SD карту. Я обнаружил, что размер файла составляет всего 150 МБ. На нем было написано около 1,2 миллиона строк. Карта все еще может быть прочитана, но не записана или отформатирована.

В следующий раз я попробовал тот же тип теста, но на этот раз я использовал функцию f_lseek(), чтобы предварительно выделить для файла 1 ГБ. Затем он будет записывать в этот файл, пока не будет достигнут этот предел. На этот раз данные будут синхронизированы после 50 операций записи. Затем он закроет этот файл и откроет другой, чтобы сделать то же самое.

Как нетрудно догадаться, в тот день из виду сошла еще одна отважная маленькая карточка.

Вот в чем я хотел бы помочь:

  1. Как предотвратить повреждение карты при записи больших объемов данных?
  2. Имеет ли оставление файла открытым на длительное время какие-либо негативные последствия?

Поскольку полный код может быть слишком длинным, вот основная часть, где происходит запись

for(file_count=3;file_count>=0;--file_count){

    ax_log_msg(E_LOG_INFO,"===================================");

    ax_log_msg(E_LOG_INFO,file_names[file_count]);


    f_open(&file_ptr,file_names[file_count],FA_WRITE|FA_OPEN_ALWAYS);

    if(result!=FR_OK){

        ax_log_msg(E_LOG_INFO,"\n\rf_open Failed\n\rResult code");
        ax_log_msg(E_LOG_INFO,FRESULT_S[result]);

        continue;

    }

    ax_log_msg(E_LOG_INFO,"\n\rf_open Sucessfull");

    result=f_lseek(&file_ptr,FILE_SIZE_LIMIT_1GB);

    if(result!=FR_OK){

        ax_log_msg(E_LOG_INFO,"\n\rf_lseek Failed for preallocation\n\rResult code");
        ax_log_msg(E_LOG_INFO,FRESULT_S[result]);

        f_close(&file_ptr);

        continue;

    }

    ax_log_msg(E_LOG_INFO,"\n\rf_lseek Sucessfull for preallocation");

    f_lseek(&file_ptr,0);

    bytes_to_write=sizeof(messages[file_count]);

    write_count=0;

    while( (f_tell(&file_ptr) < FILE_SIZE_LIMIT_1GB )){

        result=f_write(&file_ptr,messages[file_count],bytes_to_write,&bytes_written);

        if(result==FR_OK){
            ++write_count;

            if(write_count%50==0){

                f_sync(&file_ptr);
            }

        }else{

            ax_log_msg(E_LOG_INFO,"\n\rWrite failed\n\rFRESULT=");
            ax_log_msg(E_LOG_INFO,FRESULT_S[result]);

            break;

        }

    }

    f_close(&file_ptr);


}

Примечание :

  1. ax_log_msg () - это часть прошивки устройства для печати на консоли.
  2. FRESULT_S [результат] используется для преобразования кода результата перечисления в строку.

Если какие-либо данные отсутствуют, укажите это.

Спасибо


person Suman Roy    schedule 24.07.2014    source источник
comment
Вы сами реализовали функции HAL? (disk_read, disk_write?) Полагаю, вы не покупали SD-карту на ebay? :)   -  person Groo    schedule 25.07.2014
comment
Я получил функции HAL как часть исходного кода платы оценки MSP430. Но они работают.   -  person Suman Roy    schedule 30.07.2014
comment
Вопрос eBay действительно очень важен. Вы купили подлинные карты у уважаемой компании? Поддельные карты быстро умирают. Хорошей карты на 4 ГБ должно хватить на много-много гигабайт времени записи.   -  person rjp    schedule 07.08.2014


Ответы (2)


Вам, вероятно, потребуется буферизовать весь блок данных, возможно, 4 КБ, чтобы избежать перепрограммирования всего блока при каждом сбросе. Но файловая система или драйвер должны делать это за вас, если вы не вызываете fflush явно, что является настоящим уроком.

Зачем нужно так часто синхронизировать? Может быть, таймер сработает лучше, чем интервал на количество записей?

person Potatoswatter    schedule 24.07.2014
comment
Файловая система действительно регистрирует данные до тех пор, пока они не будут синхронизированы явно или пока указатель файла не будет закрыт. Я жду 50 записей перед синхронизацией с файлом. Частая синхронизация связана с тем, что регистрируемые данные чувствительны ко времени, и я хотел бы предотвратить потерю данных из-за потери мощности или другого неожиданного фактора. - person Suman Roy; 24.07.2014
comment
@SumanRoy Он будет записывать данные, когда они достаточно буферизованы. Буфер не может быть таким большим. Вы заметили компромисс между частотой синхронизации и долговечностью флэш-памяти, поэтому вам нужно решить, где находится оптимальный баланс. - person Potatoswatter; 25.07.2014
comment
На самом деле строка, которую я использовал, составляла около 115 байт, поэтому она будет синхронизироваться примерно после 5,7 КБ данных. - person Suman Roy; 25.07.2014
comment
@SumanRoy Это не принесет вам никакой пользы, если он не выровнен по границе блока. Как начало, так и конец блока размером 5,7 КБ будут смещены в последовательности блоков по 4 КБ, поэтому большую часть времени для каждой очистки по 5,7 КБ потребуется выделить два блока или записать 8 КБ пространства. Однако я не знаю, насколько большие блоки на самом деле. Я сделал такое встроенное ведение журнала и очень осторожно кодировал непосредственно во флэш-контроллере. Это просто невозможно, если вы используете интерфейс IDE. - person Potatoswatter; 25.07.2014
comment
Хорошо, так что в основном пишите кусками того же размера, что и размер сектора устройства. Это то, что вы имели ввиду? - person Suman Roy; 25.07.2014
comment
@SumanRoy Я имею в виду либо полагаться на файловую систему и драйвер, обеспечивая ожидаемое поведение, либо исследовать оборудование и напрямую управлять им. - person Potatoswatter; 25.07.2014
comment
@SumanRoy, вы уверены, что fatfs кэширует / буферизует данные, превышающие размер блока SD (почти наверняка 512B, если вы не используете карту 32GB +)? В зависимости от того, как реализован fatfs, вы можете запускать флеш-память при каждой записи крошечных 115 байт, но это будет довольно плохо написано. - person rjp; 07.08.2014
comment
@rjp Нет. Я проверил документацию FatFs. Он буферизует 512 байт и затем записывает их на карту. - person Suman Roy; 07.08.2014

Из-за ограничения в 100 000 циклов записи на сектор продление срока службы флэш-памяти является действительно сложной задачей. Одна из моих карт умерла за одну ночь после того, как я запустил на ней тесты. Затем я подсчитал периоды времени, и действительно легко выполнить 100 000 операций записи (в том же секторе) всего за одну ночь (без учета расчетов, это происходит из опыта).

В то время мне сказали, что в некоторых файловых системах есть интеллектуальные мониторы, которые подсчитывают и хранят количество записей для каждого сектора, чтобы количество записей в каждом секторе было одинаковым, я полагаю. Я не брал и не тестировал.

Теперь я нашел чрезвычайно популярный / получивший большое количество голосов ответ / предложение для Raspberrypi, и я цитирую его здесь:

Эти методы должны увеличить срок службы SD-карты за счет минимизации количества операций чтения / записи различными способами:

Отключить своп

Подкачка - это процесс использования части SD-карты в качестве энергозависимой памяти. Это увеличит объем доступной оперативной памяти, но приведет к большому количеству операций чтения / записи. Значительно увеличить производительность вряд ли получится.

Отключите своп с помощью команды swapoff:

sudo swapoff --all

Вы также должны предотвратить его повторное использование после перезагрузки:

  • Для Raspbian, который использует dphys-swapfile для управления файлом подкачки (вместо " обычный "раздел подкачки") вы можете просто sudo apt-get remove dphys-swapfile удалить его навсегда. Лучше всего удалить, потому что установка CONF_SWAPSIZE на 0, как описано в этом ответе, похоже, не работает и по-прежнему после перезагрузки создает файл подкачки размером 100 МБ.
  • Для других дистрибутивов, которые используют раздел подкачки вместо файла подкачки, удалите соответствующую строку из /etc/fstab

Отключение ведения журнала в файловой системе

Использование журналируемой файловой системы, такой как ext3 или ext4 БЕЗ журнала, позволяет уменьшить количество операций чтения / записи. Очевидным недостатком использования файловой системы с отключенным журналированием является потеря данных в результате некорректного отключения (например, после сбоя питания, блокировки ядра и т. Д.).

Вы можете отключить ведение журнала на ext3, установив его как ext2

Вы можете отключить ведение журнала ext4 на отключенном диске следующим образом:

tune4fs -O ^has_journal /dev/sdaX
e4fsck –f /dev/sdaX
sudo reboot

Флаг Noatime Mount

Назначьте флаг монтирования noatime разделам, находящимся на SD-карте, добавив его в раздел параметров раздела в /etc/fstab.

Чтение доступа к файловой системе больше не будет приводить к обновлению временной информации, связанной с файлом. Важность параметра noatime заключается в том, что он избавляет систему от необходимости производить запись в файловую систему для файлов, которые просто читаются. Поскольку запись может быть несколько дорогостоящей, как упоминалось в предыдущем разделе, это может привести к ощутимому увеличению производительности. Обратите внимание, что информация о времени записи в файл будет продолжать обновляться каждый раз, когда файл записывается с включенной этой опцией.

Каталоги в ОЗУ

Часто используемые каталоги, такие как /var/tmp/ и, возможно, /var/log, можно переместить в ОЗУ в /etc/fstab следующим образом:

tmpfs /var/tmp tmpfs nodev,nosuid,size=50M 0 0

Это позволит /var/tmp использовать 50 МБ ОЗУ в качестве дискового пространства. Единственная проблема, связанная с этим, заключается в том, что любые диски, смонтированные в ОЗУ, не сохранятся после перезагрузки. Таким образом, если вы монтируете /var/log и ваша система обнаруживает ошибку, вызывающую ее перезагрузку, вы не сможете выяснить, почему.

Каталоги на внешнем жестком диске

Вы также можете смонтировать некоторые каталоги на постоянном жестком диске USB. Более подробную информацию об этом можно найти в этом вопросе.

Raspberry Pi также может загружать свой корневой раздел с внешнего диска. Это может быть через USB или Ethernet и означает, что SD-карта будет использоваться только для делегирования другому устройству во время загрузки. Это требует небольшого взлома ядра, поскольку я не думаю, что ядро ​​по умолчанию поддерживает USB-накопители. Дополнительную информацию можно найти в этом вопросе или на этом внешняя запись в блоге.


Вот еще одно интересное соображение от другого респондента:

Отличная статья о файловых системах во флэш-памяти.

Важный вопрос, когда речь идет о файловых системах во флеш-памяти: что такое выравнивание износа? Статья в Википедии. По сути, на флеш-диски вы можете записывать ограниченное количество раз, пока блок не выйдет из строя. После этого файловая система (если на оборудовании нет встроенного управления выравниванием износа, как в случае с твердотельными накопителями) должна пометить этот блок как недопустимый и больше не использовать его.

Типичные файловые системы (например, reiserfs, ntfs, ext3 и т. Д.) Предназначены для жестких дисков, которые не имеют таких ограничений.

JFFS2

Включает компрессию и элегантную защиту от износа.

YAFFS2

  • Единственное, что имеет значение: короткое время монтирования после успешного размонтирования.
  • Реализует свойство однократной записи: как только данные записываются в один блок, нет необходимости их перезаписывать. Это важно для защиты от выравнивания износа.

LogFS

  • Не очень зрелый, но уже включен в дерево ядра Linux.
  • Без проблем поддерживает файловые системы большего размера, чем JFFS2 / YAFFS2.

УБИФС

  • Более зрелый, чем LogFS
  • Поддержка кэширования записи
  • О масштабируемости: статья. На больших дисках производительность лучше, чем с JFFS2

ext4

Если ни один драйвер или карта (например, SSD-диски не имеют внутреннего выравнивания износа, по крайней мере, обычно) не поддерживают выравнивание износа, то ext4 - не лучшая идея, поскольку он не предназначен для использования необработанной флэш-памяти.

Что лучше?

Конечно, это зависит от использования и поддержки. Из того, что я прочитал в Интернете, я бы порекомендовал UBIFS. Хорошая поддержка больших файловых систем, зрелая фаза разработки, адекватная производительность и отсутствие серьезных недостатков.

Спасибо ответчикам:

Как я могу продлить срок службы моей SD-карты ?

Выбор файловой системы для GNU / Linux на SD-карте < / а>

person Ruslan Gerasimov    schedule 27.07.2014
comment
Ваш ответ больше основан на специфике Pi, но теория все же полезна. - person Suman Roy; 29.07.2014
comment
В этом ответе все посвящено Linux. Речь не идет о Linux. - person hobbs; 23.06.2015
comment
Не все советы в этом вопросе подходят даже для Raspberry Pi. Файловые системы Flash, такие как JFFS2 и подобные, предназначены для использования на необработанных флэш-устройствах, а не на SD-картах. - person ; 15.02.2016