Blog literacki, portal erotyczny - seks i humor nie z tej ziemi


Do spisu tresci tematu 6

6.3 Pisanie - funkcja write()



Spis tresci


Objasnienia: slowo dostepu,
struct file.

Funkcja write().

Struktura file_operations.

Funkcja ext2_file_write().

Zrodla informacji

Pytania i odpowiedzi





Objasnienia.

Ponizej przedstawiam znaczenie bitow slowa
dostepu do pliku zapisanego w i-wezle na polu mode.



bit setuid - bit nadawania efektywnego identyfikatora uzytkownika (fsuid)
dla procesu wykonujacego plik,

bit setgid - to samo dla fsgid,

bit przyklejania - gdy 1, to w pamieci zostaje kopia pliku po jego wykonaniu,

typ pliku (4 bity z lewej, ósemkowo):


001 - FIFO

002 - Character Device

004 - Directory

inne: Regular (zwykly), Block Device, Link, Socket.





Przyda sie jeszcze znajomosc czesci

struktury file:

struct file {


mode_t f_mode; /* tryb otwarcia pliku (pisanie/czytanie) -
to nie jest ten sam tryb, co w i-wezle (patrz wyzej) */

loff_t f_pos; /* pozycja w pliku */

struct file_operations *f_op; /* operacje
na pliku w konkretnym file-systemie */

unsigned short f_flags; /* czy plik ma szczególne wlasciwosci
(tylko do nadpisywania, niezmienialny, do pisania synchronicznego lub inne)
- dotyczy konkretnego otwarcia pliku, a nie wspolnego dla wszystkich otwarc
i-wezla*/

struct file *f_next, *f_prev; /* wskaznik do poprzedniego i
nastepnego pliku w tablicy plikow, ktora wcale nie jest tablica, ale lista
dwukierunkowa. Jadro trzyma wskaznik do pierwszego pliku. Maksymalny rozmiar
tej listy to 1024 = NR_FILE = maksymalna liczba plikow otwartych w systemie
*/

struct inode *f_inode; /* i-wezel odpowiadajacy plikowi */

... (i inne, dla mojego tematu nieistotne)


}




Ponizej przedstawiam funkcje (jedna) z wirtualego
file-systemu. Oznacza to, ze jest ona niezalezna od file-systemu, ktory
sobie zainstalowalismy.

Funkcja write()

Sluzy do pisania do pliku (w tym rowniez gniazda, gdyz gniazdo jest
typem pliku).

DEFINICJA: int write(unsigned int fd, char *buf, unsigned int licznik)

WYNIK: liczba zapisanych bajtow lub blad.

DANE: deskryptor pliku (fd), wskaznik do danych do zapisania (buf),
ilosc bajtow do zapisania (licznik).

Algorytm pisania:

{


Sprawdz w tablicy plikow prawo do pisania (pole file->mode);

Jezeli licznik=0, zwroc zero;

Upewnij sie, ze:


nie ma blokady na rekord do zapisania (locks_verify_area);

mozemy czytac z obszaru pamieci wskazywanego przez buf o dlugosci
licznik (verify_area);


Jesli proces nie ma euid=0 (effective user id), czyli nie jest jednym
z superuserow, to:


skasuj bit setuid;

jezeli bit setgid jest ustawiony, a grupa nie ma prawa wykonywania
(odpowiedni bit w slowie dostepu do pliku w i-wezle jest zerem), to zostaw
bit setgid, gdyz plik jest kandydatem do obowiazkowego blokowania (mandatory
locking), w p.p. skasuj bit setgid (utrata nadawania efektywnego identyfikatora
grupy dla procesu przy pisaniu do pliku);


Opusc semafor w i-wezle (zabezpieczenie przed jednoczesnym pisaniem);

Wywolaj write dla konkretnego file-systemu lub, jesli mamy do czynienia
z gniazdem, to write dla gniazda - po prostu funkcje ze struktury file_operations;

Podnies semafor;


}




Kazdy filesystem ma swoja strukture file_operations,
w której okreslone sa charakterystyczne dla niego operacje
na plikach:

struct file_operations {


int (* lseek) (struct inode *, struct file *, off_t, int);

int (* read) (struct inode *, struct file *, char *, int);

int (* write) (struct inode *, struct file *, const char
*, int);

int (* open) (struct inode *, struct file *);

i inne ... (plik fs.h)


}

Do struktury tej prowadzi wskaznik z kazdego pliku w tablicy plikow.




Po opuszczeniu semafora, w file-systemie
Ext2 wykonywana przez jadro jest:

Funkcja ext2_file_write()

DEFINICJA: int ext2_file_write(inode *inode, file *file, char *buf,
int licznik)

WYNIK: liczba zapisanych bajtow lub blad.

DANE: plik oraz odpowiadajacy mu i-wezel, buf i licznik - to wskaznik
i rozmiar obszaru w pamieci z danymi (te same, co w funkcji write).

Algorytm pisania, c.d. :

{


Upewnij sie, ze:


file-system nie jest zamontowany read-only;

jestesmy plikiem regularnym, tzn. nie gniazdem, katalogiem, FIFO,
etc.


Jesli plik jest tylko do nadpisywania (mówi o tym pole f_flags
w strukturze file), to zacznij pisac na koncu pliku, w p.p. zacznij od
aktualnej pozycji pliku;

Oblicz numer bloku logicznego, w którym znajduje sie pozycja
w pliku, na której bedziemy pisali, oraz offset (to jest tak, ze
pozycje mozna traktowac jako adres: bity mowiace o numerze bloku i o przesunieciu);


while (licznik>0)

{


Jesli wyszlismy poza pozycje nr 2GB, to zakoncz petle, a na wartosc
wynikowa przypisz blad;

Pobierz bufor odpowiadajacy logicznemu blokowi i-wezla ( getblk()
);

Liczba bajtów do zapisania := min{liczba bajtów od
offsetu do konca bloku, licznik}. Chodzi o to, ze piszemy albo do konca
bloku, albo mniej. Urzadzenie blokowe potrafi zapisac tylko caly blok,
a nie pojedynczy bajt.

Odlicz od licznika liczbe bajtow pozostalych do konca bloku;

Jezli bufor nie jest aktualny i nie mamy go calego zapisac (po to
obliczalismy liczbe bajtow do zapisania), to wczytaj odpowiadajacy mu blok
z dysku (funkcja ll_rw_block(READ,...));

Skopiuj dane w pamieci z (argumentu funkcji) 'buf' do pobranego
bufora;

Zaktualizuj Virtual Memory Cache odnosnie danego bloku - pobierz
strone, zapisz do niej dane z bloku i zwolnij ja ( funkcja update_vm_cache()
);

Przesun pozycje do pisania w pliku oraz miejsce pobierania danych
w 'buf';

Zaznacz, ze bufor jest aktualny i nie jest brudny (brudny oznacza,
ze co innego jest na dysku, niz w pamieci, oraz dane w pamieci sa lepsze);


Jesli plik jest do pisania synchronicznego,
to zapisz bufor do tymczasowej tablicy i nie zapisuj go na dysk, dopoki
jej nie zapelnisz (rozmiar tablicy: NBUF =16);

w p.p. (zapis nie synchroniczny) zwolnij bufor;

Jesli tablica jest juz pelna, to zapisz ja cala ( funkcja ll_rw_block(WRITE,...)
) i pozwalniaj bufory;

Zajmij sie nastepnym blokiem w pliku i ustaw w nim offset na 0.



}

Jesli zostaly bufory w tymczasowej tablicy (liczba blokow nie byla
wielokrotnoscia 16), to je pozapisuj i pozwalniaj;

Jesli pozycja, w której skonczylismy pisac jest wieksza niz
rozmiar pliku, to zwieksz jego rozmiar;

Ustaw w i-wezle czas ostatniej modyfikacji pliku (mtime) i i-wezla
(ctime) na obecny;

Ustaw pozycje pliku w tablicy plików na ta, gdzie skonczylismy
pisac;

Zaznacz, ze i-wezel jest brudny.


}





Zrodla informacji


Przede wszystkim pliki zrodlowe Linuxa (tutaj bez moich komentarzy):



include/linux/fs.h
(naglowki funkcji i definicje stalych)

fs/read_write.c
(tresc funkcji write - pierwszy poziom)

fs/ext2/file.c (funkcja
ext2_file_write)


Opracowany przeze mnie kod zrodlowy - z komentarzem do prawie kazdej
linijki jest tu:


write - systemowy (cz.1)

ext2_file_write (czyli cz.2)


Maurice J.Bach "Budowa systemu operacyjnego UNIX", paragraf
5.3.




Pytania i odpowiedzi

Ogolne pytania pana Raczunasa:


1. Z jakich plikow zrodlowych Linuxa korzystali Panstwo przy opracowywaniu
tematu?

Z plikow wymienionych w zrodlach informacji.

2. Jakie struktury danych znalezione w tych plikach uwazaja za najwazniejsze?

Oczywiscie b.wazna jest struktura file i
slowo dostepu do pliku.

3. Jakie znalezione w plikach zrodlowych rozwiazanie programistyczne
uwazaja Panstwo za najciekawsze?

Pisanie z opoznieniem po 16 blokow w funkcji
ext2_file_write.

4. Jakie znalezli (w tej konkretnej wersji Linuxa) ograniczenia
na rozne zasoby systemowe?

Liczba otwartych plikow nie moze byc wieksza niz 1024 (NR_FILE) oraz
liczba plikow otwartych przez jeden proces nie moze byc wieksza niz 256
(NR_OPEN).


Inne pytania:

5. Czy stale O_NONBLOCK i O_NDELAY maja taka sama wartosc? (odnosnie
funkcji open)

Tak.




Autor: Mateusz Hauzer
E-mail: mhauzer@students.mimuw.edu.pl


tego samego autora: funkcja chown.
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • qualintaka.pev.pl
  •