Posted on 2008-04-16 21:18
silentneil 閱讀(439)
評論(0) 編輯 收藏 引用
一、簡介:
虛擬文件系統(也叫虛擬文件系統交換層)是在內核實現的一個軟件層,它既為用戶空間程序提供文件系統接口的調用,也是保證系統內核各種文件系統實現能夠共存的抽象層。
VFS系統調用如open(2), stat(2), read(2), write(2), chmod(2)等在進程上下文中被調用。文件系統鎖在文檔Documentation/filesystems/Locking中描述。
1、目錄結構緩存(dcache)
VFS實現了open(2), stat(2), chmod(2)以及其它類似的系統調用。VFS利用傳遞給這些調用的文件路徑參數在目錄入口緩存(dcache 或者目錄機構緩存)中進行查找。通過一種快速的轉換機制將文件路徑轉化為特定的目錄入口。目錄結構緩存只存在在RAM中而從不寫入磁盤,他們只是為了提高性能而創建的。
目錄結構緩存是整個文件空間的視圖,但是絕大多數計算機并沒有足夠的空間將所有的目錄結構同時放在RAM中,因此某些緩存將會丟棄。為了解決目錄結構中的路徑,VFS也許需要按照路徑結構重新創建該緩存,并加載inode節點。這通過查找inode節點實現。
2、Inode節點對象
一個獨立的目錄結構通常會有一個指向一個inode的指針。Inodes是文件系統的對象,例如普通文件,目錄,FIFO等。他們或者存在于磁盤上(快設備文件系統)或者內存中(偽文件系統)。被請求訪問的inode從磁盤加載道內存,在修改后再寫入磁盤。
一個獨立的inode可以同時作為多個目錄結構的指針目標(如硬鏈接時會出現這種情況)。
查找一個inode時,需要通過VFS對inode的父目錄inode調用looup()方法。該方法在inode所屬的具體文件系統中實現。一旦VFS 請求了目錄結構(同時inode),我們就可以通過open(2)打開文件,或者stat(2)查看inode數據。stat(2)操作很簡單,一旦 VFS獲得了目錄結構,它就察看inode數據,并將其中某些數據傳給用戶空間。
3、文件對象
打開一個文件還需要其它的操作:獲取文件結構(內核實現的文件描述表)。最新分配的文件結構被初始化為一個指向目錄結構的指針和一組文件操作函數集合。這些數據從inode獲得。然后調用特定的文件系統實現的open()文件操作執行相關的任務。這是VFS交換功能的一個實現。文件結構被加入進程的文件表述表。
讀、寫和關閉文件(以及其它相關的VFS操作)通過用戶空間的文件描述表獲取對應的文件結構,然后調用請求的文件結構來實現需要得功能。一旦文件被打開,目錄結構將保持在使用狀態,表示VFS inode處于被訪問狀態。
二、注冊和加載文件系統
注冊和注銷一個文件系統時,使用下面的API:
#include <linux/fs.h>
extern int register_filesystem(struct file_system_type *);
extern int unregister_filesystem(struct file_system_type *);
傳遞的參數file_system_type結構描述了注冊的文件系統。當生成將一個設備掛載到文件空間的一個目錄時,VFS將調用相應文件系統所實現的get_sb()方法。接著,被掛載點的目錄結構將被更新指向新文件系統的root inode節點。
在/proc/filesystems中可以看到在內核中注冊的所有文件系統。
1、file_system_type結構
該結構對文件系統進行描述,在2.6.20內核中,其在include/linux/fs.h定義如下:
struct file_system_type {
const char *name;
int fs_flags;
int (*get_sb) (struct file_system_type *, int,
const char *, void *, struct vfsmount *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
struct list_head fs_supers;
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
};
name: 文件系統類型名,如"ext2", "iso9660", "msdos"等
fs_flags: 幾種文件系統flag標志(FS_REQUIRES_DEV, FS_NO_DCACHE等)
get_sb: 加載(mount)新的文件系統實例時會調用的方法。sb指super block
kill_sb: 卸載(unmount)文件系統實例時調用
owner: VFS內部使用,大多數情況下,應該被初始化為 THIS_MODULE
next: VFS內部使用,初始化為NULL
s_lock_key:
s_umount_key:
get_sb參數如下:
struct super_block *sb: superblock結構,該結構部分由vFS初始化,其余的在get_sb()方法中初始化
int flags: 掛載標志
const char *dev_name: 掛載的設備名
void *data: 掛載屬性選項,通常為ASCII字符串
int silent: 出錯時的處理方式
get_sb()方法必須superblock中指定的塊設備是否包含該方法支持的文件系統。執行成功,就返回指向superblock的指針,出錯則返回NULL
s_op成員是get_sb中需要關注的項,它是一個指向結構"struct super_operations"的指針,該結構描述了文件系統的底層實現。
通常,一個文件系統使用get_sb()的具體實現中的一個,并提供fill_super方法。具體方法如下:
get_sb_bdev: 掛載塊設備上的文件系統
get_sb_nodev:掛載無設備文件系統
get_sb_single:掛載在掛載點之間共享實例的文件系統
fill_super方法實現含有的變量如下:
struct super_block *sb: super_block結構,由fill_super()初始化
void *data: 掛載屬性選項,通常為ASCII字符串
int silent: 出錯時的處理方式
三、Superblock對象
一個Superblock對象代表了一個掛載的文件系統。
1、super_operations結構
該結構描述了VFS操作文件系統的方式。在2.6.20內核中,其在include/linux/fs.h定義如下:
struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
void (*read_inode) (struct inode *);
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
void (*drop_inode) (struct inode *);
void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
int (*sync_fs)(struct super_block *sb, int wait);
void (*write_super_lockfs) (struct super_block *);
void (*unlockfs) (struct super_block *);
int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
void (*umount_begin) (struct vfsmount *, int);
int (*show_options)(struct seq_file *, struct vfsmount *);
int (*show_stats)(struct seq_file *, struct vfsmount *);
#ifdef CONFIG_QUOTA
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
#endif
};
所有的方法調用時除非特別要求,不會持有任何鎖。這意味著,這些方法可以安全的阻塞。這些發放必須在進程的上下文中調用。(不能通過中斷句柄或者下半部bottom half調用——沒有進程上下文)
alloc_inode: 該方法由inode_alloc調用,為inode結構分配空間和初始化。如果未定義該方法,將分配一個簡單的inode結構。通常,alloc_inode被用來分配一個包含inode結構的大型數據結構。
destroy_inode: 該方法由destroy_inode調用,用以釋放為inode結構分配的資源。它只在alloc_inode方法被定義時有效,簡單的逆向執行(undo)alloc_inode中的處理。
read_inode: 該方法被用來從掛載的文件系統中讀取一個特定的inode。VFS設置inode結構中的i_ino成員來指示被讀取得inode。其它的成員由該方法設置。
dirty_inode: VFS調用該方法來標記一個臟inode節點。
write_inode: VFS調用該方法將inode結構協會磁盤。第二個參數標示使用同步寫還是異步方式,不是所有的文件系統都檢查該標記。
put_inode: 在VFS的inode從cache中移除時調用。。
drop_inode: 在最后一個對該inode節點的訪問操作被放棄時調用,該操作持有inode_lock自旋鎖。該方法必須或為空(NULL,通常意義上的Unix文件系統語義),或為"generic_delete_inode"(為不需要緩存inode的文件系統,以使無論i_nlink為何值的情況下,都會調用"delete_inode") "generic_delete_inode()"和曾經在 put_inode()中使用的"force_delete"行為相似,但是不會存在"force_delete"方法的競爭。
delete_inode: VFS調用該方法刪除一個inode節點。
put_super; VFS調用該方法釋放一個superblock(如umount)。在持有superblock鎖時調用
write_super: 載VFS superblock需要寫入磁盤時調用,該方法為可選。
sync_fs: 在VFS寫一個superblock相關的所有inode節點時調用。第二個參數指示是否等待所有的寫操作完成后再執行。可選。
write_super_lockfs: 在VFS鎖住一個文件系統時調用,并強制進入一致狀態。該方法現在由邏輯卷管理器(LVM)使用。
unlockfs; VFS調用該方法釋放文件系統的鎖,使其重新可寫。
statfs: 在VFS需要獲得文件系統統計信息時調用。該方法調用需要獲得內核鎖。
remount_fs: 在文件系統重新掛載時調用。該方法調用需要獲得內核鎖。
clear_inode: 在VFS清除一個inode節點試調用。可選。
umount_begin; 在VFS卸載文件系統時調用。
//sync_inodes; VFS寫superblock關聯的臟數據時調用。 --2.6.20中取消
show_options: 在VFS顯示/proc/<pid>/mounts的掛載參數時調用。
show_stats:
quota_read: VFS調用該方法讀取文件系統的配額文件。
quota_write; VFS調用該方法寫入文件系統的配額文件。
read_inode()方法負責填充i_op域,該域是一個指向inode_operations結構的指針,該結構描述了每個inodes的操作方法。
四、inode對象
inode是文件系統中的對象元素。
1、inode_operations結構
該結構描述了VFS如何操作文件系統中的inode。在2.6.20中定義如下:
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
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,dev_t);
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
int (*readlink) (struct dentry *, char __user *,int);
void * (*follow_link) (struct dentry *, struct nameidata *);
void (*put_link) (struct dentry *, struct nameidata *, void *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, struct nameidata *);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *);
void (*truncate_range)(struct inode *, loff_t, loff_t);
};
所有方法除非特別要求,調用時不必持有鎖。
create: 由open(2)和create(2)系統調用調用。只在需要支持常規文件時必須定義。獲得的目錄結構不能存在inode(如,消極entry.如果有,就不需要創建了)。也許還需要為該dentry和新創建的inode調用d_instantiate()。
lookup: 在VFS需要從父目錄里查找一個inode時調用。查找的名字從dentry中獲得。該方法將找到的inode通過調用 d_add()插入到目錄結構中。結構中的i_count項增1。如果該名字的inode不存在,則在dentry中增加一個空的inode(該 dentryb被稱為消極dentry)
link: 由link(2)系統調用調用,只在需要支持硬鏈接(hard link)時必須定義。和在create()方法中類似,需要調用d_instantiate()。
ulink: 由ulink(2)系統調用調用,只在需要支持刪除inode時必須定義。
symlink: 由symlink(2)系統調用調用,只在需要支持軟鏈接(symbolick link)時必須定義。和在create()方法中類似,需要調用d_instantiate()。
mkdir: 由mkdir(2)系統調用調用,只在需要支持軟鏈接(symbolick link)時必須定義。和在create()方法中類似,需要調用d_instantiate()。
rmdir: 由rmdir(2)系統調用調用,只在需要支持刪除子目錄時必須定義。
mknod: 由mknode(2)系統調用用來為設備(字符或塊),命名管道或者套接字創建inode時調用,只在需要支持創建這類inode時必須定義。和在create()方法中類似,需要調用d_instantiate()。
rename: 由rename(2)系統調用調用,將源inode和dentry(前兩個)改為目標inode和dentry(后兩個)的父目錄和文件名。
readlink: 由readlink(2)系統調用調用,只在需要支持軟鏈接(symbolick link)時必須定義。
follow_link: 由VFS調用,用來獲得一個軟鏈接所指向的inode,只在需要支持軟鏈接(symbolick link)時必須定義。該方法返回一個可以傳給put_link()方法的空指針。
put_link: 由VFS調用,用來釋放由follow_link分配的資源。該方法的最后一個參數是由follow_up返回的一個空指針的值參。它在頁緩存不穩定的文件系統(如,NFS)中應用。
truncate: 由VFS調用,用來改變一個文件的大小。必須在該方法調用前用需要得大小來設置inode的i_size值。該方法被truncate(2)以及相關的系統調用調用。
permission: VFS調用該方法檢查在POSIX類的文件系統上的訪問權限。
serattr: VFS調用該方法設置文件的屬性。該方法被chmod(2)以及相關的系統調用調用。
getattr: 獲得文件屬性。由stat(2)以及相關系統調用調用。
setxattr: VFS調用該方法設置文件的擴展屬性信息。擴展屬性是inode相關的"name:value"對。該方法由setxattr(2)系統調用調用。
getxattr; VFS調用該方法獲得給定文件擴展屬性的值。該方法由getxattr(2)系統調用調用。
listxattr: VFS調用該方法列出給定文件的所有擴展屬性信息。該方法由listxattr(2)系統調用調用。
removexattr: VFS調用該方法移除給定文件的所有擴展屬性信息。該方法由removexattr(2)系統調用調用。