Milan Cizek napsal/wrote, On 09/21/09 19:31:
napise syncing disks... A vyplivne uptime.
Nic dalšího tam není.

Tak to zatuhne na DEVICE 'ad2'

Pokud ad2 fyzicky odpojim (bootuji z ad0, takze bez problemu), pak se reboot
opravdu uskutecni tak jak ma.

Jelikoz je tu nejmene jeden, ktereho zajimaji dalsi dily serialu "kdo zabil shutdown" tak sepisu kratke shrnuti.

Preci jen jsme nakonec presli k privatni komunikaci - prilis mnoho napadu nikam nevede a posilat sem rozsahlejsi vypisy taky neni vhodne. Desitku dopisu lze shrnout do par odstavcu aniz bych vas pripravil o podstatnou zapletku.

Skoncili jsme u toho, ze shutdown pocitace se nenavratne zadre behem shutdownu ovladace disku ad2.

Ta rutina (sys/dev/ata/ata-disk.c::ad_shutdown()) je primitovni - dela jen tohle: "pokud disk podporuje prikaz FLUSH tak udelej FLUSH". Konkretne zavola:

ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0);


Tahle funkce (viz sys/dev/ata/ata-queue.c) pouze vyplni predane parametry do jednoduche struktury vcetne jednoho parametru nepredaneho - timeoutu - a zavola

ata_queue_request() (stejny soubor). Tahle funkce uz je slozitejsi, jenze, vetsina z ni resi veci, tkere se naseho jednoducheho pozadavku netykaji. Nas se tyka jen to, ze je pozadavek zarazen na konec fronty (TAILQ_INSERT_TAIL) a je zavolan dispatcher (ata_start()).

Pro nas je klicovy dalsi krok:

sema_timedwait(&request->done, request->timeout * hz * 4)

To je funkce, ktera ceka az bude request vyrizen NEBO az vyprsi timeout, ktery je nastaven na 4 sekundy (mimochodem dost malo - ATA specifikace umoznuje prikazu FLUSH trvat az 30s). Pokud by funkce skoncial timeoutem tak se na consoli vypise hlaska. Ta se nam nevypisuje.

Takze vime, ze tato funkce nejenze nikdy nekonstatuje, ze pozadavek byl vyrizen, ale navic neskonci ani po ubehnuti pozadovaneho timeoutu.

Zatim jsme se nijak nevenovali prvni polovine problemu - proc neni pozadavek vyrizen (nebo prinejmensim, proc to neni rozpoznano) - je to fuk, v nejhorsim to preci ma skoncit timeoutem.

sema_timedwait() je je cekani na semafor s timeoutem.

Semafor je softwarova obdoba samoobsluhy kam se smi jen s vozikem. Prichazeji zakaznici a dokud voziky nedojdou mohou hned dovnitr. Kdyz dojdou cekaji frontu na voziky. Vime tak, ze uvnitr neni nikdy vic nez maximalni dovoleny pocet nakupujicich. Obcas nekdo zaplati a vozik vrati a prvni z fronty na voziky tak muze dovnitr. V nasem pripade je prujezdem pokladnou dokonceni zadaneho ATA pozadavku a pocatecni pocet voziku byl nastaven na nulu. sema_timedwait tak efektivne ceka na vyrizeni pozadavku. Nebo timeout, protoze toto cekani je s timeoutem.

Zjistime, ze v nasem pripade funkce nikdy neskonci. Podle ni nedoslo ani k vyrizeni pozadavku ani k timeoutu. Takze se musime podivat do ni (viz sys/kern/kern_sema.c)

Je trivialni - vsechno tam vlastne dela "nekonecna" smycka ktera vola cv_timedwait().

cv je "cekani na udalost". To je do znacne miry velice podobne semaforum s tim rozdilem, ze cekat nelze na minule udalosti - jen budouci. Zatimco u semaforu muzu prijit a pokud jsou "kosiky volne" tak ihned jit, v pripade cekani na udalost minule udalosti nehraji roli. Cekame udalost ktera nastane od ted dal. V nasem pripade je udalosti "nekdo vratil kosik" - teda chtel jsem rict - byla zvysena hodnota semaforu. Zvyseni hodnoty semaforu (a tim prehozeni na zelenou) by zajistila rutina ata_complete pote, co je dokonceno vyrizeni ATA requestu.

Cekani navic muze byt ukonceno prerusenim a v pripade timedwait take uplynutim timeoutu.

Takze - cv_timedwait() (viz sys/kern/kern_cond.c) muze skoncit ve trech pripadech - zvysila se hodnota semaforu (hodnoty > 0 se povazuji za "zelene svetlo", =0 za "cervene") nebo tak, ze vyprsel timeout nebo bylo cekani preruseno. Kvuli te treti moznosti je cekani ve smycce - zavola cekani znovu.

Skutecna implementace je ale ve skutecnosti nedokonala a komentar spravne upozornuje, ze pri prilis castem prerusovani cekani k timeoutu nikdy nedojde (po preruseni se totiz pocita "od pocatku"). Vypadalo to, jako by to mohl byt nas pripad - vypadalo to moc nadejne.

Bohuzel, testem se ukazalo, ze preruseni nedochazi vubec. Ke zmene promenne semaforu take ne (jak uz jsem psal k te by doslo, kdyby byl pozadavek vyrizen) - a nedojde ani k timeoutu.

Takze jak vlastne cekani na udalost funguje ? Thread se uspi. Vzbudit ho muze krome "vseobecnych budiku" coz je prichod signalu/preruseni take to, ze nastane ocekavana udalost. Ta svoje "nastani" oznami zavolanim cv_signal(), ktere zajisti "od-uspani". My ale cekame s timeoutem - takze k uspani threadu se pouzije funkce "uspani s nastavenym budickem" - sleepq_timedwait()

Vypada to monotonne ?
Uz jedeme treti kolo zavodu
"funkce X_timedwait() je implementovana pomoci Y_timedwait()"

Jo, je to ponekud nudne. Ale uz to konci.

Timeout "uspani" je zavisi na funkci callout_reset() - to je funkce, ktera patri ke CRONu kernelove urovne. V podstate rika kernelu "za urceny cas zavolej funkci F s parametry P" - v nasem konkretnim pripade je funkce F takova, ze provede "odespani".

No a tady (nejmene dneska) skoncime. Vime, ze sleepq_timedwait() nikdy neskonci - ale nevime, jestli je to proto, ze nas thread zustal navzdy uspan (selhal kernelovy CRON a thread tudiz nebyl odespan). Nebo je to proto, ze thread sice byl odespan, ale z nejakeho duvodu nebyl uznan hodna behu.

Jedna z teorii je, ze system si predcasne zastavi "hodiny" - tim by prestal fungovat in-kernel CRON a nedoslo by k odespani. Navic by to vysvetlovalo proc neni vyrizen ATA pozadavek - i obsluha fronty je rizena casem. Ale prepnuti kernelu na jiny casovac problem nevyresilo.

Dalsi mozna teorie je vada scheduleru - tohle cele je slozite kvuli tomu, ze veci se deji, nebo prinejmensim dit mohou, soucasne (cekame az nekdo z fronty vezme a vyridi pozadavek a da nam to vedet, pritom ale samocekani je zavisle na tom, ze nekde tikaji hodiny a provadeji nejake ukony). Pokud by byl problem se schedulerem je mozne, ze ty "soucasne" veci ve skutecnosti nebezi. Nebo bezi a jsme to my, kdo od urciteho okamziku uz nebezi ac bychom podle vseho mohli.

A tohle bude zanalyzovat komplikovany. Uvidime ...

                                                Dan



--
FreeBSD mailing list (users-l@freebsd.cz)
http://www.freebsd.cz/listserv/listinfo/users-l

Odpovedet emailem