欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Linux虛擬文件系統(tǒng)及其實(shí)例XORFS

系統(tǒng) 1941 0

用戶(hù)視角下的文件系統(tǒng)

??? “一切皆是文件”,是UNIX和Linux的基本哲學(xué)之一。Linux對(duì)于文件I/O操作,實(shí)現(xiàn)了POSIX.1和Single UNIX Specification中的接口,包括open()、read()、write()、lseek()和close()等方法。正是由于Linux所實(shí)現(xiàn)的虛擬文件系統(tǒng)對(duì)具體文件系統(tǒng)進(jìn)行了抽象,使得Linux可以方便地實(shí)現(xiàn)文件I/O操作接口。用戶(hù)視角下的文件系統(tǒng),就是一組系統(tǒng)調(diào)用接口,其與VFS的關(guān)系如下:

clip_image002

??? 每個(gè)進(jìn)程在用戶(hù)空間內(nèi)都有一張file description table,用于描述已打開(kāi)的文件。當(dāng)open()成功返回時(shí),將返回文件描述符(file description),被插入到file description table中。

clip_image004

??? 如下圖所示,當(dāng)用戶(hù)進(jìn)程調(diào)用write()方法讀取文件時(shí),將調(diào)用VFS的sys_write()方法,而在sys_write()方法中調(diào)用文件系統(tǒng)接口的具體方法進(jìn)行硬盤(pán)讀取。在Linux2.6.25以后,sys_write()為vfs_write()所替代。

clip_image006

??? vfs_write()源代碼如下:

clip_image008

??? 由此可見(jiàn),write的調(diào)用過(guò)程為:→write()→vfs_write()→file->f_op->write(),由文件系統(tǒng)提供的VFS API進(jìn)行實(shí)際的存取操作。

硬盤(pán)視角下的文件系統(tǒng)

??? Linux在硬盤(pán)上的文件系統(tǒng)與邏輯上的文件系統(tǒng)VFS完全不同。UFS(UNIX File System)基于Berkeley fast file system,如下:

clip_image010

??? UFS由許多分區(qū)構(gòu)成,可以允許分區(qū)之間采取不同的文件系統(tǒng),但同一個(gè)分區(qū)之內(nèi)必須為同一文件系統(tǒng)。上圖 啟動(dòng)塊 (Boot Block)大小確定,為1KB,由PC標(biāo)準(zhǔn)規(guī)定,用來(lái)存儲(chǔ)磁盤(pán)分區(qū)信息和啟動(dòng)信息,任何文件系統(tǒng)都不能使用啟動(dòng)塊。UFS文件系統(tǒng)將整個(gè)分區(qū)劃分成超級(jí)塊(Super Block,除塊組0之外的Super Block都為備份)、塊描述符表、i-node位圖、塊位圖、i-node表、data數(shù)據(jù)塊。

??? 超級(jí)塊 包含了關(guān)于該硬盤(pán)或分區(qū)文件系統(tǒng)的整體信息,如文件系統(tǒng)大小等。 索引結(jié)點(diǎn) ,包含了針對(duì)某一具體文件幾乎的全部信息,如文件存取權(quán)限、所有者、大小、建立時(shí)間以及對(duì)應(yīng)的目錄塊和數(shù)據(jù)塊等。 數(shù)據(jù)塊 是真正存儲(chǔ)文件內(nèi)容的位置,但索引結(jié)點(diǎn)中不包括文件名,文件名存于目錄塊。 目錄塊 里包含文件名以及文件索引結(jié)點(diǎn)編號(hào)。

clip_image012

??? 上圖中,位于數(shù)據(jù)塊中存儲(chǔ)目錄數(shù)據(jù)的directory entry均指向同一個(gè)i-node,而i-node中包括三個(gè)data block。

內(nèi)核虛擬文件系統(tǒng)VFS

內(nèi)核文件系統(tǒng)主要的四個(gè)數(shù)據(jù)結(jié)構(gòu)為:

??? superblock,代表一個(gè)具體的已掛載的文件系統(tǒng);

??? inode,代表一個(gè)具體的文件;

??? dentry,代表一個(gè)目錄項(xiàng),如/home/icanth,home和icanth都是一個(gè)目錄項(xiàng);

??? file,代表一個(gè)進(jìn)程已經(jīng)打開(kāi)的文件。

clip_image014

圖 super_block、file、dentry和inode的關(guān)系

??? 每個(gè)file結(jié)構(gòu)體都指向一個(gè)file_operations結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體的成員都是函數(shù)指針,指向?qū)崿F(xiàn)各種文件操作的內(nèi)核函數(shù)。比如在用戶(hù)程序中read一個(gè)文件描述符,read通過(guò)系統(tǒng)調(diào)用進(jìn)入內(nèi)核,然后找到這個(gè)文件描述符所指向的file結(jié)構(gòu)體,找到file結(jié)構(gòu)體所指向的file_operations結(jié)構(gòu)體,調(diào)用它的read成員所指向的內(nèi)核函數(shù)以完成用戶(hù)請(qǐng)求。在用戶(hù)程序中調(diào)用lseek、read、write、ioctl、open等函數(shù),最終都由內(nèi)核調(diào)用file_operations的各成員所指向的內(nèi)核函數(shù)完成用戶(hù)請(qǐng)求。file_operations結(jié)構(gòu)體中的release成員用于完成用戶(hù)程序的close請(qǐng)求,之所以叫release而不叫close是因?yàn)樗灰欢ㄕ娴年P(guān)閉文件,而是減少引用計(jì)數(shù),只有引用計(jì)數(shù)減到0才關(guān)閉文件。對(duì)于同一個(gè)文件系統(tǒng)上打開(kāi)的常規(guī)文件來(lái)說(shuō),read、write等文件操作的步驟和方法應(yīng)該是一樣的,調(diào)用的函數(shù)應(yīng)該是相同的,所以圖中的三個(gè)打開(kāi)文件的file結(jié)構(gòu)體指向同一個(gè)file_operations結(jié)構(gòu)體。如果打開(kāi)一個(gè)字符設(shè)備文件,那么它的read、write操作肯定和常規(guī)文件不一樣,不是讀寫(xiě)磁盤(pán)的數(shù)據(jù)塊而是讀寫(xiě)硬件設(shè)備,所以file結(jié)構(gòu)體應(yīng)該指向不同的file_operations結(jié)構(gòu)體,其中的各種文件操作函數(shù)由該設(shè)備的驅(qū)動(dòng)程序?qū)崿F(xiàn)。

??? 每個(gè)file結(jié)構(gòu)體都有一個(gè)指向dentry結(jié)構(gòu)體的指針,“dentry”是directory entry(目錄項(xiàng))的縮寫(xiě)。我們傳給open、stat等函數(shù)的參數(shù)的是一個(gè)路徑,例如/home/akaedu/a,需要根據(jù)路徑找到文件的inode。為了減少讀盤(pán)次數(shù),內(nèi)核緩存了目錄的樹(shù)狀結(jié)構(gòu),稱(chēng)為dentry cache,其中每個(gè)節(jié)點(diǎn)是一個(gè)dentry結(jié)構(gòu)體,只要沿著路徑各部分的dentry搜索即可,從根目錄/找到home目錄,然后找到akaedu目錄,然后找到文件a。dentry cache只保存最近訪問(wèn)過(guò)的目錄項(xiàng),如果要找的目錄項(xiàng)在cache中沒(méi)有,就要從磁盤(pán)讀到內(nèi)存中。

??? 每個(gè)dentry結(jié)構(gòu)體都有一個(gè)指針指向inode結(jié)構(gòu)體。inode結(jié)構(gòu)體保存著從磁盤(pán)inode讀上來(lái)的信息。在上圖的例子中,有兩個(gè)dentry,分別表示/home/akaedu/a和/home/akaedu/b,它們都指向同一個(gè)inode,說(shuō)明這兩個(gè)文件互為硬鏈接。inode結(jié)構(gòu)體中保存著從磁盤(pán)分區(qū)的inode讀上來(lái)信息,例如所有者、文件大小、文件類(lèi)型和權(quán)限位等。每個(gè)inode結(jié)構(gòu)體都有一個(gè)指向inode_operations結(jié)構(gòu)體的指針,后者也是一組函數(shù)指針指向一些完成文件目錄操作的內(nèi)核函數(shù)。和file_operations不同,inode_operations所指向的不是針對(duì)某一個(gè)文件進(jìn)行操作的函數(shù),而是影響文件和目錄布局的函數(shù),例如添加刪除文件和目錄、跟蹤符號(hào)鏈接等等,屬于同一文件系統(tǒng)的各inode結(jié)構(gòu)體可以指向同一個(gè)inode_operations結(jié)構(gòu)體。

??? inode結(jié)構(gòu)體有一個(gè)指向super_block結(jié)構(gòu)體的指針。super_block結(jié)構(gòu)體保存著從磁盤(pán)分區(qū)的超級(jí)塊讀取的信息,例如文件系統(tǒng)類(lèi)型、塊大小等。super_block結(jié)構(gòu)體的s_root成員是一個(gè)指向dentry的指針,表示這個(gè)文件系統(tǒng)的根目錄被mount到哪里,在上圖的例子中這個(gè)分區(qū)被mount到/home目錄下。

clip_image015

超級(jí)塊對(duì)象superblock

??? superblock是在<linux/fs.h>在下定義的結(jié)構(gòu)體super_block.

    
      struct super_block { //超級(jí)塊數(shù)據(jù)結(jié)構(gòu)
    
  
    
      ??????? struct list_head s_list;??????????????? /*指向超級(jí)塊鏈表的指針*/
    
  
    
      ??????? ……
    
  
    
      ??????? struct file_system_type? *s_type;?????? /*文件系統(tǒng)類(lèi)型*/
    
  
    
      ?????? struct super_operations? *s_op;???????? /*超級(jí)塊方法*/
    
  
    
      ??????? ……
    
  

struct list_head s_instances; /* 該類(lèi)型文件系統(tǒng)*/

    
      ??????? ……
    
  
    
      };
    
  
    
      ?
    
  
    
      struct super_operations { //超級(jí)塊方法
    
  
    
      ??????? ……
    
  
    
      ??????? //該函數(shù)在給定的超級(jí)塊下創(chuàng)建并初始化一個(gè)新的索引節(jié)點(diǎn)對(duì)象
    
  
    
      ??????? struct inode *(*alloc_inode)(struct super_block *sb);
    
  
    
      ?????? ……
    
  
    
      ??????? //該函數(shù)從磁盤(pán)上讀取索引節(jié)點(diǎn),并動(dòng)態(tài)填充內(nèi)存中對(duì)應(yīng)的索引節(jié)點(diǎn)對(duì)象的剩余部分
    
  

void (*read_inode) (struct inode *);

    
      ?????? ……
    
  
    
      };
    
  

索引結(jié)點(diǎn)對(duì)象inode

??? 索引節(jié)點(diǎn)對(duì)象存儲(chǔ)了文件的相關(guān)信息,代表了存儲(chǔ)設(shè)備上的一個(gè)實(shí)際的物理文件。當(dāng)一個(gè) 文件首次被訪問(wèn)時(shí),內(nèi)核會(huì)在內(nèi)存中組裝相應(yīng)的索引節(jié)點(diǎn)對(duì)象,以便向內(nèi)核提供對(duì)一個(gè)文件進(jìn)行操 作時(shí)所必需的全部信息;這些信息一部分存儲(chǔ)在磁盤(pán)特定位置,另外一部分是在加載時(shí)動(dòng)態(tài)填充的。

    
      struct inode {//索引節(jié)點(diǎn)結(jié)構(gòu)
    
  
    
      ????? ……
    
  
    
      ????? struct 
    
    
      inode_operations? *i_op;???? /*索引節(jié)點(diǎn)操作表*/
    
  
    
      ???? struct file_operations?? *i_fop;???? /*該索引節(jié)點(diǎn)對(duì)應(yīng)文件的文件操作集*/
    
  
    
      ???? struct super_block?????? *i_sb;???? /*相關(guān)的超級(jí)塊*/
    
  
    
      ???? ……
    
  
    
      };
    
  
    
      ?
    
  
    
      struct inode_operations { //索引節(jié)點(diǎn)方法
    
  
    
      ???? ……
    
  
    
      ???? //該函數(shù)為dentry對(duì)象所對(duì)應(yīng)的文件創(chuàng)建一個(gè)新的索引節(jié)點(diǎn),主要是由open()系統(tǒng)調(diào)用來(lái)調(diào)用
    
  
    
      ???? int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
    
  
    
      ?
    
  
    
      ???? //在特定目錄中尋找dentry對(duì)象所對(duì)應(yīng)的索引節(jié)點(diǎn)
    
  
    
      ???? struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
    
  
    
      ???? ……
    
  
    
      };
    
  

目錄項(xiàng)對(duì)象 dentry

??? 引入目錄項(xiàng)的概念主要是出于方便查找文件的目的。一個(gè)路徑的各個(gè)組成部分,不管是目錄還是 普通的文件,都是一個(gè)目錄項(xiàng)對(duì)象。如,在路徑/home/source/test.c中,目錄 /, home, source和文件 test.c都對(duì)應(yīng)一個(gè)目錄項(xiàng)對(duì)象。不同于前面的兩個(gè)對(duì)象,目錄項(xiàng)對(duì)象沒(méi)有對(duì)應(yīng)的磁盤(pán)數(shù)據(jù)結(jié)構(gòu),VFS在遍 歷路徑名的過(guò)程中現(xiàn)場(chǎng)將它們逐個(gè)地解析成目錄項(xiàng)對(duì)象。

    
      struct dentry {//目錄項(xiàng)結(jié)構(gòu)
    
  
    
      ???? ……
    
  
    
      ???? struct inode *d_inode;?????????? /*相關(guān)的索引節(jié)點(diǎn)*/
    
  
    
      ??? struct dentry *d_parent;???????? /*父目錄的目錄項(xiàng)對(duì)象*/
    
  
    
      ??? struct qstr d_name;????????????? /*目錄項(xiàng)的名字*/
    
  
    
      ??? ……
    
  
    
      ???? struct list_head d_subdirs;????? /*子目錄*/
    
  
    
      ??? ……
    
  
    
      ???? struct dentry_operations *d_op;? /*目錄項(xiàng)操作表*/
    
  
    
      ??? struct super_block *d_sb;??????? /*文件超級(jí)塊*/
    
  
    
      ??? ……
    
  
    
      };
    
  
    
      ?
    
  
    
      struct dentry_operations {
    
  
    
      ??? //判斷目錄項(xiàng)是否有效;
    
  
    
      ??? int (*d_revalidate)(struct dentry *, struct nameidata *);
    
  
    
      ??? //為目錄項(xiàng)生成散列值;
    
  
    
      ??? int (*d_hash) (struct dentry *, struct qstr *);
    
  
    
      ??? ……
    
  
    
      };
    
  

文件 對(duì)象 file

    
      struct file {
    
  
    
      ??? ……
    
  
    
      ???? struct list_head??????? f_list;??????? /*文件對(duì)象鏈表*/
    
  
    
      ??? struct dentry????????? *f_dentry;?????? /*相關(guān)目錄項(xiàng)對(duì)象*/
    
  
    
      ??? struct vfsmount??????? *f_vfsmnt;?????? /*相關(guān)的安裝文件系統(tǒng)*/
    
  
    
      ??? struct file_operations *f_op;?????????? /*文件操作表*/
    
  
    
      ??? ……
    
  
    
      };
    
  
    
      ?
    
  
    
      struct file_operations {
    
  
    
      ??? ……
    
  
    
      ??? //文件讀操作
    
  
    
      ??? ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    
  
    
      ??? ……
    
  
    
      ??? //文件寫(xiě)操作
    
  
    
      ??? ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    
  
    
      ??? ……
    
  
    
      ??? int (*readdir) (struct file *, void *, filldir_t);
    
  
    
      ??? ……
    
  
    
      ??? //文件打開(kāi)操作
    
  
    
      ??? int (*open) (struct inode *, struct file *);
    
  
    
      ??? ……
    
  
    
      };
    
  

文件系統(tǒng)對(duì)象

??? 根據(jù)文件系統(tǒng)所在的物理介質(zhì)和數(shù)據(jù)在物理介質(zhì)上的組織方式來(lái)區(qū)分不同的文件系統(tǒng)類(lèi)型的。 file_system_type結(jié)構(gòu)用于描述具體的文件系統(tǒng)的類(lèi)型信息。被Linux支持的文件系統(tǒng),都有且僅有一 個(gè)file_system_type結(jié)構(gòu)而不管它有零個(gè)或多個(gè)實(shí)例被安裝到系統(tǒng)中。而與此對(duì)應(yīng)的是每當(dāng)一個(gè)文件系統(tǒng)被實(shí)際安裝,就有一個(gè)vfsmount結(jié)構(gòu)體被創(chuàng)建,這個(gè)結(jié)構(gòu)體對(duì)應(yīng)一個(gè)安裝點(diǎn)。

    
      struct file_system_type {
    
  
    
      ??????? const char *name;??????????????? /*文件系統(tǒng)的名字*/
    
  
    
      ??????? struct subsystem subsys;???????? /*sysfs子系統(tǒng)對(duì)象*/
    
  
    
      ??????? int fs_flags;??????????????????? /*文件系統(tǒng)類(lèi)型標(biāo)志*/
    
  
    
      ?
    
  
    
      ??????? /*在文件系統(tǒng)被安裝時(shí),從磁盤(pán)中讀取超級(jí)塊,在內(nèi)存中組裝超級(jí)塊對(duì)象*/
    
  
    
      ??????? struct super_block *(*get_sb) (struct file_system_type*, 
    
  
    
      ??????????????????????????????????????? int, const char*, void *);
    
  
    
      ?????????? 
    
  
    
      ??????? void (*kill_sb) (struct super_block *);? /*終止訪問(wèn)超級(jí)塊*/??????????? 
    
  
    
      ??????? struct module *owner;??????????????????? /*文件系統(tǒng)模塊*/
    
  
    
      ??????? struct file_system_type * next;????????? /*鏈表中的下一個(gè)文件系統(tǒng)類(lèi)型*/
    
  
    
      ??????? struct list_head fs_supers;????????????? /*具有同一種文件系統(tǒng)類(lèi)型的超級(jí)塊對(duì)象鏈表*/
    
  
    
      };
    
  
    
      ?
    
  
    
      struct vfsmount
    
  
    
      {
    
  
    
      ??????? struct list_head mnt_hash;?????????????? /*散列表*/
    
  
    
      ??????? struct vfsmount *mnt_parent;???????????? /*父文件系統(tǒng)*/
    
  
    
      ??????? struct dentry *mnt_mountpoint;?????????? /*安裝點(diǎn)的目錄項(xiàng)對(duì)象*/
    
  
    
      ??????? struct dentry *mnt_root;???????????????? /*該文件系統(tǒng)的根目錄項(xiàng)對(duì)象*/
    
  
    
      ??????? struct super_block *mnt_sb;????????????? /*該文件系統(tǒng)的超級(jí)塊*/
    
  
    
      ??????? struct list_head mnt_mounts;???????????? /*子文件系統(tǒng)鏈表*/
    
  
    
      ??????? struct list_head mnt_child;????????????? /*子文件系統(tǒng)鏈表*/
    
  
    
      ??????? atomic_t mnt_count;????????????????????? /*使用計(jì)數(shù)*/
    
  
    
      ??????? int mnt_flags;?????????????????????????? /*安裝標(biāo)志*/
    
  
    
      ??????? char *mnt_devname;?????????????????????? /*設(shè)備文件名*/
    
  
    
      ??????? struct list_head mnt_list;?????????????? /*描述符鏈表*/
    
  
    
      ??????? struct list_head mnt_fslink;???????????? /*具體文件系統(tǒng)的到期列表*/
    
  
    
      ??????? struct namespace *mnt_namespace;???????? /*相關(guān)的名字空間*/
    
  
    
      };
    
  

打開(kāi)文件的流程

clip_image017

??? 由于sys_open()的代碼量大,函數(shù)調(diào)用關(guān)系復(fù)雜,以下主要是對(duì)該函數(shù)做整體的解析;而對(duì)其中的一些關(guān)鍵點(diǎn),則列出其關(guān)鍵代碼。

a. 從sys_open()的函數(shù)調(diào)用關(guān)系圖可以看到 ,sys_open()在做了一些簡(jiǎn)單的參數(shù)檢驗(yàn)后,就把接力棒傳給do_sys_open():

??? 1)首先,get_unused_fd()得到一個(gè)可用的文件描述符;通過(guò)該函數(shù),可知文件描述符實(shí)質(zhì)是進(jìn)程打開(kāi)文件列表中對(duì)應(yīng)某個(gè)文件對(duì)象的索引值;

??? 2)接著,do_filp_open()打開(kāi)文件,返回一個(gè)file對(duì)象,代表由該進(jìn)程打開(kāi)的一個(gè)文件;進(jìn)程通過(guò)這樣的一個(gè)數(shù)據(jù)結(jié)構(gòu)對(duì)物理文件進(jìn)行讀寫(xiě)操作。

??? 3)最后,fd_install()建立文件描述符與file對(duì)象的聯(lián)系,以后進(jìn)程對(duì)文件的讀寫(xiě)都是通過(guò)操縱該文件描述符而進(jìn)行。

b. do_filp_open()用于打開(kāi)文件 ,返回一個(gè)file對(duì)象;而打開(kāi)之前需要先找到該文件:

??? 1)open_namei()用于根據(jù)文件路徑名查找文件,借助一個(gè)持有路徑信息的數(shù)據(jù)結(jié)構(gòu)nameidata而進(jìn)行;

??? 2)查找結(jié)束后將填充有路徑信息的nameidata返回給接下來(lái)的函數(shù)nameidata_to_filp()從而得到最終的file對(duì)象;當(dāng)達(dá)到目的后,nameidata這個(gè)數(shù)據(jù)結(jié)構(gòu)將會(huì)馬上被釋放。

c.open_namei()用于查找一個(gè)文件:

??? 1)path_lookup_open()實(shí)現(xiàn)文件的查找功能;要打開(kāi)的文件若不存在,還需要有一個(gè)新建的過(guò)程,則調(diào)用path_lookup_create(),后者和前者封裝的是同一個(gè)實(shí)際的路徑查找函數(shù),只是參數(shù)不一樣,使它們?cè)谔幚砑?xì)節(jié)上有所偏差;

??? 2)當(dāng)是以新建文件的方式打開(kāi)文件時(shí),即設(shè)置了O_CREAT標(biāo)識(shí)時(shí)需要?jiǎng)?chuàng)建一個(gè)新的索引節(jié)點(diǎn),代表創(chuàng)建一個(gè)文件。在vfs_create()里的一句核心語(yǔ)句dir->i_op->create(dir, dentry, mode, nd)可知它調(diào)用了具體的文件系統(tǒng)所提供的創(chuàng)建索引節(jié)點(diǎn)的方法。注意:這邊的索引節(jié)點(diǎn)的概念,還只是位于內(nèi)存之中,它和磁盤(pán)上的物理的索引節(jié)點(diǎn)的關(guān)系就像位于內(nèi)存中和位于磁盤(pán)中的文件一樣。此時(shí)新建的索引節(jié)點(diǎn)還不能完全標(biāo)志一個(gè)物理文件的成功創(chuàng)建,只有當(dāng)把索引節(jié)點(diǎn)回寫(xiě)到磁盤(pán)上才是一個(gè)物理文件的真正創(chuàng)建。想想我們以新建的方式打開(kāi)一個(gè)文件,對(duì)其讀寫(xiě)但最終沒(méi)有保存而關(guān)閉,則位于內(nèi)存中的索引節(jié)點(diǎn)會(huì)經(jīng)歷從新建到消失的過(guò)程,而磁盤(pán)卻始終不知道有人曾經(jīng)想過(guò)創(chuàng)建一個(gè)文件,這是因?yàn)樗饕?jié)點(diǎn)沒(méi)有回寫(xiě)的緣故。

??? 3)path_to_nameidata()填充nameidata數(shù)據(jù)結(jié)構(gòu);

??? 4)may_open()檢查是否可以打開(kāi)該文件;一些文件如鏈接文件和只有寫(xiě)權(quán)限的目錄是不能被打開(kāi)的,先檢查nd->dentry->inode所指的文件是否是這一類(lèi)文件,是的話則錯(cuò)誤返回。還有一些文件是不能以TRUNC的方式打開(kāi)的,若nd->dentry->inode所指的文件屬于這一類(lèi),則顯式地關(guān)閉TRUNC標(biāo)志位。接著如果有以TRUNC方式打開(kāi)文件的,則更新nd->dentry->inode的信息。

在Linux3.2中,do_file_open->do_sys_open->do_filp_open->path_openat(nameidata)->link_path_work(pathname, nd), file = do_last

??? 查找路徑的過(guò)程定義在link_path_work中,主要傳入nameidata對(duì)象

    struct nameidata {
    struct path    path;
    struct qstr    last;
    struct path    root;
    struct inode   *inode; /* path.dentry.d_inode */
    unsigned int   flags;
    unsigned       seq;
    int            last_type;
    unsigned       depth;
    char *saved_names[MAX_NESTED_LINKS + 1];
 
    /* Intent data */
    union {
           struct open_intent open;
    } intent;
};
/*
 * Name resolution.
 * This is the basic name resolution function, turning a pathname into
 * the final dentry. We expect 'base' to be positive and a directory.
 *
 * Returns 0 and nd will have valid dentry and mnt on success.
 * Returns error and drops reference to input namei data on failure.
 */
static int link_path_walk(const char *name, struct nameidata *nd)
{
    struct path next;
    int err;
    
    while (*name=='/')
           name++;
    if (!*name)
           return 0;
 
    /* At this point we know we have a real path component. */
    for(;;) {
           unsigned long hash;
           struct qstr this;
           unsigned int c;
           int type;
 
           err = may_lookup(nd);
           if (err)
                   break;
 
           this.name = name;
           c = *(const unsigned char *)name;
 
           hash = init_name_hash();
           do {
                   name++;
                   hash = partial_name_hash(c, hash);
                   c = *(const unsigned char *)name;
           } while (c && (c != '/'));
           this.len = name - (const char *) this.name;
           this.hash = end_name_hash(hash);
 
           type = LAST_NORM;
           if (this.name[0] == '.') switch (this.len) {
                   case 2:
                           if (this.name[1] == '.') {
                                   type = LAST_DOTDOT;
                                  nd->flags |= LOOKUP_JUMPED;
                           }
                           break;
                   case 1:
                           type = LAST_DOT;
           }
           if (likely(type == LAST_NORM)) {
                   struct dentry *parent = nd->path.dentry;
                   nd->flags &= ~LOOKUP_JUMPED;
                   if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
                           err = parent->d_op->d_hash(parent, nd->inode,
                                                    &this);
                           if (err < 0)
                                  break;
                   }
           }
 
           /* remove trailing slashes? */
           if (!c)
                   goto last_component;
           while (*++name == '/');
           if (!*name)
                   goto last_component;
 
           err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
           if (err < 0)
                   return err;
 
           if (err) {
                   err = nested_symlink(&next, nd);
                   if (err)
                           return err;
           }
           if (can_lookup(nd->inode))
                   continue;
           err = -ENOTDIR; 
           break;
           /* here ends the main loop */
 
last_component:
           nd->last = this;
           nd->last_type = type;
           return 0;
    }
    terminate_walk(nd);
    return err;
}
  

一個(gè)簡(jiǎn)單的文件系統(tǒng)實(shí)現(xiàn)——XORFS

??? xorfs.c

    #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pagemap.h> /* PAGE_CACHE_SIZE */
#include <linux/fs.h>             /* This is where libfs stuff is declared */
#include <asm/atomic.h>
#include <asm/uaccess.h>   /* copy_to_user */
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
 
/*
 * Wen Hui.
 * Just for linux 2.6
 *
 * desp:
 *   innux 3.2, get_sb --> mount, 
 *     get_sb_single --> mount_single.
 */
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Wen Hui");
 
#define XORFS_MAGIC 0x20120418
#define FILE_INODE_NUMBER 2
 
/**
 * system_file_type
 */
/* get_sb */
static struct super_block * 
xorfs_get_sb(struct file_system_type *fs_type, int flags, const char *devname, void *data, struct vfsmount* mnt);
 
/* kill_sb */
static void 
xorfs_kill_sb(struct super_block *super);
 
static int 
xorfs_fill_super(struct super_block* sb, void *data, int silent);
 
 
/**
 * super_operations
 */
 
static int
xorfs_super_write_inode(struct inode *inode, struct writeback_control *wbc);
 
/*static void
xorfs_super_read_inode(struct inode *inode);*/
 
/**
 * inode_operations
 */
 
/* lookup */
static struct dentry*
xorfs_inode_lookup(struct inode*, struct dentry *, struct nameidata *);
 
static struct inode*
xorfs_iget(struct super_block *sp, unsigned long ino);
 
/**
 * file_operations
 */
static int
xorfs_file_open(struct inode *inode, struct file *file);
 
static int
xorfs_file_readdir(struct file *file, void *dirent, filldir_t filldir);
 
static int
xorfs_file_release(struct inode* ino, struct file *file);
 
static ssize_t
xorfs_file_read(struct file *file, char *buf, size_t max, loff_t* offset);
 
static ssize_t
xorfs_file_write(struct file *file, const char *buf, size_t max, loff_t* offset);
 
/**
 * address_space_operations
 */
 
/* readpage
 * old version: ->prepare_write(),->commit_write(),
 *                                        ->sync_page(),and ->readpage()
 * new version (LSF'08'): try use vm_operations
 *  instead of address_space_operations, 
 *  and a small/dummpy ->readpage is still needed because
 *  ->generic_file_mmap, still check 
 *  for the existence of the ->readpage method.
 */
static int
xorfs_readpage(struct file *file, struct page *page);
 
/* write page */
static int
xorfs_writepage(struct page *page, struct writeback_control *wbc);
 
/* write_beign */
static int 
xorfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata);
 
/* write_end */
static int 
xorfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata);
 
 
/*
 * Data declarations
 */
 
static struct super_operations xorfs_sops =
{
//  .read_inode = xorfs_super_read_inode
    .statfs = simple_statfs,
    .write_inode = &xorfs_super_write_inode
}; // struct xorfs_sops
 
static struct inode_operations xorfs_iops = 
{
    .lookup = xorfs_inode_lookup
}; // struct xorfs_iops
 
static struct file_operations xorfs_fops = 
{
    .open = xorfs_file_open,
    .read = &xorfs_file_read,
    .readdir = &xorfs_file_readdir,
    .write = &xorfs_file_write,
    .release = &xorfs_file_release,
    .fsync = &generic_file_fsync
}; // struct xorfs_fops
 
static struct file_system_type xorfs = {
    name :  "xorfs",
    get_sb :       xorfs_get_sb,
    kill_sb :      xorfs_kill_sb,
    owner : THIS_MODULE
}; // struct file_system_type
 
static struct address_space_operations xorfs_aops =
{
    .readpage = xorfs_readpage,
    .writepage = xorfs_writepage,
    .write_begin = xorfs_write_begin,
    .write_end = xorfs_write_end
}; // struct xorfs_aops
 
static struct inode *xorfs_root_inode;
 
static char file_buf[PAGE_SIZE] = "Hello World\n";
static int file_size = 12;
 
/**
 * system_file_type
 */
 
static struct super_block *
xorfs_get_sb(struct file_system_type *fs_type,
           int flags, const char *devname, void *data, struct vfsmount* mnt)
{
    printk("XORFS:xorfs_get_sb\n");
 
    return get_sb_single(fs_type, flags, data, &xorfs_fill_super, mnt);
} // xorfs_get_sb
 
static void
xorfs_kill_sb(struct super_block *super)
{
    printk("XORFS: xorfs_kill_sb\n");
 
    kill_anon_super(super);
} // xorfs_kill_sb
 
/* call the get_sb_single(), and callback the fn() */
static int 
xorfs_fill_super(struct super_block* sb, void *data, int silent)
{
    printk("XORFS: xorfs_fill_super\n");
 
    sb->s_blocksize = 1024;
    sb->s_blocksize_bits = 10;
    sb->s_magic = XORFS_MAGIC;
    sb->s_op = &xorfs_sops; // super block operation
    sb->s_type = &xorfs; // file_system_type
 
//  xorfs_root_inode = iget_locked(sb, 1); // allocate 1 node
    xorfs_root_inode = xorfs_iget(sb, 1); // allocate 1 node
    xorfs_root_inode->i_op = &xorfs_iops; // set the inode ops
    xorfs_root_inode->i_mode = S_IFDIR | S_IRWXU;
    xorfs_root_inode->i_fop = &xorfs_fops; // set the inode file operations
    // xorfs_root_inode->i_mapping->a_ops = &xorfs_aops;
 
    if(!(sb->s_root = d_alloc_root(xorfs_root_inode)))
    {
           iput( xorfs_root_inode );
           return -ENOMEM;
    } // if
 
    return 0;
} // xorfs_fill_super
 
/**
 * super_operations
 */
static int
xorfs_super_write_inode(struct inode *inode, struct writeback_control *wbc)
{
    printk("XORFS: xorfs_super_write_inode (i_ino=%d) = %d\n",
                   (int) inode->i_ino,
                   (int) i_size_read(inode));
 
    if(inode->i_ino == FILE_INODE_NUMBER)
{
           file_size = i_size_read(inode);
    }
 
    return 0;
} // xorfs_super_write_inode
 
 
/**
static void*
xorfs_super_read_inode(struct super_block *sp, struct inode *inode)
{
    inode->i_mapping->a_ops = &xorfs_aops;
} // xorfs_super_read_inode
*/
 
/**
 * inode_operations
 */
 
static char filename[] = "hello.txt";
static int filename_len = sizeof(filename) - 1;
static struct dentry*
xorfs_inode_lookup(struct inode* parent_inode, struct dentry *dentry, struct nameidata *nameidata)
{
    struct inode *file_inode;
    printk("XORFS: xorfs_inode_lookup\n");
    
    if(parent_inode->i_ino != xorfs_root_inode->i_ino ||
                   dentry->d_name.len != filename_len ||
                   strncmp(dentry->d_name.name, filename, dentry->d_name.len))
    {
           d_add(dentry, NULL);
           return NULL;
    } // if
    
    file_inode = xorfs_iget(parent_inode->i_sb, FILE_INODE_NUMBER);
    if(!file_inode)
           return ERR_PTR(-EACCES);
    file_inode->i_size = file_size;
    file_inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    file_inode->i_fop = &xorfs_fops;
    d_add(dentry, file_inode);
 
    return NULL;
} // xorfs_inode_lookup
 
static struct inode*
xorfs_iget(struct super_block *sb, unsigned long ino)
{
    struct inode *inode;
    int ret;
    printk("XORFS: xorfs_iget\n");
 
    inode = iget_locked(sb, ino);
    if(!inode)
           return ERR_PTR(-ENOMEM);
    if(!(inode->i_state & I_NEW))
           return inode;
 
    inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
    inode->i_mapping->a_ops = &xorfs_aops;
    
    unlock_new_inode(inode);
 
    return inode;
} // xorfs_iget
 
/**
 * file_operations
 */
 
static int
xorfs_file_open(struct inode *inode, struct file *file)
{
    printk("XORFS: @xorfs_file_open max_readahead = %d (size = %d)\n",
                   (int) file->f_ra.ra_pages, file_size);
 
    file->f_ra.ra_pages = 0; /* No read-ahead */
    return generic_file_open(inode, file);
} // xorfs_file_open
 
 
static ssize_t
xorfs_file_write(struct file *file, const char *buf, size_t maxlen, loff_t* offset)
{
    int count;
    if(*offset > 0)
    {
           printk("XORFS: @xorfs_file_write Positive offset %d\n", *offset);
           return 0;
    } // if
 
    count = maxlen > sizeof(file_buf) ? sizeof(file_buf) : maxlen;
    //__generic_copy_from_user(file_buf, buf, count);
    copy_from_user(file_buf, buf, maxlen);
    printk("XORFS: xorfs_file_write called with maxlen=%d, offset=%d\n", maxlen, *offset);
    *offset += count;
    if(*offset > file_size)
           file_size = *offset;
    
    return count;
} // xorfs_file_write
 
static ssize_t 
xorfs_file_read(struct file *file, char *buf, size_t max, loff_t* offset){
    int i;  
    int buflen;
    
    if(*offset > 0)
           return 0;
 
    printk("XORFS: xorfs_file_read called [%d] [%d]\n", max, *offset);
    
    buflen = (file_size > max) ? max : file_size;
    copy_to_user(buf, file_buf, buflen);
    *offset += buflen;
    
    return buflen;
} // xorfs_file_read
 
static int
xorfs_file_readdir(struct file *file, void *dirent, filldir_t filldir)
{
    struct dentry *de = file->f_dentry;
 
    if(file->f_pos > 2)
           return 1;
    if(filldir(dirent, ".", 1, file->f_pos++, de->d_inode->i_ino, DT_DIR))
           return 0;
    if(filldir(dirent, "..", 2, file->f_pos++, de->d_inode->i_ino, DT_DIR))
           return 0;
    if(filldir(dirent, filename, filename_len, file->f_pos++, FILE_INODE_NUMBER, DT_REG))
           return 0;
 
    return 1;
} // xorfs_file_readdir
 
static int
xorfs_file_release(struct inode* ino, struct file *file)
{
    struct dentry *dentry;
    dentry = file->f_dentry;
 
    return 0;
} // xorfs_file_releasei 
 
 
/**
 * address_space_operations
 */
 
static int
xorfs_readpage(struct file *file, struct page *page)
{
    void *page_addr;
    printk("XORFS: xorfs_readpage called for page index=[%d]\n",
                   (int) page->index);
 
    if(page->index > 0)
    {
           return -ENOSPC;
    }
    
    printk("XORFS: Page: [%s] [%s] [%s] [%s]\n",
                   PageUptodate(page) ? "Uptodate" : "Not Uptodate",
                   PageDirty(page) ? "Dirty" : "Not Dirty",
                   PageWriteback(page) ? "PageWriteback Set" : "PageWriteback Cleared",
                   PageLocked(page) ? "Locked" : "Unlocked");
    SetPageUptodate(page);
    page_addr = kmap(page);
    if(page_addr)
           memcpy(page_addr, file_buf, PAGE_SIZE);
    if(PageLocked(page))
           unlock_page(page);
    kunmap(page);
 
    return 0;
} // xorfs_readpage
 
static int
xorfs_writepage(struct page *page, struct writeback_control *wbc)
{
 
    void *page_addr = kmap(page);
    
    printk("[XORFS] xorfs_writepage, offset = %d\n", (int) page->index);
    printk("XORFS: WritePage: [%s] [%s] [%s] [%s]\n",
                   PageUptodate(page) ? "Uptodate" : "Not Uptodate",
                   PageDirty(page) ? "Dirty" : "Not Dirty",
                   PageWriteback(page) ? "PageWriteback Set" : "PageWriteback Cleared",
                   PageLocked(page) ? "Locked" : "Unlocked");
    memcpy(file_buf, page_addr, PAGE_SIZE);
    ClearPageDirty(page);
    if(PageLocked(page))
           unlock_page(page);
    kunmap(page);
    
    return 0;
} // xorfs_writepage
 
static int 
xorfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata)
{
    printk("XORFS: xorfs_write_begin\n");
 
    return 0;
} // xorfs_write_begin
 
 
static int 
xorfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata)
{
    struct inode *inode = page->mapping->host;
    void *page_addr = kmap(page);
    loff_t last_pos = pos + copied;
 
    printk("XORFS: xorfs_write_end: [%s] [%s] [%s] \n",
                   PageUptodate(page) ? "Uptodate" : "Not Uptodate",
                   PageDirty(page) ? "Dirty" : "Not Dirty",
                   PageLocked(page) ? "Locked" : "Unlocked");
 
    if(page->index == 0)
    {
           memcpy(file_buf, page_addr, PAGE_SIZE);
           ClearPageDirty(page);
    } // if
 
    SetPageUptodate(page);
    kunmap(page);
 
    if(last_pos > inode->i_size)
    {
           i_size_write(inode, last_pos);
           mark_inode_dirty(inode);
    } // if
 
    return 0;
} // xorfs_write_end
 
 
/*
 * register module
 */
 
static int __init
xorfs_init_module(void)
{
    int err;
    printk("XORFS: init_module\n");
 
    err = register_filesystem( &xorfs );
    return err;
} // init_module
 
static void __exit
xorfs_cleanup_module(void)
{
    unregister_filesystem(&xorfs);
} // xorfs_cleanup_module
 
module_init(xorfs_init_module);
module_exit(xorfs_cleanup_module);
  

Makefile文件如下:

    
      ifneq (${KERNELRELEASE},)
    
  
    
      obj-m += xorfs.o
    
  
    
      else
    
  
    
      KERNEL_SOURCE :=/lib/modules/$(shell uname -r)/build
    
  
    
      PWD :=$(shell pwd)
    
  
    
      export EXTRA_CFLAGS := -std=gnu99
    
  
    
      ?
    
  
    
      default:
    
  
    
      ??? $(MAKE) -C ${KERNEL_SOURCE} SUBDIRS=$(PWD) modules
    
  
    
      clean: 
    
  
    
      ??? rm *.o *.ko
    
  
    
      endif
    
  

1、編譯時(shí),運(yùn)行如下命令:

# make

2、將編譯成功的模板安裝到文件系統(tǒng)時(shí),運(yùn)行如下命令:

# insmod xorfs.ko

3、在/mnt下創(chuàng)建掛載點(diǎn) xorfs,運(yùn)行命令:

# mkdir /mnt/xorfs

4、將xorfs文件系統(tǒng)裝載到/mnt/xorfs下,運(yùn)行命令:

# mount –t xorfs xorfs /mnt/xorfs

5、若要卸載/mnt/xorfs,運(yùn)行命令:

# umount /mnt/xorfs

6、注銷(xiāo)文件系統(tǒng)xorfs時(shí),(注銷(xiāo)前先卸裁)運(yùn)行命令:

# rmmod xorfs.ko

7、查看printk日志信息,運(yùn)行命令:

# cat /var/log/messages | tail

?? 裝載xorfs之后,運(yùn)行效果如下:

clip_image019

clip_image021

clip_image023

源程序打包下載地址:

http://download.csdn.net/detail/ture010love/4235247

?

參考:

http://www.ibm.com/developerworks/cn/linux/l-cn-vfs/

http://www2.comp.ufscar.br/~helio/fs/rkfs.html

Linux虛擬文件系統(tǒng)及其實(shí)例XORFS


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 色偷偷综合 | 国内精品美女久久久久 | 亚洲影视在线观看 | 国产精品密蕾丝视频下载 | 永久免费在线播放 | 久久lu| 91在线视屏 | 欧美国产激情二区三区 | 亚洲人性生活视频 | 在线看av网址 | 一区二区三区免费在线观看 | 特级黄色小说 | 九九综合| 久久福利青草狠狠午夜 | 91一区二区三区在线观看 | 日本不卡在线观看免费v | 秋霞影院精品久久久久 | 欧美激情一区二区三级高清视频 | 亚洲韩国精品 | 五月综合激情 | 欧美日韩视频 | 黄在线观看在线播放720p | 激情视频网站 | 国产99久久精品一区二区永久免费 | 人人人人干 | 狠狠干中文字幕 | 草草草在线观看 | 精品久久久爽爽久久久AV | 成人在线免费视频观看 | 欧美一区二区三区视频 | 国内精品久久久久久99蜜桃 | 中国女警察一级毛片视频 | 欧美黄网在线 | 奇米影视亚洲四色8888 | 成人欧美一区二区 | 一级片视频免费观看 | 小明天天看 | 韩国美女激情视频一区二区 | 国产高清在线精品一区二区三区 | 91视频一区 | 久久久久亚洲精品中文字幕 |