七度黑光--当感到一切都毫无头绪的时候,最好静下心来从基础开始.
Romfs文件系统分析认识
上一篇 / 下一篇 2008-07-07 16:08:04 / 个人分类:linux学习笔记
VFS:
Virtual File System SwITch,简称VFS,是LINUX文件系统的一个重要的组成部分。它不是一个真正的文件系统,实际上它是一种软件机制。
VFS的主要内容
超级块(super_block)
超级块是文件系统中最重要的数据结构,它用来描述整个文件系统信息(组织结构和管理信息)。不涉及文件系统的内容 。VFS超级块是各种具体文件系统在安装时建立的,并在这些文件系统卸载时自动删除。VFS超级块实际上应该说成是某个具体文件系统的VFS超级块。超级 块对象由super_block结构组成。
从所有具体的文件系统所抽象出来的一个结构, 每一个文件系统实例都会有一对应super_block结构。比如每一个ext2的分区就有一个super_block结构,它记录了该文件系统实例(分 区)的某些描述性的信息,比如该文件系统实例的文件系统类型,有多大,磁盘上每一块的大小, 还有就是super_operations。它与inode,dentry一样,只是某些内容在内存中的映像。
索引节点对象(inode,即I节点)
文件系统处理文件所需的信息。索引节点对文件是唯一的。具体文件系统的索引节点存储在磁盘上,使用的时候,必须调入内存,填写VFS的索引节点。所以VFS的索引节点是动态节点。
目录项(dentry)
每个文件除了有一个索引节点结构外,还有目录项dentry结构。 dentry结构代表的是逻辑意义上的文件,在磁盘上没有对应的映象。而inode结构代表的是物理意义上的文件,对于一个具体的文件系统,在磁盘上有对应的映象。一个dentry结构必有一个inode结构,而一个inode可能对应多个dentry结构。由于从磁盘读入一个文件并构造相应的目录项需要花费大量的时间,而在完成对目录项的操作后,可能后面还会用到,所以在内存中要保留它。
LINUX可以支持诸如EXT2,Minix,FAT,VFAT,NFS,NTFS…等等10多个不同的文件系统。正是VFS,为LINUX实现了这一强大功能。实现这种支持是通过文件系统的“注册”来完成的。经由注册的文件系统,VFS会给系统内核提供一个调用该文件系统函数的接口。Linux并非通过设备标识访问某个文件系统(像DOS那样),而是捆绑于一个树状目录上,因此,mount一个文件系统不仅包含了文件及数据,还包含了文件系统本身的树形结构,目录,访问权限等等。当用户调用一个文件时,他不需要因为文件属于不同的文件系统而按照不同的方式读取。VFS本身抽象了不同文件系统共同部分,对用户屏蔽了具体的操作,使得用 户不用再去关心文件所属的文件系统的问题,实现了各个文件系统的良好兼容。当一个最新推出的文件系统普遍被采用时,LINUX借助VFS的强大功能,可以 毫不费力的实现新文件系统在本地的组织运行,同时能不干扰其他已经装配在本地的其他文件系统。
在 Linux 源代码中,每种实际的文件系统用以下的数据结构表示:
每注册一个文件系统也就要在机器里初始化一个这样的数据结构,并形成一个链表,内核中用一个名为 file_systems 的全局变量来指向该链表的表头。
整个注册过程比较复杂,概括来说大概是如下几步:
第一步:
第二步:
关于romfs_get_sb函数的分析:如下
这里单独要说一说romfs_ops:
static const struct super_operations romfs_ops = {
.alloc_inode
= romfs_alloc_inode,//生成一个节点inode
.destroy_inode
= romfs_destroy_inode,//释放一个节点inode
.read_inode
= romfs_read_inode,//读取节点,这里比较复杂,还需分析
.statfs
= romfs_statfs,//获取当前系统的一些统计信息,
.remount_fs
= romfs_remount,//这个函数比较短如下。是用新的参数再次挂载,但是看不出来,怎么会再次挂载。
/*static int romfs_remount(struct super_block *sb, int *flags, char *data)
*{*flags |= MS_RDONLY;//只独系统,
*
return 0;}
*/
};
Romfs在节点的创建和销毁上并没有多少问题,而节点读取上比较复杂
还有要提一下super_operations,它也算是VFS的一个接口。实现一个文件系统file_operations, dentry_operations, inode_operations, super_operations这四个结构都要实现。
struct romfs_super_block {
__be32 word0;
__be32 word1;
__be32 size;
__be32 checksum;
char name[0];
/* volume name */
};
/* On disk inode */
struct romfs_inode {
__be32 next;
/* low 4 bits see ROMFH_ */
__be32 spec;
__be32 size;
__be32 checksum;
char name[0];
};
super_operations,它也算是VFS的一个接口。实现一个文件系统file_operations, dentry_operations, inode_operations, super_operations这四个结构都要实现。
struct inode
{
...
const struct inode_operations
*i_op;
const struct file_operations
*i_fop;
struct super_block
*i_sb;
struct file_lock
*i_flock;
struct address_space
i_data;
(const struct address_space_operations *a_ops;)
...
}
static const struct address_space_operations romfs_aops = {
.readpage = romfs_readpage
};
static const struct file_operations romfs_dir_operations = {
.read
= generic_read_dir,
.readdir
= romfs_readdir,
};
static const struct inode_operations romfs_dir_inode_operations = {
.lookup
= romfs_lookup,
};
把一个设备安装到一个目录节点时要用一个vfsmount的作为连接件。vfsmount结构定义如下:
struct vfsmount {
struct list_head mnt_hash;
struct vfsmount *mnt_parent;
/* fs we are mounted on */
struct dentry *mnt_mountpoint;
/* dentry of mountpoint */
struct dentry *mnt_root;
/* root of the mounted tree */
struct super_block *mnt_sb;
/* pointer to superblock */
.........
}
对于某个文件系统实例,内存中super_block和vfsmount都是唯一的。比如,我们将某个挂载硬盘分区mount -t vfat /dev/hda2 /mnt/d。实际上就是新建一个vfsmount结构作为连接件,vfsmount->mnt_sb = /dev/hda2的超级块结构;vfsmount->mntroot = /dev/hda2的"根"目录的dentry;vfsmount->mnt_mountpoint = /mnt/d的dentry;vfsmount->mnt_parent = /mnt/d所属的文件系统的vfsmount。并且把这个新建的vfsmount连入一个全局的hash表mount_hashtable中。
Virtual File System SwITch,简称VFS,是LINUX文件系统的一个重要的组成部分。它不是一个真正的文件系统,实际上它是一种软件机制。
VFS的主要内容
超级块(super_block)
超级块是文件系统中最重要的数据结构,它用来描述整个文件系统信息(组织结构和管理信息)。不涉及文件系统的内容 。VFS超级块是各种具体文件系统在安装时建立的,并在这些文件系统卸载时自动删除。VFS超级块实际上应该说成是某个具体文件系统的VFS超级块。超级 块对象由super_block结构组成。
从所有具体的文件系统所抽象出来的一个结构, 每一个文件系统实例都会有一对应super_block结构。比如每一个ext2的分区就有一个super_block结构,它记录了该文件系统实例(分 区)的某些描述性的信息,比如该文件系统实例的文件系统类型,有多大,磁盘上每一块的大小, 还有就是super_operations。它与inode,dentry一样,只是某些内容在内存中的映像。
索引节点对象(inode,即I节点)
文件系统处理文件所需的信息。索引节点对文件是唯一的。具体文件系统的索引节点存储在磁盘上,使用的时候,必须调入内存,填写VFS的索引节点。所以VFS的索引节点是动态节点。
目录项(dentry)
每个文件除了有一个索引节点结构外,还有目录项dentry结构。 dentry结构代表的是逻辑意义上的文件,在磁盘上没有对应的映象。而inode结构代表的是物理意义上的文件,对于一个具体的文件系统,在磁盘上有对应的映象。一个dentry结构必有一个inode结构,而一个inode可能对应多个dentry结构。由于从磁盘读入一个文件并构造相应的目录项需要花费大量的时间,而在完成对目录项的操作后,可能后面还会用到,所以在内存中要保留它。
LINUX可以支持诸如EXT2,Minix,FAT,VFAT,NFS,NTFS…等等10多个不同的文件系统。正是VFS,为LINUX实现了这一强大功能。实现这种支持是通过文件系统的“注册”来完成的。经由注册的文件系统,VFS会给系统内核提供一个调用该文件系统函数的接口。Linux并非通过设备标识访问某个文件系统(像DOS那样),而是捆绑于一个树状目录上,因此,mount一个文件系统不仅包含了文件及数据,还包含了文件系统本身的树形结构,目录,访问权限等等。当用户调用一个文件时,他不需要因为文件属于不同的文件系统而按照不同的方式读取。VFS本身抽象了不同文件系统共同部分,对用户屏蔽了具体的操作,使得用 户不用再去关心文件所属的文件系统的问题,实现了各个文件系统的良好兼容。当一个最新推出的文件系统普遍被采用时,LINUX借助VFS的强大功能,可以 毫不费力的实现新文件系统在本地的组织运行,同时能不干扰其他已经装配在本地的其他文件系统。
在 Linux 源代码中,每种实际的文件系统用以下的数据结构表示:
代码:
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;
。。。
}; 整个注册过程比较复杂,概括来说大概是如下几步:
第一步:
代码:
nit_inodecache();//新建cache,是为了加快读写速度。在注册文件系统的时候创建,注销文件系统的时候销毁。
static int init_inodecache(void)
{/**
struct kmem_cache *
kmem_cache_create (const char *name, size_t size, size_t align,
unsigned long flags,void (*ctor)(struct kmem_cache *, void *))
* kmem_cache_create - 创建一个cache.
* @name: 在/proc/slabinfo用来识别这个cache的名称
* @size: 要创建cache的大小
* @align: 是否对齐
* @flags: SLAB 标志
* @ctor: A constructor(构造器) for the objects.
*调用成功的话返回cache的指针,@ctor在cache分配新页时运行。@name要有效到cach被销毁。也就是说cache在模块卸载前要销毁。
*/
romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
sizeof(struct romfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
init_once);
if (romfs_inode_cachep == NULL)
return -ENOMEM;
return 0;
}第二步:
代码:
register_filesystem(&romfs_fs_type);//注册文件系统
romfs_fs_type是一个file_system_type类型的结构体
static struct file_system_type romfs_fs_type = {
.owner = THIS_MODULE,
.name = "romfs",//文件系统名
.get_sb = romfs_get_sb,//实现文件系统,在mount时运行
.kill_sb = kill_block_super,//撤销文件系统,在umount时运行
.fs_flags = FS_REQUIRES_DEV,
};关于romfs_get_sb函数的分析:如下
代码:
static int romfs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{ return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super,mnt);
romfs_fill_super:实现romfs中super_block的填充,还有其他的一些op的填充.}
它只是调用了get_sb_bdev()函数。原形如下:
int get_sb_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int),
struct vfsmount *mnt)
在这个函数里它又调用了
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0)来实现super_block的填充。
MS_SILENT这个值是32768
在romfs_fill_super 这个函数中对super_block进行了初始化填充,一下是一些填充项.
sb_set_blocksize(s, ROMBSIZE);//设置块大小
s->s_maxbytes = 0xFFFFFFFF;//设置文件的最大体积
bh = sb_bread(s, 0);//这个不太清楚,好像是设置是否是块设备的
s->s_magic = ROMFS_MAGIC;//#define ROMFS_MAGIC 0x7275 据e文说是romfs的基本结构值之一
s->s_fs_info = (void *)(long)sz;//e文说是文件系统的私有信息,可是看sz其实就是一个大小。
s->s_flags |= MS_RDONLY;//只读文件系统
sz = (ROMFH_SIZE + strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD)
& ROMFH_MASK;
s->s_op = &romfs_ops;
root = iget(s, sz);
s->s_root = d_alloc_root(root);这里单独要说一说romfs_ops:
static const struct super_operations romfs_ops = {
.alloc_inode
= romfs_alloc_inode,//生成一个节点inode
.destroy_inode
= romfs_destroy_inode,//释放一个节点inode
.read_inode
= romfs_read_inode,//读取节点,这里比较复杂,还需分析
.statfs
= romfs_statfs,//获取当前系统的一些统计信息,
.remount_fs
= romfs_remount,//这个函数比较短如下。是用新的参数再次挂载,但是看不出来,怎么会再次挂载。
/*static int romfs_remount(struct super_block *sb, int *flags, char *data)
*{*flags |= MS_RDONLY;//只独系统,
*
return 0;}
*/
};
Romfs在节点的创建和销毁上并没有多少问题,而节点读取上比较复杂
还有要提一下super_operations,它也算是VFS的一个接口。实现一个文件系统file_operations, dentry_operations, inode_operations, super_operations这四个结构都要实现。
struct romfs_super_block {
__be32 word0;
__be32 word1;
__be32 size;
__be32 checksum;
char name[0];
/* volume name */
};
/* On disk inode */
struct romfs_inode {
__be32 next;
/* low 4 bits see ROMFH_ */
__be32 spec;
__be32 size;
__be32 checksum;
char name[0];
};
super_operations,它也算是VFS的一个接口。实现一个文件系统file_operations, dentry_operations, inode_operations, super_operations这四个结构都要实现。
struct inode
{
...
const struct inode_operations
*i_op;
const struct file_operations
*i_fop;
struct super_block
*i_sb;
struct file_lock
*i_flock;
struct address_space
i_data;
(const struct address_space_operations *a_ops;)
...
}
static const struct address_space_operations romfs_aops = {
.readpage = romfs_readpage
};
static const struct file_operations romfs_dir_operations = {
.read
= generic_read_dir,
.readdir
= romfs_readdir,
};
static const struct inode_operations romfs_dir_inode_operations = {
.lookup
= romfs_lookup,
};
把一个设备安装到一个目录节点时要用一个vfsmount的作为连接件。vfsmount结构定义如下:
struct vfsmount {
struct list_head mnt_hash;
struct vfsmount *mnt_parent;
/* fs we are mounted on */
struct dentry *mnt_mountpoint;
/* dentry of mountpoint */
struct dentry *mnt_root;
/* root of the mounted tree */
struct super_block *mnt_sb;
/* pointer to superblock */
.........
}
对于某个文件系统实例,内存中super_block和vfsmount都是唯一的。比如,我们将某个挂载硬盘分区mount -t vfat /dev/hda2 /mnt/d。实际上就是新建一个vfsmount结构作为连接件,vfsmount->mnt_sb = /dev/hda2的超级块结构;vfsmount->mntroot = /dev/hda2的"根"目录的dentry;vfsmount->mnt_mountpoint = /mnt/d的dentry;vfsmount->mnt_parent = /mnt/d所属的文件系统的vfsmount。并且把这个新建的vfsmount连入一个全局的hash表mount_hashtable中。
TAG:
标题搜索
日历
|
|||||||||
| 日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
| 1 | 2 | 3 | 4 | ||||||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 | |||
| 12 | 13 | 14 | 15 | 16 | 17 | 18 | |||
| 19 | 20 | 21 | 22 | 23 | 24 | 25 | |||
| 26 | 27 | 28 | 29 | 30 | 31 | ||||
数据统计
- 访问量: 7677
- 日志数: 50
- 图片数: 1
- 文件数: 1
- 书签数: 3
- 建立时间: 2008-03-08
- 更新时间: 2008-09-27
