next up previous
Next: O dokumentu Up: Jak jsem louskal Previous: Kořenový systém souborů

Zařízení ramdisk a loop

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/loopx; ). 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.

Ramdisk

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/ramn; . 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.

  1. Vyčištění a připravení prostoru ramdisku o velikosti 2MB (2048kB):
    dd if=/dev/zero of=/dev/ram1 bs=1k count=2048
    Napnili jsme zařízení /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.
  2. Na vyčištěném prostoru vytvoříme filesystém:
    mke2fs -vm0 /dev/ram1 2048
    Vytvořili jsme filesystém EXT2 na prostoru ramdisku o velikosti 2048kB, přičmž jsme na programu chtěli aby byl upovídaný (-v) a aby na novém filesystému nerezervoval žádné místo pro superuživatele (-m0).
  3. No a zbývá již jen připojit ramdisk k systému souborů:
    mount /dev/ram1 /mnt -t ext2
    Připojili jsme zařízení /dev/ram1, jež obsahuje připravený filesystém EXT2 (-t ext2) k adresářovému stromu v místě /mnt.
A nyní můžeme používat ramdisk připojený na /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
a uložíme si binární obraz ramdisku do souboru RAM.img:
dd if=/dev/ram1 of=RAM.img bs=1k count=2048
Po zagzipování
gzip -9v RAM.img
a přenesení na disketu
dd if=RAM.img.gz of=/dev/fd0 bs=1k
jej můžeme použít obdobně jako, například, root-disketu z distribuce Slackware 3.0.

Více o ramdisku

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 LILOgif.

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:

  1. Nahrát obraz kernelu na disketu: dd if=zImage of=/dev/fd0 bs=1k
  2. Nahrát na tu samou disketu zkomrimovaný obraz ramdisku. Přičemž v tomto případě použijeme offset 400kB, jež je trošku větší než kernel, takže případný nový, lepší, větší kernel budeme moci nahrát na disketu stejnou disketu bez toho, žebychom porušili obraz ramdisku. Tedy nahrajeme obraz ramdisku s offsetem 400k, stále používáme velikost bloku (bs) 1kB: dd if=RAM.img.gz of=/dev/fd0 bs=1k seek=400
  3. Nyní už zbývá jen nastavit příznaky:
    1. Řekneme jádru, které je na disketě, že kořenový filesystém má hledat na disketě: rdev /dev/fd0 /dev/fd0
    2. No a nyní řekneme jádru, že má hledat ramdisk (14. bit) s offsetem 400k (bity 0--10) a že má vypsat výzvu před tím, než začne číst obraz ramdisku (15. bit). Tedy desítkově bude příznak ramdisku a tento příznak zapíšeme na vymezené místo jádra rdev -r /dev/fd0 49552
A nyní můžeme nabootovat linux z jedné jediné diskety. Tolik k ramdisku

Loop

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.

  1. Nejprve si vytvořme soubor, který budeme plnit:
    dd if=/dev/zero of=RAMd.img bs=1k count=2048
  2. Tento soubor připojme k jednomu ze zařízení loop například k /dev/loop0, k tomu slouží příkaz losetup(8):
    losetup /dev/loop0 RAMd.img
  3. Teď na zařízení, potažmo v souboru RAMd.img vytvoříme filesystém EXT2:
    mke2fs /dev/loop0 2048
  4. A již nám nic nebrání připojit filesystém na /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
  5. A nyní můžeme na /loop vytvořit kořenový filesystém ramdisku.
  6. Poté adresář /loop odmontujeme:
    umount /loop
  7. Na závěr soubor odpojíme od zařízení /dev/loop0:
    losetup -d /dev/loop0
Dále ze souborem RAMd.img můžeme naložit stejně jako s obrazem vytvořeným pomocí ramdisku.

Nejmenší distribuce Linuxu

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.

Myšlenka:

Bezprostředně za bootovací obraz jádra 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.

Co vše na ramdisk?

Nepodám zde vyčerpávající seznam, nejlépe je podívat se jak to dělali bratři Böhmové v distribuci DLX. Na ramdisku se musí objevit základní systémové knihovny a programy (především shell), speciální soubory a ze síťových alespoň 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!

Postup práce

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.



next up previous
Next: O dokumentu Up: Jak jsem louskal Previous: Kořenový systém souborů

Michal Kočer
kocer@merlin.pap.univie.ac.at