Przeniesienie overlay na dysk zewnętrzny
Ostatnia zmiana: 2019-07-06 10:25

Routery wyposażone są w niewielką ilość pamięci flash, zwykle 4 lub 8MB. Wystarcza to do większości zastosowań, jednakże możemy spotkać się z sytuacją kiedy potrzebujemy więcej miejsca na instalację pakietów czy przechowywanie danych. Jeżeli router ma zrobiony tzw. SDMOD lub ma złącze USB można pokusić się o rozszerzenie pamięci flash o pojemność zewnętrznego nośnika.
Można zastosować dysk USB, pendrive a nawet czytnik kart np. SD czy kartę z modemu USB (pod pewnymi warunkami). Extroot wymaga linuksowego systemu plików, więc w przypadku formatowania dane na nim mogą zostać utracone! Oczywiście potrzebna jest tylko jedna partycja, więc można z istniejącego dysku wyodrębnić niewielką przestrzeń na extroota przy pomocy narzędzi dostępnych na Windows czy Linuksa.

Teoria

Podział pamięci flash w routerze w dużym uproszczeniu wygląda następująco:
- bootloader
- system operacyjny routera
- obszar systemowy z danymi konfiguracyjnymi, ustawieniami oryginalnego systemu itp.

Sam obszar w którym oryginalnie instalowany jest system routera, zastępowany jest obrazem z OpenWrt (zwykle jest to wysoko skompresowany system plików squashfs - tylko do odczytu). Ponieważ firmware zwykle nie zajmuje całej pamięci flash, pozostała część jest przy pierwszym uruchomieniu routera formatowana przez OpenWrt systemem plików jffs i montowana w katalogu /overlay. Następnie wykorzystując jeszcze jeden system plików o nazwie mini_fo (w Backfire) lub overlayfs (wydanie Attitude Adjustment i późniejsze), część z jffs jest "nakładana" (overlay) na squashfs, dzięki czemu użytkownik widzi oba jako jeden i ma wrażenie zapisywalnego systemu plików. A tak naprawdę wszystkie zmiany są zapisywane w przestrzeni jffs, bo squashfs jest tylko do odczytu.
Nic nie stoi na przeszkodzie, aby obszar z jffs zastąpić zewnętrznym nośnikiem - kartą SD czy pendrive. W ten sposób powstaje wspomniany extroot.

Cały poradnik zakłada że extroot będzie wykonywany na pierwszej partycji nośnika (która przedstawia się zwykle jako sda1). Jeżeli używamy innych nośników, innych partycji itd to należy odpowiednio dostosować przedstawione poniżej polecenia.

LEDE, OpenWrt 18.06 i późniejsze wydania

Podobnie jak dla wydania BB i CC możliwe jest wykonanie extroota z wykorzystaniem systemu plików ext4. Jednakże wydanie LEDE i późniejsze wspierają także inny system plików - f2fs który jest dedykowany do nośników z pamięciami NAND (karty SD, nośniki USB czy dyski SSD), jest mniejszy niż ext4 i tym samym umożliwia bezproblemowe zmieszczenie obsługi tego systemu plików wraz z odpowiednimi narzędziami w 4MB pamięci flash.

Formatowanie dysku systemem f2fs



    # opkg update
    # opkg install mkf2fs # jeżeli nie ma go jeszcze w obrazie
    # mkfs.f2fs /dev/sda1

F2FS-tools: mkfs.f2fs Ver: 1.7.0 (2016-07-28)

    Info: Debug level = 0
    Info: Label =
    Info: Trim is enabled
    Info: Segments per section = 1
    Info: Sections per zone = 1
    Info: sector size = 512
    Info: total sectors = 8025745 (3918 MB)
    Info: zone aligned segment0 blkaddr: 256
    Info: format version with
        "Linux version 4.4.50 (cezary@eko.one.pl) (gcc version 5.4.0 (LEDE GCC 5.4.0 r3103-1b51a49) ) #0 Thu Feb 23 16:34:14 2017"
    Info: Discarding device
    Info: This device doesn't support BLKSECDISCARD
    Info: This device doesn't support BLKDISCARD
    Info: Overprovision ratio = 3.220%
    Info: Overprovision segments = 130 (GC reserved = 70)
    Info: format successful

Szybka instalacja



    # opkg update
    # opkg install block-mount kmod-fs-f2fs f2fsck # jeżeli nie ma ich jeszcze w obrazie
    # block detect > /etc/config/fstab
    # uci set fstab.@mount[0].target='/overlay'
    # uci set fstab.@mount[0].enabled='1'
    # uci set fstab.@global[0].check_fs='1'
    # uci commit fstab

W tym przykładzie zrobi to extroota na pierwszej partycji zdefiniowanej w konfigu. Jeżeli extroot ma być na innej - trzeba dostosować polecenia.

Skopiowanie bieżącej konfiguracji

Opcjonalnie - przed wykonaniem reboot i aktywacją extroota można przenieść bieżącą konfigurację systemu wraz z zainstalowanymi programami czy wykonanymi modyfikacjami na nośnik który będzie extrootem, dzięki czemu nie będzie potrzeby ponownej konfiguracji systemu


    # mkdir -p /tmp/dysk
    # mount /dev/sda1 /tmp/dysk
    # tar -C /overlay -cvf - . | tar -C /tmp/dysk -xf -
    # umount /tmp/dysk

Wymagany jest restart systemu


    # reboot

Dostęp do starej zawartości flash

Dotyczy tylko systemów typu squashfs


    # uci add fstab mount
    # uci set fstab.@mount[-1].target='/tmp/flash'
    # uci set fstab.@mount[-1].device='/dev/mtdblock3'
    # uci set fstab.@mount[-1].fstype='jffs2'
    # uci set fstab.@mount[-1].options='rw,sync'
    # uci set fstab.@mount[-1].enabled='1'
    # uci set fstab.@mount[-1].enabled_fsck='0'
    # uci commit

Gdzie /dev/mtdblock3 to numer partycji we flash o nazwie rootfs_data. Można ją znaleźć poleceniem:


    # grep rootfs_data /proc/mtd | sed 's/mtd\(.*\):.*/\1/g'

Po restarcie w katalogu /tmp/flash będzie oryginalna zawartość katalogu /overlay z pamięci flash.

Barrier Breaker, Chaos Calmer

Należy podłączyć nośnik i wygenerować konfigurację. Utworzenie extroota sprowadza się tylko do zmiany opcji target na /overlay. Poniżej przedstawiono to w skrócie.

Formatowanie dysku systemem ext4

Jeżeli nie ma na nośniku jeszcze systemu plików ext4 to należy go zrobić (UWAGA: usunie to wszystkie dane z dysku). Dysk oczywiście musi być odmontowany (można to sprawdzić poleceniem mount | grep "dev/sd").


    # opkg update
    # opkg install e2fsprogs # jeżeli nie ma go jeszcze w obrazie
    # mkfs.ext4 -m 0 /dev/sda1
    mke2fs 1.42.4 (12-June-2012)
    Filesystem label=
    OS type: Linux
    Block size=1024 (log=0)
    Fragment size=1024 (log=0)
    Stride=0 blocks, Stripe width=0 blocks
    30600 inodes, 122112 blocks
    0 blocks (0.00%) reserved for the super user
    First data block=1
    Maximum filesystem blocks=67371008
    15 block groups
    8192 blocks per group, 8192 fragments per group
    2040 inodes per group
    Superblock backups stored on blocks:
        8193, 24577, 40961, 57345, 73729

    Allocating group tables: done
    Writing inode tables: done
    Creating journal (4096 blocks): done
    Writing superblocks and filesystem accounting information: done

Szybka instalacja



    # opkg update
    # opkg install block-mount kmod-fs-ext4 # jeżeli nie ma ich jeszcze w obrazie
    # block detect > /etc/config/fstab
    # uci set fstab.@mount[0].target='/overlay'
    # uci set fstab.@mount[0].enabled='1'
    # uci set fstab.@global[0].check_fs='1'
    # uci commit fstab
    # reboot

W tym przykładzie zrobi to extroota na pierwszej partycji zdefiniowanej w konfigu. Jeżeli extroot ma być na innej - trzeba dostosować polecenia.
W przypadku potrzeby ponownej aktywacji istniejącego extroota należy usunąć plik /etc/.extroot-uuid (nie etc/extroot.md5sum jak to było dla wydania Attitude Adjustment)

Attitude Adjustment

Zakładam, że mamy nośnik z systemem plików ext4. Podłączamy go do usb jako jedyny (inne należy odłączyć). Włączenie extroota sprowadza się do wydania poleceń:


    # opkg update
    # opkg install block-mount kmod-fs-ext4 # jeżeli używamy systemu pliku ext4, ext3 lub ext2.
    # uci set fstab.@mount[0].target=/overlay
    # uci set fstab.@mount[0].device=/dev/sda1
    # uci set fstab.@mount[0].fstype=ext4
    # uci set fstab.@mount[0].options=rw,noatime
    # uci set fstab.@mount[0].enabled=1
    # uci commit fstab
    # /etc/init.d/fstab enable
    # reboot

(sda1 to pierwsza partycja tego dysku). Aby przekonać się czy extroot działa, po restarcie należy wydać polecenie mount i odnaleźć linię podobną do tej:


    root@OpenWrt:/# mount
    ...
    /dev/sda1 on /overlay type ext4 (rw,noatime,errors=continue)

Uwagi

  • po włączeniu extroota system jest jak świeżo po flashowaniu: nie ma żadnej konfiguracji, nie ma ustawionego hasła, nie ma ustawionego wifi. Trzeba podłączyć się przez telnet i skonfigurować wszystko łączenie z instalacją pakietów. Lub skopiować z obszaru jffs pamięci routera.
  • trzeba podać dokładnie takie system plików jaki jest na nośniku. Jeżeli mamy tam ext2 to należy podać ext2, nie ext3 czy ext4.
  • zakładamy, że w systemie jest już zainstalowana obsługa magistrali usb, nośników usb-storage i odpowiedniego systemu plików (ext4 w przedstawionym przykładzie).

Firmware

Należy posłużyć się firmware (lub skompilować samodzielnie) który będzie zawierał następujące pakiety (mogą także zostać po prostu doinstalowane):
- obsługę usb-storage, kart SD/SDHC lub dysków IDE/SATA
- obsługę systemu plików - ext2, ext3 lub ext4. Systemu plików FAT czy NTFS nie nadaje się do tego celu!
- pakiet block-mount
oraz opcjonalnie
- e2fsprogs
- fdisk

Taki firmware należy zainstalować normalnie na routerze wykorzystując jedną z dostępnych metod.

Przygotowanie dysku

Dysk powinien być sformatowany systemem plików ext2, ext3 lub ext4. Jeżeli na routerze zainstalowane są pakiety e2fsprogs oraz fdisk (nie muszą być wkompilowane na stałe, można doinstalować), proces tworzenia partycji można wykonać właśnie z poziomu routera. Jeżeli dysk już ma taki system plików, poniższe czynności można pominąć.

Tworzenie partycji

Generalnie - dysk zapewne już ma jakąś partycję, więc nie ma zbytnio potrzeby ich robić ponownie. Nie ma także potrzeby zmieniać specjalnie typu partycji z Windows na Linux. Jeżeli jednak ktoś koniecznie chce to uczynić - informacje zawarte są poniżej.
Podłączamy dysk pod USB. Jeżeli został on zamontowany, należy go odmontować (po wykonaniu polecenia mount nie powinno być tam żadnych wpisów związanych z tym dyskiem). Zakładając że został on wykryty jako /dev/sda (można się o tym przekonać wydając polecenie logread i szukając odpowiedniego wpisu dotyczącego dysku), należy uruchomić program fdisk. W tym przykładzie usuwane były wszystkie partycje i zakładana jedna na całym dysku. Pogrubioną czcionką zaznaczono dane prowadzane przez użytkownika.


root@OpenWrt:# fdisk /dev/sda

The number of cylinders for this disk is set to 7301.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
            (e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): d
Selected partition 1

Command (m for help): n
Command action
            e extended
            p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-7301, default 1): <enter>
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-7301, default 7301): <enter>
Using default value 7301

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 83
Changed system type of partition 1 to 83 (Linux)

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
root@OpenWrt:#

Została usunięta stara partycja, a następnie założona jedna podstawowa, od pierwszego do ostatniego cylindra (cały obszar dysku) typu Linux.

Formatowanie dysku

Należy teraz utworzyć system plików na dysku. W tym przykładzie był to ext4. Do formatowania niezbędne jest zainstalowanie pakietu e2fsprogs.
Uwagi:

  • formatuje się partycję (/dev/sda1), nie dysk (/dev/sda)!
  • tworzenie systemu plików wymaga sporo pamięci ram. Routery z 32MB pamięci nie są w stanie sformatować dysku o pojemności 1TB. Należy wcześniej utworzyć i aktywować swap, podzielić dysk na mniejsze partycje lub sformatować go na normalnym komputerze.
  • nie należy tego robić na komputerze z Ubuntu. O ile operacja się uda, o tyle jest później problem z dnsami na tak zrobionym extroocie.


root@OpenWrt:# mkfs.ext4 -m 0 /dev/sda1
mke2fs 1.40.11 (17-June-2008)
Warning: 256-byte inodes not usable on older systems
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
3670016 inodes, 14661312 blocks
733065 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=0
448 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
                                32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
                                4096000, 7962624, 11239424

Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 20 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.

Konfiguracja routera

Mając tak przygotowany dysk zostaje jeszcze tylko wskazać routerowi że ma go wykorzystać. Robi się to odpowiednio konfigurując plik /etc/fstab. Dysk można wskazać na trzy sposoby:
- przez UUID (unikalny identyfikator dysku, do odczytania programem blkid). Metoda konieczna jak mamy kilka dysków!
- przez etykietę (LABEL - którą można nadać uruchamiając program tune2fs z przełącznikiem -L)
- przez urządzenie (czyli /dev/sdaX wskazywany przez system)
W tym przykładzie wykorzystano nazwę urządzenia.


    # uci set fstab.@mount[0].target=/overlay
    # uci set fstab.@mount[0].device=/dev/sda1
    # uci set fstab.@mount[0].enabled=1
    # uci set fstab.@mount[0].fstype=ext4
    # uci commit fstab

(jeżeli po pierwszym poleceniu pojawi się błąd uci, należy zrobić nową sekcję: uci add fstab mount)
Jeżeli chcemy wykorzystać UUID należy najpierw odczytać identyfikator partycji


    # blkid /dev/sda1
    /dev/sda1: UUID="f11dbc98-b4f9-4ac9-9908-03d53a8d979f"

a następnie ustawić opcję uuid w konfiguracji


    # uci set fstab.@mount[0].uuid=f11dbc98-b4f9-4ac9-9908-03d53a8d979f
    # uci commit fstab

Cały plik /etc/config/fstab może więc wyglądać następująco:


    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' '/overlay'
        option 'fstype' 'ext4'
        option 'options' 'rw,noatime'
        option 'enabled_fsck' '0'
        option 'device' '/dev/sda1'
        option 'enabled' '1'

Jeżeli zostanie ustawiona opcja enabled_fsck i został wkompilowany lub zainstalowany pakiet e2fsprogs to przy starcie routera zostanie wykonane także sprawdzenie systemu plików.

Dysk można więc podłączyć identyfikując go na trzy sposoby:
- przez UUID (option uuid): unikalny identyfikator, więc tylko ten dysk i ta partycja będzie wykorzystana do tego celu
- przez etykietę (option label): można posiadać wiele nośników z różnymi konfiguracjami, jeżeli tylko będzie miał odpowiednią etykietę to będzie wykorzystany
- przez nazwę urządzenia (option device): każdy podłączony nośnik, o ile oczywiście ma odpowiedni system plików, będzie wykorzystany

Testowanie

Wystarczy teraz wykonać restart routera z podłączonym dyskiem. Czas inicjacji i wykrycia dysku jest ustawiony domyślnie na 20s. Dysk powinien się zamontować i być widoczny w systemie. Oto wynik po zastosowaniu w/w przepisu:


root@OpenWrt:/# mount
rootfs on / type rootfs (rw)
/dev/root on /rom type squashfs (ro,relatime)
proc on /proc type proc (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,relatime,size=31040k)
tmpfs on /dev type tmpfs (rw,relatime,size=512k)
devpts on /dev/pts type devpts (rw,relatime,mode=600)
/dev/sda1 on /overlay type ext4 (rw,sync,relatime,errors=continue,data=writeback)
overlayfs:/overlay on / type mini_fo (rw,relatime)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
none on /proc/bus/usb type usbfs (rw,relatime)

root@OpenWrt:/# df -h
Filesystem Size Used Available Use% Mounted on
/dev/root 1.9M 1.9M 0 100% /rom
tmpfs 30.3M 44.0K 30.3M 0% /tmp
tmpfs 512.0K 0 512.0K 0% /dev
/dev/sda1 55.0G 180.0M 52.1G 0% /overlay
overlayfs:/overlay 1.9M 1.9M 0 100% /

Swap

Często ilość pamięci ram jest niewystarczająca i można się poratować tworzą tzw. swap. Jeżeli dzielimy dysk na partycje należy wydzielić mały obszar (np. 64MB) i utworzyć partycję typu Linux-swap:


root@OpenWrt:# fdisk /dev/sda

The number of cylinders for this disk is set to 7301.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
            (e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): d
Selected partition 1

Command (m for help): n
Command action
            e extended
            p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-7301, default 1): <enter>
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-7301, default 7301): +64M

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 82
Changed system type of partition 1 to 82 (Linux swap / Solaris)

Command (m for help): n
Command action
            e extended
            p primary partition (1-4)
p
Partition number (1-4): 2
First cylinder (132-7301, default 132): <enter>
Using default value 132
Last cylinder or +size or +sizeM or +sizeK (1-7301, default 7301): <enter>
Using default value 7301


Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
root@OpenWrt:#

W tym przykładzie została utworzona pierwsza partycja typu Linux-swap o wielkości 64MB oraz następna typu Linux na pozostałej przestrzeni. Należy teraz ten swap utworzyć poleceniem:


    # mkswap /dev/sda1

Na drugiej partycji moża utworzyć system plików:


    # mkfs.ext4 -m 0 /dev/sda2

Plik konfiguracyjny dla tego przypadku wygląda następująco:


    config 'global' 'automount'
        option 'from_fstab' '1'
        option 'anon_mount' '1'

    config 'global' 'autoswap'
        option 'from_fstab' '1'
        option 'anon_swap' '0'

...

    config 'swap'
        option 'device' '/dev/sda1'
        option 'enabled' '1'

Aktualizacja

Ostatnie wersje OpenWrt wprowadzają jeszcze jeden element do całości - sumę kontrolną. Jeżeli pierwszy raz robimy extroota, system na nośniku umieszcza plik extroot.md5sum który jest sumą kontrolną systemu. Podczas uruchamiania extroota jest ona porównywana - jeżeli się zgadza, system kontynuuje działanie uruchamiając extroota. Jeżeli nie - np. z powodu upgrade systemu - system odmawia aktywacji, bo może to oznaczać że na nośniku mogą być pliki z poprzedniej wersji systemu, niekompatybilne z bieżącą. Więc po upgrade systemu, jeżeli mamy pewność że wszystko się zgadza należy po prostu usunąć z nośnika plik kontrolny o wspomnianej nazwie i system normalnie wystartuje z nim.

Po aktualizacji systemu (mtd/sysupgrade itd) dane na nośniku zostają takie jak były - aktualizacja ani nie usunie danych z nośnika ani nie zaktualizuje pakietów które są tam zainstalowane. Co więcej - extroot zostanie zdeaktywowany! Więc po upgrade systemu należy ręcznie aktualizować pakiety i pliki konfiguracyjne na nośniku, potem zostaje tylko zmiana w fstab i usunąć z nośnika plik etc/extroot.md5sum, lub wydać polecenia


    # /etc/init.d/fstab overlay_enable
    # reboot

Zakończenie

Po uruchomieniu extroot'a znika cała pierwotna konfiguracja - więc o ile router był już wcześniej skonfigurowany (np. ustawione wifi czy zainstalowane pakiety) - po tej operacji należy jeszcze raz to zrobić. Stara konfiguracja jest "przykrywana" przez extroot, więc albo trzeba jeszcze raz wszystko skonfigurować albo przenieść pliki z pamięci flash na dysk.

Mała sztuczka (http://eko.one.pl/forum/viewtopic.php?id=1062): aby wiadomo było jak system startuje należy PRZED zrobieniem extroota zrobić:

 
    # echo "Booted from internal flash" >> /etc/banner

A po zrobieniu:


    # echo "Booted from EXTERNAL ROOT" >> /etc/banner

Po zalogowaniu przez telnet/ssh wyświetli się informacja jak został uruchomiony router.

Backfire

Wersja z Backfire wymagała innej konfiguracji:
- należało zainstalować kmod-fs-ext2, kmod-fs-ext3 lub kmod-fs-ext4 w zależności od używanego systemu plików
- block-extroot, który był oddzielnym pakietem
- w konfiguracji fstab w sekcji mount dodatkowo podać opcję option is_rootfs 1
Czyli:


    # opkg update
    # opkg install block-mount block-extroot kmod-fs-ext4 #jeżeli używamy systemu pliku ext4, ext3 lub ext2.
    # uci set fstab.@mount[0].target=''
    # uci set fstab.@mount[0].device=/dev/sda1
    # uci set fstab.@mount[0].fstype=ext4
    # uci set fstab.@mount[0].options=rw,noatime
    # uci set fstab.@mount[0].enabled=1
    # uci set fstab.@mount[0].is_rootfs=1
    # uci commit fstab
    # /etc/init.d/fstab enable
    # reboot