Do spisu tresci tematu 6

6.4.1 Opis dzialania blokad plikow i rekordow



Spis tresci


Opis dzialania blokad

Motywacja wprowadzenia blokad

Najlepszym przykladem motywujacym koniecznosc istnienia mechanizmu blokad jest system rezerwacji miejsc w samolotach. Bez mozliwosci blokowania plikow mogloby dojsc do takiej sytuacji:

Biuro w Nowym Jorku                     Biuro w Warszawie

Przychodzi klient proszac               Przychodzi klient proszac
o bilet z Paryza do Nicei               o bilet z Paryza do Nicei

Pani w okienku sprawdza
wolne miejsca w centrali
przez siec komputerowa                  Pani w okienku sprawdza
dowiaduje sie, ze jest jedno            wolne miejsca w centrali
                                        przez siec komputerowa
                                        dowiaduje sie, ze jest jedno

Pani wypisuje bilet klientowi
i zmniejsza ilosc wolnych miejsc.

                                        Pani wypisuje bilet klientowi
                                        i zmniejsza ilosc wolnych miejsc.

W wyniku takiego przeplotu mamy sprzedane dwa bilety na jedno miejsce, dwoch niezadowolonych klientow i informatyka, ktory napisal system, na liscie dymisji.
Drugim przykladem niezbednosci blokad jest wspolbiezne uzupelnianie i odczyt bazy danych. Jesli na przyklad w czasie generowania raportu zawierajacego wydatki firmy, zostanie usuniety rekord z wydatkiem, ktory zostal juz wydrukowany, a suma wydatkow liczona jest dopiero po wydrukowaniu wszystkich pozycji, to dochodzimy do sytuacji, w ktorej szef firmy stwierdza, ze lepiej bylo dawniej. Ksiegowa sumowala wolniej, ale nie mylila sie w rachunkach. Aby zapobiec takim sytuacjom wymyslono system blokowania plikow i rekordow.

Krotka historia blokad


Na poczatku blokady byly jedynie blokadami doradzanymi (ang. advisory), ktore nie mialy wplywu na dzialanie funkcji pisania i czytania. W tej sytuacji program nie uzywajacy mechanizmu blokad mial dalej pelny dostep do calego pliku pomimo zalozonych blokad. Wtedy juz istnialy dwa typy blokad. Pierwszy to propagowany przez standard POSIX blokowanie tylko rekordow pliku. Konkurencyjnym podejsciem jest blokowanie od razu calego pliku, a metode ta preferowal standard BSD. W Linuxie zaimplementowane zostaly obydwa standardy blokowania. Na poczatku istniala tylko jedna osobowosc blokady, ale po pewnym czasie, kiedy semantyka blokad nieco sie zmienila, zaimplementowane zostaly dwie rozdzielne osobowosci blokad. Rozdzielne oznacza takie, ktore nie moga jednoczesnie byc zakladane na jeden plik. Aby rozroznic obydwa typy blokad nazwano je POSIX i FLOCK. Byly to jednak nadal blokady doradzane, nie blokujace operacji wejscia/wyjscia. Poniewaz nie wszystkie programy sa pisane dobrze, a niektore sa wrecz beznadziejne, Linus zdecydowal o wpowadzeniu mozliwosci blokady pliku w sposob naprawde zakazujacy operacji. Wprowadzono obowiazkowe (and. mandatory) blokady wyspecyfikowane w Systemie V. Aby jednak zachowac zgodnosc ze starymi specyfikacjami nie zmieniono sposobu zakladania i zdejmowania blokad. Blokowanie obowiazkowe jest w Linuxie rozszerzeniem standardu POSIX. Zadna blokada FLOCK nie jest obowiazkowa.
Aby uzyskac obowiazkowe blokady nalezy ustawic odpowiednia opcje kompilacji jadra i potem ustawic odpowiednie flagi dla pliku, ktory ma byc blokowany tym mechanizmem. Pozwala to na posiadanie plikow blokowanych w sposob standardowy i obowiazkowy w jednym systemie.
Aby blokady dzialaly w sposob prawidlowy, powinny byc zaimplementowalne w sposob niepodzielny (ang. atomic) co od razu podsuwa mysl zlokalizowania funkcji blokujacych w jadrze systemu.

Struktury danych uzywane przy blokadach


Wewnetrzne struktury przechowujace informacje o blokadach zdefiniowane sa w pliku include/linux/fs.h :
struct file_lock {
    struct file_lock *fl_next;	   /* nastepna na liscie blokada pliku */
    struct file_lock *fl_nextlink; /* nastepna na liscie wszystkich blokad */
    struct file_lock *fl_prevlink; /* poprzednia blokada */
    struct file_lock *fl_block;    /* lista blokad spiacych na tej
                                      uzywane w blokadach FLOCK */
    struct task_struct *fl_owner;  /* wlasciciel blokady
                                      uzywane w blokadach POSIX */
    struct wait_queue *fl_wait;    /* struktura do usypiania procesow */
    struct file *fl_file;          /* wskaznik pliku, na ktory zalozono blokade
                                      uzywane w blokadach FLOCK */
    char fl_flags;                 /* typ blokady : POSIX lub FLOCK */
    char fl_type;                  /* typ blokady: czytanie, pisanie .. */
    off_t fl_start;                /* poczatek blokowanego rekordu
                                      uzywane w blokadach POSIX */
    off_t fl_end;                  /* koniec blokowanego rekordu
                                      uzywane w blokadach POSIX */
};

Instancje tej struktury sa podzielone na grupy dotyczace konkretnych plikow (i-wezlow) i podpiete sa pod pole i_flock w i-wezle. Dodatkowo wszystkie blokady wstawiane sa do listy file_lock_table wykorzystywanej na przyklad przy sprawdzaniu zastoju.

Semantyka blokad typu POSIX.

  1. Blokady zakladane sa na pewien obszar pliku
  2. Blokada moze byc typu: blokada zapisu lub blokada odczytu
  3. Blokada zwiazana jest z konkretnym procesem
  4. Lista blokad przechowywana jest i-wezle
  5. Blokady nalezace do jednego procesu nie moga sie pokrywac
  6. Blokady nalezace do jednego procesu nie koliduja ze soba
  7. Blokady dotyczace rozlacznych rekordow nie koliduja ze soba
  8. Dwie blokady czytania nie koliduja ze soba
  9. Blokady pisania koliduja ze soba jesli dotycza tego samego obszaru
  10. Dwie blokady pisania i czytania koliduja ze soba jesli dotycza tego samego obszaru
  11. Dwie blokady przecinajace sie nalezace do jednego wlasciciela i bedace jednego typu sa zamieniane na jedna blokade obejmujaca obszar obydwu blokad.
  12. Jesli wlasciciel starej blokady zaklada nowa to z obszaru przeciecia zostaje zdjeta stara blokada, a nowa zakladana jest na zadany obszar
  13. Tylko wlasciciel moze zdjac blokade.
  14. Dopuszczalne jest zdjecie blokady z czesci zajmowanego obszaru
  15. Nie mozna uspic procesu, jesli spowoduje to zastoj
  16. Zamkniecie pliku powoduje anulowanie wszystkich blokad na pliku zalozonych przez proces

Jak widac blokady POSIX sa bardzo poteznym narzedziem, pozwalajacym na zakladanie wielu blokad na jeden plik z zapewnieniem, ze nie doprowadzimy do zastoju. Operacje na blokadach POSIX wykonywane sa za pomoca funkcji systemowej fcntl(). Dawniej istniala funkcja lockf() bedaca nakladka (ang. wrapper) na funkcje fcntl() operujaca tylko na blokadach, jednak w najnowszych wersjach Linuxa nie zaimplementowano jej.

Semantyka blokad typu FLOCK.

  1. Blokady zakladane sa na caly plik
  2. Blokada moze byc dzielona (ang. shared) lub wylaczna (ang. exclusive)
  3. Blokada jest zwiazana ze wskaznikiem pliku (ang. file pointer, flick)
  4. Lista blokad przechowywana jest w i-wezle
  5. Na jeden wskaznik pliku (nie na plik) moze zostac zalozona tylko jedna blokada
  6. Dwie blokady dzielone nie koliduja ze soba
  7. Blokady wylaczne koliduja ze soba, jesli dotycza jednego pliku
  8. Blokady wylaczne i dzielone koliduja ze soba jesli dotycza tego samego pliku
  9. Jesli na wskaznik pliku zakladana jest nowa blokada, to stara jest kasowana
  10. Tylko proces majacy dostep do danego wskaznika pliku, moze zdjac blokade
  11. Blokada jest zdejmowana z calego pliku
  12. Zamkniecie pliku nie powoduje usuniecia blokad

Zwiazanie blokady ze wskaznikiem pliku powoduje, ze prawo zmiany blokady jest dziedziczone na potomkow. Nie mamy wiec mozliwosci stwierdzenia, kto jest faktycznym wlascicielem blokady. To wlasnie bylo powodem zabronienia uzywania roznych typow blokad na jednym pliku. A oto przyklad sytuacji, kiedy jestemy w zastoju i nie wiemy nawet o tym (zakladajac mozliwosc mieszania blokad) :
  1. Proces 100 zaklada blokade POSIX na czesc pliku A
  2. Proces 200 zaklada blokade FLOCK na plik B
  3. Proces 200 uruchamia proces 201 i konczy sie
  4. Proces 201 probuje zalozyc blokade FLOCK na plik A i zostaje uspiony
  5. Proces 100 probuje zalozyc blokade POSIX na plik B i zostaje uspiony

W momencie proby zakladania blokady na plik B nie mamy mozliwosci dowiedzenia sie, kto naprawde sprawuje wladze nad blokada, gdyz nie ma juz procesu ktory zalozyl blokade na plik A, a jednak istnieje proces mogacy zdjac blokade.
Ze specyfikacji wynika, ze nie da sie wprowadzic prostego mechanizmu kontroli, czy nie tworzymy zastoju procesow dla blokad typu FLOCK. Algorytm wykrywajacy taka sytuacje musialby posiadac bardzo wiele informacji o procesach, ktore kiedys istnialy. Poza tym czas potrzebny na sprawdzenie znacznie obnizylby wydajnosc systemu.
Do operacji na blokadach typu FLOCK sluzy funkcja systemowa flock().

Blokady obowiazkowe

Blokady obowiazkowe sa naturalnym rozszerzeniem blokad doradzanych. Zalozeniem implementacji bylo nie zmienianie istniejacych funkcji a jednoczesnie umozliwienie stosowania rownolegle blokad doradzanych i obowiazkowych. Zrealizowane zostalo to za pomoca zaznaczania pojedynczych plikow jako kandydatow do stosowania blokad obowiazkowych. Aby uzyskac blokady obowiazkowe nalezy ustawic bit group_id (ATTR_GID) flagi pliku oraz skasowac bit group_execute z praw dostepu. Od tej chwili blokada POSIX zalozona na ten plik bedzie obowiazujaca.
A oto semantyka blokad obowiazkowych:
  1. Blokada moze byc tylko typu POSIX
  2. Obszar zablokowany blokada F_RDLCK moze zostac odczytany przez inny proces, ale nie moze byc do niego nic zapisane. Proba zapisu spowoduje uspienie procesu do czasu zdjecia blokady.
  3. Obszar zablokowany blokada F_WRLCK nie moze zostac odczytany ani zapisany przez inny proces niz wlasciciel blokady. Proby zapisu/odczytu spowoduja uspienie procesu do czasu zdjecia blokady.
  4. Jesli plik zostal otwarty z flaga O_NONBLOCK, operacje pisania i czytania nie beda powodowaly uspienia tylko powrot z wynikiem EAGAIN.
  5. Wywolanie funkcji open() z flaga O_TRUNC lub funkcji creat() na istniejacym pliku z zalozona blokada obowiazkowa zakonczy sie wynikiem EAGAIN

Po wlaczeniu opcji blokad obowiazkowych zmienia sie dzialanie funkcji:


Bibliografia

  1. Pliki zrodlowe Linuxa:
  2. Dokumentacja do linuxa:


Autor: Andrzej Boczek