课程学习总结报告
作业要求:
请您根据本课程所学内容总结梳理出一个精简的Linux系统概念模型,最大程度统摄整顿本课程及相关的知识信息,模型应该是逻辑上可以运转的、自洽的,并举例某一两个具体例子(比如读写文件、分配内存、使用I/O驱动某个硬件等)纳入模型中验证模型。
一、精简的Linux系统概念模型
上完Linux系统分析这门课后,总结来看,老师讲了Linux操作系统有四大功能:进程管理、内存管理、文件系统和驱动程序管理等。
1.1 进程管理
首先,我们从进程管理开始谈起。Linux操作系统内核中最核心的功能是进程管理。这涉及一下几个部分:
- 进程的描述 (task_struct数据结构)
- 进程的初始化(init_task)
- 进程的状态以及状态之间的切换(如下图所示)
- 进程的创建(最终都调用内核函数_do_fork)
- 我们编写的可执行程序是如何作为⼀个进程工作的(ELF、程序的预处理、编译、汇编、链接过程)
- 进程的上下文切换(如下图所示)
进程上下文切换需要保持上个进程的状态,所以引入了函数调用堆栈框架。
- 进程的特权模式切换(系统调用)
这就引申到了Linux系统调用,Linux分为内核态和用户态,其提供的主要功能都在内核态,而用户程序运行在用户态,所以就需要一个中间人——“中断”来完成态的转换。系统调用(trap)是中断的一种。
中断时为了进行“态”的切换,即中断上下文切换。在中断上下文中,系统需要保存当前的状态,以便于中断服务程序执行完成后返回。
![image-20200702201540435](https://img2020.cnblogs.com/blog/1578755/202007/1578755-20200702220750844-153590207.png)
1.2 文件管理
Linux支持多种文件系统,包括ext2、ext3、vfat等等。Linux采用虚拟文件系统VFS来达到支持多种文件系统格式的目标。VFS为各类文件系统提供一个统一的操作界面和编程接口。向上提供统一的编程接口,向下对各种文件系统进行兼容
![image-20200702201540435](https://img2020.cnblogs.com/blog/1578755/202007/1578755-20200702220805006-738275753.png)
文件系统的结构包括在磁盘上的结构和在内存中的结构。磁盘上包括引导控制块、盘控制块、目录结构、FCB。在内存中包括:
- 系统打开文件表:包含每个已打开文件的FCB的副本,以及其他信息。
- 进程打开文件表:包含一个指向系统打开文件表相应项的指针,以及其他信息。
其对应关系如下:
![image-20200702201540435](https://img2020.cnblogs.com/blog/1578755/202007/1578755-20200702220819554-1594369771.png)
file结构一方面可从f_dentry链接到目录项模块以及inode模块,获取所有和文件相关的信息,另一方面链接file_operations子模块,其中包含所有可以使用的系统调用函数,从而最终完成对文件的操作。
1.3 内存管理
在讲进程地址空间时涉及到了内存管理。Linux把进程地址空间分成内核区和用户区两部分。当在内核态申请内存时直接给分配,而进程在用户态申请内存时,只是给了一个新的线性地址空间的一个使用权(打白条),真的要用的时候会产生缺页异常,然后再真的分配。请求调页是一种动态内存分配技术,它把页框的分配推迟到不能再推迟为止。与之相关的分配页框的方式为写时复制:父子进程是共享页框的,当读的时候,不分配新的页框。当写的时候,谁写就给谁分配,两者各自过运行一段时间都就都有了自己的空间。
与进程地址空间有关的全部信息都包含在一个叫做内存描述符的数据结构中,进程只能访问某个有效的线性区,进程的地址空间是线性区链表上所有线性区描述符所规定的集合(通过链表来管理,头部由mmap指向)
- 进程所拥有的线性区通过链表连接在一起
- 链表中的线性区按内存地址的升序排列,线性区可用未用的内存地址区隔开
- 内核通过进程的内存描述符的mmap字段来查找线性区, mmap字段指向链表中的第一个线性区描述符
- mmap_cache用来缓存最近用过的线性区
- 红黑树mm_rb用来定位一个给定的线性地址落在进程地址空间中的哪一个线性区中
![image-20200702201540435](https://img2020.cnblogs.com/blog/1578755/202007/1578755-20200702220832734-908985675.png)
1.4 驱动程序管理
当没有操作系统时,程序员只需要对设备驱动编程;当有操作系统时,程序员需要对设备驱动编程以及对内核接口封装。
设备驱动程序也是通过文件系统来管理的。每个设备都有对应的设备驱动文件,对这个文件的操作,就落实到设备上。设备驱动文件能够找到设备驱动开发者注册到系统中的注册表,然后对相应的设备进行open等。
libc库 open == > sys_open == >设备驱动 == >找到注册的对应的chrdev_open。read的时候返回一个数据结构表指针fd(文件打开表指针),这个系统打开表指针中包含驱动开发者所开发的各种指针。
二、具体例子
示例一:读文件:
-
进程调用库函数read向内核发起读文件请求
-
触发系统调用sys_read(),获得当前进程的控制块
-
系统调用read()会触发相应的VFS的read()函数
-
然后找到file结构,再找到fd数组,以fd为索引找到对应项,然后找到系统打开文件表
-
执行系统打开文件表里面的file operation里面的read
此处有个点需要注意:为什么read之前要先open呢?因为这个系统打开文件表是open创建的。
三、课程总结及建议
之前学习操作系统时,只知其然不知所以然。靠背记下来了一些“知识点”。通过此次课程的学习,有种豁然开朗的感觉。遗憾的是时间太紧,很多知识还没有很好的消化吸收,希望接下来的复习可以加深知识点的理解。最后,这么课真的学到了很多东西,对以后的工作和学习也有很大帮助。孟老师讲的很细致,李老师的知识拓展很全面,很深。两位老师辛苦了,希望这门课越办越好。
小建议:希望李老师的PPT中,代码段密集的地方可以再增加点如下图所示的函数调用关系图/流程图,个人觉得非常利于理清思路,上课时跟上老师的节奏: