『壹』 虛擬文件是什麼啊
虛擬文件系統
虛擬文件系統
作 者: difeijing
Richard Gooch
23-APR-1999
翻譯:difeijing
本文檔中的慣例用法
==================
文檔中的每一節標題的右邊都有一個字元串""。
每個小節都會有個""在右邊。
這些字元串是為了在文檔中查詢更容易而設的。
注意:本文檔的最新更新可在下面找到:
http://www.atnf.csiro.au/~rgooch/linux/docs/vfs.txt
它到底是什麼?
=============
Virtual File System(或者被稱為Virtual Filesystem Switch)是Linux內核中的一個軟體層,用於給用戶空間的程序提供文件系統介面。它也提供了內核中的一個抽象功能,允許不同的文件系統共存。
它的工作方式的概覽
==================
在這一節里,在講解細節問題之前,我會簡單扼要的介紹一下VFS是如何工作的。首先,介紹一下當用戶程序打開或者操作文件時發生了些什麼,然後看看一個文件系統是如何被支持的。
打開一個文件
------------
VFS實現了open(2)系統調用。路徑參數被VFS用來在目錄入口緩存(dentry cache or "dcache")。這提供了一個將路徑名轉化為特定的dentry的一個快的查找機制。
一個單獨的dentry通常包含一個指向i節點(inode)的指針。i節點存在於磁碟驅動器上,它可以是一個規則文件,目錄,FIFO文件,等等。 Dentry存在於RAM中,並且永遠不會被存到磁碟上:它們僅僅為了提高系統性能而存在。i節點存在於磁碟上,當需要時被拷入內存中,之後對它的任何改變將被寫回磁碟。存在於RAM中的i節點就是VFS的i節點,dentry所包含的指針指向的就是它。
dcache是你的整個文件空間的觀察點。跟Linus不同,我們中的大多數人不可能有足夠的RAM空間來放我們的文件空間的所有文件的目錄入口緩存 (dentry),所以我們的dcache會有缺少的項。為了將路徑名轉換為一個dentry,VFS不得不採取創建dentry的方式,並在創建 dentry時將指針指向相應的i節點。這是通過對i節點的查找完成的。
為了查找一個文件的i節點(通常從磁碟上讀),VFS需要調用該文件的父目錄的lookup()方法,此方法是特定的文件系統所設置的。後面對此將會有更詳盡的描述。
一旦VFS得到了所需要的dentry(同時也得到了相應的i節點),我們就能夠對文件做想要的操作:打開文件,或者用stat(2)來看i節點中的數據。stat(2)的操作非常簡單:在VFS得到dentry之後,它取得inode中的一些數據並將其中的一部分送回用戶空間。打開一個文件需要其它的操作:分配一個struct file(定義於linux/fs.h,這是內核中的文件描述)結構。新分配的struct file結構被指向dentry的指針和對文件進行操作的函數集合所初始化,這些都是從i節點中得到的。通過這種方式,特定的文件系統實現才能起作用。
文件結構(struct file)被放在進程的文件描述符表中。
讀,寫和關閉文件(或者其它的VFS操作)是通過使用用戶空間的文件描述符找到相應的文件結構(struct file),然後調用所需要的方法函數來實現的。
當文件處於打開狀態時,系統保持相應的dentry為"open"狀態(正在使用),這表示相應的i節點在被使用。
注冊和安裝一個文件系統
----------------------
如果你想在內核中支持一種新的文件系統的話,你所需要做的僅僅是調用函數register_filesystem().你向內核中傳遞一個描述文件系統實現的結構(struct filesystem), 此結構將被加入到內核的支持文件系統表中去。你可以運行下面的命令:
% cat /proc/filesystems
這樣可以看到你的系統支持哪些文件系統。
當一個mount請求出現時,VFS將會為特定的文件系統調用相應的方法。安裝點的dentry結構將會被改為指向新文件系統的根i節點。
現在是看看細節的時候了,nice to look!
struct file_system_type
=======================
此結構描述了文件系統。在內核2.1.99中,此結構的定義如下:
(注:在2.2的內核中,此結構也沒有變化)
struct file_system_type {
const char *name;
int fs_flags;
struct super_block *(*read_super) (struct super_block *, void *, int);
struct file_system_type * next;
};
其中各個域的意義:
name:文件系統的類型名稱,如"vfat","ext2",等等。
fs_flags:變數標志,如FS_REQUIRES_DEV, FS_NO_DCACHE,等等.
read_super:當此種文件系統的一個新的實例要被安裝時,此方法會被調用。
next:被內部的VFS實現所使用,你只需要將其初試化為NULL。
函數read_super具有以下的參數:
struct super_block *sb:超級塊結構。此結構的一部分被VFS初始化,餘下的部分必須被函數read_super初始化。
void * data:任意的安裝選項,通常是ASCII的字元串。
int silent:表示當出現錯誤時是否保持安靜。(不報警?)
read_super方法必須確定指定的塊設備是否包含了一個所支持的文件系統。當成功時返回超級塊結構的指針,錯誤時返回NULL。
read_super方法填充進超級塊結構(struct super_block)的最有用的域是"s_op"域。這是一個指向struct super_operations的指針,此結構描述了文件系統實現的下一層細節。
struct super_operations
=======================
此結構描述了VFS對文件系統的超級塊所能進行的操作。
在內核2.1.99中,此結構的定義如下:
(注:在2.2的內核中,此結構已經有了改變)
struct super_operations {
void (*read_inode) (struct inode *);
void (*write_inode) (struct inode *);
void (*put_inode) (struct inode *);
void (*delete_inode) (struct inode *);
int (*notify_change) (struct dentry *, struct iattr *);
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
int (*statfs) (struct super_block *, struct statfs *, int);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
};
除非特別提出,所有的方法都在未加鎖的情況下被調用,這意味著大多數方法都可以安全的被阻塞。所有的方法都僅僅在進程空間被調用(例如,在中斷處理程序和底半部中不能調用它們)
read_inode:從一個文件系統中讀取一個特定的i節點時調用此方法。i節點中的域"i_ino"被VFS初始化為指向所讀的i節點,其餘的域被此方法所填充。
write_inode:當VFS需要向磁碟上的一個i節點寫時調用。
put_inode:當VFS的i節點被從i節點緩沖池移走時被調用。此方法是可選的。
delete_inode:當VFS想刪除一個i節點時調用次方法。
notify_change:當VFS的i節點的屬性被改變時調用。若此域為NULL則VFS會調用rite_inode.此方法調用時需要鎖住內核。
put_super:當VFS要釋放超級塊時調用(umount一個文件系統).此方法調用時需要鎖住內核。
write_super:當VFS超級塊需要被寫入磁碟時被調用。此方法為可選的。
statfs:當VFS需要得到文件系統的統計數據時調用。此方法調用時需要鎖住內核。
remount_fs:當文件系統被重新安裝時調用。此方法調用時需要鎖住內核。
clear_inode:當VFS清除i節點時調用。可選項。
以上方法中,read_inode需要填充"i_op"域,此域為一個指向struct inode_operations結構的指針,它描述了能夠對一個單獨的i節點所能進行的操作。
struct inode_operations
=======================
此結構描述了VFS能夠對文件系統的一個i節點所能進行的操作。
在內核2.1.99中,此結構的定義如下:
(注:在2.2的內核中,此結構已經有了少許改變)
struct inode_operations {
struct file_operations * default_file_ops;
int (*create) (struct inode *,struct dentry *,int);
int (*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);
struct dentry * (*follow_link) (struct dentry *, struct dentry *);
int (*readpage) (struct file *, struct page *);
int (*writepage) (struct file *, struct page *);
int (*bmap) (struct inode *,int);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int);
int (*smap) (struct inode *,int);
int (*updatepage) (struct file *, struct page *, const char *,
unsigned long, unsigned int, int);
int (*revalidate) (struct dentry *);
};
default_file_ops:這是一個指向struct file_operations的指針,包含了對一個打開的文件所能進行的操作。
create:被open(2)和creat(2)所調用,僅僅在你要支持普通文件時才需要。參數中的dentry不應該包含有i節點的指針(即應該為一個negative dentry)。這里你可能需要對傳入的dentry和i節點調用函數d_instantiate.
lookup:當VFS要在一個父目錄中查找一個i節點時調用。待查找的文件名在dentry中。此方法必須調用d_add函數把找到的i節點插入到 dentry中,i節點的"i_count"域要加一。若指定的i節點不存在的話,一個NULL的i節點指針將被插入到dentry中去(這種情況的 dentry被稱為negative dentry)。Returning an error code from this routine must only be done on a real error, otherwise creating inodes with system calls like create(2), mknod(2), mkdir(2) and so on will fail.If you wish to overload the dentry methods then you should initialise the "d_dop" field in the dentry; this is a pointer to a struct "dentry_operations".This method is called with the directory semaphore held。
link:被link(2)所調用。僅在你需要支持hard link時才需要它。跟create方法相同的原因,你可能在此方法中也需要調用d_instantiate()函數來驗證。
unlink:被unlink(2)所調用。僅在你要支持對i節點的刪除時才需要它。
symlink:被symlink(2)調用。僅在需要支持符號鏈接時才需要它。通上面兩處,你需要對傳入的參數進行驗證,要調用d_instantiate()函數。
mkdir:被mkdir(2)調用。僅在你要支持建立子目錄時才需要它。同上,你需要調用d_instantiate()函數進行驗證。
rmdir:被rmdir(2)所調用。僅在你要支持對子目錄的刪除時才需要它。
mknod:被mknod(2)所調用,用於建立一個設備i節點,或者FIFO,或socket.僅當你需要支持對這些類型的i節點的建立時才需要此方法。同上面幾個,你可能也需要調用_instantiate來驗證參數。
readlink:被readlink(2)調用。僅當你要支持對符號鏈接的讀取才需要它。
follow_link:被VFS調用,用以從一個符號鏈接找到相應的i節點。僅當你需要支持符號鏈接時才需要此方法。
struct file_operations
======================
結構file_operations包含了VFS對一個已打開文件的操作。
在內核2.1.99中,此結構的定義如下:
(注:在2.2的內核中,此結構已經有了少許改變)
struct file_operations {
/*在VFS需要移動文件位置指針時被調用 */
loff_t (*llseek) (struct file *, loff_t, int);
/* 被read系統調用所使用 */
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
/* 被write系統調用所使用 */
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *);
int (*fasync) (struct file *, int);
int (*check_media_change) (kdev_t dev);
int (*revalidate) (kdev_t dev);
int (*lock) (struct file *, int, struct file_lock *);
};
llseek:當VFS需要移動文件指針的位置時調用。
read:被read(2)所調用。
write:被write(2)所調用。
readdir:當VFS需要讀取目錄中的內容時被調用。
poll: called by the VFS when a process wants to check if there is activity on this file and (optionally) go to sleep until there is activity.
(註:這里我怎麼想都翻不好,所以就把原文放在這里了,poll就是相當於select的東西)
ioctl:被ioctl(2)所調用。
mmap:被mmap(2)所調用。
open:當VFS要打開一個i節點時調用它。當VFS打開一個文件時,它建立一個新的struct file結構,並用i節點中的"default_file_ops"來初始化其中的f_op域,然後對新分配的文件結構調用open方法。你可以認為 open方法實際上屬於struct inode_operations。I think its done the way it is because it makes filesystems simpler to implement.open方法是一個很好的初始化文件結構中的"private_data"域的的地方。
release:當沒有對被打開文件的引用時調用此方法。
fsync:被fsync(2)所調用。
fasync:當用fcntl(2)激活一個文件的非同步模式時此方法被調用。
這些文件操作是由i節點所在的特定文件系統所實現的。當打開一個設備節點時(字元或塊設備特殊文件),大多數文件系統會調用VFS中的特定支持常式,由此來找到所需要的設備驅動信息;
這些支持常式用設備驅動程序的方法來代替文件系統的文件操作,然後繼續對文件調用新的open方法。這就是為什麼當你打開文件系統上的一個設備特殊文件時,最後被調用的卻是設備驅動程序的open方法。另外,devfs(Device Filesystem)有一個從設備節點到設備驅動程序的更直接的方式(這是非官方的內核補丁)
struct dentry_operations
========================
This describes how a filesystem can overload the standard dentry
operations.Dentries和dcache是屬於VFS和單個文件系統實現的,設備驅動與此無關。
在內核2.1.99中,此結構的定義如下:
(注:在2.2的內核中,此結構沒有改變)
struct dentry_operations {
int (*d_revalidate)(struct dentry *);
int (*d_hash) (struct dentry *, struct qstr *);
int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
void (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
};
d_revalidate:當VFS要使一個dentry重新生效時被調用。
d_hash:當VFS向哈希表中加入一個dentry時被調用。
d_compare:當指向一個dentry的最後的引用被去除時此方法被調用,因為這意味這沒有人在使用此dentry;當然,此dentry仍然有效,並且仍然在dcache中。
d_release: 當一個dentry被清除時調用此方法。
d_iput:當一個dentry釋放它的i節點時(在dentry被清除之前)此方法被調用。The default when this is NULL is that the VFS calls iput(). If you define this method, you must call iput() yourself.
每個dentry都有一個指向其父目錄dentry的指針,一個子dentry的哈希列表。子dentry基本上就是目錄中的文件。
dget:為一個已經存在的dentry打開一個新的句柄(這僅僅增加引用計數)
dput:關閉一個dentry的句柄(減少引用計數).如果引用計數減少為0,d_delete方法將會被調用;並且,如果此dentry仍然在其父目錄的哈希列表中的話,此dentry將被放置於一個未被使用的列表中。將dentry放置於未使用表中意味著當系統需要更多的RAM時,將會遍歷未使用的 dentry的列表,並回收其內存空間。假如當detry的引用計數為0時,它已經沒有在父目錄的哈希表中的話,在d_delete方法被調用之後系統就會回收起內存空間。
d_drop: 此方法將一個dentry從其父目錄的哈希列表中去掉。如果被去掉的dentry的引用計數降為0的話,系統會馬上調用d_put來去掉此dentry.
d_delete:刪除一個dentry.如果沒有別的對此dentry的打開引用的話,此dentry會變成一個negative dentry(d_iput方法會被調用);如果有別的對此dentry的引用的話,將會調用d_drop.
d_add:向父目錄的哈希列表中加入一個dentry,然後調用d_instantiate().
d_instantiate:把一個dentry加入別名哈希列表中,並更新其d_inode域為所給的i節點。i節點中的i_count域加一。假如i 節點的指針為NULL,此dentry就被稱為"negative dentry".此函數通常在為一個已存在的negative dentry建立i節點時被調用。
『貳』 既然iso文件和vhd文件都能弄成虛擬磁碟 那麼他們二者有什麼區別
iso屬於光碟鏡像文件,vhd屬於虛擬硬碟文件(微軟出品),iso文件多用於保存提取的光碟鏡像,用Winmount打開的話是光碟機圖標(只讀),想改也不是不可以(不方便,需要重新合成鏡像)vhd虛擬硬碟文件有兩個版本(大概分類)VHD/VHDX,win7及以上版本的windows系統都支持~直接從vhd文件內啟動系統,從而使安裝在物理磁碟分區里的系統文件形成一個,VHDX版本的虛擬磁碟還支持差分vhd和快速還原(雖然會默認隱藏物理C:盤),另外,vhd文件是可寫的,也廣泛用在虛擬機的虛擬磁碟文件。簡單來說就是iso是虛擬光碟文件,vhd是虛擬硬碟文件。
(可以網路:VHDX,vhd win7,iso虛擬光碟等獲得更詳細的解釋)