Disassembler

Artificial intelligence is no match for natural stupidity.
04července2012

Máte na mě vteřinku?


Víte, že letošní rok je dvojnásobně přestupný? Nejen, že jsme moli oslavit Horymírův svátek, ale v poslední červnový den se na nás přišla podívat i přestupná sekunda. Nikdo však tak úplně nepočítal s tím, jaké je tahle malá potvora schopna napáchat škody.

K čemu je to dobré?


Kdysi dávno si někdo vymyslel, že naše planeta, a vlastně i všechny ostatní planety, budou sice tak nějak kulaté, ale aby byla zábava zaručena, tak nebudou kulaté úplně. A když náš modrý šišoid běhá kolem sluníčka, u toho se otáčí kolem své osy a ještě kolem něj pobíhá Měsíc, tak se občas stane, že se někde předběhne a někde zdrží. Zdrží-li se při oběhu kolem slunce, vykoupíme si to jednou za čas přestupným rokem. Zdrží-li se však při otočení kolem své vlastní osy, je potřeba v koordinovaném časovém pásmu (UTC) zařídit také nějakou kompenzaci. O tu se postará právě přestupná vteřina. Od roku 1972, kdy byla zavedena, jsme takhle přestoupili už po pětadvacáté. A co myslíte, kolik systémů i po tolika již uskutečněných skocích ustojí injektáž jedné sekundy navíc?

Waaait for it


Stejně jako u předchozí přestupné sekundy proběhnuvší v prosinci 2008, i tentokrát tučňáci pohořeli. Důvodem byl opět livelock - tedy obdoba nekonečného cyklu, kdy program nebo jeho vlákno sice stále běží, ale ne a ne doběhnout do konce. A opět je viníkem NTP. Když ntpd zavolá funkci adjtimex(2), aby pověděl kernelu, že vkládá přestupnou sekundu, může se stát tohle:

CPU 0                                                    CPU 1
 do_adjtimex()
   spin_lock_irq(&ntp_lock);
     process_adjtimex_modes();  timer_interrupt()
       process_adj_status();                                do_timer()
         ntp_start_leap_timer();                             write_lock(&xtime_lock);
           hrtimer_start();                                  update_wall_time();
              hrtimer_reprogram();                            ntp_tick_length()
                tick_program_event()                            spin_lock(&ntp_lock);
                  clockevents_program_event()
    ktime_get()
                      seq = req_seqbegin(xtime_lock);

Chcete tu hromadu písmenek vysvětlit? Asi jo, že? Na záčátek je nutno podotknout, že NTP nevsunuje onu přestupnou vteřinu ve chvíli, kdy má nastat, ale někdy během dne nastaví STA_INS flag kernelu a zavolá zmíněnou funkci adjtimex(2), aby kernel věděl, že má o půlnoci mít o vteřinu delší šichtu. Uvnitř funkce adjtimex(2) pak proběhne volání výše popsané do_adjtimex rutiny. V té se nejprve zruší všechny existující časovače hlídající přestupnou vteřinu a pak se zamkne ntp_lock spinlock, aby kernelu do nastavování času nikdo nekecal. Spinlock je druh zámku, u kterého se musí na jeho odemčení aktivně čekat - tedy pokud je uzamčen, spotřebovávají se systémové prostředky (právě tohle odlišuje livelock od obyčejného deadlocku). Pak se volají funkce process_adjtimex_modes, process_adj_status, nastaví se onen STA_INS flag a spustí se časovač, který vteřinu o půlnoci vloží. V ideálním případě by si časovač měl spustit nižší funkci hrtimer_start a pak si po sobě odemknout zámky a uklidit. Na multicore systémech se však v mnoha případech stalo to, že zatímco si jedno jádro v klidu spouštělo časovač, druhé mu mezitím zámky sebralo a tím pádem se na odemčení čekalo do nekonečna. A protože na spinlock se čeká aktivně, byla při čekání generována zátěž. Tak dlouho, dokud nepřišel admin a nepraštil do klávesnice.

Co s tím?


Postiženi jsou všichni kernelové počínaje verzí 2.6.26 a verzí 3.3 konče. Tedy všechny před commitem 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d. Bug byl štědrý ke všem a nedělal rozdíly v tom, zda jste debianisti nebo raději provozujete rudé klobouky. Zvláštní pozornost tomuto problému pak věnujte, pokud na vašich linuxech běží MySQL nebo Java, protože tihle dva se obzvlášť nádherně zasukovali.

Jako léčbu bych rozhodně doporučoval update kernelu a následný reboot, ale pokud si takový luxus nemůžete dovolit, pak zkuste

date -s "`date -u`"

Pouhý restart nemocných služeb nepomůže.

A ještě pro zajímavost - včera mi přišel mail od společnosti, u které mám pronajatý server. Žádali zákazníky, aby si zkontrolovali, zda jejich sever není také postižen. Mimoto se také zmínili, že se v jejich datacentru vinou tohoto problému zvýšila spotřeba o cca jeden megawatt. Vzhledem k tomu, že takových datacenter mají asi dvanáct, tuhle situaci jim ani trochu nezávidím.