Do spisu treści systemu plików
Na tej stronie znajduje się skomentowany kod następujących funkcji:
static void fat_prefetch (struct inode *inode, struct fat_pre *pre, int nb)
{
Super-blok jest ten sam, co super-blok i-węzła.struct super_block *sb = inode->i_sb;Pomocnicza lista wczytywanych buforów. Inicjalnie ich liczba jest zerowa.
struct buffer_head *bhreq[MSDOS_PREFETCH];
int nbreq = 0;
int i;
for (i=0; i < nb; i++)
{
Mapujemy numer pierwszego sektora do pobrania na fizyczny
numer bloku na dysku
int sector = fat_smap(inode,pre->file_sector);
if (sector != 0){
Jeżeli mapowanie się powiodło, to wczytujemy blok do bufora.
Gdy wczytywanie bloku się powiedzie, nagłówek bufora dopisujemy
do listy w strukturze "pre". Następnie sprawdzamy, czy bufor, który
mamy, jest aktualny. Jeżeli nie jest, to dopisujemy go do
pomocniczej listy "bhreq". Ustawiamy numer kolejnego bloku do
wczytywania na następny po właśnie wczytanym.
struct buffer_head *bh;
pre->file_sector++;
bh = fat_getblk(sb, sector);
if (bh == NULL) break;
pre->bhlist[pre->nblist++] = bh;
if (!fat_is_uptodate(sb,bh))
bhreq[nbreq++] = bh;
}else{
Jeżeli mapowanie się nie udało, to kończymy.break; } }Możliwe, że niektóre bufory są nieaktualne, musimy dla tych buforów wywołać "fat_ll_rw_block", aby wymusić pobranie z dysku ich aktualnej wersji. Nieaktualne bufory zostały zapisane na liście "bhreq" podczas pobierania (patrz wyżej).
if (nbreq > 0) fat_ll_rw_block (sb,READ,nbreq,bhreq);Jeżeli wczytanych buforów jest mniej niż wynosi długość listy buforów do zapełnienia, to pozostałe miejsca wypełniamy wskaźnikiem pustym.
for (i=pre->nblist; ibhlist[i] = NULL; }
int fat_file_read(struct inode *inode, struct file *filp, char *buf, int count)
{
struct super_block *sb = inode->i_sb;
char *start = buf;
char *end = buf + count;
int i;
int left_in_file;
struct fat_pre pre;
Sprawdzamy, czy parametr wskazujący na i-węzeł jest poprawny
if (!inode) {
printk("fat_file_read: inode = NULL\n");
return -EINVAL;
}
Sprawdzamy, czy ten i-węzeł wskazuje na normalny plik lub na link do
pliku. Jeśli nie, to wychodzimy z błędem. Linki występują tu w przypadku systemu
UMSDOS, przy normalnym MSDOS nie powinno ich być.
if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
printk("fat_file_read: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
Jeżeli pozycja pliku przekracza jego rozmiar zapisany w i-węźle
albo liczba bajtów do przeczytania nie jest większa niż zero, to wyjdź
z błędem.if (filp->f_pos >= inode->i_size || count <= 0) return 0;Teraz powiemy cache'owi buforów, który blok zamierzamy wczytać z wyprzedzeniem. Czytamy z wyprzedzeniem co najwyżej MSDOS_PREFETCH buforów, ponieważ jesteśmy ograniczeni pojemnością stosu, rezultat tego wczytywania (listę buforów) musimy trzymać w lokalnych tablicach. Za każdym razem, gdy dostajemy bufor, uaktualniamy jego zawartość z dysku, jeśli to potrzebne.
{
Musimy wczytywać całe bloki, więc do liczby bajtów, które chcemy
pobrać z dysku (zmienna count_max) musimy dodać liczbę bajtów, która dzieli bieżącą
pozycję w pliku od początku bloku. Zmienna to_reada jest liczbą bloków,
które chcemy wczytać, obliczamy ją biorąc sufit z ilorazu liczby bajtów
do wczytania i rozmiaru bloku. Inicjalizujemy numer bieżącego sektora,
dzieląc pozycję w pliku przez rozmiar sektora.int count_max = (filp->f_pos & (SECTOR_SIZE-1)) + count; int to_reada; pre.file_sector = filp->f_pos >> SECTOR_BITS; to_reada = count_max / SECTOR_SIZE; if (count_max & (SECTOR_SIZE-1)) to_reada++;Jeżeli ustawiony jest znacznik czytania z wyprzedzeniem, a plik, który czytamy nie jest plikiem binarnym, to będziemy czytać z wyprzedzeniem, bo przy plikach tekstowych nie wiemy z góry ile będzie trzeba przeczytać. Plików binarnych nie czytamy domyślnie z wyprzedzeniem.
if (filp->f_reada || !MSDOS_I(inode)->i_binary){
Zwiększ ilość bloków do przeczytania o ilość bloków, które należy
przeczytać z wyprzedzeniem zapisaną w globalnej zmiennej read_ahead[] dla
tego urządzenia, ale co najmniej o osiem.int ahead = read_ahead[MAJOR(inode->i_dev)]; if (ahead == 0) ahead = 8; to_reada += ahead; }Całkowita liczba bloków, które chcemy wczytać nie może być jednak większa niż pewna zadana z góry, maksymalna liczba MSDOS_PREFETCH.
if (to_reada > MSDOS_PREFETCH) to_reada = MSDOS_PREFETCH;Inicjalizujemy listę buforów ustawiając ilość buforów na liście na zero, następnie wczytujemy do buforów.
pre.nblist = 0; fat_prefetch (inode,&pre,to_reada); }Inicjalizujemy na zero indeks na liście buforów do wczytania.
pre.nolist = 0;Dopóki nie przekroczyliśmy końca pliku ani końca bufora w pamięci użytkownika, w pętli kopiujemy zawartość buforów do pamięci i doczytujemy nowe bufory z dysku, jeśli potrzeba. Wygląda to tak, że przechodzimy przez listę buforów wczytanych uprzednio, zapamiętujemy sobie wskaźnik na bieżący bufor, zaś w odpowiadającym miejscu na liście wstawiamy wskaźnik pusty. W ten sposób zostawiamy za sobą wskaźniki puste aż dojdziemy do połowy listy buforów. Jeśli dojdziemy do połowy, to tę drugą część listy przesuwamy na początek listy i dogrywamy do drugiej połówki listy buforów kolejną porcję, po czym przesuwamy się na początek listy i cały algorytm się powtarza.
while ((left_in_file = inode->i_size - filp->f_pos) > 0
&& buf < end){
Bieżącym buforem jest teraz kolejny do zapisania na liście.
Jeżeli on nie istnieje (wskaźnik na niego jest pusty), kończymy
pętlę. W przeciwnym razie zapamiętujemy sobie wskaźnik na niego
w zmiennej "bh" i ustawiamy wskaźnik odpowiadający mu na liście
na pusty oraz przesuwamy znacznik bieżącego bufora na liście.
struct buffer_head *bh = pre.bhlist[pre.nolist]; char *data; int size,offset; if (bh == NULL) break; pre.bhlist[pre.nolist] = NULL; pre.nolist++;Jeżeli doszliśmy do połowy listy, to będzie trzeba dograć bufory z dysku. Przesuwamy zawartość drugiej połowy listy na początek, aktualizujemy ilość buforów (odejmując długość połowy listy, czyli tego, co już przetworzyliśmy od ostatniego razu) i dla tak uaktualnionej struktury wywołujemy "fat_prefetch", żądając wypełnienia drugiej połowy listy. Struktura "pre" ma pole wskazujące na numer sektora, które "fat_prefetch" uaktualnia po każdym dograniu kolejnego bufora, dlatego nie musimy dodatkowo wskazywać, które bloki wczytywać. Po wczytaniu przesuwamy się na początek listy, ponieważ adres kolejnego bufora do przetworzenia teraz, po skopiowaniu, jest na początku listy.
if (pre.nolist == MSDOS_PREFETCH/2){
memcpy (pre.bhlist,pre.bhlist+MSDOS_PREFETCH/2
,(MSDOS_PREFETCH/2)*sizeof(pre.bhlist[0]));
pre.nblist -= MSDOS_PREFETCH/2;
fat_prefetch (inode,&pre,MSDOS_PREFETCH/2);
pre.nolist = 0;
}
Aktualny bufor, którego adres wcześniej zapamiętaliśmy,
może jeszcze nie być dostępny (może być w trakcie wczytywania),
więc czekamy, aż się pojawi.wait_on_buffer(bh);Jeżeli ten bufor nie jest świeży, to prawdopodobnie mamy jakiś błąd odczytu, więc zwalniamy bufor i wychodzimy z pętli.
if (!fat_is_uptodate(sb,bh)){
fat_brelse (sb, bh);
break;
}
Dane, które chcemy wczytać z pliku nie muszą koniecznie
znajdować się na początku bufora. Ustawiamy zmienne "data" i "size"
odpowiednio tak, aby wskazywały na początek i na długość obszaru
w buforze, który nas interesuje.offset = filp->f_pos & (SECTOR_SIZE-1); data = bh->b_data + offset; size = MIN(SECTOR_SIZE-offset,left_in_file);Jeżeli plik jest binarny, to po prostu kopiujemy zawartość bufora do przestrzeni użytkownika bez żadnego filtrowania (które potrzebne jest przy plikach tekstowych), ale nie więcej niż użytkownik wyspecyfikował miejsca w buforze. Używamy do tego funkcji "memcpy_tofs" (Nazwę należy rozumieć jako "memory copy to far segment", a nie jako "memory copy to filesystem"), której definicja (inline) jest w pliku "/include/asm-i386/segment.h".
if (MSDOS_I(inode)->i_binary) {
size = MIN(size,end-buf);
memcpy_tofs(buf,data,size);
buf += size;
filp->f_pos += size;
}else{
Jeżeli wczytywany plik jest plikiem tekstowym,
to opiujemy znaki z bufora do pamięci użytkownika, pomijając
znak carriage_return i interpretując ctrl-Z jako znak końca pliku
(przesuwa się znacznik bieżącej pozycji odczytywanej na koniec
pliku). Funkcja "put_user" zapisuje jeden znak do obszaru
użytkownika pod wskazany adres. Jej definicja (inline) znajduje
się w pliku "/include/asm-i386/segment.h".
for (; size && buf < end; size--) {
char ch = *data++;
filp->f_pos++;
if (ch == 26){
filp->f_pos = inode->i_size;
break;
}else if (ch != '\r'){
put_user(ch,buf++);
}
}
}
Po wczytaniu zawartości bufora do przestrzeni użytkownika
zwlaniamy bufor, nie będzie już nam potrzebny.fat_brelse(sb, bh); }Jeżeli zostały jeszcze wśród wczytanych jakieś bufory, których nie przetworzyliśmy (np. dlatego, że napotkano znak końca pliku (ctrl-Z) w pliku tekstowym), to zwalniamy tę resztę buforów.
for (i=0; i < pre.nblist; i++) fat_brelse (sb, pre.bhlist[i]);Jeżeli po tym wszystkim znacznik bieżącej pozycji w pamięci użytkownika się nie zmienił (tzn. że nie przesunęliśmy go kopiując z pliku jakieś znaki), to zwaracamy kod błędu operacji wejścia-wyjścia.
if (start == buf) return -EIO;Jeżeli ten plik nie był tylko do odczytu, to w jego i-węźle uaktulaniamy czas ostatniego dostępu na bieżący.
if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;Ustawiamy w deskryptorze pliku znacznik informujący, że dane tego pliku są wczytywane z wyprzedzeniem.
filp->f_reada = 1;Zwracamy liczbę wczytanych bajtów równą różnicy między aktualną a (zapamiętaną uprzednio) pierwotną pozycją wskaźnika do bufora w pamięci użytkownika.
return buf-start; }
int fat_file_write(
struct inode *inode,
struct file *filp,
const char *buf,
int count)
{
struct super_block *sb = inode->i_sb;
int sector,offset,size,left,written;
int error,carry;
const char *start;
char *to,ch;
struct buffer_head *bh;
int binary_mode = MSDOS_I(inode)->i_binary;
Najpierw sprawdzamy poprawność argumentów, "inode" musi
być niepusty zaś plik musi być albo linkiem, albo zwykłym plikiem.
(Linki dotyczą systemu UMSDOS).
if (!inode) {
printk("fat_file_write: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
printk("fat_file_write: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
Niektóre pliki (np. systemowe) mogą mieć zablokowane prawo
do modyfikacji. Sprawdzamy to.if (IS_IMMUTABLE(inode)) return -EPERM;Jeżeli plik jest otwarty w trybie dopisywania, ustawiamy wskaźnik bieżącej pozycji na koniec pliku. Ale uwaga: taka obsługa operacji "append" może nie działać poprawnie, jeżeli kilka procesów próbuje dopisywać naraz.
if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size;Znów sprawdzamy argumenty.
if (count <= 0) return 0;Zapisujemy w pętli porcjami, zawsze na koniec przebiegu "size" podaje rozmiar zapisanej porcji. To dopóki nie dojdziemy do końca bufora użytkownika. Przy plikach tekstowych na ogół trzeba dopisywać znak carriage-return za użytkownika (ze względu na inny format plików tekstowych w DOSie i Linuxie, w Linuxie koniec wiersza zaznacza się jedynie przez linefeed, a w DOSie przez sekwencję carriage-return i linefeed, dlatego zapisując do pliku DOSowego przed każdym linefeed trzeba dodawać carriage-return), a te znaki wstawiane są pomiędzy dane użytkownika, więc może się zdarzyć, że w jednym przebiegu nie zapiszemy całej porcji (bo część zapisanych znaków to dodatkowo wstawione znaki końca wiersza), więc po zakończeniu jednego przebiegu może zostać trochę znaków do zapisania, wówczas może być potrzebny dodatkowy przebieg pętli. Generalnie nie jest to problemem, jeżeli są jeszcze dane do zapisania, bo wtedy wskaźnik bieżącego znaku w buforze użytkownika po prostu przesunie się naprzód mniej, niż zaplanowano i zostanie to nadrobione przy następnym przebiegu pętli. Problem jest wtedy, gdy już pobrano wszystkie znaki z przestrzeni użytkownika, a jednak nie wszystko udało się zapisać na dysk. Łatwo wydedukować, że taka sytuacja może wystąpić jedynie wtedy, gdy tym znakiem, którego nie udało się zapisać jest znak linefeed, będący ostatnim znakiem w buforze użytkownika, który poprzedzono przy zapisywaniu znakiem carriage-return. Tę właśnie sytuację obsługujemy dodatkowo. Pozwala na to zmienna "carry" w warunku końca pętli. Niżej, wewnątrz pętli, znajduje się warunek, który dopisuje linefeed, kiedy znacznik "carry" jest ustawiony i kasuje ten znacznik.
error = carry = 0;
for (start = buf; count || carry; count -= size) {
Mapujemy numer sektora a obrębie pliku na fizyczny numer
sektora na dysku. Jeżeli się to nie uda, to możliwe, że jesteśmy
na końcu sektora i trzeba doalokować do pliku nowy. Wtedy wywołujemy
funkcję "fat_add_cluster", która robi to dla nas. Jej definicja
znajduje się w pliku "/fs/fat/misc.c". Jeżeli i to się nie uda,
to kończymy, obcinamy plik na bieżącej pozycji i wyskakujemy
z błędem. Jeżeli się uda, to ten nowo zaalokowany sektor
mapujemy na fizyczny numer.
while (!(sector = fat_smap(inode,filp->f_pos >> SECTOR_BITS)))
if ((error = fat_add_cluster(inode)) < 0) break;
if (error) {
fat_truncate(inode);
break;
}
Potrzebne jest jeszcze przesunięcie początku interesującego
nas obszaru względem początku sektora oraz rozmiar porcji danych
do zapisania. Porcja danych nie może być dłuższa niż odległość
od końca sektora, bo jednorazowo zapisujemy po jednym sektorze.
W ramach tego ograniczenia sztucznie ustawiamy rozmiar porcji na
jeden, jeśli w buforze użytkownika nie ma już danych (count = 0),
ale my zapisujemy jeszcze dodatkowy znak linefeed (carry = 1).
offset = filp->f_pos & (SECTOR_SIZE-1); size = MIN(SECTOR_SIZE-offset,MAX(carry,count));Jeżeli zapisywany plik jest binarny, jesteśmy na początku sektora oraz rozmiar danych do zapisania jest taki, jak rozmiar sektora lub zapisywane dane przekraczają aktualny koniec pliku, to pobieramy bufor bloku funkcją "fat_getblk", która nie próbuje wypełniać bufora aktualnymi danymi, bo w tej sytuacji i tak cała bieżąca zawartość bloku zostanie zamazana przez nowe dane.
if (binary_mode
&& offset == 0
&& (size == SECTOR_SIZE
|| filp->f_pos + size >= inode->i_size)){
if (!(bh = fat_getblk(sb,sector))){
error = -EIO;
break;
}
W przeciwnym razie korzystamy z funkcji "fat_bread",
która dodatkowo ściąga aktualną kopię bloku z dysku.
} else if (!(bh = fat_bread(sb,sector))) {
error = -EIO;
break;
}
Jeżeli plik jest binarny, to po prostu kopiujemy porcję
danych z obszaru użytkownika do bufora i przesuwamy znacznik.
if (binary_mode) {
memcpy_fromfs(bh->b_data+offset,buf,written = size);
buf += size;
} else {
Jeżeli plik nie jest binarny, to, niestety, trzeba
kopiować bajt po bajcie, bo dokonujemy konwersji pomiędzy Linuxowym
a DOSowym formatem zapisu plików tekstowych (znaki końca wiersza
etc.). Funkcja "get_user()" zdefiniowana jest (jako inline) w pliku
"/include/asm-i386/segmeng.h". Jej zadaniem jest pobranie
znaku z obszaru użytkownika spod wskazanego adresu.
written = left = SECTOR_SIZE-offset;
to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
if (carry) {
*to++ = '\n';
left--;
carry = 0;
}
for (size = 0; size < count && left; size++) {
if ((ch = get_user(buf++)) == '\n') {
*to++ = '\r';
left--;
}
if (!left) carry = 1;
else {
*to++ = ch;
left--;
}
}
written -= left;
}
Kiedy już uaktualnimy zawartość bufora danymi z pamięci
użytkownika, informujemy cache mapujący pliki do pamięci o zmianie
zawartości bufora. Funkcja "update_vm_cache" zdefiniowana jest
w pliku "mm/filemap.c".update_vm_cache(inode, filp->f_pos, bh->b_data + (filp->f_pos & (SECTOR_SIZE-1)), written);Przesuwamy wskaźnik bieżącej pozycji w pliku o ilość zapisanych znaków. Jeżeli przekroczyliśmy koniec pliku, to rozmiar pliku się zwiększył, co odnotowujemy w i-węźle. Ten i-węzeł się teraz zmienił, oznaczamy go jako brudny, do zapisania na dysk.
filp->f_pos += written;
if (filp->f_pos > inode->i_size) {
inode->i_size = filp->f_pos;
inode->i_dirt = 1;
}
Natomiast bufor oznaczamy jako posiadający aktualne dane
i, jednocześnie, jako brudny, czyli do natychmiastowego zapisania
na dysk, po czym zwalniamy ten bufor. Podsystem obsługi buforów
zapisze go na dysk.fat_set_uptodate(sb, bh, 1); fat_mark_buffer_dirty(sb, bh, 0); fat_brelse(sb, bh); }Jeżeli po tym wszystkim okazuje się, że wskaźnik aktualnej pozyji w buforze użytkownika się nie zmienił, to znaczy, że nie udało się zapisać nic. Zwracamy błąd.
if (start == buf) return error;Uaktualniamy datę w i-węźle. Nie musimy tym razem sprawdzać, czy i-węzeł ma prawo do zapisu, bo jeśli można zmieniać zawartość pliku, to można też zmieniać zawartość i-węzła. Ustawiamy dla tego i-węzła atrybut "archived" i zonaczamy jako brudny, ale nie zwalniamy, bo te modyfikacje nie mają znaczenia dla innych procesów korzystających z tego pliku. Zwracamy ostatecznie ilość zapisanych bajtów.
inode->i_mtime = inode->i_ctime = CURRENT_TIME; MSDOS_I(inode)->i_attrs |= ATTR_ARCH; inode->i_dirt = 1; return buf-start; }
void fat_truncate(struct inode *inode)
{
int cluster;
if (IS_IMMUTABLE(inode))
return;
Obliczamy ilość bloków do zwolnienia dzieląc rozmiar pliku
przez rozmiar sektora (w bajtach) i zaokrąglając w górę - w ten
sposób otrzymujemy całkowitą liczbę bloków zajętych przez plik.
Używamy jej jako parametru dla funkcji "fat_free". I-węzeł
oznaczamy jako brudny, bo jego zawartość się zmieniła.cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size; (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster); MSDOS_I(inode)->i_attrs |= ATTR_ARCH; inode->i_dirt = 1; }
struct buffer_head *fat_bread (
struct super_block *sb,
int block)
{
struct buffer_head *ret = NULL;
Rozmiar bloku może wynosić 512 bajtów lub 1k.
Dla standardowego rozmiaru bloku (512 bajtów)
wywołujemy standardową funkcję "bread" (plik "/fs/buffer.c").
if (sb->s_blocksize == 512) {
ret = bread (sb->s_dev,block,512);
} else {
Wczytujemy zatem 1k blok, dane są w pierwszej lub drugiej
połówce tego bloku, ale odczytać i tak musimy cały.
struct buffer_head *real = bread (sb->s_dev,block>>1,1024);
if (real != NULL){
Nagłówek bufora, który został stworzony przy okazji
wczytywania, nie nadaje się do zwrócenia bezpośrednio,
ponieważ dotyczy większego, jednokilobajtowego bufora.
Musimy stworzyć nowy. Używamy funkcji "kmalloc" (kernel malloc)
z pliku "/mm/kmalloc.c".
ret = (struct buffer_head *)
kmalloc (sizeof(struct buffer_head), GFP_KERNEL);
if (ret != NULL) {
Jeżeli właściwe dane zaczynają się w połowie sektora,
to musimy przesunąć dodatkowo wskaźnik. Poniżej widać, jak
połowa zaalokowanego bufora pozostaje niewykorzystana.memset (ret,0,sizeof(*ret)); ret->b_data = real->b_data; if (block & 1) ret->b_data += 512;Zwracać będziemy nowo stworzony nagłówek bufora, jednak stary musimy zapamiętać, żeby go potem móc skasować.
ret->b_next = real;
}else{
brelse (real);
}
}
}
return ret;
}
struct buffer_head *fat_getblk (
struct super_block *sb,
int block)
{
struct buffer_head *ret = NULL;
Gdy urządzenie ma bloki o długości 512 bajtów, takie,
jake ext2 (patrz też niżej, do opisu funkcji
fat_ll_rw_block()), to po prostu
wywołujemy standardową funkcję obsługi urządzenia
(zdefniowaną w "/fs/buffer.c").
if (sb->s_blocksize == 512){
ret = getblk (sb->s_dev,block,512);
}else{
Gdy urządzenie ma większe bloki, wywołujemy funkcję
dedykowaną dla systemu plików FAT.ret = fat_bread (sb,block); } return ret; }
void fat_brelse (
struct super_block *sb,
struct buffer_head *bh)
{
if (bh != NULL){
Standardowe bloki obsługujemy w standardowy sposób.
Standardowa funkcja "brelse" zdefiniowana jest w "/fs/buffer.c".
if (sb->s_blocksize == 512){
brelse (bh);
}else{
Zwalniamy niepotrzebny już bufor stworzony
przy czytaniu z dysku. Nie próbujemy odzyskiwać jego drugiej
połowy. Funkcja "kfree" zdefiniowana jest w "/mm/kmalloc.c".
brelse (bh->b_next); kfree (bh); } } }
void fat_mark_buffer_dirty (
struct super_block *sb,
struct buffer_head *bh,
int dirty_val)
{
Jeżeli mamy do czynienia z blokiem należącym do systemu
plików, w którym sektory są 1-kilobajtowe, to tym, co zapisujemy
jest jednokilobajtowy bufor wczytany z dysku, a nie jego połówka.
Standardowa fukcja "mark_buffer_dirty" zdefiniowana jest (inline)
w pliku "/include/linux/fs.h".
if (sb->s_blocksize != 512){
bh = bh->b_next;
}
mark_buffer_dirty (bh,dirty_val);
}
void fat_set_uptodate (
struct super_block *sb,
struct buffer_head *bh,
int val)
{
Podobnie jak wyżej, jeżeli mamy do czynienia z blokiem
należącym do systemu plików, w którym sektory są 1-kilobajtowe,
to tym, co zapisujemy jest jednokilobajtowy bufor wczytany z
dysku, a nie jego połówka. Standardowa funkcja
"mark_buffer_uptodate" zdefiniowana jest w "/fs/buffer.c".
if (sb->s_blocksize != 512){
bh = bh->b_next;
}
mark_buffer_uptodate(bh, val);
}
int fat_is_uptodate (
struct super_block *sb,
struct buffer_head *bh)
{
Analogicznie jak wyżej, z punktu widzenia podsystemu
obsługi buforów buforem jest całe 1k wczytane z dysku, a nie
połówka, z której korzystamy.
if (sb->s_blocksize != 512){
bh = bh->b_next;
}
Standardowa funkcja buffer_uptodate zdefiniowana jako
inline w "fs.h" zwraca po prostu wartość bitu "BH_Uptodate"
z pola "b_state" nagłówka bufora.return buffer_uptodate(bh); }
void fat_ll_rw_block (
struct super_block *sb,
int opr,
int nbreq,
struct buffer_head *bh[32])
{
Odczytujemy rozmiar bloku dyskowego z super-bloku. Jeżeli
ten rozmiar jest taki sam jak rozmiar bloku w systemie plików ext2,
czyli 512 bajtów (chodzi tu o rozmiar fizycznego bloku na dysku,
a nie logicznego, który może mieć 1024, 2048 lub 4096 bajtów),
to po prostu wywołujemy funkcję "ll_rw_block".
if (sb->s_blocksize == 512){
ll_rw_block(opr,nbreq,bh);
}else{
Jeżeli rozmiar bloku jest większy, to wielokrotnie
wywołujemy funkcję "ll_rw_block", zaś kolejne pozycje listy
nagłówków buforów wskazują kolejne bufory, do których należy czytać
lub z których należy pisać na dysk.
struct buffer_head *tmp[32];
int i;
for (i=0; i < nbreq; i++){
tmp[i] = bh[i]->b_next;
}
ll_rw_block(opr,nbreq,tmp);
}
}