OpenWrt & /jffs na zewnętrznym nośniku... czyli z cyklu: "potrzebuję więcej miejsca".
|
kabal |
Dodano 08-01-2010 17:23
|
User
Posty: 54
Dołączył: 21/02/2008 14:48
|
Przedmowa
Celem niniejszego artykułu będzie wprowadzenie użytkownika w temat przeniesienia systemu plików z partycji /jffs na zewnętrzny nośnik. Możliwość taką oferują nam urządzenia z SD-modem (np. Linksys WRT54GL) oraz wyposażone w port USB. Sprzęt jaki został użyty podczas pisania tego artykułu to ASUS WL-500gP v1.
Przy okazji artykuł ten wprowadzi mniej zaawansowanego użytkownika w etap budowania (krok po kroku) własnego obrazu OpenWrt.
Wstęp
Wielu z nas (w swoich domowych sieciach) korzysta z routerów które posiadają możliwość wgrania alternatywnego firmware'u OpenWrt. Flash w naszych urządzeniach to przeważnie 8MB. Niejednemu z nas ta ilość okazała sie niewystarczająca do zainstalowania wszystkiego co akurat jest nam potrzebne. Wtedy nachodzi myśl.. co zrobić żeby było więcej "placu". Istnieją oczywiście rozwiązania jak np. instalowanie programów na podłączonych do routera dyskach czy pendrive'ach. Niestety często zdarza się sytuacja gdzie program wymaga do działania określonych bibliotek. Wtedy musimy kombinować z ustawieniami zmiennych środowiskowych czy wykonywaniem dowiązań symbolicznych co nie zawsze daje pozytywny efekt. Przeniesienie /jffs na zewnętrzny nośnik załatwia wszystkie problemy z tym związane. Instalujesz programy bez żadnego kombinowania ze zmiennymi czy dowiązaniami. Zainteresowany jak przenieść /jffs? Zapraszam dalej :)
Plik mount_root
Cała "tajemnica" montowania systemu plików znajduje się w pliku mount_root. Przechowywany jest on w katalogu: /sbin. Oryginalnie podczas uruchamiania, OpenWrt całą zawartość katalogu /jffs montuje w pamięci flash. Oto jak wygląda oryginalny plik mount_root dla wersji 2.4:
Cytat #!/bin/sh
# Copyright (C) 2006 OpenWrt.org
. /etc/functions.sh
jffs2_ready () {
mtdpart="$(find_mtd_part rootfs_data)"
magic=$(hexdump $mtdpart -n 4 -e '4/1 "%02x"')
[ "$magic" != "deadc0de" ]
}
grep rootfs_data /proc/mtd >/dev/null 2>/dev/null && {
. /bin/firstboot
mtd unlock rootfs_data
jffs2_ready && {
echo "switching to jffs2"
mount "$(find_mtd_part rootfs_data)" /jffs -t jffs2 && \
fopivot /jffs /rom
} || {
echo "jffs2 not ready yet; using ramdisk"
ramoverlay
}
} || {
mtd unlock rootfs
mount -o remount,rw /dev/root /
}
Aby nasz /jffs został przeniesiony na zew nośnik USB, będziemy musieli zmodyfikować ten plik oraz skompilować obraz OpenWrt.
Istnieje kilka sposobów aby /jffs został przeniesiony na nośnik USB. Oto niektóre z nich:
- montowanie pierwszej partycji na pierwszym urządzeniu (dla 2.4: /dev/scsi/host0/bus0/target0/lun0/part1) w określonym systemie plików np. EXT2 i przeniesienie /jffs na tą partycje,
- sprawdzanie czy na partycjach istnieje plik np: ".mount_jffs", zamontowanie i przeniesienie /jffs na tą partycje,
- wyszukanie partycji z określoną etykietą (LABEL) np: "jffs", zamontowanie i przeniesienie /jffs na tą partycje.
W tym artykule zająłem się opisaniem sposobu trzeciego.
Zdarza się sytuacja gdy do naszego routera podłączonych jest więcej niż jedno urządzenie (używamy np. Hub'a USB). Załóżmy że nasz dysk który miał być wykryty w "/dev/scsi/host0/" zostaje wykryty w "/dev/scsi/host1/".. partycja nie zostaje odnaleziona a wraz z nim /jffs. Wtedy system uruchamia się z ramdysku. Z kolei wyszukiwanie na partycjach pliku ".mount_jffs" na pewno wydłuży czas uruchamiania routera, gdyż wszystkie partycje musiałyby być najpierw zamontowane, a dopiero później nastąpiło bu wyszukiwanie pliku. Zatem najszybszą opcją dla routera będzie montowanie partycji po etykiecie.
Skrypt w pliku mount_root najlepiej utworzyć z wyjściem awaryjnym..czyli mam tu na myśli sytuację kiedy nie ma partycji z etykietą "jffs". Wtedy najlepiej aby router wystartował i przeniósł /jffs na pamięć flash (jak w oryginalnym OpenWrt). Można to traktować jako alternatywę z dwoma konfiguracjami.
Zmodyfikowany plik mount_root dla wersji OpenWrt 2.4:
Cytat #!/bin/sh
# Copyright (C) 2006 OpenWrt.org
. /etc/functions.sh
jffs2_ready () {
mtdpart="$(find_mtd_part rootfs_data)"
magic=$(hexdump $mtdpart -n 4 -e '4/1 "%02x"')
[ "$magic" != "deadc0de" ]
}
grep rootfs_data /proc/mtd >/dev/null 2>/dev/null && {
. /bin/firstboot
mtd unlock rootfs_data
jffs2_ready && {
echo "Loading USB and ext2 modules" >> /tmp/x.txt
insmod usbcore
insmod ext2
insmod ehci-hcd
insmod scsi_mod
insmod sd_mod
insmod usb-storage
lsmod > /tmp/x.txt
sleep 9
find /dev/scsi/ -type b >> /tmp/x.txt 2>&1
echo "Switching to external device if exist 'jffs' label" >> /tmp/x.txt
mount LABEL=jffs /jffs -t ext2 >> /tmp/x.txt 2>&1
if [ $? -eq 0 ]
then
fopivot /jffs /rom
echo "Switching to external device completed successful"
else
echo "No 'jffs' label on external device or file system failed; switching to jffs2" >> /tmp/x.txt
mount "$(find_mtd_part rootfs_data)" /jffs -t jffs2 && \
fopivot /jffs /rom
fi
} || {
echo "jffs2 not ready yet; using ramdisk" >> /tmp/x.txt
ramoverlay
}
} || {
mtd unlock rootfs
mount -o remount,rw /dev/root /
}
Zmodyfikowany plik mount_root dla wersji OpenWrt 2.6:
Cytat #!/bin/sh
# Copyright (C) 2006 OpenWrt.org
. /etc/functions.sh
jffs2_ready () {
mtdpart="$(find_mtd_part rootfs_data)"
magic=$(hexdump $mtdpart -n 4 -e '4/1 "%02x"')
[ "$magic" != "deadc0de" ]
}
grep rootfs_data /proc/mtd >/dev/null 2>/dev/null && {
. /sbin/firstboot
mtd unlock rootfs_data
jffs2_ready && {
echo "Loading USB and ext2 modules" >> /tmp/x.txt
insmod usbcore
insmod ext2
insmod ehci-hcd
insmod scsi_mod
insmod sd_mod
insmod usb-storage
lsmod > /tmp/x.txt
sleep 9
find /dev/sd* -type b >> /tmp/x.txt 2>&1
echo "Switching to external device if exist 'jffs' label" >> /tmp/x.txt
mount LABEL=jffs /jffs -t ext2 >> /tmp/x.txt 2>&1
if [ $? -eq 0 ]
then
fopivot /jffs /rom
echo "Switching to external device completed successful"
else
echo "No 'jffs' label on external device or file system failed; switching to jffs2" >> /tmp/x.txt
mount "$(find_mtd_part rootfs_data)" /jffs -t jffs2 && \
fopivot /jffs /rom
fi
} || {
echo "jffs2 not ready yet; using ramdisk" >> /tmp/x.txt
ramoverlay
}
} || {
mtd unlock rootfs
mount -o remount,rw /dev/root /
}
Oba skrypty podczas startu wysyłają komunikaty do pliku /tmp/x.txt (>> /tmp/x.txt). Dzięki temu mamy możliwość podpatrzenia czy wszystko wykonało sie poprawnie. Oto przykładowy wynik z pliku x.txt:
Utworzenie partycji "jffs" i kompilacja obrazu OpenWrt
Zacznijmy od przygotowania pendrive'a/dysku. W tym celu w OpenWrt możemy skorzystać np. z narzędzia cfdisk:
Cytat cfdisk /dev/scsi/host0/bus0/target0/lun0/disc
i w kreatorze cfdisk tworzymy partycje (nie musi być oznaczona jako bootowalna). Po zakończeniu formatujemy partycję w EXT2:
Cytat mkfs.ext2 /dev/scsi/host0/bus0/target0/lun0/part1
Następnie opatrujemy ją etykietą "jffs". W OpenWrt zmiany etykiety można dokonać za pomocą tune2fs:
Cytat tune2fs -L jffs /dev/scsi/host0/bus0/target0/lun0/part1
Przechodzimy teraz do kompilacji OpenWrt. Do tego celu musimy mieć zainstalowanego Linuxa (np. Ubuntu) na swoim PC lub Notebooku lub skorzystać z maszyny wirtualnej. Zaznaczę że powinniśmy przeznaczyć na tą operacje ok 10GB wolnej przestrzeni dyskowej.
Uwaga:
Przed kompilacją nowego obrazu OpenWrt będziemy musieli dołożyć kilka niezbędnych pakietów które zostaną wykorzystane podczas uruchamiania systemu. Będą to miedzy innymi pakiety potrzebne do wykrycia urządzeń USB oraz zamontowania partycji po etykiecie. A więc do dzieła.
Uruchamiamy konsole/terminal.
Dla wersji stabilnej wykonujemy kolejno:
- tworzymy sobie na wybranym dysku/partycji katalog "8.09":
- pobieramy stabilną wersje OpenWrt 8.09:
Cytat svn co svn://svn.openwrt.org/openwrt/branches/8.09/
- przechodzimy do utworzonego katalogu 8.09:
Dla wersji trunk wykonujemy kolejno:
- tworzymy sobie na wybranym dysku/partycji katalog "trunk":
- pobieramy rozwojową wersję OpenWrt:
Cytat svn co svn://svn.openwrt.org/openwrt/trunk/
- przechodzimy do utworzonego katalogu trunk:
Reszta jest identyczna dla obu wersji. Wykonujemy kolejno:
Cytat ./scripts/feeds update -a
./scripts/feeds install -a
Po czym wykonujemy polecenie:
Otworzy nam się ekran kompilacji OpenWrt. Wybieramy teraz kolejno:
Target System - wybieramy platformę oraz wersję jądra dla którego tworzymy obraz
Target Profile - pozostawiamy domyślnie
Target Image - pozostawiamy domyślnie
Następnie dołożymy niezbędne pakiety (zaznaczamy (*) obok pakietu) które będą wykorzystywane podczas uruchomiania OpenWrt z zmodyfikowanym plikiem mount_root.
Pakiety niezbędne do poprawnego montowania urządzeń po etykiecie:
Przechodzimy do:
Base system > busybox > Configuration > Linux System Utilities
I zaznaczamy:
Routines for detecting label and uuid on common filesystems (w trunku nie występuje ta opcja)
Ext filesystem
fat filesystem
Support option -f
Support option -v
Support mount helpers
Support specifiying devices by label or UUID
Pakiety wymagane do obsługi systemu plików:
Przechodzimy do:
Kernel modules > Filesystems
I zaznaczamy:
kmod-fs-ext2
kmod-fs-ext3
kmod-fs-vfat
Pakiety wymagane do wykrywania urządzeń USB:
Przechodzimy do:
Kernel modules > USB Support
I zaznaczamy:
kmod-usb-core
kmod-usb-storage
kmod-usb-uhci-iv (dla jądra 2.6: kmod-usb-uhci)
kmod-usb2
Oraz dla wersji trunk 2.6 aby działało szyfrowanie WPA:
W zakładce:
Network
zaznaczamy:
wpa-supplicant
Resztę dokładamy wedle własnych upodobań.
Zamykamy konfigurator OpenWrt i zapisujemy. Nie zamykamy jeszcze konsoli.
Teraz pozostało nam tylko podmienić plik mount_root.
Podmiana pliku mount_root:
Na dysku gdzie jest pobrana wersja OpenWrt przechodzimy do folderu:
/nasze_wydanie/package/base-files/files/sbin/
gdzie znajduje się plik mount_root. Edytujemy go i wklejamy odpowiedni dla naszego wydania (2.4 lub 2.6) zmodyfikowany skrypt mount_root który został przedstawiony wyżej. Zapisujemy, zamykamy i możemy już zacząć kompilacje naszego obrazu.
Zaznaczę że w katalogu:
/nasze_wydanie/package/base-files/files/
możemy wyedytować np. nasze pliki konfiguracyjne "network" czy "wireless" (etc/config/) itp.
Teraz wracamy do konsoli i wykonujemy:
lub
Cytat make -jX (gdzie X to liczba rdzeni naszego procesora).
Po skompilowaniu nasz gotowy obraz znajduje się w katalogu:
/nasze_wydanie/bin/
Teraz wystarczy wgrać nasz nowo utworzony firmware do routera, wpiąć zew. urządzenie z etykietą "jffs" i możemy instalować wszystko na co brakowało nam wcześniej miejsca :)
Podsumowanie:
Przeniesienie /jffs na zewnętrzny nośnik w większości sytuacji usprawnia działanie i użytkowanie OpenWrt choć dla początkujących barierą (którą warto przeskoczyć:) ) może okazać się etap kompilacji obrazu. Nie zastanawiamy się co usunąć podczas instalacji nowego pakietu by nie brakło nam miejsca. Jednocześnie pozostawiamy sobie wyjście awaryjne.. czyli w przypadku braku zew nośnika z etykietą "jffs" sprzęt wystartuje nam z wew. flasha trzymając skonfigurowane wcześniej ustawienia.
Reasumując.. same zalety :)
Pozdrawiam
kabal
P.S. Dla leniwych - gotowe obrazy można znaleźć na moim FTP: ftp://jambi.mine.nu
P.S.2. Podziękowania za cenne rady/sugestie dla Jejka, Obsego oraz Andrzeja P.
Edytowany przez kabal dnia 22-01-2010 15:27
|
|
|
|
Tytan69 |
Dodano 16-02-2010 17:37
|
User
Posty: 191
Dołączył: 09/01/2010 00:48
|
Mam prośbę do fachowców od jffs.
Wiele osób używa pendriva lub SD jako dodatkową pamięć montując tradycyjnie jako przykładowy katalog /opt z systemem ext2 lub ext 3 itp.
Jest to proste jednak ciągle biję siez myślami ile wytryznma mi pendrive gdy zapisy mam co jedną minutę i to ciągle nadpisywanie tewgo samego pliku (w ramoie nie mogę go umieścić bo dane są jak baza).
Z tego wywodzu się chęć optymlanego wykorzystania pendriva przez użycie jff2. Wedug tego co czytam jffs2 oprócz kompresji danych dba o równomierne zużycie pamęci flash.
Poproszę o poradę jak załozyć jffs2 (openwrt) na pendrivie z przykładowym katalogiem montowania /opt w głownym systemie plików.
Jeśli mój pomysł nei ma sensu to może jakiś innny psosób aby pendriv równo był zużywane.
Edytowany przez Tytan69 dnia 16-02-2010 17:44
Openwrt na WRT160NL.
|
|
|
|
obsy |
Dodano 16-02-2010 18:04
|
VIP
Posty: 5775
Dołączył: 31/10/2006 20:06
|
Nie ma sensu . Nowoczesne pendrive same dbają o odpowiedni wear leveling.
Wystarczy że zrobisz ext2, zamontujesz z noatime, powinien pożyć trochę. Ew możesz faktycznie umieścić to w ramie i kopiować np co godzinę.
Edytowany przez obsy dnia 16-02-2010 19:19
|
|
|
|
kabal |
Dodano 16-02-2010 19:15
|
User
Posty: 54
Dołączył: 21/02/2008 14:48
|
Dokładnie tak jak Obsy pisze.
Ja używam już jakiś kawałek czasu starego Kingstona 1GB i nie mam żadnych problemów. Utworzone 3 partycje 1-/jffs (ext2), 2-64MB SWAP, 3-logi (ext2). Gdzie przy logach mam zapisy co chwile (logi www oraz systemu).
Natomiast o dziwo miałem problemy jak wcześniej używałem HDD.. Nie wiem jaki masz sprzęt ale u mnie w Asusie USB czasami jakoś "wariowało" mi na HDD. Miałem przypadki iż po nocy musiałem resetować router bo HDD zażądał więcej napięcia i się rozłączał (ale to zdarzyło mi się może z 2-3 razy).
Użyj pendriva i działaj
Edytowany przez kabal dnia 16-02-2010 19:19
|
|
|
|
Tytan69 |
Dodano 16-02-2010 19:46
|
User
Posty: 191
Dołączył: 09/01/2010 00:48
|
dzięki.
zajeżdżam wrt160nl i mam na tym kupę rzeczy.
Miedzy innymi serwerek www widoczny w internecie ze stacją pogody i obrazkami generowanymi w php i kamerkę
Ze dwa miesiące zajeżdżam pendriva Cruiser 8GB z ext3 a zapisy co minutę, odczyty częściej.
ta opcja noatimie przyda mi się. O zapisach cyklicznych z ramu na flash myślałem ale na razie za często robię restarty i bym tracił dane.
Openwrt na WRT160NL.
|
|
|
|
obsy |
Dodano 16-02-2010 19:52
|
VIP
Posty: 5775
Dołączył: 31/10/2006 20:06
|
ext3 wywal. Zniszczysz pendrive wlaśnie przez journaling.
|
|
|
|
Tytan69 |
Dodano 16-02-2010 20:09
|
User
Posty: 191
Dołączył: 09/01/2010 00:48
|
kurde masz rację. da się wyłączyć pewnie journaling bo zmieniać system teraz nie pora.
Openwrt na WRT160NL.
|
|
|
|
jejek |
Dodano 17-02-2010 13:17
|
User
Posty: 59
Dołączył: 25/01/2009 14:56
|
Ponieważ od jakiegoś czasu trunk zamiast /sbin/mount_root korzysta z katalogu /lib/preinit/ to żeby zaproponowane rozwiązanie działało w przyszłości, trzeba modyfikację wykonać na jednym z plików z tego katalogu. Ja wybrałem 40_mount_jffs2, ale ładniej byłoby napisać własny plik.
Moja propozycja podmienia funkcję find_mount_jffs2 i opiera się na bezpośrednim przekazaniu nazwy urządzenia a nie etykietce:
find_mount_jffs2() {
local plik_logu="/tmp/mount_root.log"
echo "Historyjka o montowaniu /jffs na dysku USB" > $plik_logu
echo -e "\nModuły dziewiczo:" >> $plik_logu
lsmod >> $plik_logu
insmod usbcore
insmod ext2
insmod ehci-hcd
insmod scsi_mod
insmod sd_mod
insmod usb-storage
echo -e "\nModuły po insmodach:" >> $plik_logu
lsmod >> $plik_logu
sleep 9
echo -e "\nUrządzenia SCSI:" >> $plik_logu
ls -l /dev/scsi/host0/bus0/target0/lun0/ >> $plik_logu
mount /dev/scsi/host0/bus0/target0/lun0/part1 /jffs -t ext2 || mount "$(find_mtd_part rootfs_data)" /jffs -t jffs2
echo -e "Efekt\n" >> $plik_logu
df -h >> $plik_logu
}
Nie widzę łatwego sposobu napisania swojego skryptu. I tak trzeba by modyfikować skrypt wbudowany, żeby sprawdzał czy /jffs jest zamontowany.
Uwaga. Przy modyfikowaniu skryptu uważajcie na pliki typu kopia bezpieczeństwa. Taki zostawiony i ujęty w obrazie plik też się wykona.
P.S. 1 : Jest jakiś sposób zachowania wcięć w cytowanym tekście? Spodziewałbym się teo po tagu "code"
P.S. 2 : Może by wprowadzić śmiały zwyczaj komentowania w forum "Artykuły" samych artykułów? A problemy rozwiązywać osobnym tematem? Już z drugiego tematu się @#$%^, tzn. bałagan robi...
Z komsomolskim pozdrowieniem... |
|
|
|
Tytan69 |
Dodano 20-02-2010 22:59
|
User
Posty: 191
Dołączył: 09/01/2010 00:48
|
Cytat kabal napisał/a:
Dokładnie tak jak Obsy pisze.
Ja używam już jakiś kawałek czasu starego Kingstona 1GB i nie mam żadnych problemów. Utworzone 3 partycje 1-/jffs (ext2), 2-64MB SWAP, 3-logi (ext2). Gdzie przy logach mam zapisy co chwile (logi www oraz systemu).
Natomiast o dziwo miałem problemy jak wcześniej używałem HDD.. Nie wiem jaki masz sprzęt ale u mnie w Asusie USB czasami jakoś "wariowało" mi na HDD. Miałem przypadki iż po nocy musiałem resetować router bo HDD zażądał więcej napięcia i się rozłączał (ale to zdarzyło mi się może z 2-3 razy).
Użyj pendriva i działaj
Panowie chciałem coś na początek poprawić czyli dodać noatime.
Pojawia się problem podstawowy jak to wymusić.
Mam trzy partycje sda1, sda2, sda3.
sda2 to akurat swap. No ale problem jest taki że nei wiedzę configa gdzie mogę dopisać noatime bo w /ect/fstab jest tylko opis sda1 a w /etc/config/fstab jest sda1 i sda2. Nie widzę nigdzie wpisów dotyczących sda3 a tu właśnie mam robocze pliki.
Gdzie to noatime dopisać? W tym /etc/config/fstab sda1 ma target /home a faktycznie montowany jest do /mnt/sda1 czyli to nie jest używane.
Wyedytowałem ten /etc/config/fstab tak aby wskazywał prawidłowo na wszystkie trzy partycje (postawiłem też jedynki). Po restarcie wygląda wszytko prawidłowo - to znaczy nic się nie zepsuło bo montuje dyski.
Tylko czy robię to prawidłowo i czy to nie gryzie się z automontowaniem?
Edytowany przez Tytan69 dnia 20-02-2010 23:34
Openwrt na WRT160NL.
|
|
|
|
jejek |
Dodano 21-02-2010 02:49
|
User
Posty: 59
Dołączył: 25/01/2009 14:56
|
Gdybym był adminem to byś już bana na tydzień dostał, bo dokładnie o tobie traktuje PS2 mojego poprzedniego posta. Tylko, że Tobie trzeba to drukowanymi literami. Dlatego ćwiczenie umysłowe: co będzie czytał ktoś, kogo zainteresuje kompilowanie OpenWRT czy montowanie roota na zewnętrznym nośniku? To, że w styczniu 2010 miałeś problemy w temacie pierwszego, a w lutym - drugiego.
Wybacz, może jakiś nadwrażliwy jestem. Tyle w temacie.
Zdrówko! |
|
|
|
obsy |
Dodano 21-02-2010 07:15
|
VIP
Posty: 5775
Dołączył: 31/10/2006 20:06
|
@Tytan69: albo fstab albo hotplug. Nie mieszaj jednego z drugiim.
|
|
|