操作系统源码学习笔记(五) blk_dev_init/块设备初始化

/ 默认分类 / 0 条评论 / 562浏览

上一节,我们看了中断描述符的初始化过程,下面开始做的操作就是块设备的初始化。 下面我们来详细介绍下,这部分操作。首先来看下源码:

blk_dev_init(); 
void blk_dev_init(void)
{
	int i;

	for (i=0 ; i<NR_REQUEST ; i++) {
		request[i].dev = -1;
		request[i].next = NULL;
	}
}

可以发现,源码很简单明了,无非就是给request数组的每一项的元素的dev和next属性赋值一个默认值数据。但是有的概念我们还是要弄清楚。

一.什么是块设备和字符设备

首先,块设备和字符设备都是计算机外设的一种类型,在操作系统中,块设备(block device)和字符设备(character device)是两种不同类型的设备,它们之间的主要区别在于数据传输的单位和方式。

块设备(Block Device)

  1. 数据传输单位:块设备以固定大小的数据块(通常是以扇区为单位)为传输单位进行数据读写操作。这些数据块是以固定大小进行分割的,通常每个数据块的大小是512字节或4KB。
  2. 访问方式:块设备支持随机访问,即可以直接访问设备中的任意数据块,而不需要按照顺序逐个访问。
  3. 典型示例:硬盘、固态硬盘(SSD)等存储设备通常被视为块设备,因为它们支持随机访问,并且以固定大小的块存储数据。
  4. 特点:块设备通常具有较高的性能和较大的存储容量,适合用于存储大量数据并支持随机访问的场景。由于数据以固定大小的块存储,因此对于大容量的数据传输操作效率较高。

字符设备(Character Device)

  1. 数据传输单位:字符设备以字符流(byte stream)的形式进行数据传输,数据没有固定的大小单元,可以是任意长度的字节序列。
  2. 访问方式:字符设备通常是按照顺序访问的,每次读取或写入都是从设备的当前位置开始,顺序逐个处理字符流数据。
  3. 典型示例:键盘、鼠标、串口设备等通常被视为字符设备,因为它们以字符流的形式进行数据传输,没有固定大小的数据块。
  4. 特点:字符设备通常用于处理流式数据或者与用户交互的设备。它们可以是输入设备(如键盘、鼠标)或输出设备(如显示器、打印机),用于实时处理数据或与用户进行交互。

总的来说,块设备和字符设备是操作系统中常见的两种设备类型,它们在数据传输单位、访问方式以及典型应用场景上有所不同,适用于不同的应用场景和数据处理需求。

综上,我们可以理解为,进程和块设备之间如果想进行数据通信,那么就需要将数据交互的操作需要的东西都封装到一个叫做请求项的request结构体中,也就是说一个请求项就是代表着一次存储盘操作,所以request这个数据结构中应该包含了数据交互需要的所有信息,下面我们来详细看下是不是这样。

二.request请求项数据结构

程序进程如果要和块设备进行通信,必须通过内存缓冲区作为中介,而上面程序中的requests数组就是这种用于通信的数据结构。

/*
 * The request-struct contains all necessary data
 * to load a nr of sectors into memory
 */
struct request request[NR_REQUEST];
/*
 * NR_REQUEST is the number of entries in the request-queue.
 * NOTE that writes may use only the low 2/3 of these: reads
 * take precedence.
 *
 * 32 seems to be a reasonable number: enough to get some benefit
 * from the elevator-mechanism, but not so much as to lock a lot of
 * buffers when they are in the queue. 64 seems to be too many (easily
 * long pauses in reading when heavy writing/syncing is going on)
 */
#define NR_REQUEST	32

/*
 * Ok, this is an expanded form so that we can use the same
 * request for paging requests when that is implemented. In
 * paging, 'bh' is NULL, and 'waiting' is used to wait for
 * read/write completion.
 */
struct request {
	int dev;		/* -1 if no request */
	int cmd;		/* READ or WRITE */
	int errors;
	unsigned long sector;
	unsigned long nr_sectors;
	char * buffer;
	struct task_struct * waiting;
	struct buffer_head * bh;
	struct request * next;
};

request是一个结构体,并且是一个单向链表。request[NR_REQUEST]也就是请求项的数组,数组大小是32. 所以这个数组的结构大致是下面这样的: image.png 这里数组的每个元素在后续的计算机运行过程中可能会通过next指针进行连接,只是最开始执行初始化的时候,是没有连接的,因此next都是赋值了null。

好的,介绍完整体的结构,下面我们来看下request结构体中的每一个属性所代表的含义。

这些数据就可以描述一个块设备的 I/O 请求。使得 Linux 操作系统能够有效地管理和处理块设备的读写操作。

说白了就是为了告诉cpu。 操作什么设备?进行什么操作?从哪里开始操作?操作得到的数据放到哪里?这几个问题。 好了,这一节我们就简单了解到这,只是了解关于读写操作的准备工作,初始化请求项数组。后面会详细介绍io操作。