Linux虚拟文件系统(2)– 初始化流程

索引

Linux虚拟文件系统(1)

Linux虚拟文件系统(3)– VFS系统调用

上文介绍了Linux VFS的基本架构与数据结构,本文介绍Linux虚拟文件系统的初始化过程。

如下图

+----------------------------XXXX
|     start_kernel()         |  X
|                            |  X
+-------------+--------------+  X
              |                 X
+-------------v--------------+  X  +---------------+
|    vfs_cache_init_early()  |  XXX|Linux Init Flow|
|                            |  X  +---------------+
+-------------+--------------+  X
              |                 X
+-------------v--------------+  X
|       vfs_cache_init()     |  X
|                            |  X
+-------------+--------------+XXX
              |
+-------------v--------------+
|      File System Operation |
|                            |
+----------------------------+

在Linux kernel的入口函数start_kernel中,系统调用vfs_caches_init_early和vfs_caches_init进行必要的初始化。

vfs_caches_init_early

Dentry和inode cache是linux为了加速对虚拟文件系统管理,在内存中分配的的hash Cache,用来存放最近访问的inode或dentry节点。

一般而言,最近访问的节点也是最容易被再次访问的。当要访问inode或dentry节点时,先到内存中的cache查找(Hash链表)。如果可以找到,便可以直接使用内存中的节点,否则才到文件系统中去找。

static void __init dcache_init_early(void)
{
  unsigned int loop;

  /* If hashes are distributed across NUMA nodes, defer
   * hash allocation until vmalloc space is available.
   */
  if (hashdist)
    return;

  dentry_hashtable =
    alloc_large_system_hash("Dentry cache",
          sizeof(struct hlist_bl_head),
          dhash_entries,
          13,
          HASH_EARLY,
          &d_hash_shift,
          &d_hash_mask,
          0,
          0);

  for (loop = 0; loop < (1U << d_hash_shift); loop++)
    INIT_HLIST_BL_HEAD(dentry_hashtable + loop);
}
void __init inode_init_early(void)
{
	unsigned int loop;
	if (hashdist)
		return;
	inode_hashtable =
		alloc_large_system_hash("Inode-cache",
					sizeof(struct hlist_head),
					ihash_entries,
					14,
					HASH_EARLY,
					&i_hash_shift,
					&i_hash_mask,
					0,
					0);

	for (loop = 0; loop < (1U << i_hash_shift); loop++)
		INIT_HLIST_HEAD(&inode_hashtable[loop]);
}

上述代码可以看出,vfs_caches_init_early创建了inode和dentry cache的hash链表,但是这里并没有分配dentry和inode的cache(vfs_caches_init中才会创建)。Hash 链表的结构如下图所示。

Linux虚拟文件系统(2)-- 初始化流程vfs_caches_init

相较于vfs_caches_init_early, vfs_caches_init则会做更多的事情。如下代码

void __init vfs_caches_init(void)
{
  names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
      SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);

  dcache_init();   //初始化dentry cache,此时才会创建cache
  inode_init();    //类上
  files_init();    //初始化文件cache
  files_maxfiles_init(); //初始化系统最大文件数
  mnt_init();      // 初始化文件系统挂载相关资源并挂载特殊文件系统
  bdev_cache_init(); //初始化块设备管理伪文件系统
  chrdev_init();   //初始化字符设备相关
}

dcache_init/inode_init: 初始化dentry和inode cache,如果没有创建对应的哈希链表,就创建之(前边vfs_caches_init_early已经创建)

files_init: 根据当前系统内存计算最大文件数

n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10;
files_stat.max_files = max_t(unsigned long, n, NR_FILE);

mnt_init:与文件系统mount相关的初始化。细节流程如下:

+----------------------+
| Create MNT cache and |
| MNT cache Hash table |
+-----------+----------+
            |
+-----------v----------+    +---------------------+
| Create Mount Point   |    | init mount tree     |
| Hash Table           |    |                     |
+-----------+----------+    +----------^----------+
            |                          |
+-----------v----------+    +----------+----------+
| kernfs_init()        |    | init_rootfs()       |
|                      |    |                     |
+-----------+----------+    +----------^----------+
            |                          |
+-----------v----------+    +----------+----------+
| sysfs_init()         +--> | Register FS folder  |
|                      |    | to sysfs            |
+----------------------+    +---------------------+

首先,创建struct mount cache及哈希链表,之后创建文件系统加载点(struct mountpoint)Cache Hash。 其中前者为系统中已经Mount的VFS相关信息(包含不同VFS Mount的相互关系),后者主要存放的是系统加载点Dentry。

kernfs_init:主要创建kernfs_node的cache。kernfs_node主要为创建kernfs结构的结构体。kernfs的作用引用wiki如下:

In the Linux kernel, kernfs is a set of functions that contain the functionality required for creating pseudo file systems used internally by various kernel subsystems. The creation of kernfs resulted from splitting off part of the internal logic used by sysfs, which provides a set of virtual files by exporting information about hardware devices and associated device drivers from the kernel’s device model to user space, into an independent and reusable functionality so other kernel subsystems can implement their own pseudo file systems more easily and consistently

sysfs_init:初始化sysfs,并向系统中注册该文件系统。sysfs.txt(Documentation/zh_CN/filesystems/sysfs.txt)对sysfs的简介如下:

sysfs 是一个最初基于 ramfs 且位于内存的文件系统。它提供导出内核
数据结构及其属性,以及它们之间的关联到用户空间的方法。sysfs 目录的安排显示了内核数据结构之间的关系。顶层 sysfs 目录如下:
block/
bus/
class/
dev/
devices/
firmware/
net/
fs/

紧接着注册fs目录到sysfs(fs_kobj = kobject_create_and_add(“fs”, NULL);),即构成sysfs顶级目录的fs目录。

init_rootfs(): 主要向系统中注册rootfs与tmpfs文件系统,以及执行Mount(具体下一篇文章介绍)

init_mount_tree(): 如其名,初始化文件系统挂载树。代码如下:

static void __init init_mount_tree(void)
{
  struct vfsmount *mnt;
  struct mnt_namespace *ns;
  struct path root;
  struct file_system_type *type;

  type = get_fs_type("rootfs"); //获取已注册到kernel中的rootfs
  if (!type)
    panic("Can't find rootfs type"); //前方init_rootfs已经向系统注册rootfs,若此处找不到,视为异常
  mnt = vfs_kern_mount(type, 0, "rootfs", NULL); //挂载rootfs,其中会执行对应rootfs的mount callback,具体下一篇文章介绍
  put_filesystem(type);
  if (IS_ERR(mnt))
    panic("Can't create rootfs");

  ns = create_mnt_ns(mnt);     //创建mnt命名空间,并将rootfs加入到对应命名空间,作为命名空间的root
  if (IS_ERR(ns))
    panic("Can't allocate initial namespace");

  init_task.nsproxy->mnt_ns = ns;
  get_mnt_ns(ns);
  root.mnt = mnt;
  root.dentry = mnt->mnt_root;
  mnt->mnt_flags |= MNT_LOCKED;
  set_fs_pwd(current->fs, &root);   //设定init进程的当前目录为挂载点的主目录
  set_fs_root(current->fs, &root);  //设定init进程的root为挂载点的主目录
}

至此,start_kernel中的vfs初始化流程结束

相关文章

Linux中断学习笔记(2) — 嵌入式设备中断... 在Linux中断学习笔记(1)提到,外设通过中断控制器连接到CPU的中断线。嵌入式系统也不例外。 ARM嵌入式系统GIC架构 ARM官网所举图为例:ARM的中断控制器GIC(General Interrupt Controller)将从外设输入的中断通过CPU的IRQ信号线(ARM中主要为FIQ...
Linux虚拟文件系统(1) 索引 http://l2h.site/linux-vfs-2/ http://l2h.site/linux-vfs-3/ VFS简介 Linux将系统中很多资源都抽象成文件,如Socket、设备节点、以及内存。可以如此做,归功于Linux操作系统的虚拟文件系统(VFS)。 有了VFS,...
Linux中断学习笔记(1) 什么是中断 CPU获取外设状态变化有两种方式: Polling:不断跟外设询问它的状态 当外设状态变化后主动通知CPU CPU要负责处理系统中各种各样的业务,如果频繁地轮询外设状态,必然会对整个系统的吞吐量产生影响,影响操作系统的正常运作。 中断便是外设通知CPU其状态变化...
Linux虚拟文件系统(3)– VFS系统调用... 索引 http://l2h.site/linux-vfs-1/ http://l2h.site/linux-vfs-2/ 前言 前2章分别介绍了VFS的基本数据结构和初始化流程。本章介绍VFS文件系统的使用。文件系统使用大多是从应用层系统调用开始的,下表是对文件系统系统调用的一个整理。 ...

“Linux虚拟文件系统(2)– 初始化流程”的2个回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注