18 мая в 21:12

Увеличиваем потенциал брошенного производителем сетевого хранилища tutorial

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


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


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


image


Для нетерпеливых: в конце получился полноценный аппарат с актуальной версией загрузчика U-Boot, image Debian Jessie и image OpenMediaVault на борту.


Содержание:


  1. Устройство
  2. Подготовка устройства
  3. Сборка и обновление
  4. Установка и настройка
  5. Заключение


Устройство


Встречайте подопытного — D-Link DNS-325.


image


На устройстве установлен ARM процессор Marvell Kirkwood 88F6281 (EABI) архитектуры armel, NAND память на 128MB, RAM на 256MB. Оснащен двумя отсеками для HDD, сетевым и USB разъемом на задней панели.


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


Глюки


В порядке убывания важности:


  1. Глюки UPnP AV медиа сервера. На хранилище настроен медиа сервер, который индексирует аудио и видео материалы и раздает их по DLNA протоколу. Проблема в том, что некоторые файлы, добавляемые на жесткий диск, не индексируются автоматически и не отображаются при заходе с телевизора/другого DLNA совместимого устройства. Помогает ручное переключение режима медиа сервера, тогда база создается с нуля, но это занимает пару часов. Не самое лучшее решение, когда хочется скачать и посмотреть фильм.


  2. Внезапное пробуждение из состояния "сна" посреди ночи (шуршание диском, шум вентилятора) создает дискомфорт. И ни строчки в логе о том, какая же сервисная задача запустилась. Только событие запуска вентилятора:
    Apr 20 03:55:09 Set Fan Speed To "LOW".


  3. Веб-интерфейс. Наблюдаются зависания, отвалы сессии, и т. п.


  4. Дополнения. Есть как официальные, так и неофициальные. Проблема в том, что никто не занимается поддержанием актуальности ПО. В таком виде исправления ошибок и уязвимостей ждать также не стоит.


  5. Система логирования просто ужасна. Мало того, что она малоинформативна, так еще и с какими-то мифическими артефактами.


  6. Linux. Как в основе многих современных кофеварок встраиваемых устройств, в основе лежит Linux. А это значит, что рядом стоят вопросы стабильности, уязвимостей и т. д. В стоковой прошивке крутится ядро Linux 2.6, а на дворе уже Linux 4.11.


  7. Странный баг с USB принтером. Хранилище оснащено USB портом для подключения флешек, USB дисков, принтеров и сканеров. И мой USB принтер отлично расшаривался по сети, пока внутри был установлен 1 HDD на 2 TB. Как только я вставил в правый кейс HDD на 3 TB, принтер переставал работать. После ряда тестов с различными комбинациями различных дисков я выяснил, что работает он только с одним, установленном в левом кейсе.

Выбор альтернативной ОС


Alt-F


Первым, что нашлось из адаптированных альтернатив, стала открытая прошивка Alt-F. Функционал не уступает фирменной прошивке, минималистичный веб-интерфейс, обновления выходят стабильно. Даже есть поддержка плагинов fun_plug.


image FreeNAS и image NAS4Free


Проекты интересные, но громоздкие. Основаны на FreeBSD. Слишком высокие системные требования.


Вот, например, системные требования для FreeNAS 10 "Corral":


  • процессор с поддержкой 64-bit
  • система с поддержкой загрузки через legacy BIOS или EFI
  • 8 GB RAM
  • 8 GB USB флешка или другой накопитель
  • хотя бы один диск для хранения данных
  • порт Ethernet для сетевого обмена

Кстати, недавно релиз FreeNAS 10 "Corral" отозвали, в т.ч. и по причине повышения системных требований.


image OpenMediaVault


OMV — система для NAS с открытым исходным кодом. Является ответвлением от FreeNAS, но адаптированного под Debian Linux, в следствие чего мультиплатформенна. В сочетании с относительно невысокими системными требованиями делает себя единственным подходящим кандидатом. Функционал более чем достаточный, расширяемый своими плагинами, но самое главное, что полноценный Debian дает доступ к репозиториям, а значит можно поставить все что угодно установкой пары пакетов.


Для данной модели есть несложный способ запустить Debian с помощью хака с fun_plug, но это всего лишь real-time расширение, к тому же не удастся запустить Debian версии старше Wheezy.


К сожалению, у OMV нет готовой сборки Debian со своим пакетом для архитектуры armel. Более того, разработчики пока признают стабильными только i386 и amd64 сборки. Поддержка ARM экспериментальная:


Support for OpenMediaVault on Arm is experimental. In most situations you will need to determine how to install Debian Wheezy on you device.

Подготовка устройства


Встроенная NAND память не подходит для нашей задумки — слишком маленькая. Хранить систему на вставляемых в хранилище дисках желания нет совсем. Получится смешивание мозгов устройства с периферийными составляющими. А если я захочу диск поменять или он сломается?


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


Для USB устройств было решено взять отдельный USB Network Hub, все равно одного слота не хватает :)


Дополнительное железо


Для доступа к мозгам извне на плате есть последовательный UART порт. Вместо того, чтобы перепрошивать ROM специальными программаторами, можно подключиться к контактам на плате и через специальный преобразователь общаться с устройством через эмулятор терминала.


Тема UART во встраиваемых устройствах довольно обширна, кому интересно, можете прочесть хорошую обзорную статью: https://geektimes.ru/post/253786/


Были выбраны и куплены следующие комплектующие:


  • Преобразователь USB — UART на PL2303HX
  • Провода "мама-мама" 20см, 20 шт.
  • Вилка штыревая PLS-40 (DS1021-1x40), прямая черная
  • SanDisk Ultra Fit USB 3.0 16GB

Подключение преобразователя


Вскрываем устройство, достаем плату

image


Ищем UART порт (4 пина слева)

image


Распиновка такая (в обратном порядке): { RXD, (пусто), 3.3v, GND, TXD }


Припаиваем вилку, вставляем провода

image


Собираем корпус, оставляем снятой только крышку

image


Теперь для доступа к встроенному микрокомпьютеру не надо будет доставать плату — провода уже выведены, останется снять переднюю крышку сетевого хранилища.


Так как это последовательный порт, то и соединяем последовательно.


RX на TX, TX на RX

image


На этом вся механическая работа с оборудованием закончена.


Пробный запуск


Для общения по протоколу UART нам понадобятся:
kwboot — утилита для запуска загрузчика на устройстве "на лету"
minicom — эмулятор терминала для UART протокола


Запускаем minicom на хост системе:


# minicom -D /dev/ttyAMA0 -b 115200 -8

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


Лог загрузки
** MARVELL BOARD: DB-88F6281A-BP LE 

U-Boot 1.1.4 (Jan 21 2011 - 09:42:39) Marvell version: 3.4.14.DNS-325.02

U-Boot code: 00600000 -> 0067FFF0  BSS: -> 006CEE80

Soc: MV88F6281 Rev 3 (DDR2)
CPU running @ 1200Mhz L2 running @ 400Mhz
SysClock = 400Mhz , TClock = 200Mhz

DRAM CAS Latency = 5 tRP = 5 tRAS = 18 tRCD=6
DRAM CS[0] base 0x00000000   size 256MB
DRAM Total size 256MB  16bit width
Flash:  0 kB
Addresses 8M - 0M are saved for the U-Boot usage.  
Mem malloc Initialization (8M - 7M): Done
NAND:128 MB

***

NAND read: device 0 offset 0x100000, size 0x300000
load addr ....  =a00000

 3145728 bytes read: OK

NAND read: device 0 offset 0x600000, size 0x300000
load addr ....  =f00000

 3145728 bytes read: OK 
## Booting image at 00a00000 ...
   Image Name:   Linux-2.6.31.8
   Created:      2012-06-26   3:38:43 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    2565784 Bytes =  2.4 MB
   Load Address: 00008000
   Entry Point:  00008000
   Verifying Checksum ... OK
OK
## Loading Ramdisk Image at 00f00000 ...
   Image Name:   Ramdisk
   Created:      2014-01-21   4:33:41 UTC
   Image Type:   ARM Linux RAMDisk Image (gzip compressed) 
   Data Size:    1581012 Bytes =  1.5 MB
   Load Address: 00e00000
   Entry Point:  00e00000
   Verifying Checksum ... OK

Starting kernel ...                                                             

Uncompressing Linux.............................................................
**Linux version 2.6.31.8** (jack@swtest6) (gcc version 4.2.1) #8 Tue Jun 26 11:38:42
CPU: Feroceon 88FR131 [56251311] revision 1 (ARMv5TE), cr=00053977
CPU: VIVT data cache, VIVT instruction cache
Machine: Feroceon-KW
Using UBoot passing parameters structure
Memory policy: ECC disabled, Data cache writeback
Built 1 zonelists in Zone order, mobility grouping off.  Total pages: 65024
Kernel command line: root=/dev/ram console=ttyS0,115200 :::DB88FXX81:egiga0:none
PID hash table entries: 1024 (order: 10, 4096 bytes) 
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 256MB = 256MB total
Memory: 246528KB available (4828K code, 323K data, 136K init, 0K highmem)

***

NAND device: Manufacturer ID: 0xec, Chip ID: 0xf1 (Samsung NAND 128MiB 3,3V 8-b)
Scanning device for bad blocks
Using static partition definition
Creating 6 MTD partitions on "nand_mtd":
0x000000000000-0x000000100000 : "u-boot"
0x000000100000-0x000000600000 : "uImage"
0x000000600000-0x000000b00000 : "ramdisk"
0x000000b00000-0x000007100000 : "image"
0x000007100000-0x000007b00000 : "mini firmware"
0x000007b00000-0x000008000000 : "config"

Если интересно, вот полный вывод:
https://pastebin.com/6SRA6Qgq


Сборка и обновление


Все действия по сборке будут проводиться на основной (хост) системе под управлением Debian Stretch (amd64).


Собирать и обновлять будем:


  1. Загрузчик — U-Boot
  2. Ядро — Linux Kernel 4.10
  3. Корневую файловую систему Debian Jessie
  4. Образ начальной инициализации системы — Initramfs

Основные инструменты для сборки:


  1. Кросс-компилятор для armel архитектуры. В Debian это пакет gcc-arm-linux-gnueabi
  2. Вспомогательные утилиты:
    • git — для скачивания нужных версий с репозиториев проектов
    • make — для выполнения сборочных скриптов
    • debootstrap — для скачивания корневой файловой системы
    • mkimage — утилита для переформатирования файлов в формат, понятный загрузчику
    • BusyBox — набор утилит для начальной инициализации системы
    • сопутствующие зависимости и библиотеки.

Загрузчик


В данном устройстве установлен немного урезанный загрузчик U-Boot 2011 года. Обновлять будем до актуальной стабильной версии.


Скачиваем:


$ git clone --branch v2017.05 git://git.denx.de/u-boot.git

Настраиваем:


$ cd u-boot
$ nano u-boot/include/configs/dns325.h

Добавляем строки:
#define CONFIG_CMD_BOOTZ — для поддержки загрузки zImage ядра.
#define CONFIG_CMD_EXT4 — для поддержки ФС ext4 и связанных команд консоли загрузчика.


$ make dns325_defconfig
#
# configuration written to .config
#
$ make u-boot.kwb CROSS_COMPILE=arm-linux-gnueabi-

На этом этапе нужно знать, сколько весит этот файл:


$ printf "0x%x\n" `stat -c "%s" u-boot.kwb`
0x7315c

Выводим размер образа в шестнадцатеричной системе счисления (HEX), в таком виде он пригодится при записи в NAND память.


Записать полученный образ U-Boot в NAND память можно из работающего в памяти загрузчика. Я решил не делать это из текущего стокового загрузчика, так как хотелось сначала убедиться, что новый образ вообще загрузится на железе, да и поддержка ext4 была включена ранее в новом образе загрузчика, так что можно сделать финт ушами: скопировать этот образ на флешку и загрузить с этого же образа при помощи kwboot.


Есть несколько вариантов, как передать файл в память миникомпьютера: через Kermit, через TFTP, а также через физически подключенные накопители (наш выбор).


kwboot позволяет запустить плату с передаваемым ей загрузчиком, не записывая ничего физически (только в RAM) и вообще игнорируя NAND память. Этот механизм позволяет аварийно загружать устройство даже когда оно окирпичилось в следствие порчи NAND памяти или неудачной прошивки.


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


Заливка и загрузка
# tools/kwboot -p -b u-boot.kwb -B115200 -t /dev/ttyUSB0
Sending boot message. Please reboot the target.../
Sending boot image...
  0 % [......................................................................]
  1 % [......................................................................]
  3 % [......................................................................]
***
 96 % [......................................................................]
 98 % [...........................................]
[Type Ctrl-\ + c to quit]


U-Boot 2017.05-dirty (May 10 2017 - 02:56:44 +0300)
D-Link DNS-325

SoC:   Kirkwood 88F6281_A1
DRAM:  256 MiB
WARNING: Caches not enabled
NAND:  128 MiB
In:    serial
Out:   serial
Err:   serial
Net:   egiga0
IDE:   ide_preinit failed
Hit any key to stop autoboot:  0 
=>

Загрузились. Далее надо записать наш u-boot.kwb образ в область NAND. Но чтобы записать его в NAND память, надо сначала считать его и записать в RAM память.


Делаем ext4 флешку и даем разделу имя "rootfs" (чтобы монтировать корневую ФС по имени раздела):


# mkfs.ext4 /dev/sdb1
# e2label /dev/sdb1 rootfs

Копируем файл на флешку, вставляем флешку в NAS и инициализируем ее:


=> usb start                 
starting USB...
USB0:   USB EHCI 1.00
scanning bus 0 for devices... 2 USB Device(s) found
       scanning usb for storage devices... 1 Storage Device(s) found

Записываем образ в память. Адрес (смещение) не имеет значения, главное не выходить за пределы RAM). В данном случае будет 0x1000000.


=> ext4load usb 0:1 0x1000000 /u-boot.kwb
471388 bytes read in 77 ms (5.8 MiB/s)

Очищаем область NAND, в которой хранится загрузчик:


=> nand erase 0x000000 0x7315c

NAND erase: device 0 offset 0x0, size 0x7315c
Erasing at 0x60000 -- 100% complete.
OK

(с начала NAND памяти до смещения, равного размеру файла, который мы высчитали ранее)


Записываем загрузчик из области RAM памяти в область NAND памяти:


=> nand write 0x1000000 0x000000 0x7315c 

NAND write: device 0 offset 0x0, size 0x7315c
 471388 bytes written: OK

0x1000000 — откуда читаем в RAM
0x000000 — куда записываем в NAND
0x73044 — размер


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


U-Boot 2017.05-dirty (May 10 2017 - 02:56:44 +0300)
D-Link DNS-325

SoC:   Kirkwood 88F6281_A1
DRAM:  256 MiB
WARNING: Caches not enabled
NAND:  128 MiB
In:    serial
Out:   serial
Err:   serial
Net:   egiga0
IDE:   ide_preinit failed
Hit any key to stop autoboot:  0       
=>

Если на данном этапе устройство окирпичилось и отказалось загружаться, например, как сначала получилось у меня (видимо, опечатался, когда вводил размер образа загрузчика при записи из RAM памяти в NAND), не спешите паниковать. Вы также можете загрузить устройство при помощи kwboot и повторить запись.


Корневая система (этап первый)


Воспользуемся инструментом debootstrap. Обычно формирование rootfs для систем с другой архитектурой делается в 2 этапа: скачивание в каталог с флагом --foregin, а потом настройка qemu и запуск в нем "debootstrap --second-stage". Мне не хотелось возиться с qemu, и я решил делать второй этап сразу на работающем NAS-е.


Скачиваем содержимое на флешку (примонтирована в /mnt/usb/):


# debootstrap --variant=minbase --foreign --arch=armel --include=dbus,nano jessie /mnt/usb/ http://ftp.ru.debian.org/debian/ 

Переименуем на время init файл, чтобы наполовину установленая система не запустилась:


# mv /mnt/usb/sbin/init /mnt/usb/sbin/init.bak

Первый этап готов.


Ядро


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


Сначала мне посчастливилось найти уже готовое ядро для Kirkwood, но оно всячески отказывалось монтировать флеш накопитель в любом из режимов (OHCI, EHCI), так что все равно пришлось собирать ядро самостоятельно.


Скачивание:


$ git clone --branch v4.10 git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git

Загружаем предустановленный конфиг для нашей платы (ARMv5). В моем случае это mvebu_v5_defconfig.


$ make ARCH=arm mvebu_v5_defconfig
#
# configuration written to .config
#
$ make ARCH=arm menuconfig

Настраиваем. Настраивать и проверять нужно все, в идеале изучить каждый параметр и решить, нужен он или нет. Мной был выставлен hostname, включена поддержка initramfs/initrd, отключена поддержка звука и USB 3.0, отключены драйвера для ext2 и ext3 (драйвер ext4 умеет монтировать все ранние версии), включены дисковые квоты, включена поддержка плат Kirkwood, Marvell Orion. Также включены обязательные параметры для поддержки systemd. Скорее всего, есть есть что-то, чего я не упомянул, ибо настроек много. Вот мой конфиг ядра: https://pastebin.com/MZrRXnXX


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


Сборка:


$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j5 zImage kirkwood-dns325.dtb

Получили само ядро zImage и файл kirkwood-dns325.dtb. Последний файл — Device Tree — нужен для правильной работы ядра конкретно с нашей платой.


Копируем эти файлы в каталог /boot на флешке:


# cp arch/arm/boot/zImage arch/arm/boot/dts/kirkwood-dns325.dtb /mnt/usb/boot/

Initramfs


Далее делаем легковесный образ, который будет загружаться в память и инициализировать нашу систему. Его делать вовсе необязательно, загрузчик умеет напрямую стартовать ядро с указанием корневого каталога (root=). Однако полезно, т. к. в случае отсутствия доступа к корневой ФС будет доступна консоль с минимальным набором команд.


Костяк образа составит джентльменский набор BusyBox.


Скачивание:


$ git clone --branch 1_26_2 git://git.busybox.net/busybox/

Настройка:


$ make defconfig
$ make menuconfig

Единственное, что лучше выставить в настройках дополнительно — это статическая линковка библиотеки glibc, чтобы не пришлось запихивать его отдельно в образ.


Статическая линковка glibc

image


Сборка:


$ make ARCH=arm

Далее создаем структуру образа, помещаем в него busybox:


$ mkdir -p initramfs/{bin,sbin,etc,proc,sys,newroot,usr/{bin,sbin}}
$ cp busybox/bin/bisybox initramfs/bin
$ ln -s initramfs/bin/busybox initramfs/bin/sh

Далее необходимо написать init скрипт. Именно тут будет происходить вся магия по инициализации устройств и передаче управлению Debian-у.


init скрипт
#!/bin/sh

/bin/busybox --install -s

#Mount things needed by this script
mount -t proc proc /proc
mount -t sysfs sysfs /sys

#Disable kernel messages from popping onto the screen
echo 0 > /proc/sys/kernel/printk

#Clear the screen
clear

#Create device nodes
mknod /dev/null c 1 3
mknod /dev/tty c 5 0

#Pause bebore USB Storage init
sleep 3

#Mount devices
mdev -s

#Defaults
init="/sbin/init"

#Mount the root device
mount LABEL=rootfs /newroot

#Check if $init exists and is executable
if [ -h  "/newroot/${init}" ] ; then
    #Unmount all other mounts so that the ram used by
    #the initramfs can be cleared after switch_root
    umount /sys /proc

    #Switch to the new root and execute init
    exec switch_root /newroot "${init}"
fi

#This will only be run if the exec above failed
echo "Failed to switch_root, dropping to a shell"
exec setsid sh
exec <"${console}" >"${console}" 2>&1
exec sh

Пакуем и преобразуем в понятный для U-Boot-а формат:


$ cd initramfs/
$ find . | cpio -H newc -o > ../initramfs.cpio
$ cd ..
$ cat initramfs.cpio | gzip > initramfs.igz
$ mkimage -n 'uInitramfs' -A arm -O linux -T ramdisk -C gzip -d initramfs.igz initramfs.uImage

Копируем initramfs:


# cp initramfs.uImage /mnt/usb/boot/

Со сборкой закончили.


Установка и настройка


Переменные окружения загрузчика


В процессе обновления загрузчика затерлись конфиги, надо настроить загрузку нового ядра, Initramfs, Device Tree, также восстановить настройки сети.


Загружаемся с minicom, выполняем на устройстве в консоли U-Boot:


=> setenv console ttyS0,115200
=> setenv bootargs console=${console}
=> setenv bootcmd usb start; run load_kernel; run load_init; run load_dtree; run boot_system
=> setenv load_kernel ext4load usb 0:1 0x1000000 boot/zImage
=> setenv load_init ext4load usb 0:1 0x1800000 boot/initramfs.uImage
=> setenv load_dtree ext4load usb 0:1 0x2000000 boot/kirkwood-dns325.dtb
=> setenv boot_system bootz 0x1000000 0x1800000 0x2000000
=> setenv ethaddr xx:xx:xx:xx:xx:xx
=> setenv ipaddr 192.168.0.32
=> saveenv

Тут все предельно просто: выставляем параметры консоли, загрузки ядра, прописываем куда будут копироваться (ext4load) в память файлы и откуда считываться (bootz). Прописываем ip и mac адреса (mac адрес можно посмотреть на наклейке устройства).


Вставляем флеш накопитель в NAS, перезагружаемся.


Корневая система (этап второй)


Загрузившись, попадаем в BusyBox. Можем завершить формирование rootfs:


# chroot /newroot
# mv /sbin/init.bak /sbin/init
# /debootstrap/debootstrap --second-stage
# passwd

Перезагружаем устройство, логинимся под root-ом. С этого момента мы загружаемся полностью и работаем в Debian-е.


Настройка сети


Далее следует настроить и включить сеть.


# touch /etc/systemd/network/wired.network
# nano /etc/systemd/network/wired.network

Пишем простой конфиг для статического ip на проводном интерфейсе eth0
[Match]
Name=eth0


[Network]
Address=192.168.0.32/24
Gateway=192.168.0.1


Включаем и запускаем сетевые службы


# systemctl enable systemd-networkd
# systemctl enable systemd-resolved
# systemctl start systemd-networkd
# systemctl start systemd-resolved

Сеть есть.


Настройка вентилятора и кнопок


Прежде чем делать высоконагруженные операции, необходимо настроить вентилятор на охлаждение. Обычно настройка происходит просто: при помощи команды pwmconfig находится датчик температуры ЦП, находится вентилятор, они связывается и выставляются граничные параметры активации режимов охлаждения.


В случае с домашним NAS так делать не стоит, ибо основную долю тепла выделяют жесткие диски, а не процессор.


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


Выход есть: можно обмануть fancontrol, заставив его считывать информацию из нужного нам места. Для считывания данных с HDD используем пакет smartmontools.


Устанавливаем:


# apt install fancontrol lm-sensors smartmontools

Настраиваем по умолчанию:


# pwmconfig

Тонкости настройки можно почитать, например, здесь.


Далее открываем конфиг /etc/fancontrol, смотрим содержимое. Интересна переменная "FCTEMPS" — она ставит в соответствие устройству место, откуда следует брать температуру:
FCTEMPS=hwmon0/pwm1=hwmon1/temp1_input


Путь относительный, сам файл генерируется в /sys/class/hwmon/hwmon1/temp1_input. Посмотрим в каком формате хранится информация:


# cat /sys/class/hwmon/hwmon1/temp1_input 
41500

Значение в цельсиях, умноженное на 1000 (для точности). Значит нужен файл, в котором периодически будет обновляться значение температуры жестких дисков. Значение допускается одно, а жеских дисков у нас может быть 2. Значит, будем считать максимальное, записывать в файл.


Напишем небольшой скрипт:


#!/bin/bash

while sleep 60
do
    TEMP1=`smartctl -A /dev/disk/by-id/ata-Hitachi_HDS723030ALA640_MK0311YHG1ZGJA | grep Temperature_Celsius | awk '{print $10 "000"}'`
    TEMP2=`smartctl -A /dev/disk/by-id/ata-WDC_WD2003FYYS-02W0B1_WD-WMAY05168428 | grep Temperature_Celsius | awk '{print $10 "000"}'`
    echo $(( $TEMP1 > $TEMP2 ? $TEMP1 : $TEMP2 )) > /etc/temp_hdd
done

Каждую минуту считывается S.M.A.R.T. информация с датчиков HDD, из всей информации выделяется только значение температуры, и в нужном формате наиболшее из 2-х записывается в файл /etc/temp_hdd. Диски я указал по id, потому что буквы дисков /dev/sd[a-z] могут меняться в зависимости от порядка и кол-ва вставленных физических дисков.


Записываем скрипт в /etc/temp_hdd.sh. Дальше нужно его каким-то образом запускать при старте. Для этого как раз подойдет файл /etc/rc.local


Прописываем прямо перед "exit 0" строчку
/etc/temp_hdd.sh &


Теперь процесс будет запускаться при старте системы и выполняться в фоне.


Когда есть файл с актуальной температурой, впишем это в конфиг /etc/fancontrol, настроив при этом граничные значения температуры. Получилось как-то так:


# Configuration file generated by pwmconfig, changes will be lost
INTERVAL=10
DEVPATH=hwmon0=devices/platform/gpio_fan hwmon1=devices/platform/ocp@f1000000/f1011000.i2c/i2c-0/0-0048
DEVNAME=hwmon0=gpio_fan hwmon1=lm75
FCTEMPS=hwmon0/pwm1=/etc/temp_hdd
FCFANS= hwmon0/pwm1=hwmon0/fan1_input
MINTEMP=hwmon0/pwm1=45
MAXTEMP=hwmon0/pwm1=55
MINSTART=hwmon0/pwm1=4
MINSTOP=hwmon0/pwm1=0

Реакцию на кнопки настроить гораздо проще. Устанавливаем пакет esekeyd и настраиваем:


# apt install esekeyd
# nano /etc/esekeyd.conf

Ставим команды на выключение и перезагрузку:


POWER:/sbin/shutdown -h now
RESTART:/sbin/reboot

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


Установка OMV


Добавим репозиторий OMV и установим основной пакет:


# echo "deb http://packages.openmediavault.org/public erasmus main" > /etc/apt/sources.list.d/openmediavault.list
# apt update
# apt install openmediavault-keyring
# apt install openmediavault

Дальше apt предложит устрановить много пакетов (у меня 457), устанавливаем. В процессе установки будет задано несколько вопросов по настройке пакетов, можно везде оставлять дефолт.


В конце apt может сообщить об ошибке настройки collectd и nginx:


dpkg: dependency problems prevent configuration of openmediavault:
 openmediavault depends on collectd (>= 5.1.0); however:
  Package collectd is not configured yet.
 openmediavault depends on nginx (>= 1.6.2); however:
  Package nginx is not configured yet.

Для nginx надо убрать в файле /etc/nginx/sites-available/default строчку
listen [::]:80 default_server;
Такое происходит в случае невозможности использовать IPv6 протокол.


Для collectd надо добавить строчку с hostname и ip в /etc/hosts. В нашем случае
127.0.1.1 dns325


Исправляем зависимости:


# apt install -f

Скрипт рапортует об успешной установке пакета. Запускаем скрипт инициализации:


# omv-initsystem

Все! Система установлена. Дальше заходим в веб панель по адресу 192.168.0.32, настраиваем все окружение по вкусу.


image


Заключение


Функционал полученной системы намного шире, чем в заводской прошивке, но пришлось пожертвовать единственным USB портом.


Конечно, это не единственный и не универсальный способ для всех устройств. Не на каждом устройстве можно вообще установить Linux. Здесь показывалась возможность большого апгрейда в рамках существующей концепции.


На момент написания статьи устанавливался OpenMediaVault 3.x ("Erasmus"), который еще не вышел из статуса бета-версии. Это означает, что возможны баги в работе, однако связаться с разработчиками OMV намного проще, чем пытаться достучаться по почте до производителя D-Link.


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


Из всех перечисленных глюков большинство перестало существовать сразу же: ядро свежей версии, устройство само не просыпается без надобности, в веб-панели есть целая вкладка с логами и фильтрами. Не удалось пока проверить стабильность DLNA плагина, но это вопрос времени. Также слегка подтормаживает веб-интерфейс, но не больше, чем было с заводской прошивкой, и это скорее вопрос точной настройки связки nginx + FastCGI.


Enjoy Embedding!

Роман Дудин @dudinroman
карма
10,0
рейтинг 0,0
Программист
Самое читаемое Администрирование

Комментарии (31)

  • +1
    Я бы попытался сделать максимально самостоятельное устройство. Т.е. что бы его можно было сбросить и привести тем самым к какому-то состоянию по умолчанию. Если посмотреть на устройство прошивок всяких подобных сетевых хранилищь, да и прочей техники, то можно заметить, что там есть базовая система, которая хранится на отдельном разделе, и этот раздел монтируется в режиме «только чтение». И есть второй раздел, на котором уже хранятся настройки пользователя. Это даёт преимущество на случай неправильного отключения питания — основная система не повредится. Настройки так же можно хранить в двух разделах: текущие и некий бэкап.
    Дальше небольшое замечание по идеи самого POSIX. Скрипты хранить в каталоге etc не хорошо. Надо бы перенести либо в /usr/local, либо создать подобную структуру в /opt. Так же запуск скрипта я бы оформил как демон в systemd. Сам systemd его и отслеживать может и в случае падения перезапускать.
    Информацию о температуре писать на флешку — тратить ресурс флешки. Имеет смысл всякие каталоги типа /var, /tmp и /run монтировать в tmpfs.
    Возможно, как вариант решения первого и последнего моих предложений, использовать overlayfs или aufs. Это такая штука, которая позволяет хранить основную систему нетронутой, используя её только для чтения, а все изменения хранить на другом разделе, либо в оперативной памяти.
    • 0
      По поводу скриптов — согласен, надо было идеологически правильно разместить. Не критично.

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

      Про tmpfs тоже была идея в контексте постоянно пишущегося лога, но я решил этого не делать в следствие итак малого размера RAM + сейчас необходимо вести все логи чтобы ловить глюки OMV и чтобы они были доступны даже после ребута. По сравнению с логами, обновление температуры в файле нестрашно. Пока OMV в бете, часто приходится делать apt upgrade. Ну и, как я уже писал, иногда опять приходится включать что-то в ядре, перекомпиллировать и подкладывать ядро.

      А вот с overlayfs идея крутая, возьму на заметку, в идеологии решает много проблем.

      Когда приду к стабильной по всем параметрам системе, подберу идеальную конфигурацию, сделаю готовый образ или скрипт для его формирования.
      • 0

        В часности посмотрите на overlayroot.
        Он просто устанавливается и как правило не требует лишних телодвижений:


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


        apt-get install overlayroot
        echo 'overlayroot="tmpfs"' >> /etc/overlayroot.conf
        reboot

        На случай если нужно внести какие-то изменения:


        overlayroot-chroot
        • 0

          Да, только в Дебиане этого пакета нет. По крайней мере, в стабильной ветке.

      • 0
        Тогда снова берите пример с производителей — сделайте отдельный раздел для логов. По крайней мере, портить флешку вы будете только в одном месте, а на качестве работы испорченный файл с логами не скажется.
        • 0
          портить флешку вы будете только в одном месте
          А разве в USB флэшки (как и в SD-карты) не встраивают контроллеры износа? Давно может и не делали, но сейчас… (по смыслу поста — отдельный раздел для логов — понятно, и согласен)
          • 0
            Технически — никто не мешает сделать выравнивание износа, но практически, похоже, никому это не нужно по отношению к USB флешкам. Не предназначены они для такой работы, да и мало кто их использует так. Плюс, довольно распространённая схема использования — вставил, записал, вынул. Контроллеру чисто физически некогда будет заниматься выравниванием износа, особенно, если учесть стоимость всех этих флешек и их скорость работы.
      • 0
        Про tmpfs тоже была идея в контексте постоянно пишущегося лога, но я решил этого не делать в следствие итак малого размера RAM + сейчас необходимо вести все логи чтобы ловить глюки OMV и чтобы они были доступны даже после ребута.
        1. Использовать удаленный syslog сервер. Самое кошерное для embedded devices.
        2. Для rsyslog и journalctl можно настроить лимит размера лога.

        Диски я указал по id, потому что буквы дисков /dev/sd[a-z] могут меняться в зависимости от порядка и кол-ва вставленных физических дисков.
        Не понял этот момент. В fstab давно используется идентификация по UUID.
        Так же в статье не затронут момент с тюнинга ФС (discard,noatime) для флешки.
  • +1
    Грандиозная работа. По хорошему если компания не хочет поддерживать свой продукт, ей надо платить таким как вы чтобы они занимались этим!
    • 0

      Они скорее в суд подадут, как в той истории с тракторами и украинской прошивкой.

  • 0

    Удалено

  • 0
    Synology не рассматривал? Если по архитектуре влезет — будет наилучшее решение.
    • 0
      Чтобы портировать Synology DSM — надо будет много мучиться с ядром и модулем SynoBios в частности (Это модуль ядра отвечает за связь с отдельным микроконтроллером на плате, который управляет питанием, вентиляторами, светодиодами и фиг знает чем ещё).
      В проекте XPenlogy патчат сами бинарники, лично я нашол реализацию «Заглушки» и дописал её функционал. Работает. (Портировал для WD MyCloud)
    • 0
      Работал с тем, что было на руках. Насколько я знаю, D-Link DNS-325 вообще популярная модель и мини статей по тюнингу уже много накопилось в сети, вот и решил показать что вообще можно сделать глобально.

      Был бы Synology, тюнили бы Synology :)
  • 0
    Интересно, что данный девайс (И некоторые другие серии Dlink nas) аппаратно похожи на девайсы серии WD MyCloud. Причем на столько похожи, что даже в исходниках прошивки WD можно найти упоминания DNS327.
    Ну а в самой прошивки — ровно теже баги с незасыпанием девайса, глюками Twonky (DLNA) и обилие костылей, которые можно было сделать в разы проще (И «правильнее»).
    Интересно — это наследие некой SDK от Marvell (Производитель SoC) или просто обе компании заказали прошивки для своих девайсов одной фирме со стороны?
  • 0
    с DNS-323 можно такое же как в статье провернуть? или лучше сразу на свалку?
    • 0
      Можно, но во некоторых местах процедура будет отличаться. Например, поддержку другого чипа надо включить в ядре, вентилятор по другому настроить. В статье старался делать рассуждения и расписывать как правильно прийти к конкретным конфигам.

      Но тут я согласен, такие эксперементы лучше проводить с настроением «или на свалку», ибо если это рабочий инструмент, убить его ненароком труда не составит :)
    • 0
      Посмотрите эту ссылку. Installing Debian On D-Link DNS-323
  • 0
    проделана работа грандиозная, но главное, вы нашли «правильный» проект, который смогли импортировать на железку, так что плюсую, а вот по поводу DLNA плагина — к сожалению и в этой версии наблюдаются сбои в индексировании контента… по умолчанию, стоит обновление базы каждый час, если не ошибаюсь, но уже дважды за месяц приходилось вырубать и снова включать службу((( грешу на траблы с загрузкой процессора и пр. перепетии с локалкой, которые сам же и вызвал своими же экспериментами, но все же случаи когда загрузил фильм в папку, а телек его не видит — были… возможно стоит поставить по крону задачу на перезагрузку данного сервиса, например в глубокой ночи, но чессло пока не нашел, как правильно это сделать((( плюс наблюдаются траблы с miniDLNA, на телеках гнусмас и филипс, когда через N кол-во минут фильм вылетает((( тоже вариантов решений много данного трабла, но пока и в этом направлении ничего дельного не нашел((( все сугубо ИМХО
    • 0
      На то она и бета, буду отлавливать баги и связываться с разработчиками.
  • 0
    У меня NAS WD My Cloud, как штатно хранит систему на том же HDD, что и данные. Также существуют сборки OMV по тому же принципу.
    Много лет всё нормально работает, хотя девайс мне один раз меняли по гарантии. После неудачной штатной прошивки штатными же средствами было три варианта: разобрать и восстановить штатную прошивку, поставить OMV и поменять девайс целиком по гарантии (что я и сделал). Благо, там только WEB-морда накрылась, а доступ по SMB был. А сервисный центр был как раз по пути дом-работа.
    PS: правда там внутри штатно сразу debian, и он совершенно открытый.
  • 0
    Не очень вкурсе, потому хочу спросить. kwboot — фишка только для Marvell SoC? Есть в наличии NAS eTRAYz и вот хотелось бы с ним что-то подобное провернуть.
    • 0
      Нет, kwboot подходит для всего, где есть U-Boot.

      Кто-то уже пытался, кстати: http://orangepi.pp.ua/index.php?topic=565.0
      • 0
        Да собственно я и пытался) Но уже давно было. А тут увидел Вашу статью, и прям аж вдохновился и захотелось всё же закончить начатое.
  • 0
    Также включены обязательные параметры для поддержки systemd.
    systemd — в нём была необходимость? Можно обойтись без него? (как на обычных архитектурах типа amd64)
  • 0
    А на EMC / iomega StorCenter ix2 (теперь Lenovo ix2-2) прокатит ли такая модификация прошивки?
    Вроде сходная платформа, но не нагуглил для неё прямого рецепта…
    root@ix2-2:/# cat /proc/cpu
    cpu/     cpuinfo
    root@ix2-2:/# cat /proc/cpuinfo
    Processor       : Feroceon 88FR131 rev 1 (v5l)
    BogoMIPS        : 1589.24
    Features        : swp half thumb fastmult edsp
    CPU implementer : 0x56
    CPU architecture: 5TE
    CPU variant     : 0x2
    CPU part        : 0x131
    CPU revision    : 1
    
    Hardware        : Feroceon-KW
    Revision        : 0000
    Serial          : 0000000000000000
    root@ix2-2:/# uname -a
    Linux ix2-2 2.6.31.8 Thu Feb 16 17:58:20 EST 2017 v0.0.9 Thu Feb 16 17:58:20 EST 2017 armv5tel GNU/Linux
    
    • 0

      В теории — да.


      Device Tree исходник — arm-soc/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts

  • 0
    вот бы так замутить на DNS-320 rev.A1 — ни в какую не хочет u-boot компилироваться с Джеймевского гита, а со статьи для 325-ого не подходит.
    • 0

      В чем проблема, на что ругается? Я привел универсальный способ, введите 320 вместо 325 и должно все сработать.

      • 0
        в git'е оригинального u-boot'a нет поддержки 320-ого. Она есть в джеймевском, но он не компилируется, валится куча ошибок. Пытался найденный в сети dns320_support поверх разных версий оригинального u-boot копировать — тоже ошибки при компиляции.
        В общем, сижу с оригинальным u-boot, прописал вместо флешки пути к ядру и рамдиску на винте, остальное все по статье сделал, все ок.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.