Linux块设备IO子系统(二)

磁盘驱动就是实现磁盘空间和内存空间数据上的交互,在上一篇中我们讨论了内存端的Page Segment Block Sector相关的概念,本文以3.14内核为例,讨论这部分内存是如何被组织管理的。我们知道,为了解决CPU和内存的速度不匹配,计算机系统引入了Cache缓存机制,这种硬件Cache的速度接近CPU内部寄存器的速度,可以提高系统效率,同样的思路也适用于解决内存和磁盘的速度不匹配问题,此外,磁盘多是机械式的,从寿命的角度考虑也不适合频繁读写,所以内核就将一部分内存作为缓存,提高磁盘访问速度的同时延长磁盘寿命,这种缓存就是磁盘高速缓存。包括页高速缓存(Page Cache,对完整数据页进行操作的磁盘高速缓存) + 目录项高速缓存(Dentry Cache,描述文件系统路径名的目录项对象) + 索引节点高速缓存(Buffer Cache,存放的是描述磁盘索引节点的索引节点对象),本文主要讨论页高速缓存,有了页高速缓存,内核的代码和数据结构不必从磁盘读,也不必写入磁盘。页高速缓存可以看作特定文件系统层的一部分。

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
  └── vfs_read(f.file, buf, count, &pos);
        └──file->f_op->read(file, buf, count, pos);
        └──do_sync_read(file, buf, count, pos);
                └──filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
                        ├──generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
                        └──filemap_write_and_wait_range(mapping, pos, pos + iov_length(iov, nr_segs) - 1);
-----------------------------------Page Cache----------------------------------------------------
int mpage_readpage(struct page *page, get_block_t get_block)
        └──wait_on_sync_kiocb(&kiocb);
                ├──do_mpage_readpage(bio, page, 1, &last_block_in_bio, &map_bh, &first_logical_block, get_block);
                └──mpage_bio_submit(READ, bio);
                        └──submit_bio(rw, bio);

Linux块设备IO子系统(二)

绝大多数情况下,内核在读写磁盘时都引用页高速缓存。新页被追加到页高速缓存以满足用户态进程的读请求。如果页不再高速缓存中,新页就被加到高速缓存中,然后用从磁盘读出的数据填充它,如果内存有足够的空闲空间,就让该页在高速缓存中长期保留,使其他进程再使用该页时不再访问磁盘。

同样,在把一页数据写到块设备之前,内核首先检查对应的页是否已经在高速缓存中,如果不在,就要先在其中增加一个新项,并用要写到磁盘中的数据填充该项。IO数据的传送不是马上开始,而是延迟几秒才对磁盘进行更新,从而使进程有机会队要写入磁盘的数据做进一步的修改。

页高速缓存肯可能是下面几种之一:

含有普通文件数据的页(上篇中的一个Page)

含有目录的页

含有直接从块设备文件(跳过文件系统)读出的数据的页。

含有用户态进程数据的页

属于特殊文件系统文件的页,如shm

从inode到page

既然是建立一块磁盘空间和一块内存空间之间的关系,那么就要通过相关的结构表示这种关系,在磁盘端,存储空间本质上都是属于一个文件,Linux中用inode结构表示一个文件,内存端,Linux内核用address_space来组织一组内存页,所以,我们可以在inode结构中找到相应的address_space对象域,而这个文件就成为该页的所有者(owner)。简单的追一下代码,我们可以画出下面这张关系图,本节主要围绕这张图讨论

inode

inode是内核中描述一个文件的结构,更多关于inode的讨论,可以参考Linux设备文件三大结构:inode,file,file_operations,本文中我们主要关心i_mapping和i_data两个成员。

//3.14/include/linux/fs.h 527 struct inode { 541 struct address_space *i_mapping; 594 struct address_space i_data; 616 };

struct inode
--541-->指向这个inode拥有的address_space对象
--594-->这个inode拥有的address_space对象

address_space

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

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