GLAVA 5. SISTEMNYE OPERACII DLYA RABOTY S FAJLOVOJ SISTEMOJ V poslednej glave rassmatrivalis' vnutrennie struktury dannyh dlya fajlo- voj sistemy i algoritmy raboty s nimi. V etoj glave rech' pojdet o sistemnyh funkciyah dlya raboty s fajlovoj sistemoj s ispol'zovaniem ponyatij, vvedennyh v predydushchej glave. Rassmatrivayutsya sistemnye funkcii, obespechivayushchie obra- shchenie k sushchestvuyushchim fajlam, takie kak open, read, write, lseek i close, za- tem funkcii sozdaniya novyh fajlov, a imenno, creat i mknod, i, nakonec, fun- kcii dlya raboty s indeksom ili dlya peredvizheniya po fajlovoj sisteme: chdir, chroot, chown, stat i fstat. Issleduyutsya bolee slozhnye sistemnye funkcii: pipe i dup imeyut vazhnoe znachenie dlya realizacii kanalov v shell'e; mount i umount rasshiryayut vidimoe dlya pol'zovatelya derevo fajlovyh sistem; link i unlink izmenyayut ierarhicheskuyu strukturu fajlovoj sistemy. Zatem daetsya pred- stavlenie ob abstrakciyah, svyazannyh s fajlovoj sistemoj, v otnoshenii podder- zhki razlichnyh fajlovyh sistem, podchinyayushchihsya standartnym interfejsam. V pos- lednem razdele glavy rech' pojdet o soprovozhdenii fajlovoj sistemy. Glava znakomit s tremya strukturami dannyh yadra: tablicej fajlov, v kotoroj kazhdaya zapis' svyazana s odnim iz otkrytyh v sisteme fajlov, tablicej pol'zovatel'- skih deskriptorov fajlov, v kotoroj kazhdaya zapis' svyazana s fajlovym desk- riptorom, izvestnym processu, i tablicej montirovaniya, v kotoroj soderzhitsya informaciya po kazhdoj aktivnoj fajlovoj sisteme. Funkcii dlya raboty s fajlovoj sistemoj +----------------------------------------------------------------+ +------+--------------+--------+-------+-------+---------+-------+ | Voz- | Ispol'zuyut | Nazna- | Rabo- | Vvod- | Rabota- | Uprav-| | vra- | algoritm | chayut | tayut | vyvod | yut so | lenie | | shchayut | namei | indek- | s at- | iz | struktu-| de- | | desk-| | sy | ribu- | fajla | roj faj-| rev'- | | rip- | | | tami | | lovyh | yami | | tory | | | fajla | | sistem | | | fajla| | | | | | | +------+--------------+--------+-------+-------+---------+-------+ | open | open stat | | | | | | | creat| creat link | creat | chown | read | | | | dup | chdir unlink| mknod | chmod | write | mount | chdir | | pipe | chroot mknod | link | stat | lseek | umount | chown | | close| chown mount | unlink | | | | | | | chmod umount| | | | | | +------+--------------+--------+-------+-------+---------+-------+ +---+--+--------------+--------+-------+-------+---------+----+--+ | Algoritmy raboty s fajlovoj sistemoj na nizhnem urovne | +-------------+------------------+------------------------+ | namei | | | +-------------+ ialloc ifree | alloc free bmap | | iget iput | | | +-------------+------------------+------------------------+ +---------------------------------------------------------+ | algoritmy raboty s buferami | +---------------------------------------------------------+ | getblk brelse bread breada bwrite | +---------------------------------------------------------+ Risunok 5.1. Funkcii dlya raboty s fajlovoj sistemoj i ih svyaz' s drugimi algoritmami 85 Na Risunke 5.1 pokazana vzaimosvyaz' mezhdu sistemnymi funkciyami i algo- ritmami, opisannymi ranee. Sistemnye funkcii klassificiruyutsya na neskol'ko kategorij, hotya nekotorye iz funkcij prisutstvuyut bolee, chem v odnoj katego- rii: * Sistemnye funkcii, vozvrashchayushchie deskriptory fajlov dlya ispol'zovaniya drugimi sistemnymi funkciyami; * Sistemnye funkcii, ispol'zuyushchie algoritm namei dlya analiza imeni puti poiska; * Sistemnye funkcii, naznachayushchie i osvobozhdayushchie indeks s ispol'zovaniem algoritmov ialloc i ifree; * Sistemnye funkcii, ustanavlivayushchie ili izmenyayushchie atributy fajla; * Sistemnye funkcii, pozvolyayushchie processu proizvodit' vvod-vyvod dannyh s ispol'zovaniem algoritmov alloc, free i algoritmov vydeleniya bufera; * Sistemnye funkcii, izmenyayushchie strukturu fajlovoj sistemy; * Sistemnye funkcii, pozvolyayushchie processu izmenyat' sobstvennoe predstavle- nie o strukture dereva fajlovoj sistemy. 5.1 OPEN Vyzov sistemnoj funkcii open (otkryt' fajl) - eto pervyj shag, kotoryj dolzhen sdelat' process, chtoby obratit'sya k dannym v fajle. Sintaksis vyzova funkcii open: fd = open(pathname,flags,modes); gde pathname - imya fajla, flags ukazyvaet rezhim otkrytiya (naprimer, dlya chte- niya ili zapisi), a modes soderzhit prava dostupa k fajlu v sluchae, esli fajl sozdaetsya. Sistemnaya funkciya open vozvrashchaet celoe chislo (*), imenuemoe pol'zovatel'skim deskriptorom fajla. Drugie operacii nad fajlami, takie kak chtenie, zapis', po- zicionirovanie golovok chteniya-zapisi, vosproizvedenie deskriptora fajla, us- tanovka parametrov vvoda-vyvoda, opredelenie statusa fajla i zakrytie fajla, ispol'zuyut znachenie deskriptora fajla, vozvrashchaemoe sistemnoj funkciej open. YAdro prosmatrivaet fajlovuyu sistemu v poiskah fajla po ego imeni, is- pol'zuya algoritm namei (sm. Risunok 5.2). Ono proveryaet prava na otkrytie fajla posle togo, kak obnaruzhit kopiyu indeksa fajla v pamyati, i vydelyaet ot- kryvaemomu fajlu zapis' v tablice fajlov. Zapis' tablicy fajlov soderzhit ukazatel' na indeks otkrytogo fajla i pole, v kotorom hranitsya smeshchenie v bajtah ot nachala fajla do mesta, otkuda predpolagaetsya nachinat' vypolnenie posleduyushchih operacij chteniya ili zapisi. YAdro sbrasyvaet eto smeshchenie v 0 vo vremya otkrytiya fajla, imeya v vidu, chto ishodnaya operaciya chteniya ili zapisi po umolchaniyu budet proizvodit'sya s nachala fajla. S drugoj storony, process mozhet otkryt' fajl v rezhime zapisi v konec, v etom sluchae yadro ustanavlivaet znachenie smeshcheniya, ravnoe razmeru fajla. YAdro vydelyaet zapis' v lichnoj (zak- rytoj) tablice v adresnom prostranstve zadachi, vydelennom processu (tablica eta nazyvaetsya tablicej pol'zovatel'skih deskriptorov fajlov), i zapominaet ukazatel' na etu zapis'. Ukazatelem vystupaet deskriptor fajla, vozvrashchaemyj pol'zovatelyu. Zapis' v tablice pol'zovatel'skih fajlov ukazyvaet na zapis' v global'noj tablice fajlov. --------------------------------------- (*) Vse sistemnye funkcii vozvrashchayut v sluchae neudachnogo zaversheniya kod -1. Kod vozvrata, ravnyj -1, bol'she ne budet upominat'sya pri rassmotrenii sintaksisa vyzova sistemnyh funkcij. 86 +------------------------------------------------------------+ | algoritm open | | vhodnaya informaciya: imya fajla | | rezhim otkrytiya | | prava dostupa (pri sozdanii fajla) | | vyhodnaya informaciya: deskriptor fajla | | { | | prevratit' imya fajla v identifikator indeksa (algoritm | | namei); | | esli (fajl ne sushchestvuet ili k nemu ne razreshen dostup) | | vozvratit' (kod oshibki); | | vydelit' dlya indeksa zapis' v tablice fajlov, iniciali- | | zirovat' schetchik, smeshchenie; | | vydelit' zapis' v tablice pol'zovatel'skih deskriptorov | | fajla, ustanovit' ukazatel' na zapis' v tablice fajlov;| | esli (rezhim otkrytiya podrazumevaet usechenie fajla) | | osvobodit' vse bloki fajla (algoritm free); | | snyat' blokirovku (s indeksa); /* indeks zablokirovan | | vyshe, v algoritme | | namei */ | | vozvratit' (pol'zovatel'skij deskriptor fajla); | | } | +------------------------------------------------------------+ Risunok 5.2. Algoritm otkrytiya fajla Predpolozhim, chto process, otkryvaya fajl "/etc/passwd" dvazhdy, odin raz tol'ko dlya chteniya i odin raz tol'ko dlya zapisi, i odnazhdy fajl "local" dlya chteniya i dlya zapisi (**), vypolnyaet sleduyushchij nabor operatorov: fd1 = open("/etc/passwd",O_RDONLY); fd2 = open("local",O_RDWR); fd3 = open("/etc/passwd",O_WRONLY); Na Risunke 5.3 pokazana vzaimosvyaz' mezhdu tablicej indeksov, tablicej fajlov i tablicej pol'zovatel'skih deskriptorov fajla. Kazhdyj vyzov funkcii open vozvrashchaet processu deskriptor fajla, a sootvetstvuyushchaya zapis' v tabli- ce pol'zovatel'skih deskriptorov fajla ukazyvaet na unikal'nuyu zapis' v tab- lice fajlov yadra, pust' dazhe odin i tot zhe fajl ("/etc/passwd") otkryvaetsya dvazhdy. Zapisi v tablice fajlov dlya vseh ekzemplyarov odnogo i togo zhe otkrytogo fajla ukazyvayut na odnu zapis' v tablice indeksov, hranyashchihsya v pamyati. Pro- cess mozhet obrashchat'sya k fajlu "/etc/passwd" s chteniem ili zapis'yu, no tol'ko cherez deskriptory fajla, imeyushchie znacheniya 3 i 5 (sm. risunok).YAdro zapomina- et razreshenie na chtenie ili zapis' v fajl v stroke tablicy fajlov,vydelennoj vo vremya vypolneniya funkcii open. Predpolozhim, chto vtoroj process vypolnyaet sleduyushchij nabor operatorov: --------------------------------------- (**) V opisanii vyzova sistemnoj funkcii open soderzhatsya tri parametra (tre- tij ispol'zuetsya pri otkrytii v rezhime sozdaniya), no programmisty obych- no ispol'zuyut tol'ko pervye dva iz nih. Kompilyator s yazyka Si ne prove- ryaet pravil'nost' kolichestva parametrov. V sisteme pervye dva parametra i tretij (s lyubym "musorom", chto by ni proizoshlo v steke) peredayutsya obychno yadru. YAdro ne proveryaet nalichie tret'ego parametra, esli tol'ko neobhodimost' v nem ne vytekaet iz znacheniya vtorogo parametra, chto poz- volyaet programmistam ukazat' tol'ko dva parametra. 87 tablica pol'zova- tel'skih deskrip- torov fajla tablica fajlov tablica indeksov +---------+ +------------+ +--------------+ 0| | | | | - | +---------+ | | | - | 1| | | | | - | +---------+ +------------+ | - | 2| | | - | | - | +---------+ | - | | - | 3| ----+----+ | - | | - | +---------+ | | - | +--------------+ 4| ----+---+| | - | +---->| schet- | +---------+ || | - | |+--->| chik (/etc/ | 5| ----+--+|| +------------+ || | 2 passwd)| +---------+ ||| | schet- | || +--------------+ 6| | ||+-->| chik CHtenie+--+| | - | +---------+ || | 1 | | | - | 7| | || +------------+ | | - | +---------+ || | - | | | - | | - | || | - | | | - | +---------+ || +------------+ | | - | || | schet- CHte-| | | - | |+--->| chik nie-+---|-+ | - | | | 1 Zapis'| | | | - | | +------------+ | | | - | | | - | | | +--------------+ | | - | | | | schet- | | | - | | +->| chik (local)| | | - | | | 1 | | | - | | +--------------+ | +------------+ | | - | | | schet- | | | - | +---->| chik Zapis'+---+ | - | | 1 | | - | +------------+ | - | | - | | - | | - | | - | +------------+ +--------------+ Risunok 5.3. Struktury dannyh posle otkrytiya fd1 = open("/etc/passwd",O_RDONLY); fd2 = open("private",O_RDONLY); Na Risunke 5.4 pokazana vzaimosvyaz' mezhdu sootvetstvuyushchimi strukturami dan- nyh, kogda oba processa (i bol'she nikto) imeyut otkrytye fajly. Snova rezul'- tatom kazhdogo vyzova funkcii open yavlyaetsya vydelenie unikal'noj tochki vhoda v tablice pol'zovatel'skih deskriptorov fajla i v tablice fajlov yadra, i yad- ro hranit ne bolee odnoj zapisi na kazhdyj fajl v tablice indeksov, razmeshchen- nyh v pamyati. Zapis' v tablice pol'zovatel'skih deskriptorov fajla po umolchaniyu hranit smeshchenie v fajle do adresa sleduyushchej operacii vvodavyvoda i ukazyvaet nepos- redstvenno na tochku vhoda v tablice indeksov dlya fajla, ustranyaya neobhodi- most' v otdel'noj tablice fajlov yadra. Vysheprivedennye primery pokazyvayut vzaimosvyaz' mezhdu zapisyami tablicy pol'zovatel'skih deskriptorov fajla i za- 88 tablicy pol'zova- tel'skih deskrip- torov fajla (process A) tablica fajlov tablica indeksov +---------+ +------------+ +--------------+ 0| | | | | - | +---------+ | | | - | 1| | | | | - | +---------+ +------------+ | - | 2| | | - | | - | +---------+ | - | | - | 3| ----+----+ | - | | - | +---------+ | | - | +--------------+ 4| ----+---+| | - | +---->| schet- | +---------+ || | - | |+--->| chik (/etc/ | 5| ----+--+|| +------------+ ||+-->| 3 passwd)| +---------+ ||| | schet- | ||| +--------------+ | - | ||+-->| chik CHtenie+--+|| | - | | - | || | 1 | || | - | | - | || +------------+ || | - | +---------+ || | - | || | - | || | - | || | - | (process B) || | - | || | - | +---------+ || | - | || | - | 0| | || +------------+ || | - | +---------+ || | schet- CHte-| || | - | 1| | |+--->| chik nie-+---||+ | - | +---------+ | | 1 Zapis'| ||| | - | 2| | | +------------+ ||| | - | +---------+ | | - | ||| +--------------+ 3| ----+--|--+ | - | ||| | schet- | +---------+ | | | - | ||+->| chik (local)| 4| ----+-+| | | - | || | 1 | +---------+ || | | - | || +--------------+ 5| | || | | - | || | - | +---------+ || | +------------+ || | - | | - | || | | schet- | || | - | | - | || +->| chik CHtenie+---+| | - | | - | || | 1 | | | - | +---------+ || +------------+ | | - | || | - | | | - | || | - | | +--------------+ || | - | | | schet- | || +------------+ |+->| chik (private)| || | schet- | || | 1 | |+---->| chik Zapis'+----+| +--------------+ | | 1 | | | - | | +------------+ | | - | | | - | | +--------------+ | | - | | | +------------+ | | | schet- | | +----->| chik CHtenie+-----+ | 1 | +------------+ Risunok 5.4. Struktury dannyh posle togo, kak dva processa proizveli otkrytie fajlov 89 pisyami v tablice fajlov yadra tipa "odin k odnomu". Tompson, odnako, otmecha- et, chto im byla realizovana tablica fajlov kak otdel'naya struktura, pozvolya- yushchaya sovmestno ispol'zovat' odin i tot zhe ukazatel' smeshcheniya neskol'kim pol'zovatel'skim deskriptoram fajla (sm. [Thompson 78], str.1943). V sistem- nyh funkciyah dup i fork, rassmatrivaemyh v razdelah 5.13 i 7.1, pri rabote so strukturami dannyh dopuskaetsya takoe sovmestnoe ispol'zovanie. Pervye tri pol'zovatel'skih deskriptora (0, 1 i 2) imenuyutsya deskripto- rami fajlov: standartnogo vvoda, standartnogo vyvoda i standartnogo fajla oshibok. Processy v sisteme UNIX po dogovorennosti ispol'zuyut deskriptor faj- la standartnogo vvoda pri chtenii vvodimoj informacii, deskriptor fajla stan- dartnogo vyvoda pri zapisi vyvodimoj informacii i deskriptor standartnogo fajla oshibok dlya zapisi soobshchenij ob oshibkah. V operacionnoj sisteme net ni- kakogo ukazaniya na to, chto eti deskriptory fajlov yavlyayutsya special'nymi. Gruppa pol'zovatelej mozhet uslovit'sya o tom, chto fajlovye deskriptory, imeyu- shchie znacheniya 4, 6 i 11, yavlyayutsya special'nymi, no bolee estestvenno nachinat' otschet s 0 (kak v yazyke Si). Prinyatie soglasheniya srazu vsemi pol'zovatel'- skimi programmami oblegchit svyaz' mezhdu nimi pri ispol'zovanii kanalov, v chem my ubedimsya v dal'nejshem, izuchaya glavu 7. Obychno operatorskij terminal (sm. glavu 10) sluzhit i v kachestve standartnogo vvoda, i v kachestve standartnogo vyvoda i v kachestve standartnogo ustrojstva vyvoda soobshchenij ob oshibkah. 5.2 READ Sintaksis vyzova sistemnoj funkcii read (chitat'): number = read(fd,buffer,count) gde fd - deskriptor fajla, vozvrashchaemyj funkciej open, buffer - adres struk- tury dannyh v pol'zovatel'skom processe, gde budut razmeshchat'sya schitannye dannye v sluchae uspeshnogo zaversheniya vypolneniya funkcii read, count - koli- chestvo bajt, kotorye pol'zovatelyu nuzhno prochitat', number - kolichestvo fak- ticheski prochitannyh bajt. Na Risunke 5.5 priveden algoritm read, vypolnyayushchij chtenie obychnogo fajla. YAdro obrashchaetsya v tablice fajlov k zapisi, kotoraya sootvetstvuet znacheniyu pol'zovatel'skogo deskriptora fajla, sleduya za ukazatelem (sm. Risunok 5.3). Zatem ono ustanavlivaet znacheniya neskol'kih parametrov vvoda-vyvoda v adresnom prostranstve processa (Risunok 5.6), tem samym ustranyaya neobhodimost' v ih peredache v kachestve parametrov funkcii. V chastnosti, yadro ukazyvaet v kachestve rezhima vvoda-vyvoda "chtenie", ustanav- livaet flag, svidetel'stvuyushchij o tom, chto vvod-vyvod napravlyaetsya v adresnoe prostranstvo pol'zovatelya, znachenie polya schetchika bajtov priravnivaet koli- chestvu bajt, kotorye budut prochitany, ustanavlivaet adres pol'zovatel'skogo bufera dannyh i, nakonec, znachenie smeshcheniya (iz tablicy fajlov), ravnoe sme- shcheniyu v bajtah vnutri fajla do mesta, otkuda nachinaetsya vvod-vyvod. Posle togo, kak yadro ustanovit znacheniya parametrov vvoda-vyvoda v adresnom prost- ranstve processa, ono obrashchaetsya k indeksu, ispol'zuya ukazatel' iz tablicy fajlov, i blokiruet ego prezhde, chem nachat' chtenie iz fajla. Zatem v algoritme nachinaetsya cikl, vypolnyayushchijsya do teh por, poka opera- ciya chteniya ne budet proizvedena do konca. YAdro preobrazuet smeshchenie v bajtah vnutri fajla v nomer bloka, ispol'zuya al- 90 +------------------------------------------------------------+ | algoritm read | | vhodnaya informaciya: pol'zovatel'skij deskriptor fajla | | adres bufera v pol'zovatel'skom pro- | | cesse | | kolichestvo bajt, kotorye nuzhno prochi- | | tat' | | vyhodnaya informaciya: kolichestvo bajt, skopirovannyh v pol'-| | zovatel'skoe prostranstvo | | { | | obratit'sya k zapisi v tablice fajlov po znacheniyu pol'zo-| | vatel'skogo deskriptora fajla; | | proverit' dostupnost' fajla; | | ustanovit' parametry v adresnom prostranstve processa, | | ukazav adres pol'zovatelya, schetchik bajtov, parametry | | vvoda-vyvoda dlya pol'zovatelya; | | poluchit' indeks po zapisi v tablice fajlov; | | zablokirovat' indeks; | | ustanovit' znachenie smeshcheniya v bajtah dlya adresnogo | | prostranstva processa po znacheniyu smeshcheniya v tablice | | fajlov; | | vypolnit' (poka znachenie schetchika bajtov ne stanet udov-| | letvoritel'nym) | | { | | prevratit' smeshchenie v fajle v nomer diskovogo bloka | | (algoritm bmap); | | vychislit' smeshchenie vnutri bloka i kolichestvo bajt, | | kotorye budut prochitany; | | esli (kolichestvo bajt dlya chteniya ravno 0) | | /* popytka chteniya konca fajla */ | | prervat'sya; /* vyhod iz cikla */ | | prochitat' blok (algoritm breada, esli proizvoditsya | | chtenie s prodvizheniem, i algoritm bread - v protiv- | | nom sluchae); | | skopirovat' dannye iz sistemnogo bufera po adresu | | pol'zovatelya; | | skorrektirovat' znacheniya polej v adresnom prostran- | | stve processa, ukazyvayushchie smeshchenie v bajtah vnutri | | fajla, kolichestvo prochitannyh bajt i adres dlya pe- | | redachi v prostranstvo pol'zovatelya; | | osvobodit' bufer; /* zablokirovannyj v algoritme | | bread */ | | } | | razblokirovat' indeks; | | skorrektirovat' znachenie smeshcheniya v tablice fajlov dlya | | sleduyushchej operacii chteniya; | | vozvratit' (obshchee chislo prochitannyh bajt); | | } | +------------------------------------------------------------+ Risunok 5.5. Algoritm chteniya iz fajla +------------------------------------------------------+ | mode chtenie ili zapis' | | count kolichestvo bajt dlya chteniya ili zapisi | | offset smeshchenie v bajtah vnutri fajla | | address adres mesta, kuda budut kopirovat'sya dannye,| | v pamyati pol'zovatelya ili yadra | | flag otnoshenie adresa k pamyati pol'zovatelya ili | | k pamyati yadra | +------------------------------------------------------+ Risunok 5.6. Parametry vvoda-vyvoda, hranyashchiesya v prostranstve processa 91 goritm bmap, i vychislyaet smeshchenie vnutri bloka do mesta, otkuda sleduet na- chat' vvod-vyvod, a takzhe kolichestvo bajt, kotorye budut prochitany iz bloka. Posle schityvaniya bloka v bufer, vozmozhno, s prodvizheniem (algoritmy bread i breada) yadro kopiruet dannye iz bloka po naznachennomu adresu v pol'zovatel'- skom processe. Ono korrektiruet parametry vvoda-vyvoda v adresnom prostrans- tve processa v sootvetstvii s kolichestvom prochitannyh bajt, uvelichivaya zna- chenie smeshcheniya v bajtah vnutri fajla i adres mesta v pol'zovatel'skom pro- cesse, kuda budet dostavlena sleduyushchaya porciya dannyh, i umen'shaya chislo bajt, kotorye neobhodimo prochitat', chtoby vypolnit' zapros pol'zovatelya. Esli zap- ros pol'zovatelya ne udovletvoren, yadro povtoryaet ves' cikl, preobrazuya sme- shchenie v bajtah vnutri fajla v nomer bloka, schityvaya blok s diska v sistemnyj bufer, kopiruya dannye iz bufera v pol'zovatel'skij process, osvobozhdaya bufer i korrektiruya znacheniya parametrov vvoda-vyvoda v adresnom prostranstve pro- cessa. Cikl zavershaetsya, libo kogda yadro vypolnit zapros pol'zovatelya pol- nost'yu, libo kogda v fajle bol'she ne budet dannyh, libo esli yadro obnaruzhit oshibku pri chtenii dannyh s diska ili pri kopirovanii dannyh v prostranstvo pol'zovatelya. YAdro korrektiruet znachenie smeshcheniya v tablice fajlov v soot- vetstvii s kolichestvom fakticheski prochitannyh bajt; poetomu uspeshnoe vypol- nenie operacij chteniya vyglyadit kak posledovatel'noe schityvanie dannyh iz fajla. Sistemnaya operaciya lseek (razdel 5.6) ustanavlivaet znachenie smeshcheniya v tablice fajlov i izmenyaet poryadok, v kotorom process chitaet ili zapisyvaet dannye v fajle. +------------------------------------------------------+ | #include | | main() | | { | | int fd; | | char lilbuf[20],bigbuf[1024]; | | | | fd = open("/etc/passwd",O_RDONLY); | | read(fd,lilbuf,20); | | read(fd,bigbuf,1024); | | read(fd,lilbuf,20); | | } | +------------------------------------------------------+ Risunok 5.7. Primer programmy chteniya iz fajla Rassmotrim programmu, privedennuyu na Risunke 5.7. Funkciya open vozvrashcha- et deskriptor fajla, kotoryj pol'zovatel' zasylaet v peremennuyu fd i ispol'- zuet v posleduyushchih vyzovah funkcii read. Vypolnyaya funkciyu read, yadro prove- ryaet, pravil'no li zadan parametr "deskriptor fajla", a takzhe byl li fajl predvaritel'no otkryt processom dlya chteniya. Ono sohranyaet znachenie adresa pol'zovatel'skogo bufera, kolichestvo schityvaemyh bajt i nachal'noe smeshchenie v bajtah vnutri fajla (sootvetstvenno: lilbuf, 20 i 0), v prostranstve proces- sa. V rezul'tate vychislenij okazyvaetsya, chto nulevoe znachenie smeshcheniya soot- vetstvuet nulevomu bloku fajla, i yadro vozvrashchaet tochku vhoda v indeks, so- otvetstvuyushchuyu nulevomu bloku. Predpolagaya, chto takoj blok sushchestvuet, yadro schityvaet polnyj blok razmerom 1024 bajta v bufer, no po adresu lilbuf kopi- ruet tol'ko 20 bajt. Ono uvelichivaet smeshchenie vnutri prostranstva processa na 20 bajt i sbrasyvaet schetchik dannyh v 0. Poskol'ku operaciya read vypolni- las', yadro pereustanavlivaet znachenie smeshcheniya v tablice fajlov na 20, tak chto posleduyushchie operacii chteniya iz fajla s dannym deskriptorom nachnutsya s mesta, raspolozhennogo so smeshcheniem 20 bajt ot nachala fajla, a sistemnaya fun- kciya vozvrashchaet chislo bajt, fakticheski prochitannyh, t.e. 20. Pri povtornom vyzove funkcii read yadro vnov' proveryaet korrektnost' uka- zaniya deskriptora i nalichie sootvetstvuyushchego fajla, otkrytogo processom dlya 92 chteniya, poskol'ku ono nikak ne mozhet uznat', chto zapros pol'zovatelya na chte- nie kasaetsya togo zhe samogo fajla, sushchestvovanie kotorogo bylo ustanovleno vo vremya poslednego vyzova funkcii. YAdro sohranyaet v prostranstve processa pol'zovatel'skij adres bigbuf, kolichestvo bajt, kotorye nuzhno prochitat' pro- cessu (1024), i nachal'noe smeshchenie v fajle (20), vzyatoe iz tablicy fajlov. YAdro preobrazuet smeshchenie vnutri fajla v nomer diskovogo bloka, kak ran'she, i schityvaet blok. Esli mezhdu vyzovami funkcii read proshlo neprodolzhitel'noe vremya, est' shansy, chto blok nahoditsya v bufernom keshe. Odnako, yadro ne mozhet polnost'yu udovletvorit' zapros pol'zovatelya na chtenie za schet soderzhimogo bufera, poskol'ku tol'ko 1004 bajta iz 1024 dlya dannogo zaprosa nahodyatsya v bufere. Poetomu ono kopiruet ostavshiesya 1004 bajta iz bufera v pol'zovatel'- skuyu strukturu dannyh bigbuf i korrektiruet parametry v prostranstve proces- sa takim obrazom, chtoby sleduyushchij shag cikla chteniya nachinalsya v fajle s bajta 1024, pri etom dannye sleduet kopirovat' po adresu bajta 1004 v bigbuf v ob- ®eme 20 bajt, chtoby udovletvorit' zapros na chtenie. Teper' yadro perehodit k nachalu cikla, soderzhashchegosya v algoritme read. Ono preobrazuet smeshchenie v bajtah (1024) v nomer logicheskogo bloka (1), ob- rashchaetsya ko vtoromu bloku pryamoj adresacii, nomer kotorogo hranitsya v indek- se, i otyskivaet tochnyj diskovyj blok, iz kotorogo budet proizvodit'sya chte- nie. YAdro schityvaet blok iz bufernogo kesha ili s diska, esli v keshe dannyj blok otsutstvuet. Nakonec, ono kopiruet 20 bajt iz bufera po utochnennomu ad- resu v pol'zovatel'skij process. Prezhde chem vyjti iz sistemnoj funkcii, yadro ustanavlivaet znachenie polya smeshcheniya v tablice fajlov ravnym 1044, to est' ravnym znacheniyu smeshcheniya v bajtah do mesta, kuda budet proizvodit'sya sleduyu- shchee obrashchenie. V poslednem vyzove funkcii read iz primera yadro vedet sebya, kak i v pervom obrashchenii k funkcii, za isklyucheniem togo, chto chtenie iz fajla v dannom sluchae nachinaetsya s bajta 1044, tak kak imenno eto znachenie budet obnaruzheno v pole smeshcheniya toj zapisi tablicy fajlov, kotoraya sootvetstvuet ukazannomu deskriptoru. Primer pokazyvaet, naskol'ko vygodno dlya zaprosov vvoda-vyvoda rabotat' s dannymi, nachinayushchimisya na granicah blokov fajlovoj sistemy i imeyushchimi raz- mer, kratnyj razmeru bloka. |to pozvolyaet yadru izbegat' dopolnitel'nyh ite- racij pri vypolnenii cikla v algoritme read i vseh vytekayushchih posledstvij, svyazannyh s dopolnitel'nymi obrashcheniyami k indeksu v poiskah nomera bloka, kotoryj soderzhit dannye, i s konkurenciej za ispol'zovanie bufernogo pula. Biblioteka standartnyh modulej vvoda-vyvoda sozdana takim obrazom, chtoby skryt' ot pol'zovatelej razmery buferov yadra; ee ispol'zovanie pozvolyaet iz- bezhat' poter' proizvoditel'nosti, prisushchih processam, rabotayushchim s nebol'shi- mi porciyami dannyh, iz-za chego ih funkcionirovanie na urovne fajlovoj siste- my neeffektivno (sm. uprazhnenie 5.4). Vypolnyaya cikl chteniya, yadro opredelyaet, yavlyaetsya li fajl ob®ektom chteniya s prodvizheniem: esli process schityvaet posledovatel'no dva bloka, yadro pred- polagaet, chto vse ocherednye operacii budut proizvodit' posledovatel'noe chte- nie, do teh por, poka ne budet utverzhdeno obratnoe. Na kazhdom shage cikla yad- ro zapominaet nomer sleduyushchego logicheskogo bloka v kopii indeksa, hranyashchejsya v pamyati, i na sleduyushchem shage sravnivaet nomer tekushchego logicheskogo bloka so znacheniem, zapomnennym ranee. Esli eti nomera ravny, yadro vychislyaet nomer fizicheskogo bloka dlya chteniya s prodvizheniem i sohranyaet eto znachenie v pros- transtve processa dlya ispol'zovaniya v algoritme breada. Konechno zhe, poka process ne schital konec bloka, yadro ne zapustit algoritm chteniya s prodvizhe- niem dlya sleduyushchego bloka. Obrativshis' k Risunku 4.9, vspomnim, chto nomera nekotoryh blokov v in- dekse ili v blokah kosvennoj adresacii mogut imet' nulevoe znachenie, pust' dazhe nomera posleduyushchih blokov i nenulevye. Esli process popytaetsya prochi- tat' dannye iz takogo bloka, yadro vypolnit zapros, vydelyaya proizvol'nyj bu- fer v cikle read, ochishchaya ego soderzhimoe i kopiruya dannye iz nego po adresu pol'zovatelya. |tot sluchaj ne imeet nichego obshchego s tem sluchaem, kogda pro- cess obnaruzhivaet konec fajla, govoryashchij o tom, chto posle etogo mesta zapis' informacii nikogda ne proizvodilas'. Obnaruzhiv konec fajla, yadro ne vozvra- 93 shchaet processu nikakoj informacii (sm. uprazhnenie 5.1). Kogda process vyzyvaet sistemnuyu funkciyu read, yadro blokiruet indeks na vremya vypolneniya vyzova. Vposledstvii, etot process mozhet priostanovit'sya vo vremya chteniya iz bufera, associirovannogo s dannymi ili s blokami kosvennoj adresacii v indekse. Esli eshche odnomu processu dat' vozmozhnost' vnosit' izme- neniya v fajl v to vremya, kogda pervyj process priostanovlen, funkciya read mozhet vozvratit' nesoglasovannye dannye. Naprimer, process mozhet schitat' iz fajla neskol'ko blokov; esli on priostanovilsya vo vremya chteniya pervogo blo- ka, a vtoroj process sobiralsya vesti zapis' v drugie bloki, vozvrashchaemye dannye budut soderzhat' starye dannye vperemeshku s novymi. Takim obrazom, in- deks ostaetsya zablokirovannym na vse vremya vypolneniya vyzova funkcii read dlya togo, chtoby processy mogli imet' celostnoe videnie fajla, to est' vide- nie togo obraza, kotoryj byl u fajla pered vyzovom funkcii. YAdro mozhet vygruzhat' process, vedushchij chtenie, v rezhim zadachi na vremya mezhdu dvumya vyzovami funkcij i planirovat' zapusk drugih processov. Tak kak po okonchanii vypolneniya sistemnoj funkcii s indeksa snimaetsya blokirovka, nichto ne meshaet drugim processam obrashchat'sya k fajlu i izmenyat' ego soderzhi- moe. So storony sistemy bylo by nespravedlivo derzhat' indeks zablokirovannym vse vremya ot momenta, kogda process otkryl fajl, i do togo momenta, kogda fajl budet zakryt etim processom, poskol'ku togda odin process budet derzhat' vse vremya fajl otkrytym, tem samym ne davaya drugim processam vozmozhnosti ob- ratit'sya k fajlu. Esli fajl imeet imya "/etc/ passwd", to est' yavlyaetsya faj- lom, ispol'zuemym v processe registracii dlya proverki pol'zovatel'skogo pa- rolya, odin pol'zovatel' mozhet umyshlenno (ili, vozmozhno, neumyshlenno) vospre- pyatstvovat' registracii v sisteme vseh ostal'nyh pol'zovatelej. CHtoby pre- dotvratit' vozniknovenie podobnyh problem, yadro snimaet s indeksa blokirovku po okonchanii vypolneniya kazhdogo vyzova sistemnoj funkcii, ispol'zuyushchej in- deks. Esli vtoroj process vneset izmeneniya v fajl mezhdu dvumya vyzovami funk- cii read, proizvodimymi pervym processom, pervyj process mozhet prochitat' nepredvidennye dannye, odnako struktury dannyh yadra sohranyat svoyu soglaso- vannost'. Predpolozhim, k primeru, chto yadro vypolnyaet dva processa, konkuriruyushchie +------------------------------------------------------------+ | #include | | /* process A */ | | main() | | { | | int fd; | | char buf[512]; | | fd = open("/etc/passwd",O_RDONLY); | | read(fd,buf,sizeof(buf)); /* chtenie1 */ | | read(fd,buf,sizeof(buf)); /* chtenie2 */ | | } | | | | /* process B */ | | main() | | { | | int fd,i; | | char buf[512]; | | for (i = 0; i < sizeof(buf); i++) | | buf[i] = 'a'; | | fd = open("/etc/passwd",O_WRONLY); | | write(fd,buf,sizeof(buf)); /* zapis'1 */ | | write(fd,buf,sizeof(buf)); /* zapis'2 */ | | } | +------------------------------------------------------------+ Risunok 5.8. Processy, vedushchie chtenie i zapis' 94 mezhdu soboj (Risunok 5.8). Esli dopustit', chto oba processa vypolnyayut opera- ciyu open do togo, kak lyuboj iz nih vyzyvaet sistemnuyu funkciyu read ili write, yadro mozhet vypolnyat' funkcii chteniya i zapisi v lyuboj iz shesti posle- dovatel'nostej: chtenie1, chtenie2, zapis'1, zapis'2, ili chtenie1, zapis'1, chtenie2, zapis'2, ili chtenie1, zapis'1, zapis'2, chtenie2 i t.d. Sostav in- formacii, schityvaemoj processom A, zavisit ot posledovatel'nosti, v kotoroj sistema vypolnyaet funkcii, vyzyvaemye dvumya processami; sistema ne garanti- ruet, chto dannye v fajle ostanutsya takimi zhe, kakimi oni byli posle otkrytiya fajla. Ispol'zovanie vozmozhnosti zahvata fajla i zapisej (razdel 5.4) pozvo- lyaet processu garantirovat' sohranenie celostnosti fajla posle ego otkrytiya. Nakonec, programma na Risunke 5.9 pokazyvaet, kak process mozhet otkry- vat' fajl bolee odnogo raza i chitat' iz nego, ispol'zuya raznye fajlovye des- kriptory. YAdro rabotaet so znacheniyami smeshchenij v tablice fajlov, associiro- vannymi s dvumya fajlovymi deskriptorami, nezavisimo, i poetomu massivy buf1 i buf2 budut po zavershenii vypolneniya processa identichny drug drugu pri us- lovii, chto ni odin process v eto vremya ne proizvodil zapis' v fajl "/etc/passwd". 5.3 WRITE Sintaksis vyzova sistemnoj funkcii write (pisat'): number = write(fd,buffer,count); gde peremennye fd, buffer, count i number imeyut tot zhe smysl, chto i dlya vy- zova sistemnoj funkcii read. Algoritm zapisi v obychnyj fajl pohozh na algo- ritm chteniya iz obychnogo fajla. Odnako, esli v fajle otsutstvuet blok, soot- vetstvuyushchij smeshcheniyu v bajtah do mesta, kuda dolzhna proizvodit'sya zapis', yadro vydelyaet blok, ispol'zuya algoritm alloc, i prisvaivaet emu nomer v so- otvetstvii s tochnym ukazaniem mesta v tablice soderzhimogo indeksa. Esli sme- shchenie v bajtah sovpadaet so smeshcheniem dlya bloka kosvennoj adresacii, yadru, vozmozhno, pridetsya vydelit' neskol'ko blokov dlya ispol'zovaniya ih v kachestve blokov kosvennoj adresacii i informaci- +------------------------------------------------------------+ | #include | | main() | | { | | int fd1,fd2; | | char buf1[512],buf2[512]; | | | | fd1 = open("/etc/passwd",O_RDONLY); | | fd2 = open("/etc/passwd",O_RDONLY); | | read(fd1,buf1,sizeof(buf1)); | | read(fd2,buf2,sizeof(buf2)); | | } | +------------------------------------------------------------+ Risunok 5.9. CHtenie iz fajla s ispol'zovaniem dvuh deskriptorov onnyh blokov. Indeks blokiruetsya na vse vremya vypolneniya funkcii write, tak kak yadro mozhet izmenit' indeks, vydelyaya novye bloki; razreshenie drugim pro- cessam obrashchat'sya k fajlu mozhet razrushit' indeks, esli neskol'ko processov vydelyayut bloki odnovremenno, ispol'zuya odni i te zhe znacheniya smeshchenij. Kogda zapis' zavershaetsya, yadro korrektiruet razmer fajla v indekse, esli fajl uve- 95 lichilsya v razmere. Predpolozhim, k primeru, chto process zapisyvaet v fajl bajt s nomerom 10240, naibol'shim nomerom sredi uzhe zapisannyh v fajle. Obrativshis' k bajtu v fajle po algoritmu bmap, yadro obnaruzhit, chto v fajle otsutstvuet ne tol'ko sootvetstvuyushchij etomu bajtu blok, no takzhe i nuzhnyj blok kosvennoj adresa- cii. YAdro naznachaet diskovyj blok v kachestve bloka kosvennoj adresacii i za- pisyvaet nomer bloka v kopii indeksa, hranyashchejsya v pamyati. Zatem ono vydelya- et diskovyj blok pod dannye i zapisyvaet ego nomer v pervuyu poziciyu vnov' sozdannogo