Seagate Dockstar jako router.

Jakiś czas temu było o HP T5520 jako routerze, który działał i byłem z niego zadowolony, ale trzeba poznawać nowe rzeczy (w tym przypadku: sprzęt na ARM). Poza tym, z T5520 można zrobić nieco więcej, niż tylko router (ma wyjście audio, w połączeniu z MPD będzie pewnie robił za odtwarzacz radiowy, shell i NAS w innej lokalizacji). Jasne, mogłem dołożyć do Dockstara kartę dźwiękową na USB, ale ciekawiło mnie też, czy modem USB (Sagem F@st 800) zadziała na ARM.

Wybór padł na Seagate Dockstar, bo był to tani sprzęt (wówczas ~100 zł, obecnie dwa razy drożej), o niezłych parametrach (128 MB RAM, procesor 1,2 GHz). Jako alternatywa dla T5520 w tym zastosowaniu – teoretycznie idealny. I – z racji architektury ARM – znacznie bardziej energooszczędny (maksymalnie poniżej 10W poboru prądu). Last but not least – Dockstar obsługuje niemodyfikowanego Debiana.

Od zakupu do uruchomienia minęło sporo czasu. O ile instalacja Debiana była bezproblemowa, o tyle działało to nieco losowo, więc dwa podejścia spędziłem na ustalaniu, co się sypie, że czasem wstaje z Debianem, a czasem z oryginalnym systemem. W końcu doszedłem, że winny był pendrive. Faktycznie, po wymianie na inny zaczęło działać stabilnie i można było się zająć przeniesieniem konfiguracji.

Przeniesienie było proste, podłączenie modemu i… zonk. Okazało się, że debianowe kernele nie są równe, konkretnie brakowało modułu br2684. Niby żaden problem przekompilować kernel, ale jeśli mam to robić na niedużym pendrive zamiast dysku, albo crosskompilując, to tak różowo nie jest. Ostatecznie zgłosiłem błąd dotyczący braku br2684, który szybko został poprawiony.

Niestety, poprawka wyszła dla kernela w wersji 3.0 z experimental. Jakoś nie ciągnęło mnie do wrzucania na produkcyjną (choć prywatną) maszynkę takiego wynalazku, tym bardziej, że nie sam kernel trzeba wymienić. A cokolwiek innego wiązało się z kompilacją… No dobrze, niech będzie. Skoro już kompilować, to jednak 2.6 ze Squeeze. I natywnie, na Dockstarze (jakoś się na tym pendrive zmieściło po rozpakowaniu).

Pobrane źródła, pobrane i nałożone patche, korekta pliku konfiguracyjnego, make-kpkg… I zonk z kryptycznym komunikatem (niestety nie zanotowałem). Okazuje się, że make-kpkg nie potrafi sam wykryć architektury, na której jest uruchamiany. Po podaniu –arch armel (dzięki przewodnikowi po crosskompilacji dla Dockstara) poszło dalej, choć niewiele. Tym razem winne lzma i cannot allocate memory (OSLT; mimo sporego swapa – IIRC 160 MB) i tyle. A przecież nie tak dawno kompilowałem kernele na maszynach z 64 MB RAM…

Na szczęście ww. przewodnik po crosskompilacji ładnie opisuje jak stworzyć środowisko i krok po kroku wyjaśnia, jak zrobić kernel. Stwierdziłem, że skoro akcja pewnie będzie się powtarzać, to warto mieć coś szybszego do kompilacji… Opis jest bdb, używanie środowiska do crosskompilacji proste. Wystarczyło poczekać parę h (tak, kernel debianowy to krowa z masą zbędnych opcji, ale stawiałem na kompatybilność i nie chciałem się bawić…) i kernel gotowy.

Kolejna ARMowa ciekawostka to instalacja. Zwykłe dpkg -i nie wystarcza. Jak widać w przewodniku po crosskompilacji kernela, trzeba jeszcze odczynić ręczną magię z uImage i uInitrd. Z pozytywów: wstało od kopa. Jest moduł, ale… nadal nie działa. Tym razem po podłączeniu modemu masa wpisów w stylu:

ATM dev 0: usbatm_submit_urb: urb 0xc6c50b40 submission failed (-28)!

Oczywiście modem się nie łączy… Googlanie po całości wpisu nie dało efektów, ale ostatecznie, szukając po fragmentach, trafiłem na ten błąd dla OpenWRT, który sugeruje wymuszenie bulk mode. Niby wolniejsze przy większych prędkościach, ale dla łącza 1 Mbps nie stanowi. Zresztą, innych pomysłów brak, zatem:

echo "options ueagle-atm altsetting=0,0,0,0" > /etc/modprobe.d/eagle-usb.conf

W końcu działa. Nawet się połączył. Małe dopieszczenie konfigów i w końcu maszynka przeniesiona. Generalnie z odkrytych wad Dockstara: nie ma RTC, więc po restarcie startuje bez aktualnej daty i godziny. Oczywiście instalacja ntp załatwia problem po nawiązaniu łączności z Internetem, ale przy ppp chwilę to trwa i przez tę chwilę wpisy w logach będą ze złą datą.

Inna uwaga odnośnie Debiana i ARM: nie jest to tak dopracowane jak architektury i386 i amd64. Generalnie działa, ale zamiast po prostu działa, trzeba bawić się w podawanie opcji (make-kpkg) lub nawet robienie części rzeczy ręcznie (initrd).

Parę przydatnych/użytych linków, niekoniecznie występujących w treści:

Wiki Debian on Dockstar

Zgłoszenie błędu z modemem USB dla OpenWRT

Komunikaty błędu na Dockstarze dotyczące Sagem F@st 800

Opis przygotowania środowiska do crosskompilacji i zrobienia nowszego kernela dla Dockstara

Póki co, trwa niezbyt obiecująco wyglądające (wygląda, że raz się wywalił z powodu loadu…) wygrzewanie sprzętu.

UPDATE: Jednak działa stabilnie od blisko dwóch tygodni. Prawdopodobna przyczyna ww. wywałki – błędy filesystemu (pewnie z czasu instalacji, kiedy nie był read only jeszcze). Po fsck, naprawieniu błędów i reboocie bez problemu.

UPDATE2: W jednym z kolejnych wpisów opisuję jak zrobić na Linuksie router Wi-Fi. Po dołożeniu karty Wi-Fi na USB Dockstar się nada.

Grub2, memmap i problemy z upgrade do Squeeze.

Ostatni upgrade systemu (z prywatnych, głównie desktopy) do Squeeze’ego zakończony. Zasadniczo bez zgrzytów, poza tym, że wyglądał trochę inaczej niż inne, a pakietów było mnóstwo. Naprawdę mnóstwo, apt-cacher wiele nie pomógł, choć inny desktop też z niego korzysta. KDE4 robi swoje, niestety. Łącze 1Mbps to przeżytek. No i jeszcze szopka z upgrade do grub2 była.

Desktop ma uszkodzony RAM, więc korzystam ze sposobu na uszkodzoną pamięć RAM, który opisywałem wcześniej. W grub miałem wpis:

/boot/vmlinuz-2.6.32.11 root=/dev/hda2 ro memmap=2M$311M

Przy dist-upgrade wszytko wykrył poprawnie, łącznie z dodatkowymi opcjami. Oczywiście skorzystałem z proponowanej opcji chainload (i całe szczęście…). Po reboocie wchodzę do grub2, tam wybieram nowy kernel (dystrybucyjny) i… reboot. Bez żadnego komunikatu. Niefajnie. Niestety to samo powtórzyło się przy wybraniu z grub2 kernela własnej roboty, którego używałem na Lenny.

Za to – ku mojemu zdziwieniu – ze starego gruba nowy kernel zadziałał. Co ciekawe, w przeciwieństwie do wersji z Lenny’ego, obsługiwał poprawnie wpis dla memmap – przy szybkim teście podlinkowanym wyżej nie było błędów.

Chwila zabawy i jasne było, że coś się skopało. Zamiast memmap=2M$311M było widoczne… memmap=2M11M. WTF? A po usunięciu opcji memmap wszystko ładowało się poprawnie (tyle, że korzystając ze skopanego obszaru RAM). Chwila googlania i wydało się, że do /etc/default/grub trafiła linia

GRUB_CMDLINE_LINUX="memmap=2M$311M"

która po przetworzeniu przez *sh będzie faktycznie wyglądała tak, jak wyglądała, bo $3 zostanie uznane za zmienną… Grub2 dodatkowo wymaga w swoim menu postaci memmap=2M\$311M czyli ostatecznie poprawna wersja w pliku /etc/default/grub to:

GRUB_CMDLINE_LINUX="memmap=2M\\\$311M"

Jutro zgłaszam buga.

Jak bezpiecznie korzystać z uszkodzonej pamięci RAM bez BadRAM.

BadRAM był fajny, ale jest nieutrzymywany. Ostatnią działająca u mnie wersja była do kernela 2.6.25.x, późniejsze, choć istniały (np. dla 2.6.29; dead link), to nie udało się ich – wbrew wcześniejszej radości – zmusić do poprawnego działania – nadal pojawiały się błędy np. na liczeniu sum kontrolnych.

Winny w tej maszynie jest ewidentnie RAM, co zostało już dawno stwierdzone, ale maszyna na tyle niekrytyczna, że inwestować się nie opłaca (poza tym, szkoda środowiska), a ze starszym (tj. 2.6.25.x) kernelem spokojnie i poprawnie działa. Poza tym, przecież to Linux, więc da się poprawić. I jaki uroczy temat do notek jest. 😉 Z okazji świątecznej wizyty w domu, postanowiłem jednak zerknąć, czy nie pojawiły się patche BadRAM do jakichś nowszych kerneli (serii 2.6.3x, znaczy).

Nie pojawiły się, ale zamiast tego, trafiłem na pierwszej stronie wyników na sposób radzenia sobie z uszkodzoną pamięcią pod Ubuntu, który w ogóle z BadRAM nie korzysta. Chwilę później trafiłem na ten wpis (dead link). Okazuje się, że za pomocą parametrów, które można przekazać kernelowi, w szczególności mem=XX oraz memmap=X$YY, można wyłączyć obszary pamięci z użytkowania, co przekłada się w praktyce, na możliwość bezpiecznego korzystania z uszkodzonej i dotychczas powodującej błędy pamięci. Więcej o parametrach w kernelowym Documentation/kernel-parameters.txt, ale na potrzeby tego zagadnienia wystarczą te dwa.

Pierwszy parametr (mem=) ogranicza wykorzystaną pamięć. Jeśli uszkodzenie jest w okolicy 312 MB (memtest+ prawdę powie), to mem=310M co prawda obniży dostępną pamięć do 310 MB, za to system będzie działał bez problemów. Tyle tylko, że stracimy 200 MB pamięci. Trochę sporo, zwłaszcza, jeśli całość do dyspozycji to tylko 512 MB.

Drugi (memmap=) jest ciekawszy, bo rezerwuje X pamięci od adresu YY. Przykładowo memmap=10M$305M oznaczy pamięć od  305 MB do 315 MB jako wykorzystaną. Czyli stracimy raptem 10 MB, a zyskamy niezawodny system. Tyle teorii. W praktyce na dystrybucyjnym 2.6.26 z Lenny’ego, mem=300M działało poprawnie (najprościej sprawdzić przez free -m), natomiast memmap=10M$305M był radośnie olewany – nadal pokazywało dostępną całą pamięć.

Przyczyny tego stanu rzeczy nie udało mi się ustalić (podejrzewam limit 4GB zamiast 1GB, błąd w kernelu lub korzystanie z initrd – jeśli ktoś zna odpowiedź, to proszę o info), natomiast skompilowanie własnego 2.6.32.2 na podstawie konfiga od 2.6.25.x (z którego spatchowanego BadRAM korzystałem do tej pory) rozwiązało problem – memmap=2M$311M, czyli wyłączenie tylko 2 MB spowodowało, że system działa poprawnie.

Ponieważ najłatwiej zaobserwować błędy było dotychczas na sumach kontrolnych, to testowanie wykonałem prostym skryptem (brzydki bash napędzany perlem – pewnie dałoby się prosto przespisać na gołego basha, ale kto tam ma czas…; skrypt na końcu wpisu). Stosunkowo duży plik (większy, niż dostępna pamięć RAM, mój tworzony przez dd if=/dev/urandom of=random.dat bs=1MB count=1024), z losową zawartością (tworzony raz, bo czasochłonne), liczenie sum kontrolnych. Jeśli błąd pojawi się w buforze dyskowym, to przy braku wielkiego pecha suma kontrolna będzie się różnić przed i po skopiowaniu. Zapuszczone w pętli, z logowaniem do pliku – nawet przy uszkodzonej pamięci nie wystarczy 1 przebieg – błąd nie pojawia się za każdym razem. Natomiast choćby jeden błąd oznacza, że coś jest nie tak jak być powinno.

Podstawą jest jednak free -m. Jeśli on nie widzi mniej pamięci, to można nie zaczynać nawet ze skryptem.

Jeśli po dłuższym teście brak błędów (pojedynczy błąd oznacza, że nie jest dobrze), to wystarczy dopisać linię do konfigu gruba, by przy każdej aktualizacji kernela dodawał do parametrów określony argument:

#kopt=root=/dev/hda2 ro memmap=2M$311M

Dzięki temu możemy korzystać z dowolnej (najnowszej!) wersji jądra, bez upierdliwego patchowania (cóż, patche badram były dość kijowe, włączenie z tym, że zdarzało im się mieć literówki uniemożliwiające kompilację).

Na koniec wspomniany skrypcik:

#!/usr/bin/perl
$src="/random.dat";
$dst="/tmp/memtest_tmp.dat";
$log="memtest_copy.log";
if (-f $dst){
   system (" rm $dst ");
}
system (" date >> $log ");
while (1){
  system (" cp $src $dst ");
  $res = `md5sum $dst`;
  $res2 = `sha1sum $dst`;
  $res_ = `md5sum $src`;
  $res2_ = `sha1sum $src`;
  $check = "ERROR";
   if (($res == $res_) && ($res2 == $res2_)){
     $check="OK";
   }
system (" echo \"$check $res $res_ $res2 $res2_ \" >> $log ");
system ("rm $dst");
}

Podsumowując: żegnaj BadRAM!