频 道 直 达 - 新闻 - 读书 - 培训 - 教程 - 前沿 - 组网 - 系统应用 - 安全 - 编程 - 存储 - 操作系统 - 数据库 - 服务器 - 专题 - 产品 - 案例库 - 技术圈 - 博客 - BBS
51CTO.COM_中国领先的IT技术网站
找资料:

解析 Linux 中的 VFS 文件系统机制(2)

作者: FOXL 出处:51CTO整理 2008-03-14 16:23    砖    好    评论   进入论坛
阅读提示:本文阐述 Linux 中的文件系统部分,源代码来自基于 IA32 的 2.4.20 内核。总体上说 Linux 下的文件系统主要可分为三大块:一是上层的文件系统的系统调用,二是虚拟文件系统 VFS(Virtual Filesystem Switch),三是挂载到 VFS 中的各实际文件系统,例如 ext2,jffs 等。

4. VFS 目录树的建立

既然是树,所以根是其赖以存在的基础,本节阐述 Linux 在初始化阶段是如何建立根结点的,即 "/"目录。这其中会包括挂载 rootfs 文件系统到根目录 "/" 的具体过程。构造根目录的代码是在 init_mount_tree() 函数 (fs\namespace.c) 中。

首先,init_mount_tree() 函数会调用 do_kern_mount("rootfs", 0, "rootfs", NULL) 来挂载前面已经注册了的 rootfs 文件系统。这看起来似乎有点奇怪,因为根据前面的说法,似乎是应该先有挂载目录,然后再在其上挂载相应的文件系统,然而此时 VFS 似乎并没有建立其根目录。没关系,这是因为这里我们调用的是 do_kern_mount(),这个函数内部自然会创建我们最关心也是最关键的根目录(在 Linux 中,目录对应的数据结构是 struct dentry)。

在这个场景里,do_kern_mount() 做的工作主要是:

1)调用 alloc_vfsmnt() 函数在内存里申请了一块该类型的内存空间(struct vfsmount *mnt),并初始化其部分成员变量。

2) 调用 get_sb_nodev() 函数在内存中分配一个超级块结构 (struct super_block) sb,并初始化其部分成员变量,将成员 s_instances 插入到 rootfs 文件系统类型结构中的 fs_supers 指向的双向链表中。

3) 通过 rootfs 文件系统中的 read_super 函数指针调用 ramfs_read_super() 函数。还记得当初注册rootfs 文件系统时,其成员 read_super 指针指向了 ramfs_read_super() 函数,参见图2.

4) ramfs_read_super() 函数调用 ramfs_get_inode() 在内存中分配了一个 inode 结构 (struct inode) inode,并初始化其部分成员变量,其中比较重要的有 i_op、i_fop 和 i_sb:

inode->i_op = &ramfs_dir_inode_operations;
inode->i_fop = &dcache_dir_ops;
inode->i_sb = sb;

这使得将来通过文件系统调用对 VFS 发起的文件操作等指令将被 rootfs 文件系统中相应的函数接口所接管。

图3
图3

5) ramfs_read_super() 函数在分配和初始化了 inode 结构之后,会调用 d_alloc_root() 函数来为 VFS的目录树建立起关键的根目录 (struct dentry)dentry,并将 dentry 中的 d_sb 指针指向 sb,d_inode 指针指向 inode。

6) 将 mnt 中的 mnt_sb 指针指向 sb,mnt_root 和 mnt_mountpoint 指针指向 dentry,而 mnt_parent指针则指向自身。

这样,当 do_kern_mount() 函数返回时,以上分配出来的各数据结构和 rootfs 文件系统的关系将如上图 3 所示。图中 mnt、sb、inode、dentry 结构块下方的数字表示它们在内存里被分配的先后顺序。限于篇幅的原因,各结构中只给出了部分成员变量,读者可以对照源代码根据图中所示按图索骥,以加深理解。

最后,init_mount_tree() 函数会为系统最开始的进程(即 init_task 进程)准备它的进程数据块中的namespace 域,主要目的是将 do_kern_mount() 函数中建立的 mnt 和 dentry 信息记录在了 init_task 进程的进程数据块中,这样所有以后从 init_task 进程 fork 出来的进程也都先天地继承了这一信息,在后面用sys_mkdir 在 VFS 中创建一个目录的过程中,我们可以看到这里为什么要这样做。为进程建立 namespace 的主要代码如下:

namespace = kmalloc(sizeof(*namespace), GFP_KERNEL);
   list_add(&mnt->mnt_list, &namespace->list);  //mnt is returned by do_kern_mount()
namespace->root = mnt;
init_task.namespace = namespace;
for_each_task(p) {
get_namespace(namespace);
p->namespace = namespace;
}
set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
set_fs_root(current->fs, namespace->root, namespace->root->mnt_root);

该段代码的最后两行便是将 do_kern_mount() 函数中建立的 mnt 和 dentry 信息记录在了当前进程的 fs结构中。

以上讲了一大堆数据结构的来历,其实最终目的不过是要在内存中建立一颗 VFS 目录树而已,更确切地说, init_mount_tree() 这个函数为 VFS 建立了根目录 "/",而一旦有了根,那么这棵数就可以发展壮大,比如可以通过系统调用 sys_mkdir 在这棵树上建立新的叶子节点等,所以系统设计者又将 rootfs 文件系统挂载到了这棵树的根目录上。关于 rootfs 这个文件系统,读者如果看一下前面图 2 中它的file_system_type 结构,会发现它的一个成员函数指针 read_super 指向的是 ramfs_read_super,单从这个函数名称中的 ramfs,读者大概能猜测出这个文件所涉及的文件操作都是针对内存中的数据对象,事实上也的确如此。从另一个角度而言,因为 VFS 本身就是内存中的一个数据对象,所以在其上的操作仅限于内存,那也是非常合乎逻辑的事。在接下来的章节中,我们会用一个具体的例子来讨论如何利用 rootfs所提供的函树为 VFS 增加一个新的目录节点。

VFS 中各目录的主要用途是为以后挂载文件系统提供挂载点。所以真正的文件操作还是要通过挂载后的文件系统提供的功能接口来进行。


共5页: 上一页 [1] 2 [3] [4] [5] 下一页
【内容导航】
 第 1 页:VFS 目录树结构  第 2 页:VFS 目录树的建立
 第 3 页:VFS 下目录的建立  第 4 页:VFS 树中挂载文件系统
 第 5 页:安装根文件系统
专题
Linux——从菜鸟到高手
AMD Phenom三核处理器解析
解析Ajax开发框架 走进Ajax开发应用
Linux/Solaris服务器的安全配置
IBM System i5全内置服务器解析
我也说两句

匿名发表

(如果看不清请点击图片进行更换)


中 国 领 先 的 IT 技 术 网 站 ·
技 术 成 就 梦 想
·Windows XP远程桌面连接图解(.. (查看46173次)
·Solaris基础知识入门 (查看37519次)
·Windows操作系统安装 (查看28684次)
·Linux的安装 (查看25992次)
·设置远程桌面连接 (查看25085次)
订阅技术快讯
电子杂志下载
名称:SQL Server数据库管理精品黄皮书
简介:书中文章经过精挑细选,便于用户能根据自己的实际工作和学习,快速在本书寻找到相关资料。内容涵盖了SQL Server的安装与升级、语句查询、数据备份和恢复、自动化任务、数据同步、数据字典、安全和预防、性能和优化、集群等各方面应用信息,以及DBA管理人员在数据库管理工作中
名称:2007路由技术大全
简介:《2007路由技术大全》由51CTO.com网站特别策划制作,该书包括路由器技术、路由器产品、路由器配置、安全设置、路由器故障处理、路由器密码恢复,以及广大网友在实践使用中的心得经验和技巧文章,内容注重实用性,适用于初学者入门,也适合多年从业者提高,是一本实践和理论完
名称:网络安全精品应用黄皮书
简介:《2007精品网络安全黄皮书》包括了9个大类24个小类, 800余篇文章,内容包含了熊猫烧香病毒、DDOS攻击、ARP病等热点问题的介绍及解决方案。从病毒查杀、防范、系统、数据等各方面的安全设置到黑客技术的了解、防范,涉及到了安全应用的全部领域, 由浅至深内容全面。