文件系统(十二)—伪文件系统

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前文中我们已经分析了文件系统而文件系统的精髓所在是让用户可以通过文件描述符来对指定的inode进行一系列的操作。

本章开始学习伪文件系统伪文件系统和普通文件系统的区别在于其inode对用户不可访问即仅在内核态可见从用户层的视角来看该文件系统并不存在。伪文件系统的作用是对一些操作系统中的元素进行封装和普通的文件统一接口如块设备bdevfs管道文件pipefs套接字socketfs等。通过这种方式的统一封装才实现了Linux一切皆文件的思想。如下图中红色的都应该算是伪文件系统本章就学习其中的procfs/sysfs/pipefs。

在这里插入图片描述

1 proc文件系统

1.1 数据结构

proc文件系统由proc_dir_entry结构体实例组成内核各子系统可通过接口函数向proc文件系统添加目录和文件。proc_dir_entry结构体定义在fs/proc/internal.h头文件

在这里插入图片描述

在VFS中proc文件系统节点由proc_inode结构体表示其定义在fs/proc/internal.h
在这里插入图片描述

1.2 初始化

内核在启动函数start_kernel()中调用proc_root_init()函数完成proc文件系统的初始化工作函数定义在/fs/proc/root.c文件内代码如下
在这里插入图片描述

proc_root_init()函数的主要工作是创建proc_inode结构体slab缓存注册proc_fs_type文件系统类型为各子系统添加目录项和文件。

在这里插入图片描述

proc文件系统需要挂载到根文件系统通常是/proc挂载点才能对用户进程可见。那么如何对proc文件系统的挂载以及用户进程对proc文件系统中文件的操作。

在这里插入图片描述

1.3 挂载文件系统

proc文件系统类型挂载函数proc_mount()定义如下fs/proc/root.c

在这里插入图片描述

其与前面介绍过的文件系统挂载类似主要是通过proc_fill_super填充超级块实例创建设置denry、proc_inode实例等主要来看看proc_fill_super函数实现(fs/proc/inode.c)

在这里插入图片描述

内核在/fs/proc/root.c文件内静态创建了proc文件系统根目录项的proc_dir_entry实例proc_root

在这里插入图片描述

proc_fill_super()函数首先对super_block实例进行初始化设置其超级块操作结构实例为proc_sops然后调用proc_get_inode()函数创建proc_inode实例并建立其与proc_root实例的关联创建文件系统根目录项dentry实例并关联proc_inode.vfs_inode成员inode实例最后在根目录下创建self和thread-self目录项。所以其数据结构如下图所示

在这里插入图片描述

proc文件系统需要由用户挂载才能对用户可见。通常在操作系统启动脚本中会将proc文件系统挂载到/proc目录下。

  • 挂载操作将创建proc文件系统超级块super_block实例文件系统根目录项dentry实例以及proc_inode实例。proc_inode实例中包含节点inode结构体成员其i_op、i_fop成员分别指向proc_root实例中proc_iops、proc_fops指向的实例。
  • 对于根节点proc_iops、proc_fops指向的实例是专用的它们分别为proc_root_inode_operations、proc_root_operations。
  • 用户打开proc文件系统中文件时将为每个路径分量目录项创建dentry和proc_inode实例并建立proc_inode实例与proc_dir_entry实例之间的关联。

1.4 添加普通目录项

向proc文件系统添加普通目录项的接口函数为proc_mkdir_data()定义如下fs/proc/generic.c
在这里插入图片描述

设置普通目录文件的节点操作结构和文件操作结构实例为proc_dir_inode_operations和proc_dir_operations这两个实例都是通用的实例最后调用proc_register()函数注册proc_dir_entry实例主要是将其添加到父目录项管理的红黑树中。

向proc文件系统添加文件的操作与添加普通目录项的操作类似主要区别是添加文件时需要定义文件操作结构file_operations实例传递给proc_dir_entry实例。

在这里插入图片描述

对于普通目录项proc_inode内嵌inode实例i_op和i_fop成员赋值为proc_dir_entry实例proc_iops、proc_fops成员值。对于文件目录项proc_inode内嵌inode实例i_op赋值为proc_dir_entry实例proc_iops成员值而i_fop成员指向proc_reg_file_ops实例

在这里插入图片描述

1.6 打开文件

proc文件系统中路径搜索都是从其根目录项开始的根目录项与普通目录项关联inode_operations实例不同搜索函数也不同如下图所示。

在这里插入图片描述

根目录项关联inode_operations实例定义如下fs/proc/root.c

在这里插入图片描述

普通目录项关联inode_operations实例定义如下fs/proc/generic.c

在这里插入图片描述

在打开文件的操作中将调用proc_get_inode()函数为proc_dir_entry实例创建proc_inode实例如果实例代表的是普通文件则inode实例关联的文件操作结构实例设为proc_reg_file_ops定义如下

在这里插入图片描述

打开文件后需要读写文件其也就可以调用该接口的read/write接口其整个流程如下

在这里插入图片描述

2. sysfs

sys文件系统与proc文件系统一样通过内核数据结构实例组织成文件系统它由kernfs_node结构体实例构成。

kernfs文件系统并不是一个完整的文件系统它只是提供构建文件系统的基础组件及相关的接口函数使用kernfs文件系统的子系统需要定义并注册文件系统类型file_system_type实例。其过程与procfs文件基本类似就不单独介绍。

3 pipefs

管道(pipe)和命名管道是进程间通信的机制用于进程间的单向数据传输。管道和命名管道的两端分别是写进程和读进程本质上是一种特殊的文件文件的内容保存在一个内存的缓冲区中(FIFO)。

管道没有文件名称由内核管理只能用于同源的进程间fork()出来的进程间通信对其它非同源的进程不可见。命名管道与普通文件一样具有文件名称文件保存在具体文件系统中导出到内核根文件系统对用户可见可用于任意进程之间的通信。

管道/命名管道包含一个缓存区缓存区可认为有一个进口和一个出口写进程从进口写入数据读进程从出口读取数据数据在缓存区中按写入时间先后顺序排列先进的数据先读出只能按顺序读取不能任意读取。

在这里插入图片描述

父进程创建子进程后表示管道的两个文件描述符将传递给子进程。如果父进程要通过管道向子进程传递数据则关闭父进程读端文件描述符和子进程写端文件描述符。父进程则可以向管道写入数据子进程可从管道读取数据。

pipefs伪文件系统类型pipe_fs_type实例定义如下/fs/pipe.c

在这里插入图片描述

pipefs伪文件系统初始化函数init_pipe_fs()中注册了文件系统类型并执行了内核挂载函数定义如下

在这里插入图片描述

其pipefs_mount比较简单主要工作是创建挂载mount结构体实例调用文件系统类型中定义的mount()函数创建超级块super_block、根目录项dentry和inode结构体实例并建立以上数据结构实例之间的关系执行结果如下图所示。
在这里插入图片描述

我们来学习下如何使用的管道用户进程创建管道的系统调用为pipe和pipe2实现如下

在这里插入图片描述

pipe2()系统调用实现函数定义如下

在这里插入图片描述

pipe()/pipe2()系统调用将返回2个文件描述符参数fildes指向的数组用于存放返回的文件描述符fildes[0]表示读取端文件描述符只读形式fildes[1]表示写入端文件描述符只写形式。
在这里插入图片描述

系统调用内通过__do_pipe_flags()函数创建表示管道的dentry和inode实例分配并初始化表示管道的pipe_inode_info结构体实例分配2个file实例2个文件描述符2个file实例关联到同一个inode实例file和inode关联的文件操作结构实例为pipefifo_fops
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6