next up previous contents
Next: Przykład funkcji VFS Up: System Plików Wirtualny system Previous: Wstęp   Spis rzeczy

Subsections

Podstawowe struktury VFS

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

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ł

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:

  1. lista nie używanych i-węzłów, lista ta działa jako pamięć podręczna.
  2. lista aktualnie używanych i-węzłów.
  3. 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

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:

  1. 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).
  2. lista obiektów używanych (anon_list).

VFS definiuje między innymi następujące operacje na plikach (struct file_operations):

  1. llseek(file, pos, whence) - zmiana bieżącej pozycji w pliku.
  2. read(file, buf, count, offset) - czyta określoną przez count liczbę bajtów.
  3. write(file, buf, count, offset) - zapisuje count bajtów do pliku.
  4. readdir(dir, dirent, filldir) - zwraca kolejny wpis w katalogu dirent.
  5. poll(file, poll_table) - sprawdza czy plik jest używany i zasypia do czasu, aż coś się wydarzy.
  6. ioctl(inode, file, cmd, arg) - wysyła polecenie do urządzenia sprzętowego.
  7. mmap(file, vma) - odwzorowuje plik w pamięci.
  8. open(inode, file) - otwiera plik.
  9. flush(file) - funkcja wywoływana jest przy zmniejszaniu pola count.
  10. release(inode, file) - uwalnia obiekt pliku (f_count = 0).
  11. fsync(file, dentry) - zapisuje przechowywane w pamięci dane na dysk.

Pozycja katalogu

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 up previous contents
Next: Przykład funkcji VFS Up: System Plików Wirtualny system Previous: Wstęp   Spis rzeczy
2001-12-18