在 Unix 的世界里,有句很經(jīng)典的話:一切對(duì)象皆是文件。這句話的意思是說,可以將 Unix 操作系統(tǒng)中所有的對(duì)象都當(dāng)成文件,然后使用操作文件的接口來(lái)操作它們。Linux 作為一個(gè)類 Unix 操作系統(tǒng),也努力實(shí)現(xiàn)這個(gè)目標(biāo)。
虛擬文件系統(tǒng)簡(jiǎn)介
為了實(shí)現(xiàn)一切對(duì)象皆是文件這個(gè)目標(biāo),Linux 內(nèi)核提供了一個(gè)中間層:虛擬文件系統(tǒng)(Virtual File System)。
如果大家使用過面向?qū)ο?a target="_blank">編程語(yǔ)言(如C++/Java等)的話,應(yīng)該對(duì)接口這個(gè)概念并不陌生。而虛擬文件系統(tǒng)類似于面向?qū)ο笾械慕涌冢x了一套標(biāo)準(zhǔn)的接口。開發(fā)者只需要實(shí)現(xiàn)這套接口,即可以使用操作文件的接口來(lái)操作對(duì)象。如下圖所示:
上圖中的藍(lán)色部分就是虛擬文件系統(tǒng)所在位置。
從上圖可以看出,虛擬文件系統(tǒng)為上層應(yīng)用提供了統(tǒng)一的接口。如果某個(gè)文件系統(tǒng)實(shí)現(xiàn)了虛擬文件系統(tǒng)的接口,那么上層應(yīng)用就能夠使用諸如open()、read()和write()等函數(shù)來(lái)操作它們。
今天,我們就來(lái)介紹虛擬文件系統(tǒng)的原理與實(shí)現(xiàn)。
虛擬文件系統(tǒng)原理
在闡述虛擬文件系統(tǒng)的原理前,我們先來(lái)介紹一個(gè) Java 例子。通過這個(gè) Java 例子,我們能夠更容易理解虛擬文件系統(tǒng)的原理。
一個(gè)Java例子
如果大家使用過 Java 編寫程序的話,那么就很容易理解虛擬文件系統(tǒng)了。我們使用 Java 的接口來(lái)模擬虛擬文件系統(tǒng)的定義:
publicinterfaceVFSFile{ intopen(Stringfile,intmode); intread(intfd,byte[]buffer,intsize); intwrite(intfd,byte[]buffer,intsize); ... }
上面定義了一個(gè)名為VFSFile的接口,接口中定義了一些方法,如open()、read()和write()等?,F(xiàn)在我們來(lái)定義一個(gè)名為Ext3File的對(duì)象來(lái)實(shí)現(xiàn)這個(gè)接口:
publicclassExt3FileimplementsVFSFile{ @Override publicintopen(Stringfile,intmode){ ... } @Override publicintread(intfd,byte[]buffer,intsize){ ... } @Override publicintwrite(intfd,byte[]buffer,intsize){ ... } ... }
現(xiàn)在我們就能使用VFSFile接口來(lái)操作Ext3File對(duì)象了,如下代碼:
publicclassMain(){ publicstaticvoidmain(String[]args){ VFSFilefile=newExt3File(); intfd=file.open("/tmp/file.txt",0); ... } }
從上面的例子可以看出,底層對(duì)象只需要實(shí)現(xiàn)VFSFile接口,就可以使用VFSFile接口相關(guān)的方法來(lái)操作對(duì)象,用戶完全不需要了解底層對(duì)象的實(shí)現(xiàn)過程。
虛擬文件系統(tǒng)原理
上面的 Java 例子已經(jīng)大概說明虛擬文件系統(tǒng)的原理,但由于 Linux 是使用 C 語(yǔ)言來(lái)編寫的,而 C 語(yǔ)言并沒有接口這個(gè)概念。所以,Linux 內(nèi)核使用了一些技巧來(lái)模擬接口這個(gè)概念。
下面來(lái)介紹一下 Linux 內(nèi)核是如何實(shí)現(xiàn)的。
1. file結(jié)構(gòu)
為了模擬接口,Linux 內(nèi)核定義了一個(gè)名為file的結(jié)構(gòu)體,其定義如下:
structfile{ ... conststructfile_operations*f_op; ... };
在 file 結(jié)構(gòu)中,最為重要的一個(gè)字段就是f_op,其類型為file_operations結(jié)構(gòu)。而file_operations結(jié)構(gòu)是由一組函數(shù)指針組成,其定義如下:
structfile_operations{ ... loff_t(*llseek)(structfile*,loff_t,int); ssize_t(*read)(structfile*,char__user*,size_t,loff_t*); ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*); ... int(*open)(structinode*,structfile*); ... };
從file_operations結(jié)構(gòu)的定義可以隱約看到接口的影子,所以可以猜想出,如果實(shí)現(xiàn)了file_operations結(jié)構(gòu)中的方法,應(yīng)該就能接入到虛擬文件系統(tǒng)中。
在 Linux 內(nèi)核中,file結(jié)構(gòu)代表著一個(gè)被打開的文件。所以,只需要將file結(jié)構(gòu)的f_op字段設(shè)置成不同文件系統(tǒng)實(shí)現(xiàn)好的方法集,那么就能夠使用不同文件系統(tǒng)的功能。
這個(gè)過程在__dentry_open()函數(shù)中實(shí)現(xiàn),如下所示:
staticstructfile* __dentry_open(structdentry*dentry, structvfsmount*mnt, tructfile*f, int(*open)(structinode*,structfile*), conststructcred*cred) { ... inode=dentry->d_inode; ... //設(shè)置file結(jié)構(gòu)的f_op字段為底層文件系統(tǒng)實(shí)現(xiàn)的方法集 f->f_op=fops_get(inode->i_fop); ... returnf; }
設(shè)置好file結(jié)構(gòu)的f_op字段后,虛擬文件系統(tǒng)就能夠使用通用的接口來(lái)操作此文件了。調(diào)用過程如下:
2. file_operations結(jié)構(gòu)
底層文件系統(tǒng)需要實(shí)現(xiàn)虛擬文件系統(tǒng)的接口,才能被虛擬文件系統(tǒng)使用。也就是說,底層文件系統(tǒng)需要實(shí)現(xiàn)file_operations結(jié)構(gòu)中的方法集。
一般底層文件系統(tǒng)會(huì)在其內(nèi)部定義好file_operations結(jié)構(gòu),并且填充好其方法集中的函數(shù)指針。如minix文件系統(tǒng)就定義了一個(gè)名為minix_file_operations的file_operations結(jié)構(gòu)。其定義如下:
//文件:fs/minix/file.c conststructfile_operationsminix_file_operations={ .llseek=generic_file_llseek, .read=do_sync_read, .aio_read=generic_file_aio_read, .write=do_sync_write, .aio_write=generic_file_aio_write, .mmap=generic_file_mmap, .fsync=generic_file_fsync, .splice_read=generic_file_splice_read, };
也就是說,如果當(dāng)前使用的是 minix 文件系統(tǒng),當(dāng)使用read()函數(shù)讀取其文件的內(nèi)容時(shí),那么最終將會(huì)調(diào)用do_sync_read()函數(shù)來(lái)讀取文件的內(nèi)容。
3. dentry結(jié)構(gòu)
到這里,虛擬文件系統(tǒng)的原理基本分析完畢,但還有兩個(gè)非常重要的結(jié)構(gòu)要介紹一下的:dentry和inode。
dentry結(jié)構(gòu)表示一個(gè)打開的目錄項(xiàng),當(dāng)我們打開文件/usr/local/lib/libc.so文件時(shí),內(nèi)核會(huì)為文件路徑中的每個(gè)目錄創(chuàng)建一個(gè)dentry結(jié)構(gòu)。如下圖所示:
可以看到,file結(jié)構(gòu)有個(gè)指向dentry結(jié)構(gòu)的指針,如下所示:
structfile{ ... structpathf_path; ... conststructfile_operations*f_op; ... }; structpath{ ... structdentry*dentry; };
與文件類似,目錄也有相關(guān)的操作接口,所以在dentry結(jié)構(gòu)中也有操作方法集,如下所示:
structdentry{ ... structdentry*d_parent;//父目錄指針 structqstrd_name;//目錄名字 structinode*d_inode;//指向inode結(jié)構(gòu) ... conststructdentry_operations*d_op;//操作方法集 ... };
其中的d_op字段就是目錄的操作方法集。
內(nèi)核在打開文件時(shí),會(huì)為路徑中的每個(gè)目錄創(chuàng)建一個(gè)dentry結(jié)構(gòu),并且使用d_parent字段來(lái)指向其父目錄項(xiàng),這樣就能通過d_parent字段來(lái)追索到根目錄。
4. inode結(jié)構(gòu)
在 Linux 內(nèi)核中,inode結(jié)構(gòu)表示一個(gè)真實(shí)的文件。為什么有了dentry結(jié)構(gòu)還需要inode結(jié)構(gòu)呢?這是因?yàn)?Linux 存在硬鏈接的概念。
例如使用以下命令為/usr/local/lib/libc.so文件創(chuàng)建一個(gè)硬鏈接:
ln/usr/local/lib/libc.so/tmp/libc.so
現(xiàn)在/usr/local/lib/libc.so和/tmp/libc.so指向同一個(gè)文件,但它們的路徑是不一樣的。所以,就需要引入inode結(jié)構(gòu)了。如下圖所示:
由于/usr/local/lib/libc.so和/tmp/libc.so指向同一個(gè)文件,所以它們都使用同一個(gè)inode對(duì)象。
inode 結(jié)構(gòu)保存了文件的所有屬性值,如文件的創(chuàng)建時(shí)間、文件所屬用戶和文件的大小等。其定義如下所示:
structinode{ ... uid_ti_uid;//文件所屬用戶 gid_ti_gid;//文件所屬組 ... structtimespeci_atime;//最后訪問時(shí)間 structtimespeci_mtime;//最后修改時(shí)間 structtimespeci_ctime;//文件創(chuàng)建時(shí)間 ... unsignedshorti_bytes;//文件大小 ... conststructfile_operations*i_fop;//文件操作方法集(用于設(shè)置file結(jié)構(gòu)) ... };
我們注意到 inode 結(jié)構(gòu)有個(gè)類型為file_operations結(jié)構(gòu)的字段i_fop,這個(gè)字段保存了文件的操作方法集。當(dāng)用戶調(diào)用open()系統(tǒng)調(diào)用打開文件時(shí),內(nèi)核將會(huì)使用inode結(jié)構(gòu)的i_fop字段賦值給file結(jié)構(gòu)的f_op字段。我們?cè)賮?lái)重溫下賦值過程:
staticstructfile* __dentry_open(structdentry*dentry, structvfsmount*mnt, tructfile*f, int(*open)(structinode*,structfile*), conststructcred*cred) { ... //文件對(duì)應(yīng)的inode對(duì)象 inode=dentry->d_inode; ... //使用inode結(jié)構(gòu)的i_fop字段賦值給file結(jié)構(gòu)的f_op字段 f->f_op=fops_get(inode->i_fop); ... returnf; }
總結(jié)
本文主要介紹了虛擬文件系統(tǒng)的基本原理,從分析中可以發(fā)現(xiàn),虛擬文件系統(tǒng)使用了類似于面向?qū)ο缶幊陶Z(yǔ)言中的接口概念。正是有了虛擬文件系統(tǒng),Linux 才能支持各種各樣的文件系統(tǒng)。
審核編輯:劉清
-
JAVA
+關(guān)注
關(guān)注
19文章
2952瀏覽量
104489 -
UNIX操作系統(tǒng)
+關(guān)注
關(guān)注
0文章
13瀏覽量
15292 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7595瀏覽量
135871 -
LINUX內(nèi)核
+關(guān)注
關(guān)注
1文章
316瀏覽量
21608
原文標(biāo)題:細(xì)說 Linux 虛擬文件系統(tǒng)原理
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論