V novém jádře najdeme vylepšenou verzi ramdisku, tedy možnosti užití části paměti jako velice rychlého diskového prostoru, který lze připojit (přimontovat) k adresářovému stromu, či spíše častěji, tvoří kořenový systém adresářového stromu na různých disketových instalací; například instalačních disket systému či opravné diskety.
Zcela novým zařízením ve stabilním jádře je zpětnovazební (loopback) zařízení
loop
(resp.
/dev/loop
x; ).
Pomocí tohoto zařízení lze pracovat z jakýmkoli
souborem (v unixovém smyslu slova) jako s diskovým prostorem. Lze tedy
vytvořit či editovat soubor obsahující obraz diskety, například, uživatel dosemu
se může probírat obrazem bootovací diskety tak, jako kdyby se probíral
soubory přímo na disketě samé. Pomocí tohoto zařízení lze rovněž vytvořit
komprimovaný obraz ramdisku pro naši uržovací bootovací disketu přímo do
souboru.
V novém jádře je explicite imlementováno 16 ramdisků, lze jich ovšem
nakonfigurovat až 255. Pro toho, kdo hodlá užívat více než jeden ramdisk,
je vhodné kromě /dev/ramdisk
a /dev/ram
mít možnost přístupu
i k dalším ramdiskům, je proto třeba vytvořit specielní soubory
/dev/ram
n; . K tomu poslouží jednoduchý
script:
#!/bin/sh # Script na vytvoření spec. souborů ramdisku DISKS="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16" for disk in ${DISKS} do echo " Vytvářím /dev/ram$disk" mknod /dev/ram$disk b 1 $disk done # Konec scriptu
Velikost ramdisku je limitováva pouze velikostí paměti.
Uveďme si nyní nejednodužší případ práce z ramdiskem.
Nabootovali jsme system z novým jádrem a chceme se podívat jak se ramdisk
používá, vytvoříme ramdisk o velikosti 2MB a vytvoříme na něm filesystém
EXT2 a přimontujeme ho k adresářovému stromu na místo /mnt
.
dd if=/dev/zero of=/dev/ram1 bs=1k count=2048
/dev/ram1
NULLami ze zařízení
/dev/zero
, přičemž jsme používali bloky o velikosti 1kByte a
takových bloků bylo lze napočítati 2048.
mke2fs -vm0 /dev/ram1 2048
-v
) a aby na
novém filesystému nerezervoval
žádné místo pro superuživatele (-m0
).
mount /dev/ram1 /mnt -t ext2
/dev/ram1
, jež obsahuje připravený filesystém
EXT2 (-t ext2
) k adresářovému stromu v místě
/mnt
.
/mnt
stejně jako
kterýkoli jiný diskový prostor, například do něj můžeme nakopírovat
soubory tak, jak bychom je měli na root-disku naší udržovací diskety.
Máme-li vše potřebné na ramdisku, ramdisk odmontujeme umount /dev/ram1
RAM.img
: dd if=/dev/ram1 of=RAM.img bs=1k count=2048
gzip -9v RAM.img
dd if=RAM.img.gz of=/dev/fd0 bs=1k
Ramdisku jako kořenového diskového prostoru můžeme použít tehdy, dáme-li nějakým způsobem bootovanému jádru zprávu, že má hledat ramdisk a také kde ho má hledat. Tyto údaje lze jádru předat jako parametr, například pomocí zaváděče systému LILO.
Pro bootovací disketu je lépe použít jiného způsobu. Na začátku
bootovacího obrazu jádra je několik bytů, které specifikují
zařízení, jež obsahuje kořenový filesystém, video mód, parametry ramdisku a
zařízení určené pro swap. K těmto informacím lze přistupovat pomocí
rdev(8)
.
Pro nás jsou důležité parametry
ramdisku. Dříve tato část bootovacího obrazu jádra obsahovala velikost
ramdisku, ta je nyní explicitè nastavena na 4MB.
Co dané jádra má na tomto místě zapsáno zjistíte pomocí příkazu:
rdev -r zařízení
, kde
zařízení
je zařízení, či
soubor obsahující bootovací obraz jádra.
Informace o ramdisku zabírá dva byty.
Spodních 11 bitů (bit 0--10) obsahuje offset ramdisku na daném zařízení (v 1k blocích), tj. offset do 2MB. Bit 14 indikuje, zda se bude při bootování nahrávat ramdisk a bit 15 indikuje, zda má být tištěna výzva na výměnu media před počátkem čtení ramdisku. Bity 11--13 nejsou v současné době využity.
K čemu je to dobré? Pomocí takového řešení můžeme přeskočit nutnost dvou disket, bootovací a té s kořenovým filesystémem. Jelikož kernel je komprimován zabírá na bootovací disketě, řekněme, do 400kB a zbylých 1040kB je volných, nevyužitých. A toto volné místo lze zaplnit zkomprimovaným obrazem ramdisku.
Nechť máme skompilovaný nový kernel
zImage
a obraz ramdisku RAM.img.gz
. K vytvoření jedné
bootovací diskety systému, která jako kořenového filesystému užije ramdisku
stačí udělat toto:
dd if=zImage of=/dev/fd0 bs=1k
bs
) 1kB: dd if=RAM.img.gz of=/dev/fd0 bs=1k seek=400
rdev /dev/fd0 /dev/fd0
rdev -r /dev/fd0 49552
Jak již bylo řečeno, zařízení loop umožňuje pracovat pouze s obsahem souboru tak, jako by to byl samostatný diskový prostor. Zařízení loop umožňuje i zakódování takového prostoru.
Nejprve si použití zařízení loop ukážene na jednoduchém příkladě. Vytvořme si opět binární obraz ramdisku o velikosti 2MB, který poté můžeme použít obdobně jako obraz vytvořený pomocí ramdisku.
dd if=/dev/zero of=RAMd.img bs=1k count=2048
/dev/loop0
, k tomu slouží příkaz losetup(8)
: losetup /dev/loop0 RAMd.img
RAMd.img
vytvoříme
filesystém EXT2: mke2fs /dev/loop0 2048
/dev/loop0
k našemu adresářovému stromu, například k adresáři /loop
, který
pro tento případ vytvoříme: mkdir /loop
mount /dev/lopp0 /loop -t ext2
/loop
vytvořit kořenový filesystém ramdisku.
/loop
odmontujeme: umount /loop
/dev/loop0
: losetup -d /dev/loop0
RAMd.img
můžeme naložit stejně jako
s obrazem vytvořeným pomocí ramdisku.
V tomto odstavci si ukážeme, že pomocí zařízení loop a ramdisku lze vytvořit jednodisketovou plně funkční distribuci linuxu. Tuto distribuci naleznete na ftp://gd.tuwien.ac.at/pub/pss/aux/opsys/linux/DLX/. My se nyní budeme spíše zabývat tím jakým způsobem jsou použity ramdisk a loop společně v této distribuci, pro nikoho by pak neměl býti problém vytvořiti si takový jednodiskový linux sám.
zImage
zapíšeme obraz ramdisku ramImage.gz
, který bude tvořit kořenový
systém souborů. Místo, které ještě za ramdiskem zbude pomocí zařízení
loop použijeme jako uživatelský diskový prostor, na nějž bude uživatel moci
uložit později dopsané scripty, či soubory stažené ze sítě, např., ve školní
laboratoři.
telnet
a ftp
, tj.
skoro vše, ale ne úplně vše z /lib, /bin, /sbin, /dev
,
podpůrné systémové programy z /usr/sbin
. Pak je dobré míti
nějaké aplikace minimálně editor (elvis
) a stránkovač (less
).
Vše potřebné si skopírujte do příslušného stromu v adresáři
./rd-tree
a nezapomeňte přidat scripty
mountloop
a umountloop
, které jsou popsány níže.
Velikost užitého místa v tomto adresáři musí
být, po nakopírování všeho pořebného, menší než 2700kB, aby zbylo trocha místa
na ramdisku pro /tmp
, jejž užívá například editor!
Vytvoříme si komprimovaný obraz ramdisku ramImage.gz
,
tj. pomocí loop přimontujeme
soubor o velikosti 2840kB do něj překopírujeme obsah adresáře
./rd-tree
, odmontujeme a soubor skomprimujeme pomocí gzipu.
To vše udělá script createImage
:
#!/bin/sh # # Script createImage upraveno podle scriptu Ericha Boehma # RD_SIZE=2840 ######################################### # # Potřebné adresáře a zařízení RDHOME=. RD_SOURCE=$RDHOME/rd-tree/* RD_IMAGE=$RDHOME/ramImage.gz MNTDIR=/mnt # kam se dočasně připojí loop? LOOPDEV=/dev/loop0 # užité zařízení loop TMPFILE=/tmp/loop_tmp # dočasný soubor, na který se připojí loop FLOPPYDEV=/dev/fd0 # použitá disketová jednotka echo echo "---------------------------------------------------" echo "Tvořím obraz ramdisku..." echo " --> chvilku to potrvá" echo "---------------------------------------------------" echo # vytvoření dočasného souboru o velikosti $RD_SIZE echo "Plním soubor $TMPFILE na velikost $RD_SIZE" dd if=/dev/zero of=$TMPFILE bs=1k count=$RD_SIZE > /dev/null # a přiřazení tohoto souboru zařízení loop echo "Připojuji $TMPFILE k $LOOPDEV" losetup $LOOPDEV $TMPFILE # vytvoření ext2 fs na zařízení loop echo "Na $LOOPDEV tvořím ext2t filesystém" mke2fs -m 0 $LOOPDEV > /dev/null # přimontování zařízení loop k adresářovému stromu echo "Montuji $LOOPDEV na $MNTDIR" mount $LOOPDEV $MNTDIR -t ext2 # překopírování potřebného do vytvářeného souboru echo "Kopíruji vše potřebné z $RD_SOURCE do $MNTDIR" cp -a $RD_SOURCE $MNTDIR # odmontování a odpojení zařízení loop od souboru echo "Odmontovávám $MNTDIR a odpojuji soubor od $LOOPDEV" umount $MNTDIR losetup -d $LOOPDEV # vytvoření zagzipovaného obrazu ramdisku echo "Komprimuji obraz ramdisku $TMPFILE do souboru $RD_IMAGE" dd if=$TMPFILE bs=1k | gzip -9v > $RD_IMAGE echo "Mažu $TMPFILE" rm -f $TMPFILE # bezpečnostní vyčkání na dobu až se vše zapíše na medium sync echo "Hotovo --- konec" ############ Konec scriptu createImage
Nyní již máme vše potřebné soubor zImage
a ramImage.gz
,
proto bude dobré popřemýšlet jak vše na disketu umístíme.
Nejprve přijde jádro o velikosti KERNELSIZE
pak bychom chtěli
umístit ramdisk o velikosti IMAGESIZE
a za ním zbude místo
na EXT2-FS, které budeme připojovat pomocí zařízení loop.
K tomu všemu je třeba určit offsety.
Offset pro ramdisk se uloží pomocí rdev
jako příznak do obrazu
kernelu, ale
offset zbylého diskového místa pro loop budeme potřebovat někde uložit,
jelikož bychom se pak k tomuto místu těžko propracovávali.
Proto hned za zImage
do dalšího 1kB bloku zapíšeme offset
místa pro loop, tento blok nazveme looptable.
Naplnění diskety bude vypadat asi takto: =0.5mm
V obrázku uvedené symboly mají následující význam:
looptable ();
první blok looptable (t), ramdisku (r) a místa pro ext2 fs (l);
poslední blok obrazu kernelu K= 0+KERNELSIZE
a poslední blok obrazu ramdisku IMAGESIZE
.
Z obrázku je patrné, že , .
Tak známe vše potřebné, abychom mohli pochopit následující script
WriteDisk
,
který vypočítá všechny potřebné offsety a pak vše uloží na správné
místo na disku:
#!/bin/sh # # Script WriteDisk upraveno podle Ericha Boehma # # # definice proměnných RDHOME=. RD_KERNEL=$RDHOME/zImage RD_IMAGE=$RDHOME/ramImage.gz LOOPDEV=/dev/loop0 # zařízení loop, které hodláme použít FLOPPYDEV=/dev/fd0 # disketová jednotka, na kterou se vše zapíše # Výpočty velikostí KERNELSIZE=`ls -s $RD_KERNEL | cut -f2 '-d '` # velikost obrazu kernelu IMAGESIZE=`ls -s $RD_IMAGE | awk '{print $1}'` # velikost obrazu ramdisku LOOPTABLE=$[$KERNELSIZE + 1] # offset pro looptable v kB RDSTART=$[$KERNELSIZE + 2] # offset ramdisku v kB LOOPSTART=$[1024 * ($RDSTART + $IMAGESIZE)] # offset pro místo na EXT2-FS # v bytech # velikost volného místa na ext2 fs LOOPSIZE=$[1440 - ($RDSTART + $IMAGESIZE)] # Příprava příznaku ramdisku, která se uloží do kernelu # nastavený bit 14 (2^14=16384) znamená, že se má hledat ramdisk. # Je požné nastavit i bit 15 (tj. přičíst 2^15) aby se objevil prompt RD_FLAG=$[$RDSTART + 16384] ######################################### # # začátek echo echo "-------------------------------" echo "vytvářím disk ..." echo "-------------------------------" echo "velikost kernelu : $KERNELSIZE kByte" echo "velikost ramdisku : $IMAGESIZE kByte" echo "offset ramdisku : $RDSTART kByte" echo "offset zbylého místa : $LOOPSTART Byte" echo "offset tabulky looptable: $LOOPTABLE kByte" echo "velikost zbytku na loop: $LOOPSIZE kByte" echo # nastavení příznaků kernelu a zápis kernelu na disketu echo " Nastavuji příznaky pomocí rdev --- pro ramdisk užiji $RD_FLAG" rdev $RD_KERNEL $FLOPPYDEV # nastavení bootvacího zařízení rdev -r $RD_KERNEL $RD_FLAG # nastavení příznaků ramdisku rdev -R $RD_KERNEL 0 # užití VGA echo "Kopíruji $RD_KERNEL na $FLOPPYDEV" cp $RD_KERNEL $FLOPPYDEV # kopírování kernelu na disk # zápis obrazu ramdisku na disk s offsetem RDSTART echo "Kopíruji $RD_IMAGE na $FLOPPYDEV přičemž přeskočím prvních $RDSTART kB" dd if=$RD_IMAGE of=$FLOPPYDEV bs=1k seek=$RDSTART # zápis počátku zbylého místa do looptable # konverze sync znamená, že se nevyužité místo bloku zaplní NULLami echo \ "Zapisuji hodnotu $LOOPSTART na $FLOPPYDEV, přeskakuji prvních $LOOPTABLE kB" echo "$LOOPSTART" | dd of=$FLOPPYDEV bs=1k seek=$LOOPTABLE conv=sync # vytvoření filesystému ext2 na zbylém místě echo "Tvořím ext2 fs na $FLOPPYDEV od bloku $LOOPSTART + 1" losetup $LOOPDEV $FLOPPYDEV -o $LOOPSTART # připojení místa s offsetem LOOPSTART mke2fs -m 0 $LOOPDEV > /dev/null # vytvoření filesystému losetup -d $LOOPDEV # odpojení sync # vyčkání na skutečný zápis na medium echo echo "hotovo --- disk byl vytořen" ################ Konec scriptu WriteDisk
Abychom mohli využít zbylých asi 100kB, na nichž jsme vytvořili
systém souborů EXT2, je třeba
nejprve určit, kde je na disketě looptable, pak musíme looptable přečíst
a podle obsahu určit offset místa, kde je vytvořen ext2-fs, toto místo
se pak pomocí losetup
přiřadí zařízení loop, např.
/dev/loop0
,
a zařízení
loop se poté připojí ke kořenovému systému souborů na ramdisku na
místo, řekněme, /loop
.
Při vytváření ./rd-tree
je dobré na tuto skutečnost pomyslet a
je dobré někam vhodně umístit scripty mountloop
a umountloop
, kreré za nás provedou veškerou špinavou práci
s výpočty offsetu, čtením looptable a montováním:
#!/bin/sh # Script mountloop podle Ericha Boehma # # Vypočtení polohy looptable: LOOPTABLE=$[(`rdev -r /dev/fd0 | cut -f2 '-d '` & 16383) - 1] # Poznámka: # rdev -r /dev/fd0 přečte příznak pro ramdisk z kernelu na disketě # výsledek příkazu rdev se ořeže tak, aby zbylo pouze číslo bez # kometářů a z tohoto čísla se odstraní byty 14 a 15 přes # masku 0x7FFF (16383). Tím jsme získali offset ramdisku a víme, že # looptable je o jeden 1kB blok dříve # přečteme si z looptable offset pro filesystém ext2 na konci diskety # a upravíme ho tak, aby zbylo pouze číslo. LOOPSTART=`dd if=/dev/fd0 bs=1k skip=$LOOPTABLE count=1 | tr -cd '0-9'` # připojíme filesystém ext2 na disketě s offsetem LOOPSTART k zařízení loop0 losetup /dev/loop0 /dev/fd0 -o $LOOPSTART # neexistuje-li adresář /loop tak ho vytvoříme # a přimontujeme naň /dev/loop0 if [ ! -d /loop ]; then mkdir /loop fi mount /dev/loop0 /loop -t ext2 ######### Konec scriptu mountloop #!/bin/sh # # Script umountloop podle Ericha Boehma # # odmontujeme /loop a odpojíme disketu od /dev/loop0 umount /loop losetup -d /dev/loop0 ######### Konec scriptu umountloop
No a nyní bychom měli bez problémů nabootvat z právě vytvořené diskety. Je zřejmé, že je třeba míti více než 4MB RAM, jelikož jen pro samotný obraz ramdisku jsme zvolili velikost 2840kB. Jestliže jsme naplnili ramdisk správně, měl by se nám rozběhnout jednodisketový Linux.
Michal Kočer