当用户层程序员在编写文件函数时,常常会用到open(),read()和write()这类系统调用,而且用的也很爽,因为我们只需要知道这些函数如何调用就OK了,而不用深究具体文件系统和实际物理介质是如何实现的。而我们内核编程人员就要了解这些底层实现,给上层人员提供更多的方便。因此我们的任务就更复杂,佛家有一句名言:“我不入地狱,谁如地狱”因此我们就要有奉献精神编写出具有统一简单效率高的接口为用户层程序员提供方便。
如果你有这种奉献精神和喜爱Linux内核以及有着很高的好奇心的话,那我们就来深入学习内核看看Linux内核到底是如何实现这些功能的。
一.VFS的概念
Linux 之所以能支持除了Ext2文件系统之外的各种文件系统,是因为Linux提供了一种统一的框架,就是所谓的虚拟文件系统转换(Virtual FilesystemSwitch),简称虚拟文件系统(VFS)。这样, 用户程序可以通过同一个文件系统界面,也就是同一组系统调用,能够对各种不同的文件系统以及文件进行操作。
1.在上面提到Linux中支持几十种文件系统,它是怎么管理的呢,它都管理什么呢?
首先,VFS 只对挂载到文件系统种的文件系统进行管理,即它时按需管理的。
其次,因为它继承了Unix的设计思想,所以它也是对文件,目录项,索引节点和超级块进行管理。
2.VFS中四个主要对象:
1>超级块对象:描述已安装文件系统。
每个文件系统 都对应一个超级对象。文件系统的控制信息存储在超级块中。
2>索引节点对象:描述一个文件。
每个文件 都有一个索引节点对象。每个索引节点对象都有一索引节点号---->正是用这个号来唯一的标识某个文件系统中的指定文件。
3>目录项对象:描述一个目录项,是路径的组成部分。
VFS把每个目录看作一个由若干子目录和文件组成的常规文件。
例如:我们在查找路径名:/tmp/test时,内核为根目录“/”创建第一个目录项对象,为根目录下tmp项创建第二级目录项对象,为/tmp目录下的test项创建第三级目录项对象。
4>文件对象:描述由进程打开的文件。
Tiger-John说明:
1.因为 VFS 将目录作为一个文件来处理,所以不存在目录对象。虽然目录项不同于目录,但目录却和文件相同。
2.Linux中将文件的相关信息和文件本身区分开了。
在Linux 中文件的相关信息,被存储在一个单独的数据结构中,该结构被称为索引节点。文件(目录)信息按照索引节点形式存储在单独的块中;控制信息被集中存储在磁盘的超级块中
说了这么多,VFS到底是如何实现的呢?----现在我们就来深入内核代码来看看吧
二.VFS四个主要对象的实现
VFS采用的是面向对象的设计思想,使用一簇数据结构来代表通用文件对象。所以内核中的数据结构都使用C结构体实现。
1.superblock(超级块)对象:
1>超级块用来描述特定文件系统的信息。它存放在磁盘特定的扇区中 ,它在使用的时候将信息存在于内存中。
2> 当内核对一个文件系统进行初始化和注册时在内存为其分配一个超级块,这就是VFS超级块。
即,VFS超级块是各种具体文件系统在安装时建立的,并在这些文件系统卸载时被自动删除 。
3>超级块对象由结构体 super_block来体现。
VFS超级块的数据结构为 super_block在include/linux/fs.h中可以查看
1318struct super_block {
1319 struct list_head s_list; // 超级快链表指针
1320 dev_t s_dev; // 设备表示符
1321 unsigned char s_dirt; //脏标志
1322 unsigned char s_blocksize_bits; //以位为单位的块的大小
1323 unsigned long s_blocksize; //以字节为单位的块大小
1324 loff_t s_maxbytes; //文件大小上限
1325 struct file_system_type *s_type; //指向文件系统的file_system_type 数据结构的指针
1326 const struct super_operations *s_op; //超级块方法
1327 const struct dquot_operations *dq_op; //磁盘限额方法
1328 const struct quotactl_ops *s_qcop; //限额控制方法
1329 const struct export_operations *s_export_op; //导出方法
1330 unsigned long s_flags; //登录标志
1331 unsigned long s_magic; //文件系统的魔数
1332 struct dentry *s_root; //目录登录点
1333 struct rw_semaphore s_umount; //卸载信号量
1334 struct mutex s_lock; //超级块信号量
1335 int s_count; //超级块引用计数
1336 atomic_t s_active; //活动引用记数
1337#ifdef CONFIG_SECURITY
1338 void *s_security; //安全模块
1339#endif
1340 const struct xattr_handler **s_xattr;
1341
1342 struct list_head s_inodes; //把所有索引对象链接在一起,存放的是头结点
1343 struct hlist_head s_anon; //匿名目录项
1344#ifdef CONFIG_SMP
1345 struct list_head __percpu *s_files;
1346#else
1347 struct list_head s_files; //链接所有打开的文件。
1348#endif
1349 /* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
1350 struct list_head s_dentry_lru; /* unused dentry lru */
1351 int s_nr_dentry_unused; /* # of dentry on lru */
1352
1353 struct block_device *s_bdev; //相关的块设备
1354 struct backing_dev_info *s_bdi;
1355 struct mtd_info *s_mtd;
1356 struct list_head s_instances; //该类型文件系统
1357 struct quota_info s_dquot; //限额相关选项
1358
1359 int s_frozen;
1360 wait_queue_head_t s_wait_unfrozen;
1361
1362 char s_id[32]; //文本名字
1363
1364 void *s_fs_info; //文件系统特设信息
1365 fmode_t s_mode;
1366
1367 /* Granularity of c/m/atime in ns.
1368 Cannot be worse than a second */
1369 u32 s_time_gran;
1370
1371 /*
1372 * The next field is for VFS *only*. No filesystems have any business
1373 * even looking at it. You had been warned.
1374 */
1375 struct mutex s_vfs_rename_mutex; /* Kludge */
1376
1377 /*
1378 * Filesystem subtype. If non-empty the filesystem type field
1379 * in /proc/mounts will be "type.subtype"
1380 */
1381 char *s_subtype;
1382
1383 /*
1384 * Saved mount options for lazy filesystems using
1385 * generic_show_options()
1386 */
1387 char *s_options;
1388};
现在我们来对其中主要的数据结构进行分析
比较重要的数据结构以在上面有注释。
我们先来看一个图,再来具体解释: