【操作系统-哈工大李治军】---学习笔记(下)---操作系统管理内存

# 操作系统—内存
----------------操作系统如何管理CPU------>操作系统如何管理内存-----------------------------------

1 内存使用

1.1 从计算机如何工作开始

在这里插入图片描述
(1)内存使用:将程序放到内存中,PC指向开始地址;

1.1.1 首先程序进入内存

在这里插入图片描述
(1)因为是call 40,因此将程序从磁盘放在内存中,就必须将call 40 放在物理内存的0地址处,_main:mov[300],0指令(main函数入口指令)放在物理内存地址为40的地方,才可以正常执行;但是地址0不一定空闲,或者其他程序也需要放在0地址呢?

(2)应该是在内存中找一段空闲地址,然后放程序;实际上,物理内存0地址处放的是OS操作系统的核心代码;因此,必须修改call 40这里的40;

1.1.2 重定位:修改程序中的地址(相对地址)

在这里插入图片描述
(1)40称为逻辑地址/相对地址;必须修改为实际地址;找到空闲内存,将程序载入内存,然后重定位,设置好PC,修改为物理地址1040;这种修改称为“重定位”

(2)重定位的时间?编译时(执行困难,因为编译时空闲不代表载入时空闲)在嵌入式系统,在固定位置放置固定程序可以,载入时(灵活改变,根据当前空闲,找到一个基址,程序中地址都+基址执行);

1.1.3 程序载入后还需要移动

在这里插入图片描述
(1)进程在执行过程中遇到阻塞,可以换出到磁盘中,执行时再换回来,但地址可能会改变;

1.1.4 重定位最合适的时机,—运行时重定位

在这里插入图片描述
(1)在进程阻塞切换地址时,都是根据PCB中的基址信息,在执行时,每一条指令都会去PCB取出基址进行相加,在运行时才开始重定位;
在这里插入图片描述
(1)在进程切换时,会根据当前运行进程对应的PCB的基地址来修改基地址从2000变为1000;
在这里插入图片描述

1.2 引入分段

在这里插入图片描述
(1)实际上不是将整个程序一起放入,而是由若干部分(段)组成,每个段有各自的特点用途;

(2)每一部分都是从0开始,程序段从0开始,数据段也是从0开始,例如mov[es:bx],ax,就是段寄存器es开始,偏移bx;

(3)将其分段是为了分开管理,例如主程序段是“只读”;而变量集为“可写”;函数库有可能是动态载入;通过分段分治可以增加效率;

1.2.1 进程段表

在这里插入图片描述
(1)因此,**不是将整个程序,而是将各段分别放入内存;**加入3执行中,预留内存不够,那么只需要移动3就可以,如果是整个程序,就需要移动所有程序内存;这移动中,旧内存块和新内存块都不可以使用,降低了使用效率;

(2)不同段有不同的基地址;此时需要一个表记录不同段+偏移;

**(3)对于操作系统OS,将其看做一个整个程序分段,的段表就是GDT;而对于用户进程的段表就叫LDT;**对于每个进程在切换的时候,相应的LDT也需要切换,每次进行地址翻译,需要根据LDT表从逻辑地址到物理地址;

1.2.2 GDT+LDT

在这里插入图片描述
(1)执行每一条指令都需要进行LDT基址查询,地址翻译

1.3 内存分区

  • 冯 * 诺依曼思想,将程序指令放入内存中,CPU取指执行;
  • 分段,不同段不同特点,分段分治;
  • 主要有三个部分:
  • 1、将程序分段,编译器的工作;
  • 2、找到空闲内存,将段放入内存中;
  • 3、读入内存,并初始化LDT表在PCB中,做好地址映射;
1.3.1 内存分区–固定分区与可变分区

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3.2 可变分区的管理—再次申请(算法选择最合适的)

在这里插入图片描述
维护数据结构+算法选择

(1)最佳适配:结果空闲分区会越来越小;

(2)最差适配:结果空闲分区会越来越均匀;

(3)首先适配:最快,其他都要遍历一遍,O(n)

1.4 内存分页—解决内存分区导致的内存效率问题

1.4.1 可变分区造成内存碎片的问题

在这里插入图片描述

(1)当产生内存碎片无法使用时,**将空闲分区合并,称为内存紧缩,**而在合并过程中,上层应用程序不可以运行,因为指令的地址在改变(基址在改变),对外显示为死机;

(2)因此,内存紧缩来处理内存碎片问题并不可行;

1.4.2 分页,从连续到离散

在这里插入图片描述

**(1)!!将物理内存等分为一页一页!!**一页4K最多也就浪费一页4K,就少多了;

(2)从物理内存角度来说:分页(内存浪费少);从用户角度来说:分段(分治);因此,操作系统同时支持分段和分页;

1.4.3 分页中重定位利用页表

在这里插入图片描述
(1)页表寄存器是cr3;一页是4K,2的12次方,例如mov[0x2240],将地址右移12位,也就是去掉后三位,(16进制,2的4次方);剩下0就是02页,这个计算过程是硬件MMU完成的;

(2)一个程序·,一个段打散成好多页,在内存中寻找空闲页框放置;

1.5 多级页表与快表

1.5.1 页表大小

在这里插入图片描述
(1)如果是32位程序,那么地址2的32次方为4G,除以4K(每一页的大小)就等于1M;对应的页表就会很大;
在这里插入图片描述
(1)实际程序运行只有一小部分会使用到;尝试只存放用到的页;

1.5.2 第一次尝试:只存放用到的页表(失败)

在这里插入图片描述
(1)例如,是一个4M内存的程序,那么4M/4K(每一页的大小)=1000;平均需要查找500次,每执行一条指令就要重定位,就要查500次表,表也在内存中,因此每执行访问内存一次需要额外访问内存500次!!!----------因为不顺序了

(2)二分法也是1000就是2的10次方,10次;也依旧不划算;执行指令的速度也会变慢很多;

(3)CPU执行一条指令关键就在于访问内存,自己CPU内部进行计算操作是很快的;

(4)因此,必须要连续!!;

1.5.3 第二种尝试:多级页表,即页目录表(章)+页表(节)

在这里插入图片描述
(1)一个页目录4K+3个页号表(每个4K)=16K;

(2)页目录是连续的,不用进行比较;有位置不存储;

1.5.4 快表的引出

在这里插入图片描述
(1)每增加一级页表就会增加一次访问内存,因此多级页表提高了空间效率,但增加了额外的访问次数;页表级数增多可以节省内存,但是会增加访问内存的次数;

(2)对于64位系统,可能就有5.6级的页表,会增加访问内存的次数;多级页表在保证空间连续和时间,节省了空间,但是时间访问内存也有消耗(比二分法少多了);

(3)保证空间连续同时减少内存,采用多级页表,但对于增加的访问内存次数,需要引用快表;

(4)快表使用TLB寄存器完成,寄存器访问很快,稀缺硬件资源,存储最近访问的逻辑地址(页号),物理地址(页框号);

(5)这里的寻找页号,是通过硬件电路一次实现;但是如果不再快表中,就去多级页表中继续查找,同时将查找结果更新进快表;
在这里插入图片描述
(1)关键命中率,一方面提高快表大小(但寄存器稀缺),一方面怎么选择存储哪些地址映射;
在这里插入图片描述
(1)因为我们写的程序多呈现出“局部性”和“循环性”

1.6 段页结合的实际内存管理

在这里插入图片描述
在这里插入图片描述
(1)一个程序还是分段,但是映射到一个中间体(地址空间),然后将中间体按页映射到物理内存中;地址空间像内存,但不是真的内存,称为“虚拟内存”;

1.6.1 段、页同时存在:段面向用户/页面向硬件

在这里插入图片描述
(1)将虚拟内存引入后,有机结合段和页;

1.6.2 段、页同时存在时的重定位(地址翻译)

妙啊!!
在这里插入图片描述

1.6.3 实际的段页式内存管理的代码实现

在这里插入图片描述
在这里插入图片描述
(1)步骤:

  • 1、在虚拟内存中分区;
  • 2、建立段表;(建立用户与虚拟内存之间的地址映射);
  • 3、在物理内存中寻找空闲页;
  • 4、建立页表(虚拟内存与物理内存的地址映射);
  • 5、通过重定位具体的使用内存;
1.6.4 从fork()进程开始

在这里插入图片描述
(1)copy_process()形成叉子,copy_mem就是复制父进程状态到子进程,用户态相同,内核态不同;

(2)copy_mem具体要做的事情:set_base()就是设置基址(段表里就放的基址)建立段表;p就是PCB,ldt就是每个进程的段表,ldt[1]代码段基址;idt[1]数据段基址;

(3)new_data_base=nr*0x4000000,就是对虚拟内存的分割,nr代表进程,0进程nr=0;1进程nr=1;

**(4)new_data_base=nr*0x400000;是对虚拟内存进行分割;set_base是填写段表,这个例子中简单,所以代码段和数据段都相同;**P是PCB;进程切换会跟着切换;
在这里插入图片描述
**(1)不同进程之间的虚拟地址都不重叠,进程中的代码段和数据段都指向相同地址;**这个方案弱智简单,从简单开始;

(2)虚拟地址到物理地址的二次映射;

(3)互不重叠意味着简化:每个虚拟地址要对应页表;以虚拟地址为页号查找页框号(物理地址),不同进程的虚拟地址(逻辑页)不重叠,所以可以共用一套页表;
在这里插入图片描述
(1)子进程不分配内存,共用父进程分配的页,但是需要建立页表,页表的虚拟地址不同建立新的页表,copy_page_tables(old_data_base,new_data_base,data_limit);
在这里插入图片描述
(1)from_dir是虚拟地址,是32位,应该右移22位的就剩下了页目录号(4G空间中的哪一个4M(章)),**实际是右移22号再乘以4,**每个大小是4字节,*4最终就是右移20位;

(2)from_dir是找到了对应的哪一章,还需要继续找页框号(节);
在这里插入图片描述
(1)to_dir指向子进程的页目录;在创建子进程之前,to_dir这一段是空白的没有被使用,在建立子进程之后,开始get_free_table分配一个物理内存页;建立节目录,并将新申请的地址赋给to_dir;
在这里插入图片描述
(1)接下来,将新申请的页拷贝填满;根据父进程的节页表;this_page&=~2就是将其权限设置为只读,因为父子进程指向相同地方;
在这里插入图片描述
(1)此时完成了子进程的段页实现,虽然都是拷贝父进程的,但是基本样子具备了;
在这里插入图片描述
(1)最后一步,就是使用;逻辑地址到虚拟地址,虚拟地址到物理地址;

(2)在子进程中,对应找到7,但是因为设置为只读,在子进程写的时候就要进行分离,指向另一个页(新申请一个内存页),修改页表,建立新的映射;

1.7 内存换入—请求调页Swap in

!!为了实现虚拟内存,就应该换入换出!!

!!基于虚拟内存实现段页结合,而通过换入换出机制支持虚拟内存!!

1.7.1 从虚拟内存开始,段、页同时存在

在这里插入图片描述
在这里插入图片描述

1.7.2 用换入,换出实现“大内存”

在这里插入图片描述
(1)换入,从磁盘上换入到内存中;

(2)请求时才做地址映射;请求调页并建立页表映射

1.7.3 请求调页

在这里插入图片描述
(1)硬件MMU查页表,发现缺页,就会出现一个中断;CPU每执行完一条指令就回去查询是否有新的中断产生;就执行中断—页错误处理程序;就新从磁盘上调用一个新页,并建立新页的地址映射,中断重新返回到当前指令(PC自动+1,此处硬件会特殊改动,继续执行当前指令);
在这里插入图片描述
(1)C

1.7.4 一个实际系统的请求调页

从中断处理程序—页错误处理程序开始

查询中断号,14:页不在内存

!!从磁盘中读入页到内存,建立映射!!
在这里插入图片描述
(1)从系统初始化开始,修改中断向量映射表idt;

1.7.5 处理中断page fault

在这里插入图片描述
(1)虚拟地址就是线性地址;压入参数调用C函数do_no_page;
在这里插入图片描述
(1)找空闲页,读磁盘到内存,建立映射;

(2)address&=0xffff000;是为了得到虚拟页号,最后12位是页内偏移;get_free_page是得到物理空闲页;bread_page是根据空闲页从磁盘上读取;bread_page,b代表磁盘(block),read就是读操作;put_page就是建立页表,物理page和虚拟地址address建立映射;
在这里插入图片描述

1.8 内存换出

在这里插入图片描述

1.8.1 选择淘汰(换出)的页

1、FIFO页面置换
在这里插入图片描述
2、MIN页面置换
在这里插入图片描述
(1)需要知道后面的事情,不知道!

3、LRU页面置换
在这里插入图片描述
(1)利用程序的**“局部性”和“循环性”**;

1.8.2 LRU的准确实现,用时间戳/页码栈

1、时间戳实现
在这里插入图片描述
(1)实际上并不可行,A是逻辑页,每执行一条指令,要取值,要重定位(地址翻译)MMU查页面,每个时间戳都要维护这样一个数组或修改;时间戳很容易溢出;

2、页码栈实现
在这里插入图片描述

1.8.3 LRU近似实现

1、将时间计数变为是否判断,clock算法
在这里插入图片描述
(1)最近是否被使用,在转一圈的时间内没有被访问过;

(2)这个引用位放在页表中,MMU硬件实现就很快了,每次访问只需要置一位0/1就可以;不需要LRU维护一个复杂的数据结构;使用这个引用位来近似最近是否被访问;SCR,clock算法;

(3)但是它对于LRU的近似不好;

2、clock算法的分析与改造
在这里插入图片描述
(1)缺页是很少的,局部性+循环性;缺页很少意味着从1变0很少;是在缺页转动指针时从1到0的改动;访问这一页就会从1变成0;这些页一直被访问,就都变成1,最终效果是R都是1;一旦发生缺页,会将所有1变成0,很长时间内都不缺页都变成0,然后再发生缺页就会换成依次换出;算法就退化为FIFO;

(2)来一个扫描指针(转的快),定时清除R位,将R=1都置为R=0;要表达最近没有被使用过的思想;之前是因为时间太长了,基本上所有都被访问过了,变得一样,加快扫描,就突出最近没有被使用过;

3、给进程分配多少个页框
在这里插入图片描述
(1)颠簸:进程的执行不断等待内存与磁盘间的调页完成,导致CPU利用率急剧下降

(2)根据工作集;确定进程的页框数量,应该足以盖住这个局部;

1.8.4 换入和换出组合

在这里插入图片描述

2 IO设备驱动

2.1 I/O与显示器

2.1.1 “计算机样子”

在这里插入图片描述

2.2 显示器

2.2.1 让外设工作起来
  • CPU向外设控制器显卡发送指令;(发送out指令)
  • 显卡向CPU发出中断;
  • 写中断处理程序;
    在这里插入图片描述
    (1)操作系统让外设工作起来,很简单主要使用Out指令就可以,

(2)但是,还要处理三件事:

  • 核心的out指令;
  • 中断处理程序;
  • 为了使用外设使用更加简单,形成一个统一的视图(接口):文件视图
2.2.2 一段操纵外设的程序

在这里插入图片描述
1、一个统一的视图–文件视图
在这里插入图片描述
2、开始给显示器输出
在这里插入图片描述
(1)从write开始分支,最后out不同的外设设备;

(2)write从int 0x80开始进入内核sys_write,传入参数关键在于1区分外设设备,fd接收1,current是当前进程;

(3)操作打印机,操作显示器等等本质都是操作文件

3、fd=1的filp从哪里来
在这里插入图片描述
(1)current当前进程都是通过fork()从父进程那里拷贝来的;分析shell,

(2)init()就是打开了文件,dup(0)拷贝了两份;

4、open系统调用完成了什么
在这里插入图片描述
(1)filename文件名字,核心是****inode就是在磁盘上的对应外设设备的信息;open**

关键在于根据1读取外设存储在磁盘上的信息inode;

5、根据inode找out,前面是对out的封装统一接口
在这里插入图片描述
(1)区分char设备(字符设备)和块设备;rw_char就是读写char设备;

(2)crw_table就是一个函数指针数组;

(3)rw=WRITE;写;
在这里插入图片描述
(1)write(_q)是一个缓冲队列;如果缓冲区满,就睡眠等待;
在这里插入图片描述
(1)c=get_fs_byte(b)从用户缓冲区buf中读一个字符c,PUTCH将字符c放在队列;调用tty->write真正开始输出屏幕;

(2)从文件视图->字符设备->tty(4号)字符设备->缓冲区->tty->write写入显卡->out
在这里插入图片描述
(1)fd->找inode(文件类型)->确定了是tty(显示器)->转交给驱动程序(由驱动程序写寄存器);

(2)这里的movw就是Out;

(3)以上代码就是设备驱动程序;
在这里插入图片描述
在这里插入图片描述

2.2.3 printf的整个过程

在这里插入图片描述

2.3 键盘

!!终端设备包括显示器和键盘!!
在这里插入图片描述
(1)三件事:

  • 核心向外设端口或寄存器发出读写指令(out指令);
  • 统一文件视图,隐藏端口等复杂细节,out指令通过文件封装;
  • 中断处理程序

(2)键盘—中断处理程序

2.3.1 键盘从中断开始

在这里插入图片描述
(1)查询键盘中断号为0x21;**inb $0x60,%al;outb是输出一个字节,inb就是读入一个字节;将60端口的内容(扫描码)读入al寄存器;**根据不同的扫描码来key_table不同的操作;

2.3.2 处理扫描码key_table+eax*4

在这里插入图片描述
(1)do_self就是一个函数,
在这里插入图片描述
(1)将得到的ASCII码放在缓冲队列中;
在这里插入图片描述

2.3.3 键盘处理小结

在这里插入图片描述
在这里插入图片描述

3 磁盘管理

”仍然是Out+文件视图+中断处理“三个核心

3.1 生磁盘的使用

在这里插入图片描述

3.1.1 认识磁盘

在这里插入图片描述
1、磁盘的I/O过程
在这里插入图片描述
(1)首先将磁头移动到相应磁道上,旋转磁道,找到512字节的扇区,磁生电;磁信号变为电信号,将电信号内容写入内存缓存中,如果在内存缓存中写一个字节,就将电信号转为磁信号写到对应磁道扇区内;

3.1.2 最直接的使用磁盘

在这里插入图片描述
**(1)往控制器中写柱面、磁头、扇区、缓存位置;**通过DMA总线盗用技术,将信息读入内存或写入磁盘;重点在于传递这几个数值;使用out指令,将对应信息sec,head,cyl拼接形成信息

(2)进行抽象,不用这好几个信息,通过告诉第几个磁盘块来读写磁盘,相应转化由操作系统完成;

3.1.3 通过盘块号读写磁盘(一层抽象)

在这里插入图片描述
(1)隐藏信息,从一维信息到三维信息的编址过程;

(2)block相邻的盘块可以快速读出,因为用户经常会访问相邻的磁盘盘块;

(3)寻道时间:磁臂运动到相应柱面的时间(机械运动);主要的时间消耗;因此将相邻盘块尽量放在同一个磁道上;可以放在相邻或者下一个盘面,因此最好放在相邻位置;一个磁臂上有多个磁头;
在这里插入图片描述
(1)因此,7号扇区放在垂直方面的下一个盘面的对应位置0号扇区的下面;编址方式就是这样,就可以根据盘块号确定C\H\S;柱面、磁头、扇区号

(2)**从扇区到盘块:**提高效率,每次寻道可以多读几个扇区;但是会造成空间碎片;每次读写的单位(连续的几个扇区)一起读写,读写单位从扇区->盘块;

(3)空间和速度的权衡,硬盘越来越大,可以用空间来换取时间;

3.1.4 接着使用磁盘:程序输出block盘块号

在这里插入图片描述
(1)根据盘块号Block得到sec,cyl和head;

(2)Linux0.11盘块就是两个扇区,扇区号是盘块号右移一位;每个盘块读写出两个扇区;

3.1.5 多个进程通过队列使用磁盘(第二层抽象)

在这里插入图片描述
(1)多个进程需要一个请求队列,缓冲队列;操作系统要进行调度,磁盘读写完成后发出中断之后,继续会到队列中取盘块号来进行读写磁盘

(2)此时还是生磁盘,通过盘块号访问磁盘就是生磁盘,根据文件访问磁盘就是熟磁盘;

(3)FCFS先来先服务最简单;寻道时间是主要矛盾;让寻道时间越小越好;

1、FCFS磁盘调度算法
在这里插入图片描述
(1)多个进程交替进行,也是完全混乱的,应该是没有规律的;

(2)在移动过程中把经过的请求处理了

2、SSTF磁盘调度(最近优先访问)
在这里插入图片描述
(1)从最近的开始,先将最近的都访问了,再往远处访问;

(2)位于中间磁道的多,就总是在中间来回移动,那么在远处的磁道访问就会造成饥饿;

3、SCAN磁盘调度(SSTF+中途不回折)—电梯算法
在这里插入图片描述
(1)回顾,CPU调度是轮转+优先级折中算法;页面设计的时候是Clock算法;磁盘设计调度就是SCAN磁盘调度算法;

3.1.6 多个进程共同使用磁盘

在这里插入图片描述
(1)多进程通过电梯算法将自己的请求放入请求队列,多个进程访问磁盘产生请求,放入请求队列中,在磁盘中断从队列中取出盘块号,计算CHS,再通过out指令发给磁盘控制器;使用生磁盘的完整流程;

(2)make_request根据用户发来的盘块号计算扇区号,调用add_request将请求放在队列中,开闭中断进行保护变量;

(3)放入队列中应该满足红色if条件(电梯算法,形成一个电梯队列),两种情况满足if插入,tmp<req<tmp ->next;或者,tmp<tmp ->next && req<tmp ->next;

3.1.7 生磁盘(raw disk)的使用整理

在这里插入图片描述

  • 进程得到盘块号,计算扇区号;

  • 根据扇区号make_req用电梯算法放入请求队列中;

  • 进程将请求放在队列中,进程就开始sleep on,接下来等待硬件(磁盘);

  • 磁盘中断处理就开始调用do_hd_request从队列中取出请求,计算出cyl,head,sector根据out指令,开始访问磁盘信息,通过DMA放入缓冲内存;

  • 磁盘工作完成后,再次发出中断进入中断处理程序,end_request(1)结束这个请求,就会唤醒进程;进程就可以在缓冲内存区发现自己想取到的信息;

3.2 从生磁盘到文件

!!用户使用磁盘,往往是通过文件,而不是盘块号!!

如何从文件得到盘块号?重点—Files-cooked Disks

3.2.1 引入文件,对磁盘使用的第三层抽象

在这里插入图片描述
(1)核心:建立字符流到盘块集合的映射关系;

3.2.2 映射的作用(线性结构)

在这里插入图片描述
(1)操作系统负责维护这个映射;

(2)每个文件都用FCB数据结构来确定映射关系,只需要存放文件的起始块和块数;

(3)上述就是按照连续结构来实现文件;缺点在于增加到一定程度,就需要整体移动整个文件到别的磁盘位置;读写处理起来比较快,不适合动态增长;

3.2.3 链式结构实现文件存放

在这里插入图片描述

3.2.4 文件实现的第三种结构:索引结构inode

在这里插入图片描述
(1)索引类似于目录;根据inode找到索引块,添加也方便,覆盖-1增加表就可以;

1、实际系统是多级索引
在这里插入图片描述

3.3 文件使用磁盘的实现

核心:从字符流位置算出盘块号,有多种不同结构及对应映射FCB

3.3.1 再一次使用磁盘,通过文件使用

在这里插入图片描述
(1)通过read_write来读写磁盘,fd为文件描述符,buf是内存缓冲区指针,count是读取字符数;函数内部一定会被转化为盘块号,通过盘块号计算出扇区号;
(2)进入内核调用sys_write,根据PCB,获得inode,计算盘块号;

3.3.2 file_write的工作过程

在这里插入图片描述
1、file_write的实现
在这里插入图片描述
(1)file是一个指针,filp->f_ pos就是字符流中的读写位置(200-212);if(append)就是追加,如果追加就是从文件末尾inode->i_size开始pos;

(2)核心:根据inode(读写位置)得到盘块号, ,block左移一位就可以得到扇区号;bread()就是要make_request放入请求队列,阻塞进程等待磁盘读写完成中断唤醒;

2、create_block算盘块,文件抽象的核心
在这里插入图片描述
(1)有7级索引,0-6个是直接数据块,直接new_block;如果大于等于7,block-=7,再判断是一重间接和二重间接;

(2)**一个盘块=2个扇区=512*2=1024=1K;一个盘块号2个字节=16位=65536;**如果是直接索引就是直接读取i_zone中对应的盘块号,如果是多重间接的话,再进行判断操作;

(3)pos作为参数传入后,pos/BLOCK_SIZE计算出逻辑号,根据block再索引盘块号;

3、m_inode,设备文件的inode
在这里插入图片描述
(1)inode提供统一的文件视图,如果是文本文件就找inode里的pos确定字符流中的字符读写位置i_zone,如果是特殊的文件(设备),就有对应的主设备号,从设备号;

3.3.3 统一的文件视图

在这里插入图片描述
(1)用户使用文件是通过**,fd=open(“test.c”);read(fd);这一节讲的是read,根据fd获取inode,获取字符读写位置pos,再获取盘块号block,根据盘块号往电梯队列中放,计算CHS,发送out指令到磁盘控制器,控制器驱动马达形成数据;**

(2)下一节是通过文件名找到fd->inode;
在这里插入图片描述

3.4 目录与文件系统

在这里插入图片描述
(1)之前是一个文件对应一个盘块集合

3.4.1 文件系统,抽象整个磁盘(第四层抽象)

在这里插入图片描述
(1)左侧树就是用户看到的文件系统,而**操作系统通过维护在磁盘块中一个数据结构来映射左侧的文件树系统,**一旦形成结构,即使更换系统,也可以一样读取文件;

3.4.2 从多个文件开始,引入目录树

在这里插入图片描述
(1)之前是一层,所有文件都放在一起,不好管理;
在这里插入图片描述
(1)核心:形成目录作为关键问题
在这里插入图片描述
(1)用户发送下来的就是路径“/my/data/a”,根据路径名找到文件a的FCB(inode)

3.4.3 树状目录的完整实现

在这里插入图片描述
(1)需要根据上层目录找到下层目录,**因此上层目录应该存放有下层目录的FCB;**但这种方式比较慢,**要匹配文件名字符串,不需要读取存储FCB,因此只需要存放FCB的指针就可以;FCB的编号,将FCB形成数组 **

(2)如果使得整个文件系统能够自举,需要存放放信息能成功找到根目录;
在这里插入图片描述

3.4.4 "完成全部映射下"的磁盘使用

在这里插入图片描述

3.5 目录解析代码实现

在这里插入图片描述
就是将最上面一层的抽象open代码学习明白,通过文件路径找到对应的FCB指针下的inode

3.5.1 将open弄明白

在这里插入图片描述
(1)open核心:找到inode; 内核实现是sys_open中的open_namei,根据传入的filename从磁盘上找到inode,再将其写到传入的inode的地址&inode;

3.5.2 get_dir完成真正的目录解析

在这里插入图片描述
(1)先判断路径是否为/开头的根目录,否则为当前路径下的绝对路径;

(2)current->root就是根目录的FCB的inode;首先磁盘启动时,会将最基本的磁盘amount上去,最基本磁盘的根目录就会到初始进程shell里面,其他进程都是shell的fork()进程,自然会拷贝根目录,所以root一直都有;

(3)根据根目录的inode找到根目录的数据内容,一堆数据项,每一个数据项是一个字符串+这个文件名对应的inode数组编号;

(4)从根目录开始,依次向下级目录索引;

3.5.3 目录解析—从根目录开始

在这里插入图片描述
(1)从最init()进程开始,iget读取根目录,current->root就是根目录;
在这里插入图片描述
(1)读取某一个节点,要获取前面超级块+i节点位图+盘块位图的长度,得到某一节点的内存地址,获取盘块号;

(2)get_super开始,block=2(引导块+超级块)+节点位图imap+盘块位图zmap+i_num=nur(传入的参数nr编号)/PER/BLOCK=第几个盘块;启动bread开始从磁盘读取;
在这里插入图片描述
(1)find_entry找到var对应的编号13;match(namelen,anme,de)就是挨个匹配“var”
在这里插入图片描述

4 操作系统全图

在这里插入图片描述

  • 多进程图像,程序就可以开始执行,CPU取指执行,多进程交替执行

  • 有的指令要*p=7读取磁盘(重定位,段页结合,虚拟内存,换入换出)使用内存

  • open,bread,文件名为普通磁盘,得到inode,计算盘块号,如果是特殊文件(显示器)就对应主次磁盘号;形成文件视图view,IO就使用起来;

  • 管理CPU,内存,IO

  • 两大视图:多进程视图+文件视图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值