Page Cache与Page回写详述(2)

readpage()首先会调用find_get_page(mapping, index)在page cache中寻找请求的数据,mapping是要寻找的page cache对象,即address_space对象,index是要读取的数据在文件中的偏移量。如果请求的数据不在该page cache中,那么内核就会创建一个新的page加入page cache中,并将要请求的磁盘数据缓存到该page中,同时将page返回给调用者。

writepage() 函数

对于文件映射(host指向一个inode对象),page每次修改后都会调用SetPageDirty(page)将page标识为dirty。(个人理解swap映射的page不需要dirty,是因为不需要考虑断电丢失数据的问题,因为内存的数据断电时默认就是会失去的)内核首先在指定的address_space寻找目标page,如果没有,就分配一个page并加入到page cache中,然后内核发起一个写请求将数据从用户空间拷入内核空间,最后将数据写入磁盘中。(对从用户空间拷贝到内核空间不是很理解,后期会重点学习Linux读、写文件的详细过程然后写一篇详细的blog介绍)

Buffer Cache

在Block I/O的文章中提到用于表示内存到磁盘映射的buffer_head结构,每个buffer-block映射都有一个buffer_head结构,buffer_head中的b_assoc_map指向了address_space。在Linux2.4中,buffer cache和 page cache之间是独立的,前者使用老版本的buffer_head进行存储,这导致了一个磁盘block可能在两个cache中同时存在,造成了内存的浪费。2.6内核中将两者合并到了一起,使buffer_head只存储buffer-block的映射信息,不再存储block的内容。这样保证一个磁盘block在内存中只会有一个副本,减少了内存浪费。

Flusher线程群(Flusher Threads)

Page cache推迟了文件写入后备存储的时间,但是dirty page最终还是要被写回磁盘的。

内核在下面三种情况下会进行会将dirty page写回磁盘:

用户进程调用sync() 和 fsync()系统调用

空闲内存低于特定的阈值(threshold)

Dirty数据在内存中驻留的时间超过一个特定的阈值

线程群的特点是让一个线程负责一个存储设备(比如一个磁盘驱动器),多少个存储设备就用多少个线程。这样可以避免阻塞或者竞争的情况,提高效率。当空闲内存低于阈值时,内核就会调用wakeup_flusher_threads()来唤醒一个或者多个flusher线程,将数据写回磁盘。为了避免dirty数据在内存中驻留过长时间(避免在系统崩溃时丢失过多数据),内核会定期唤醒一个flusher线程,将驻留时间过长的dirty数据写回磁盘。

Linux公社的RSS地址https://www.linuxidc.com/rssFeed.aspx

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/12338.html