首页 > 代码库 > 虚拟文件系统

虚拟文件系统

VFS的层次

文件系统实现与用户进程(或C库)之间。

 

文件系统分类

基于磁盘的文件系统(ext2/3  fat  iso9660…)、虚拟文件系统(proc)、网络文件系统(nfs)

 

 

通用文件模型

VFS提供一种结构模型,包含了一个强大的文件系统所应具备的所有组件。所有的文件系统实现,都必须提供与VFS定义的结构配合的例程,以弥补两种试图之间的差异。

 

文件描述符

一个整数,在用户层所有有关文件的操作中用于标识一个文件,在打开文件时由内核创建,特定于进程。

 

 

inode

 

l  inode是什么?

2  inode用来存放文件的元数据(例如,文件的创建者、文件的创建日期、文件的大小等等)

2  注意inode并不包含文件名。

 

l  inode的内容

inode包含文件的元信息,具体来说有以下内容:

2  文件的size、文件属主的User ID、Group ID

 

2  文件的读、写、执行权限

2  文件的时间戳,:ctime(inode上一次变动的时间)、mtime(文件内容上一次变动的时间)、atime(文件上一次打开的时间)。

2  链接数,即有多少文件名指向这个inode。

2  文件数据分布在哪些磁盘Block。

 

l  inode的状态

每个inode处于三种状态中的一个:

2  inode位于内存中,未关联到文件;(inode_unused)

2  inode位于内存中,由一个或多个进程使用,已与磁盘同步;(inode_in_used)

2  inode处于活动使用状态,与磁盘上内容未同步,脏inode;

 

l  inode是如何组织的?

2  内核使用两种方式组织inode。

2  链表:每个inode都有一个i_list成员,可将inode存储在链表中。(inode出现在特定于超级块的链表中i_sb_list,同时出现在特定于状态的链表中,例如inode_in_used)

2  散列:每个inode同时出现在一个散列表中(根据inode号快速访问inode)。

 

l  目录是什么?

2  Linux下,目录也是文件,也有inode和数据部分,其数据部分内容如下:

第一部分表示对应inode的编号(系统内唯一),第二部分表示文件或目录的名字。

内核如何访问/user/bin/emacs

 

首先读取根目录(这个在内核中一直被维护,),在根目录文件的数据部分查找user这个目录项,根据其中的inode编号,获取inode。bin的查找类似,一直到查找到emacs,找到emacs对应的inode,该inode的数据部分即emacs这个文件(普通数据文件)的内容。

图示:

 

 

目录项缓存dentry

 

l  引入dentry

 

上述访问/user/bin/emacs过程非常耗时,需要不断地读取inode和对应的数据部分。为了加速,内核将之前访问过的目录或文件(统称为目录项)缓存起来,下次再访问同样的目录项(例如,/user/bin/vi的/user/bin/部分)时,可以直接找到对应的inode(上图中为10号)。

 

l  dentry的目的:

dentry的主要用途是建立文件名和inode之间的关联。

所以该结构体包括两个最主要的字段,d_inoded_name

其中,d_name为文件名。qstr是内核对字符串的封装(可以理解为带有散列值的char*)。

d_inode是与该文件名对应的inode。

 

l  dentry结构体:

struct dentry {

   

 

/* Where the name belongs to - NULL is negative */

    struct inode *d_inode; 

 

struct qstr d_name;

 

struct dentry *d_parent; /* parent directory */

    union {

    struct list_head d_child; /* child of parent list */

    struct rcu_head d_rcu;

    } d_u;

    struct list_head d_subdirs; /* our children */

    struct dentry_operations *d_op;

    struct super_block *d_sb; /* The root of the dentry tree */

    unsignedchard_iname[DNAME_INLINE_LEN_MIN]; /* small names */

 

};

 

l  什么时候创建

在VFS(以及文件系统实现)读取一个目录项(目录或普通文件)后,则创建一个dentry来缓存找到的数据。

 

l  内存中这些dentry如何组织管理

2  结构:各个dentry实例组成了一个网络,例如,当前dentry实例对应的所有文件和子目录相关联的dentry都归入到d_subdirs中。

2  组织方式一:内核所有活动的dentry实例都保存在一个散列表中,该散列表使用dentry_hashtable实现(全局dentry散列表)。

2  组织方式二:LRU链表,长时间不使用的dentry会被删除。

 

 

链接link

 

l  两类链接:符号链接(软链接)和硬链接。

l  符号链接(软链接)文件使用自己的inode,该inode的数据部分包含了一个字符串,给出了链接目标的路径。

l  硬链接创建时,使用了已有的inode编号。硬链接建立以后,无法区分原来的文件和新建的硬链接文件。这种情况下,inode使用计数器来确保文件删除操作中,当没有其他文件使用该inode时,才能真正删除该inode。

示意图:

 

 

 

 

特定于进程的信息

struct task_struct {

     ...

     /* 进程的文件系统相关的信息*/

     struct fs_struct *fs;

     /* 该进程打开的文件 */

     struct files_struct *files;

     ...

}

 

struct files_struct {

     ...

     struct fdtable fdtab;

     struct file * fd_array[NR_OPEN_DEFAULT];

};

 

struct file {

     ...

 

struct path *f_path;

     loff_t   f_pos;

     ...

 

};

 

 

struct file_operations {

     ...

     ssize_t (*write) (struct file *, constchar __user *, size_t, loff_t *);

     int (*readdir) (struct file *, void *, filldir_t);

     unsignedint (*poll) (struct file *, struct poll_table_struct *);

     int (*ioctl) (struct inode *, struct file *, unsignedint, unsignedlong);

     int (*mmap) (struct file *, struct vm_area_struct *);

     int (*open) (struct inode *, struct file *);

     ...

};

 

struct file_operations->open函数实质上是将一个file对象关联到一个inode。

poll函数也在其中。

 

 

 

从task到dentry/inode