Linux将一切设备视为文件,所以对于块设备也一样。块设备常见的有软盘和硬盘两种,虽然当今的硬盘传输速率已经非常快,但还是远不及内存,所以当CPU访问这类块设备的时候需要借助一个缓冲,以求得效率的最大化。因此,在分析块设备数据传输过程前,先了解下高速缓冲区(cache)的结构。
Linux0.11划分内存的一部分作为cache,这部分内存从内核末端开始到4M内存处,一共可以划出3千多个逻辑块,注意一个逻辑块大小为1KB,与minix1.0文件系统定义的盘块大小一致。
当用户调用高层的块设备写函数时(block_write),首先该函数根据要写的字节数count向cache申请相应的缓冲块(不足一块以一块算),然后将用户要写入的数据拷贝到对应的缓冲块上,最后将缓冲块的b_dirt成员置位,表示该缓冲块未同步到设备,并释放该块,唤醒用户进程。
读(block_read)过程与写差不多,首先该函数也是要根据要写的字节数count向cache申请相应的缓冲块(不足一块以一块算),然后将缓冲块中的数据拷贝到用户缓冲区,最后并释放该块,唤醒用户进程。
可以看到,块设备的读写只与cache打交道,并不直接操作块设备,所以大大提高了块设备的读写效率。但是这里有几个关键点要注意:
1.一个文件在第一次读取的时候,由于缓冲区中并没有该文件的缓存,所以该操作还是要慢慢等待块设备的IO操作(低层的ll_rw_block),但是这是一个阻塞式的操作,也即该任务在等待期间将被挂起,所以并不影响其他进程的执行。
2. 对于写操作由于是在cache上进行,当然这个过程会非常快,但终究数据还是要写入到设备上(低层的ll_rw_block),也就是要做一个同步。什么时候同步,第一,如果下次从cache中申请到刚好是已经被之前申请过但还未被同步的块(b_dirt被置位),这时就对该块进行同步;第二就是用户主动调用sync系统调用,手动进行同步。
Linux是如何去管理这个高速缓