DIR825. USB-накопитель под «ОСь».

DIR825. USB-накопитель под «ОСь».

Немного лирического отступления … «Покопавшись» с фонерой — в результате чего родилась эта статья, были обнаружены ряд аппаратных ограничений сего девайса (FON 2201), не позволяющих «в полную меру развернуться» и превратить фонеру в гибкое и универсальное устройство, хотя изначальные предпосылки к этому есть (это ведь, попросту, линуксовая машинка). Основной «загвоздкой» явилось весьма малое количество встроенной флэш-памяти (8МБайт), часть которой занимает сама операционка (операционная система, далее «ось»). Устранение данного нюанса путем расширения встроенной памяти (перепайки микросхемы на более емкую) — во-первых трудоемко, во-вторых не решает проблемы координально (максимальное увеличение в 2-4 раза, что, собственно, не много). Вариант распаивать интерфейс SPI для использования карты памяти MMC|SD — мне также не показался привлекательным — скорость этого интерфейса невелика. Да и в целом на текущий момент мне не очень хочется лезть во внутрь моей единственной фонеры (а заполучить еще одну у нас не так-то и просто). Из всего этого стало понятно, что нужен подобный девайс, но с USB-портом … Такой железкой могла бы успешно стать фонера 2.0g (FON 2202) — таже полуторная фонера (как у меня) плюс наличие USB 2.0 порта и удвоенное количество ОЗУ (32МБайта), но добыть ее в России непросто (не переплачивая двойной цены). И в данной ситуации я решил подобрать иной девайс, с целью «прошивки» под OpenWRT и с тем железом, которое нужно мне. А уж раз постановка задачи дала мне возможность выбора, а также было ясно, что по габаритам и функционалу устройств сопоставимых Fonera 2.0g нет, — то планка аппаратных требований была поднята — уже требовалось «переплюнуть» так продвигаемую в сообществе FON фонеру 2.0n (FON 2303). Соответственно требования были таковы:

  • процессор Atheros (архитектура mips — поддержка со стороны OpenWRT) — так сложилось, но «броадкомы» я «недолюбливаю»;
  • наличие USB 2.0 порта;
  • размер ОЗУ не менее 32МБайт;
  • WiFi-карта, под стандарт 802.11n (с минимум двумя антеннами);
  • антенны должны быть съемным;

Выбор пал на DIR825 (HW: B1 или B2) — подробнее о нем в сравнении с разными фонерами можно прочесть в предыдущей статье. К сожалению не так просто выбрать маршрутизатор по его «начинке» — производители скрывают эту информацию, считая ее видимо не интересной для конечного пользователя — а зря …

Теперь к теме настоящей статьи. Материал будет справедлив не только для DIR825, но и для прочих устройств с операционкой OpenWRT BackFire 10.03. Тут несколько определимся в терминах. Понятие «прошивка» для беспроводных маршрутизаторов не отражает объективной картины ее внутреннего функционала. Мы привыкли «прошивать» разные устройства от системных плат и видео-карт до мобильных и стационарных телефонов, плееров и т.п. Во всех этих случаях «прошивка» представляет собой «черный» ящик с неким содержимом, которое по нашему разумению, чем свежее — тем лучше. В случае же с маршрутизаторами работающими под OpenWRT «прошивка» представляет собой сборку базового образа операционной системы, с которой в дальнейшем предстоит работать (дополнять, настраивать и пр.).

OpenWRT в настоящей редакции (для DIR825) представлен в виде двух образов, имеющих координальные различия в своей структуре:

  • openwrt-ar71xx-dir-825-b1-jffs2-backup-loader.bin — На разделе с файловой системой jffs2, доступной как для чтения, так и для записи — хранится операционная система, а также имеется свободной пространство. Есть возможность не только добавлять, но и заменять или даже удалять имеющиеся файлы. Понятно что такая структура требует квалифицированного обращения, ибо некорректности могут привести к невозможности загрузки операционной системы и необходимости прошивки и настройки с нуля. Помимо этого на встроенной флэш-памяти маршрутизатора (8МБайт) хранится загрузчик и еще некоторые вещи (не описываемые в рамках данной статьи).
  • openwrt-ar71xx-dir-825-b1-squashfs-backup-loader.bin — Файлы операционной системы и базовой конфигурации хранятся на файловой системе squashfs, доступной только для чтения. Также есть раздел jffs2 (доступный для чтения и записи — изначально он чист). Кроме этого применена виртуальная файловая система mini_fo — осуществляющая маскИрование раздела squashfs, данными из jffs2 (называемой также overlay). Идея такова: на разделе с jffs2 (примонтированного к /overlay) по мере работы создается копия корневой структуры, содержимое которой преволирует (имеет более высокий приоритет) над файлами из squashfs, т.е. при обращении к файлу его наличие проверяется сначала на jffs2 и лишь за тем на squashfs (если на jffs2 его не оказалось). Таким образом все изменения и дополнения сохраняются на jffs2 маскИруя базовый образ на squashfs (данные на котором, в случае их наличия остаются там «мертвым грузом»), также jffs2 может содержать метку «удаления» файла из squashfs. При подобной структуре мы всегда можем очистить jffs2 раздел и тем самым вернуться к «настройкам по умолчанию» (базовому образу) без процедуры перепрошивки. Еще раз обращаю внимание — технологию маскирования обеспечивает виртуальная файловая система mini_fo, органицующая единый системный «корень» из двух разделов: squashfs и jffs2.

Есть не мало документов на различных сайтах и обсуждений на форумах каким образом «мигрировать» работу оси на внешний USB-флэш накопитель, присутствуют примеры скриптов, в том числе и на официальном сайте OpenWRT. Но есть ряд нюансов, которые недостаточно документированы или не документированы вовсе. В большинстве случаев приводятся лишь куски скриптов, а общую картину приходится достраивать самому.

И так. С первого взгляды бы казалось с первой конфигурацией разделов (все на jffs2) мигрировать должно было бы проще, но при тестировании возникли осложнения с синхронизацией папок /var и /tmp — а на структуре с mini_fo все прошло более гладко (с удалением одной строчки относительно предыдущего варианта). Теперь по пунктам что нужно предпринять:

Перенос системы на внешний USB-флэш накопитель.

  • Для начала определимся — в какую файловую систему будем форматировать флэш-накопитель (или жесткий диск). Это может быть ext2 или ext3. Предлагаю остановиться на ext2, ибо основное преимущество ext3 — журналируемость для флэш-накопителей не очевидно (требует больше операций чтение/запись, что не прибавляет шансов на сохранность данных при сравнительно невысоких скоростях). В любом случае рекомендую отключать кеш на запись (в случае с ext3 это сделать чуть сложнее — и в этом случае теряется возможная прелесть журналируемости). Размечать и форматировать накопитель можно как средствами OpenWRT, так и на компе например утилитой parted magic. Тут же можно создать swap-раздел («файл подкачки»). Как основной раздел, так и swap-раздел целесообразно организовывать в виде «основных» разделов (подробности раметки накопителей выходят за рамки данной статьи).
  • Для начала установим необходимые «драйверы» — модули ядра (с префиксом kmod*) необходимые для взаимодействия с USB-портом, накопителем и файловой системой (можно ограничиться только выбранной файловой системой или сразу добавить и прочие, на будущее — места они занимают мало). Выполнить это можно например следующей командой (предварительно обновив лист репозитория: opkg update — при настроенном подключении маршрутизатора к интернету):

opkg install kmod-usb2 kmod-usb-storage kmod-fs-ext2 kmod-fs-ext3 usbutils e2fsprogs

Данные пакеты как и все модули ядра устанавливаются на встроенную память маршрутизатора, даже после того как мы успешно мигрируем.

  • Создадим файл /etc/init.d/pivotroot следующего содержания (предполагаем что флэшка видна системе как устройство /dev/sda1):
Листинг файла - /etc/init.d/pivotroot

#!/bin/sh
# change this to your boot device (put here the name of your umsd drive)
boot_dev="/dev/sda1"
# starting hotplug daemon
/sbin/hotplug2 --override --persistent --max-children 1 --no-coldplug &
# loading kernel modules for umsd drive by ext2 & ext3 file system
for module in nls_base usbcore ehci-hcd scsi_mod sd_mod usb-storage jbd ext2 ext3 ; do {
     insmod $module
     }; done

     # this may need to be higher if your disk is slow to initialize
     sleep 3s
     # check partition for errors & fix it
     e2fsck -p "$boot_dev" > /var/log/e2fsck
     sleep 1s
     # mount the usb stick
     mount -t ext2 "$boot_dev" /mnt
     # mount -t ext3 -o noatime,data=ordered "$boot_dev" /mnt

killall hotplug2

     # if /etc/pivotroot not empty ...
     # and if everything looks ok, do the pivot root
     [ -s /etc/pivotroot ] && [ -x /mnt/sbin/init ] && {
          mount -o move /proc /mnt/proc && \
          pivot_root /mnt /mnt/mnt && {
          mount -o move /mnt/dev /dev
          mount -o move /mnt/tmp /tmp
          mount -o move /mnt/sys /sys 2>&-
          }
     }

Присвоим ему права 755. Данный скрипт выполняется в самом начале загрузки оси: выполняет проверку файловой системы на внешнем накопителе на наличие логических ошибок и исправляет их, далее осуществляется монтирование внешнего накопителя и перенаправление «корня» на него (средствами встроенного в операционную систему скрипта pivot_root).

  • Пропишем этот скрипт в автозапуск следующей командой:

ln -s /etc/init.d/pivotroot /etc/rc.d/S10pivotroot
  • Скопируем файлы операционной системы на внешний накопитель — откуда они впоследствии и будут использоваться (предполагаем что флэшку уже отформатировали, драйвера установили, маршрутизатор перезагрузили). Создадим в каталоге /tmp произвольный файл, присвоим ему права на исполнение (777) и запишем в него следующее (для развертывания содержимого — кликните на стрелочку справа от заголовка):
Листинг файла - /tmp/install.sh

#!/bin/sh
mkdir /tmp/root
mount -o bind /rom /tmp/root
mount /dev/sda1 /mnt
cp /tmp/root/* /mnt -a
cp /overlay/* /mnt -a
umount /tmp/root
umount /mnt

Выполним получившийся скрипт. Эти же строки (за исключением первой) можно выполнить и покомандно.

  • Модифицируем скрипт /etc/init.d/rcS к следующему виду:
Листинг файла - /etc/init.d/rcS

#!/bin/sh
# Copyright (C) 2006 OpenWrt.org

run_scripts() {
for i in /etc/rc.d/$1*; do
[ -x $i ] && $i $2 2>&1
done | $LOGGER
}

LOGGER="cat"
[ -x /usr/bin/logger ] && LOGGER="logger -s -p 6 -t sysinit"

if test $2 == "boot" ; then
/etc/init.d/pivotroot
fi

if [ "$1" = "S" ]; then
run_scripts "$1" "$2" &
else
run_scripts "$1" "$2"
fi

Красным помечены добавленные строки.

  • Создадим файл /etc/pivotroot — поместим в него произвольный текст (хоть один символ — и уже файл не пустой).
  • Перезагружаемся.
  • Проверяем что у нас получилось:

df -h

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

  • Для корректности работы выполним еще пару крманд:

rm /etc/resolv.conf
ln -s /tmp/resolv.conf.auto /etc/resolv.conf

  • В случае, если в п.1 был также создан swap-раздел, то организуем его использование. Для этого создадим демона управления в виде файла /etc/init.d/swapctrl:
Листинг файла - /etc/init.d/swapctrl

#!/bin/sh /etc/rc.common

START=40
STOP=40

start() {
# Don't stop processing
( startup ) &
}

stop() {
sync
sync
swapoff /dev/sda2
}

restart() {
stop
start
}

startup() {
mkswap /dev/sda2
swapon /dev/sda2
}

Установим файлу права 755. В данном случае подразумевается что swap-раздел виден системе как /dev/sda2. Активировать swap-раздел (как и любой другой демон) можно командой:


/etc/init.d/swapctrl start

Для автозапуска данного демона можно выполнить:


/etc/init.d/swapctrl enable

Удедиться в активности swap-раздела, а также посмотреть общий раздер доступной памяти можно командой free.

  • Вот собственно и все. «Старый корень» (содержимое squashfs), при текущем корне на внешнем накопителе — имеет точку монтирования /mnt, как и прежде маскируется через mini_fo из папки /mnt/overlay (учитывая это можно вносить изменения в файлы на встроенной памяти). В случае если нам будет необходимо загрузиться со встроенной памяти (например для установки модулей ядра), то следует очистить содержимое файла /mnt/etc/pivotroot и перезагрузиться — корнем будет структура mini_fo (overlay поверх squashfs) на встроенной памяти. Сотворив необходимые операции — для возврата обратно (к использованию внешнего накопителя в качестве корня) вносим любое содержимое в файл /etc/pivotroot (на встроенной памяти). Файл /etc/pivotroot на внешнем накопителе должен быть пустым!
  • Есть замечания и вопросы ? — пишем комментарии …

Продолжение (2010-09).

Не так давно (июль 2010) в OpenWrt появился новый модуль — «extroot», организующий функцию миграции корня на внешний накопитель меньшими «плясками», в сравнении с описанным выше способом (которому до этого времени альтернативы собственно и не было).

Extroot — как им воспользоваться?

Для начала можно прочитать доку с официального сайта http://wiki.openwrt.org/doc/howto/rootfsonexternalstorage. Далее обратиться к уже упомянутому мной сайту, и на этот раз статье http://dipcore.com/?p=296. Из прочитанного стоит понять, что без пересборки прошивки в данном случае не обойтись. Обзор и линки на материалы по самостоятельной компиляции прошивки из исходников описаны ранее здесь. Разобраться и собрать прошивку самому — это правильный путь, и в этом нет ничего сложного (и это под силу тем, кто выполнил первую часть этой статьи ;-) Тем немее, кто не хочет заморачиваться с данным процессом, могут воспользоваться последней версией моей компиляции, всегда доступной для скачивания: http://maslenizza.ru/ar71xx/openwrt-ar71xx-dir-825-b1-squashfs-backup-loader.bin.

Немножко подробностей.

Все статьи на разных сайтах грешат отсутствием четкого алгоритма, более того информация, порой, содержит неточности — в общем всегда приходится не тупо копи-пастить, а включать мозги и обобщать ;-) Так вот еще один элемент для обобщения создаю и я ;-)) Ориентир, как всегда, больше на понимание, чем на тупой алгоритм для «чайника».

  • Создаем разделы и форматируем наш «внешний накопитель» (жесткий диск, флешку, карту памяти в ридере) любыми средствами (утилитами в маршрутизаторе, опреционкой на виртуальной машине, загрузившись с лайв-сиди) — кому как удобнее. Число разделов и их порядок — опять-таки на ваше усмотрение (лучше создавать все разделы как «основные», а не логические диски в расширенном). В принципе можно ограничиться и одним разделом — в который и мигрирует наш «корень» — и файловую систему на нем ext2 (не стоит создавать под корень раздел с ext3, тем более на накопителе флеш — из-за пресловутого «журналирования», которое для корректности придется отключать*). Также целесообразно создать swap-раздел. Ну и для упорядочения хранимых данных (в случае большой емкости внешнего накопителя) можно изначально не распределять все пространство между «корнем» и «свопом», а оставить еще местечка под раздел данных, который можно отформатировать в любую linux-систему (ext2, ext3).
  • Заливаем прошивку (предложенную выше, или собранную самостоятельно). При самостоятельной сборке в образ помимо драйверов usb, внешних накопителей и файловых систем (описано вначале статьи), необходимо также включить модули block-hotplug и block-mount (автоматизация монтирования), e2fsprogs (проверка целостности файловой системы), block-extroot (ради чего все и затевалось).
  • Убедиться в работоспособности ;-) Скопировать содержимое корня образа на радел внешнего накопителя (в примере подразумевается, что файловая система накопителя ext2, а подключен он как sda1), сформировать swap-раздел (находится на sda2) — при помощи следующего скрипта (или покомандно из консоли):
Листинг файла - /tmp/install.sh


#!/bin/sh

mount -t ext2 /dev/sda1 /mnt
mkdir /tmp/root
mount -o bind /rom /tmp/root
cp /tmp/root/* /mnt -a
mkswap /dev/sda2

  • И напоследок (перед перезагрузкой) для обеспечения автоматического старта всей конструкции откорректируем файл /etc/config/fstab — приведя его к следующему виду:
Листинг файла - /etc/config/fstab


config global automount
     option from_fstab 1
     option anon_mount 1

config global autoswap
     option from_fstab 1
     option anon_swap 0

config mount
     option target /
     option device /dev/sda1
     option fstype ext2
     option options rw,sync
     option enabled 1
     option enabled_fsck 1
     option is_rootfs 1

config mount
     option target /root
     option device /dev/sda3
     option fstype ext3
     option options rw,sync
     option enabled 1
     option enabled_fsck 1

config swap
     option device /dev/sda2
     option enabled 1

В нашем случае sda1 — новый корень (ext2); sda2 — swap-раздел; sda3 — пользовательская область, монтируемая в /root (ext3). Впрочем значение всех параметров легко угадывается по названию. Считаю не лишним до перезагрузки скопировать этот файл и на новый корень, после чего выполнить команду sync и umount /mnt.

  • Все (правда — все значительно упростилось?).

«Лирические отступления» — по тексту .

* «Журналирование» — хитрый процесс, в теории направленный на повышение вероятности сохранения целостности данных на накопители при внезапном его отключении в самые неподходящие моменты. Под «журнал» выделяется (резервируется) часть дискового пространства (пропорциональная его емкости). Журналироваться могут как непосредственно сами данные, так и только мета-информация. В первом случае запись происходит не на предполагаемое место хранения данных на диске в отведенную область журнала (при отключении диска на этой стадии и последующем включении и проверке — данные журнала признаются недействительными, а фактическая информация на диске остается в целостности, хоть и в устаревшем виде) — в случае успеха делается пометка, что для фактических данных требуется обновление из журнала. Далее предполагается процесс обновления фактических данных по данным «журнала» (при отключении накопителя в этот момент — считаются подлинными данные журнала, попытка записи которых на фактическое место происходит повторно) — в случае успеха (проверки соответствия) делаются соответствующие пометки и журнал «очищается». Такой алгоритм в два раза снижает скорость записи на накопитель, а в случае использования флеш-накопителя существенно способствует его износу (журнал хранится в фиксированном месте и являясь буфером постоянно перезаписывается). Если же применяется алгоритм журналирования мета-информации — достичь безусловной целостности не удастся — возможно лишь зафиксировать ее нарушения (мета-информация — фактически контрольные суммы блоков данных на накопителе). Как показала практика использование системы ext3 под «корнем» на внешнем накопителе с журналированием только мета-информации (режим по умолчанию) ведет к частому нарушению целостности информации (возможно мнимому), на инфа «коцаеца» корректность работы теряется, приходится либо включать полное журналирование (что для флеш-накопителя нежелательно по описанным выше причинам), либо отключать его вовсе — тогда вопрос: зачем на ext3 без журналирования — это уже фактически ext2 (использовать которую под «корень» я и рекомендую).