page IO,顾名思义,一端连接着内存,一端连接着IO系统,可以看作内存子系统和IO子系统的中间层,部分资料把这部分划归到Block层, 但我觉得虽然这部分上和IO强相关, 但同时又涉及到很多内存页的数据结构, 所以还是单独划归到一层比较好. 通常,对一个文件的回写IO数据首先通过文件系统写入到Page Cache中,之后,就通过Page IO层,以异步的方式下发到Block IO子系统。当然,文件系统的数据也可以直接写入到Block IO子系统(Direct IO)。
Page IO层的核心工作就是构造并管理bio, bio作为IO的基本单位,描述了IO从内存到磁盘的映射,bio的构造借助了内存管理中的buffer_head结构完成其构造。 buffer_head负责page到扇区的固定映射,在此基础上,bio只需了解IO的内存端,即可计算出它的磁盘端位置
在IO路径中,构造bio的代码流程如下:
__filemap_fdatawrite_range() //mm/filemap.c +286 struct writeback_control wbc = {...} do_writepages() //mm/page-writeback.c +2337 mapping->a_ops->writepages() //mm/page-writeback.c +2035 ext4_writepages() write_cache_pages(mapping, wbc, __writepage, mapping) __writepage() ext4_writepage() ext4_io_submit_init(&io_submit, wbc) io->io_wbc = wbc; io->io_bio = NULL; io->io_end = NULL; ext4_init_io_end(inode, GFP_NOFS) ext4_bio_write_page() bh = head = page_buffers(page) io_submit_add_bh() ext4_io_submit() io_submit_init_bio() //分配并初始化bio bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES); wbc_init_bio(io->io_wbc, bio); bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; bio->bi_end_io = ext4_end_bio; bio->bi_private = ext4_get_io_end(io->io_end); io->io_bio = bio; io->io_next_block = bh->b_blocknr; bio_add_page() ext4_io_submit(&io_submit)