Next: Przykład funkcji VFS
Up: System Plików Wirtualny system
Previous: Wstęp
  Spis rzeczy
Subsections
Aby użytkownik miał jednakowy dostęp do każdego systemu plików, VFS wprowadza
wspólny model pliku (ang. common file model). Model ten składa się z kilku
obiektów (struktur), które udostępniają jednolity interfejs do korzystania
z systemu plików.
Z każdym z tych obiektów związana jest struktura zawierająca wskaźniki do
funkcji realizujących operacje z nim związane. Dla każdego konkretnego
systemu struktura ta zawiera wskaźniki do odpowiednich, napisanych specjalnie
dla tego systemu, funkcji.
Poniżej przedstawiam opis podstawowych obiektów i ich metod.
Superblok jest reprezentowany przez strukturę super_block zdefiniowaną
w pliku include/linux/fs.h. Superblok zawiera podstawowe informacje
o zamontowanym systemie plików i odpowiada fizycznemu superblokowi dysku.
Tablica:
Wybrane pola struct super_block
typ |
pole |
opis |
struct list_head |
s_list |
lista superbloków |
kdev_t |
s_dev |
identyfikator urządzenia |
unsigned long |
s_blocksize |
rozmiar bloku w bajtach |
unsigned char |
s_blocksize_bits |
liczba bitów rozmiaru bloku |
unsigned char |
s_dirt |
flaga modyfikacji bloku |
unsigned char |
s_posix_acl_flag |
|
unsigned long |
s_maxbytes |
maksymalny rozmiar pliku |
struct file_system_type * |
s_type |
typ systemu plików |
super_operations * |
s_op |
metody superbloku |
dquot_operations * |
dq_op |
metody limitu dyskowego |
unsigned long |
s_flags |
flagi montowania |
unsigned long |
s_magic |
numer systemu plików |
struct dentry * |
s_root |
obiekty pozycji katalogu dla katalogu montowania |
list_head |
s_dirty |
lista zmodyfikowanych i-węzłów |
list_head |
s_locked_inodes |
|
list_head |
s_files |
|
block_device * |
s_bdev |
|
list_head |
s_mounts |
wskaźnik do listy zamontowanych systemów plików |
struct quota_mount_options |
s_dquot |
opcje limitu dyskowego |
union { ... } |
u |
unia zawierająca informacje specyficzne dla danego systemu plików np. dla
ext2 będzie to struct ext2_sb_info |
struct semaphore |
s_vfs_rename_sem |
|
struct semaphore |
s_nfsd_free_path_sem |
|
|
Wszelkie modyfikacje na superbloku są odzwierciedlane na tej strukturze.
Aby uniknąć niespójności informacji, każdą
modyfikację zaznacza się za pomocą pola s_dirt. Linux okresowo
przeszukuje superbloki i uaktualnia informacje na dysku.
Wskaźnik s_op opisywanej struktury wskazuje na strukturę zawierającą
metody superbloku.
struct super_operations {
void (*read_inode) (struct inode *);
void (*read_inode2) (struct inode *, void *) ;
void (*dirty_inode) (struct inode *);
void (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
void (*write_super_lockfs) (struct super_block *);
void (*unlockfs) (struct super_block *);
int (*statfs) (struct super_block *, struct statfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
void (*umount_begin) (struct super_block *);
struct dentry * (*fh_to_dentry)(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent);
int (*dentry_to_fh)(struct dentry *, __u32 *fh, int *lenp, int need_parent);
int (*dmapi_mount_event) (struct super_block *, char *);
int (*quotactl) (struct super_block *, int, int, int, caddr_t);
};
I-węzeł (ang. i-node) odpowiada fizycznemu blokowi kontrolnemu pliku,
zawiera informacje o danym pliku. I-węzeł jednoznacznie identyfikuje plik
i jego fizyczną pozycji na dysku.
I-węzeł w pamięci reprezentowany jest przez strukturę inode.
Tablica:
Wybrane pola struct inode
typ |
pole |
opis |
struct list_head |
i_hash |
lista przemieszczania |
struct list_head |
i_list |
lista i-węzłów |
struct list_head |
i_dentry |
lista pozycji katalogu |
struck list_head |
i_dirty_buffers |
lista zmodyfikowanych i-węzłów |
unsigned long |
i_ino |
numer i-węzła |
unsigned int |
i_count |
licznik użycia |
nlink_t |
i_nlink |
liczba sztywnych dowiązań |
uid_t |
i_uid |
identyfikator właściciela |
gid_t |
i_gid |
identyfikator grupy |
off_t |
i_size |
długość pliku w bajtach |
time_t |
i_atime |
czas ostatniego dostępu |
time_t |
i_mtime |
czas ostatniego zapisu |
time_t |
i_ctime |
czas ostatniej zmiany i-węzła |
unsigned long |
i_version |
numer wersji, zwiększany automatycznie po każdym użyciu |
struct super_block * |
i_sb |
wskaźnik obiektu superbloku |
struct wait_queue * |
i_wait |
kolejka oczekiwania i-węzła |
unsigned long |
i_state |
flaga statusu i-węzła |
|
Każdy obiekt i-węzła znajduje się w jednej z następujących list podwójnych:
- lista nie używanych i-węzłów, lista ta działa jako pamięć podręczna.
- lista aktualnie używanych i-węzłów.
- lista brudnych i-węzłów, czyli takich które należy uaktualnić.
Ponieważ dany i-węzeł w systemie plików może być dostępny z różnych miejsc
(dowiązania twarde i symboliczne) i-węzeł przechowuje listę odwołujących się
do niego pozycji katalogowych i_dentry.
Z jednego i-węzła może korzystać wiele procesów w jednym czasie. Liczba
użyć jest zapisana w polu i_count. Jeśli to pole będzie miało
wartość 0 to i-węzeł nie jest używany i zostaje przeniesiony do odpowiedniej
listy.
Oprócz tego istnieje jeszcze tablica inode_hashtable, na której znajdują
się i-węzły z listy używanych i ,,brudnych''. Tablica ta służy do przyspieszenia
wyszukiwania i-węzłów. Pozycja w tablicy obliczana jest na podstawie
numeru i-węzła oraz adresu superbloku, który odpowiada systemowi plików,
na którym znajduje się dany plik.
VFS definiuje następujące także operacje na i-węzłach.
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int);
struct dentry * (*lookup) (struct inode *,struct dentry *);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*unlink) (struct inode *,struct dentry *);
int (*symlink) (struct inode *,struct dentry *,const char *);
int (*mkdir) (struct inode *,struct dentry *,int);
int (*rmdir) (struct inode *,struct dentry *);
int (*mknod) (struct inode *,struct dentry *,int,int);
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
int (*readlink) (struct dentry *, char *,int);
int (*follow_link) (struct dentry *, struct nameidata *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int);
int (*revalidate) (struct dentry *);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct dentry *, struct iattr *);
int (*attrctl) (struct inode *, struct attr_op *, int);
int (*acl_get) (struct dentry *, struct acl *, struct acl *);
int (*acl_set) (struct dentry *, struct acl *, struct acl *);
};
Plik (ang. file) związany jest bezpośrednio z procesem korzystającym
z danego pliku. Tworzony jest w chwili otwarcia pliku. W pamięci
reprezentowany jest poprzez strukturę file.
Tablica:
Wybrane pola struct file
typ |
pole |
opis |
struct list_head |
f_list |
lista otwartych plików |
struct dentry * |
f_dentry |
wskaźnik do związanego obiektu pozycji katalogu |
struct file_operations * |
f_op |
metody pliku |
atomic_t |
f_count |
licznik użycia pliku |
unsigned int |
f_flags |
flagi określone przy otwieraniu pliku |
mode_t |
f_mode |
tryb dostępu procesu |
loff_t |
f_pos |
aktualna pozycja w pliku |
unsigned long |
f_reada |
flaga odczytu z wyprzedzeniem |
unsigned long |
f_ramax |
maksymalna liczba czytanych z wyprzedzeniem stron |
unsigned long |
f_raend |
wskaźnik pliku po ostatnim czytaniu z wyprzedzeniem |
unsigned long |
f_ralen |
liczba przeczytanych z wyprzedzeniem bajtów |
unsigned long |
f_rawin |
liczba przeczytanych z wyprzedzeniem stron |
struct fown_struct |
f_owner |
dane dla asynchronicznych operacji wejścia-wyjścia za pomocą sygnałów |
unsigned int |
f_uid |
UID użytkownika |
unsigned int |
f_gid |
GID użytkownika |
int |
f_error |
kod błędu sieciowych operacji zapisu |
unsigned long |
f_version |
numer wersji, zwiększany automatycznie po każdym użyciu |
void * |
private_data |
pole wymagane przez sterownik tty |
|
Podstawową informacją, charakterystyczną dla pliku, jest pole f_pos, czyli
aktualna pozycja w pliku. Kilka procesów może jednocześnie czytać ten
sam plik dlatego nie można tej informacji trzymać w i-węźle.
Plik jest związany z i-węzłem poprzez pozycję katalogu (pole f_dentry).
Każdy plik znajduje się w jednej z poniżej przedstawionych list:
- lista nie używanych obiektów plików (free_list). Jeśli następuje
otwarcie nowego pliku to system wykorzystuje struktury z tej listy, o ile
liczba plików na tej liście jest większa od stałej NR_RESERVED_FILES,
w przeciwnym przypadku następuje zwykła alokacja nowej struktury.
Pliki te trzymane są jako pamięć podręczna oraz jako zabezpieczenie na wypadek
wykorzystania całej pamięci dynamicznej (w tej sytuacji superużytkownik
może wykorzystać pliki z tej listy).
- lista obiektów używanych (anon_list).
VFS definiuje między innymi następujące operacje na plikach
(struct file_operations):
- llseek(file, pos, whence) - zmiana bieżącej pozycji w pliku.
- read(file, buf, count, offset) - czyta określoną przez count liczbę
bajtów.
- write(file, buf, count, offset) - zapisuje count bajtów do pliku.
- readdir(dir, dirent, filldir) - zwraca kolejny wpis w katalogu
dirent.
- poll(file, poll_table) - sprawdza czy plik jest używany i zasypia
do czasu, aż coś się wydarzy.
- ioctl(inode, file, cmd, arg) - wysyła polecenie do urządzenia
sprzętowego.
- mmap(file, vma) - odwzorowuje plik w pamięci.
- open(inode, file) - otwiera plik.
- flush(file) - funkcja wywoływana jest przy zmniejszaniu pola count.
- release(inode, file) - uwalnia obiekt pliku (f_count = 0).
- fsync(file, dentry) - zapisuje przechowywane w pamięci dane na dysk.
Obiekty pozycji katalogu są tworzone dla każdego składnika ścieżki
poszukiwanej przez proces, np. jeśli korzystamy z pliku /etc/passwd to jądro
utworzy trzy obiekty, odpowiednio dla /, etc, passwd.
Pozycja katalogu reprezentowana jest przez strukturę dentry.
struct dentry {
atomic_t d_count;
unsigned int d_flags;
struct inode * d_inode;
struct dentry * d_parent;
struct list_head d_hash;
struct list_head d_lru;
struct list_head d_child;
struct list_head d_subdirs;
struct list_head d_alias;
int d_mounted;
struct qstr d_name;
unsigned long d_time;
struct dentry_operations *d_op;
struct super_block * d_sb;
unsigned long d_vfs_flags;
void * d_fsdata;
unsigned char d_iname[DNAME_INLINE_LEN];
};
struct dentry_operations {
int (*d_revalidate)(struct dentry *, int);
int (*d_hash) (struct dentry *, struct qstr *);
int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
};
Obiekty dentry powiązane są w drzewo (drzewo katalogów) za pomocą pól:
d_parent, d_child, d_subdirs. Każda pozycja katalogowa jest
związana z pewnym i-węzłem (pole i_node).
Użytkownicy w systemie identyfikują pliki za pomocą nazw, natomiast
system identyfikuje pliki za pomocą numerów ich i_węzłów. Rolą tej stuktury
jest więc między innymi pośredniczenie między plikiem widzianym przez użytkownika
(może on być identyfikowalny poprzez wiele ścieżek) a konkretnym plikiem, i-węzłem
widzianym przez system.
Next: Przykład funkcji VFS
Up: System Plików Wirtualny system
Previous: Wstęp
  Spis rzeczy
2001-12-18