这两天抽时间把以前的一个遗留的direct-io问题跟踪了下。
Direct-io的目的在于绕过fs的cache,直接对block设备上的文件进行读写,其目的在于提高读写性能(以读为例,毕竟少了一次从fs cache 到用户态buffer的拷贝过程),这在文件仅读/写一次的情况下应该是比较比默认的读/写方式效率高(理论上)。
首先,direct-io是以block设备的block块大小为单位进行读写,因此,用户态分配的buffer的length至少要为block块的整数倍。之所以为一个遗留问题,是因为用户态的所使用的buffer是由一块自己管理的IO内存来分的(以页为分配的基本单位,而vaddr则是由mmap默认去选择的,这里mmap会去调用find_vma从而随机的得到一个vaddr),由于脑袋中想的一直是物理页是以页为单位分配的,页就当然是block块的整数倍,因此在地址上没有多加考虑。问题就出在这里,direct-io要的虚拟内存连续,与你paddr没关系!-_-!(当然有关系,普通的内存管理中,虚拟地址到物理地址的转换是通过查询页表来实现的,页表记录着 paddr >> PAGE_SHIFT, 即页帧号,虚拟地址的在虚拟页帧内的偏移与物理地址页偏移是相同的,在IOMEM用mmap来实物理地址到虚拟地址的转换,而这个地址我们又是让kernel来选择,当然就无法保证页对其,所以fs就认为其物理地址也是非页对其,从而出现了这个现象),因此当初在使用iomem的时候就一直出 INVALID的错误,确还怀疑iomem的页表管理与普通mem页表管理不同(实际没差别)?这里贴出kernel中对vaddr检查的代码:
- if (offset & blocksize_mask) {
- if (bdev)
- blkbits = bdev_blkbits;
- blocksize_mask = (1 << blkbits) - 1;
- if (offset & blocksize_mask)
- goto out;
- }