韦东山 imx6ull Study 4-1(VFS)

本文解释了Linux内核如何通过VFS(虚拟文件系统)提供通用的文件操作接口,允许用户层通过文件描述符调用特定设备的函数。VFS采用面向对象设计,驱动程序负责填充函数指针以实现特定文件系统功能。文章详细介绍了open函数的工作原理以及设备驱动开发中的角色。
摘要由CSDN通过智能技术生成

现在我在板子上想读写一个文件。这个动作好像极其苦难。

一: Linux kernel

Linux Kernel 只是Linux系统的一部分,它管理所有的系统硬件设备,通过系统调用 向其他程序提供interface。

Linux kernel 主要分为了五大子系统:

分别是

1. Process Scheduler : 进程管理

2. Memory Manager:内存管理

3. VFS(VirtualFile System):虚拟文件系统

4. Network:网络子系统

5. IPC(Inter-Process Communication):进程间通信。

Linux下一切解文件

而对于一个文件的IO操作也是属于VFS的一部分。

二:VFS

VFS 介绍

VFS(Virtual File System,虚拟文件系统)的目的是为了在Linux系统中引入一套通用的文件模型,使其能够表示并操作所有支持的文件系统。

在Linux中,我们不能使用一个特定的函数来对所有设备执行相同的操作,比如read()和ioctl()。相反,我们可以使用指向特定对象的函数指针来执行这些操作。举个例子,如果我有两本书,一本是《哈利·波特》,另一本是《猎人笔记》,它们分别拥有自己的write操作。

当我调用write的时候内核会去钩住 猎人笔记的 write 来实现这个操作,他们都会有各自的write。

当用户层调用write()时,内核会根据文件描述符索引到相应的文件对象,然后执行相应的write操作。这可能涉及到设备驱动程序中的钩子函数,它们会执行特定设备的相关操作,比如read()和write()。

因此,Linux并不是使用一个特定的read函数来完成所有设备的读取,而是通过系统调用和文件对象中的函数指针来调用特定设备的函数,以实现对不同设备的操作。

所以并不是linux的一个特定的read函数能完成所有的设备的读取,而是系统调用会去查询到特定的read,让read能调到特定的函数。

其实通用模型就是面向对象编程的思路,上层通过钩子函数调用底层的各个对象的类来调用类中的成员函数。每个设备都被抽象为一个对象,而每个对象都有其特定的成员函数来处理对应的操作。这种设计使得Linux系统能够灵活地适配不同的设备,并利用对象的多态性来执行特定设备的操作。

虽然它是使用C实现的,但是仍然不妨碍它是面向对象的编程思路。

在VFS中,如果通用的函数无法满足特定文件系统的需求,那么就需要由实际文件系统提供的独特方法来填充这些函数指针。这就涉及到编写特定文件系统的驱动程序。

对于特定的设备或文件系统,需要编写专门的驱动程序来提供其所需的功能。这些驱动程序会实现特定的文件操作函数,比如read()、write()、ioctl()等,以及其他必要的功能。这些函数会被赋值给VFS中对应文件对象的函数指针,从而在文件操作时调用到特定文件系统的实现。

因此,驱动程序的编写就是为了填充VFS中的函数指针,以便实现特定设备或文件系统的功能,确保Linux系统能够灵活地适配各种设备和文件系统。

还好我只是想使用通用的write 和read来对文件进行操作不然,还需要去编写驱动,来填充特定的程序指针。

VFS组成:

VFS一共有4个主要的对象类型:

超级块对象:代表具体的已安装的文件系统。

索引节点对象:代表具体的文件。

目录对象:代表的目录项,是路径的组成。

文件对象:代表进程中打开的文件。

这张图展示了 3个进程来调用文件对象的一个过程。三个进程打开一个文件,每个进程都使用自己的文件对象,但是需要目录对象,目录对象指向索引对象,而索引对象表示超级块对象。如果我们站在,用户层的角度来看,我们首先看到的就是file_operations(文件对象)。下面这个类会表明一些最基本的文件对象的操作。

struct file_operations {
	struct module *owner;
    ...
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ....
    ....
	int (*open) (struct inode *, struct file *);
    ....
    int (*release) (struct inode *, struct file *);
    ....
} __randomize_layout;

当然为了,我更好的去理解,我删去了很多其他的成员函数。比如

int (*mmap) (struct file *, struct vm_area_struct *);

作用用户的我来说我最先看到的是open,所以以open为例,所谓开始

int (*open) (struct inode *, struct file *);

调用关系如下

open() -> do_sys_open() -> file_operation.open()

当然比如我们编写驱动的时候,不需要实现的成员函数我们可以设置成空。不过常见的open() read() write()这样的操作,我们总是需要实现的用来满足用户的请求。

对于open来说我们所需要的就是索引节点对象还有 file打开文件对象。

下篇文章会用以描述open的过程。希望自己能学明白。

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值