操作系统课程设计缓冲区管理

上传人:鲁** 文档编号:508104278 上传时间:2022-11-01 格式:DOC 页数:20 大小:303.50KB
返回 下载 相关 举报
操作系统课程设计缓冲区管理_第1页
第1页 / 共20页
操作系统课程设计缓冲区管理_第2页
第2页 / 共20页
操作系统课程设计缓冲区管理_第3页
第3页 / 共20页
操作系统课程设计缓冲区管理_第4页
第4页 / 共20页
操作系统课程设计缓冲区管理_第5页
第5页 / 共20页
点击查看更多>>
资源描述

《操作系统课程设计缓冲区管理》由会员分享,可在线阅读,更多相关《操作系统课程设计缓冲区管理(20页珍藏版)》请在金锄头文库上搜索。

1、 目 录一、绪论 4二、分析内容及目标4三、分析概述4四、源代码分析 7五、分析体会21六、自我评价22七、参考书目22一、绪论高速缓冲区是文件系统访问块设备中数据的必经要道。为了访问文件系统等块设备上的数据,内核可以每次都访问块设备,进行读或写操作。但是每次I/O 操作的时间与内存和CPU 的处理速度相比是非常慢的。为了提高系统的性能,内核就在内存中开辟了一个高速数据缓冲区(池)(buffer cache),并将其划分成一个个与磁盘数据块大小相等的缓冲块来使用和管理,以期减少访问块设备的次数。从而是CPU读取数据的速度大大提高。二、分析内容及目标本次操作系统的任务是分析Linux0.11文件

2、系统下的高速缓冲区源代码。在linux内核中,高速缓冲区位于内核代码和主内存区之间,高速缓冲中存放着最近被使用过的各个块设备中的数据块。当需要从块设备中读取数据时,缓冲区管理程序首先会在高速缓冲中寻找。如果相应数据已经在缓冲中,就无需再从块设备上读。如果数据不在高速缓冲中,就发出读块设备的命令,将数据读到高速缓冲中。当需要把数据写到块设备中时,系统就会在高速缓冲区中申请一块空闲的缓冲块来临时存放这些数据。至于什么时候把数据真正地写到设备中去,则是通过设备数据同步实现的。Linux 内核实现高速缓冲区的程序是buffer.c。文件系统中其它程序通过指定需要访问的设备号和数据逻辑块号来调用它的块读

3、写函数。这些接口函数有:块读取函数bread()、块提前预读函数breada()和页块读取函数bread_page()。页块读取函数一次读取一页内存所能容纳的缓冲块数(4 块)。buffer.c 程序用于对高速缓冲区(池)进行操作和管理。高速缓冲区位于内核代码块和主内存区之间。高速缓冲区在块设备与内核其它程序之间起着一个桥梁用。除了块设备驱动程序以外,内核程序如果需要访问块设备中的数据,就都需要经过高速缓冲区来间接地操作。本次课程设计的目标是通过分析一个早期的Linux内核,加深对操作系统具体的组成模块实现机制的理解,同时也为今后从事底层的研究开发增加一些实践经验。三、分析概述在前面已经看到,

4、Linux0.11的内存分布包括内核模块、高速缓存、虚拟磁盘(可选)、主存储区四个部分。高速缓冲区在块设备和内核其它之间起着桥梁作用,用于缓冲读写块设备时的数据。除了块设备驱动程序以外,内核程序如果需要访问块设备中的数据,都需要经过高速缓冲区来间接地操作。 高速缓冲区从end开始,到buffer_memory_end结束,其中包含用于显卡和BIOS ROM(640K1M)的空间。高速缓冲区被划分为两部分:低端为缓冲头,高端为缓冲块。缓冲块具有固定的长度1024字节,用来缓存从块设备上读写的数据;缓冲头用buffer_head定义,用于描述对应缓冲块的属性和把所有缓冲头连接成链表。高速缓冲区的位

5、置 在缓冲区初始化过程中,从缓冲区的两端开始,(在缓冲块部分)略过用于显卡和BIOS ROM的内存部分,分别设置缓冲头结构和划分出对应的缓冲块,直到它们之间已经不能再划分出缓冲块为止。这时可能剩下部分碎片空间无法利用。初始化结束后,高速缓冲区中的缓冲头和缓冲块一一对应,其个数保存在NR_BUFFERS中。由于缓冲块是用来缓存块设备上的读写数据的,因此有两个字段特别关键:设备号以及数据块编号。这两个字段唯一确定了缓冲块中数据对应的块设备和数据块。读写一个块设备的某个数据块前,对应的缓冲头及缓冲块必须存在;并且一个设备上的某个数据块在高速缓冲区只能有一个对应的缓冲头及缓冲块。图中高速缓冲区的起始位

6、置从内核模块末段end 标号开始,end 是内核模块链接期间由链接程序(ld)设置的一个值,内核代码中没有定义这个符号。当在连接生成system 模块时,ld 程序的digest_symbols()函数会产生此符号。该函数主要用于对全局变量进行引用赋值,并且计算每个被连接文件的其始和大小,其中也设置了end 的值,它等于data_start + datasize + bss_size,也即内核模块的末段。整个高速缓冲区被划分成1024 字节大小的缓冲块,正好与块设备上的磁盘逻辑块大小相同。高速缓冲采用hash 表和空闲缓冲块队列进行操作管理。在缓冲区初始化过程中,从缓冲区的两端开始,同时分别设

7、置缓冲块头结构和划分出对应的缓冲块。缓冲区的高端被划分成一个个1024 字节的缓冲块,低端则分别建立起对应各缓冲块的缓冲头结构buffer_head(include/linux/fs.h,68 行),用于描述对应缓冲块的属性和把所有缓冲头连接成链表。直到它们之间已经不能再划分出缓冲块为止,见下图所示。 为管理方便,buffer_head结构具有四个指针:b_prev_free和b_next_free将所有缓冲头链接成一个空闲缓冲块双向链表;而b_prev和b_next用于hash表中散列在同一项上多个缓冲块之间的双向链接。HASH表所使用的散列函数由设备号和逻辑块号组合而成,使用的具体方法是(

8、设备号逻辑块号)mod 307。 此外,buffer结构还包括一些其它字段,包括:数据有效(更新)标志,修改标志,数据被使用的进程数和本缓冲块是否上锁标志,以及指向等待该缓冲区解锁的任务。 当内核其它部分需要访问块设备中的数据时,在高速缓冲区分配缓冲头结构以及存储空间,块设备驱动程序(实际是低层读写数据块函数ll_rw_block)负责处理利用缓冲头结构构造读写请求,并调用对应块设备类型的请求处理函数向块设备控制器写入控制指令。我们将在后面讲述。现在Linux系统中已经不再有独立的缓冲区高速缓存了。但在2.2版本的内核中,存在两个独立的磁盘缓存:页高速缓存和缓冲区高速缓存。前者缓存页,后者缓存

9、缓冲。两种缓存并不统一:一个磁盘块可以在两种缓存中同时存在,因此需要对两个缓存中的同一拷贝进行很麻烦的同步操作还不用说要消耗额外的内存。该情况存在于2.2和更早版本的内核中,但是从2.4版本的内核开始,统一了这两种缓存,现在Linux只有惟一的磁盘缓存页高速缓存。虽然如此,内核仍然需要在内存中使用缓冲来表示磁盘块,幸好,缓冲是用页映射块的,所以它正好在页高速缓存中。四、源代码分析1使用的基本函数n Cli()/sti() :开关中断n bread() :块读取n breada():块提前预读函数n bread_page():页块读取函数n getblk():缓冲区搜索管理函数n brelse(

10、) :释放缓冲块函数n remove_from_queues():队列移除函数 n sleep_on(&buffer_wait); 睡眠函数n ll_rw_block():读设备块请求函数 n get_hash_table():哈希搜索函数,程序中使用的具体函数是:(设备号逻辑块号) Mod 307 2缓冲头数据结构struct buffer_head char * b_data;/指向该缓冲块区数据区(1024字节的)指针unsigned long b_blocknr; /block number */块号unsigned short b_dev; / device (0 = free) *

11、/数据源的设备号unsigned char b_uptodate; /更新标志:表示数据是否已更新unsigned char b_dirt; /修改标志:0未修改,1已修改unsigned char b_count; /使用的用户数unsigned char b_lock;/* 0 - ok, 1 -locked */ 缓冲区是否被锁定struct task_struct * b_wait; /指向等待该缓冲区解锁的任务struct buffer_head * b_prev; /hash队列上前一块(用于缓冲区管理)struct buffer_head * b_next; /hash队列上后一

12、块struct buffer_head * b_prev_free; /空闲表上前一块struct buffer_head * b_next_free;/ 空闲表上后一块;3buffer.c 程序结构buffer.c 程序用于对高速缓冲区(池)进行操作和管理。高速缓冲区位于内核代码块和主内存区之间。高速缓冲区在块设备与内核其它程序之间起着一个桥梁用。除了块设备驱动程序以外,内核程序如果需要访问块设备中的数据,就都需要经过高速缓冲区来间接地操作。各个buffer_head 被链接成一个空闲缓冲块双向链表结构。详细结构见下图所示。缓冲头结构中“其它字段”包括块设备号、缓冲数据的逻辑块号,这两个字段

13、唯一确定了缓冲块中数据对应的块设备和数据块。另外还有几个状态标志:数据有效(更新)标志、修改标志、数据被使用的进程数和本缓冲块是否上锁标志。内核程序在使用高速缓冲区中的缓冲块时,是指定设备号(dev)和所要访问设备数据的逻辑块号(block),通过调用bread()、bread_page()或breada()函数进行操作的。这几个函数都使用了缓冲区搜索管理函数getblk(),该函数将在下面重点说明。在系统释放缓冲块时,需要调用brelse()函数。这些缓冲区数据存取和管理函数的调用层次关系可用下图来描述。为了能够快速地在缓冲区中寻找请求的数据块是否已经被读入到缓冲区中,buffer.c 程序

14、使用了具有307 个buffer_head 指针项的hash 表结构。上图中buffer_head 结构的指针b_prev、b_next 就是用于hash表中散列在同一项上多个缓冲块之间的双向连接。Hash 表所使用的散列函数由设备号和逻辑块号组合而成。程序中使用的具体函数是:(设备号逻辑块号) Mod 307。对于动态变化的hash 表结构某一时刻的状态可参见下图所示。其中,双箭头横线表示散列在同一hash 表项中缓冲块头结构之间的双向链接指针。虚线表示当前连接在空闲缓冲块链表中空闲缓冲块之间的链接指针,free_list 是空闲链表的头指针。上面提及的三个函数在执行时都调用了缓冲块搜索函数

15、getblk(),以获取适合的缓冲块。该函数首先调用get_hash_table()函数,在hash 表队列中搜索指定设备号和逻辑块号的缓冲块是否已经存在。如果存在就立刻返回对应缓冲头结构的指针;如果不存在,则从空闲链表头开始,对空闲链表进行扫描,寻找一个空闲缓冲块。在寻找过程中还要对找到的空闲缓冲块作比较,根据赋予修改标志和锁定标志组合而成的权值,比较哪个空闲块最适合。若找到的空闲块既没有被修改也没有被锁定,就不用继续寻找了。若没有找到空闲块,则让当前进程进入睡眠状态,待继续执行时再次寻找。若该空闲块被锁定,则进程也需进入睡眠,等待其它进程解锁。若在睡眠等待的过程中,该缓冲块又被其它进程占用,那么只要再重头开始搜索缓冲块。否则判断该缓冲块是否已被修改过,若是,则将该块写盘,并等待该块解锁。此时如果该缓冲块又

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 工作计划

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号