Linux mmap():如何阻止MTD设备映射区域脏页刷写至底层文件
关于mmap映射MTD设备的缓存与同步问题解答
我用mmap()把设备文件/dev/mtdblock0映射到进程1的虚拟地址空间,这块映射区的数据一直在变。我想在计算完成前,阻止这些数据变更刷写到设备,避免映射同一文件的进程2读到中间状态。
我试过把dirty_writeback_centisecs设为0来禁用内核刷写线程,计算完再恢复默认值,但这个方法只部分生效——就算参数设为0,还是偶尔会有数据刷到设备。以下是针对疑问的解答:
1. mmap()的同步机制对设备文件和普通文件的处理是否一致?
不一致。普通文件依赖**页缓存(page cache)**做读写缓冲,mmap的同步操作(比如msync())是先和页缓存交互,再由内核统一刷到磁盘;但像mtdblock这类块设备文件,多数情况下会绕开页缓存(取决于驱动实现),直接和设备物理存储映射,同步逻辑、缓存层级完全不同。比如普通文件的msync(MS_SYNC)是确保页缓存数据刷盘,而MTD设备可能直接操作闪存擦写块,没有中间缓存缓冲。
2. 负责刷写页缓存的线程是否也负责将内存映射区域刷写到底层文件?
分场景:
- 普通文件的mmap映射的是页缓存的页,页缓存刷写线程(如
pdflush、kworker系列线程)会负责把这些脏页刷到磁盘; - 但MTD这类直接映射的块设备,映射内存页不经过页缓存,页缓存刷写线程管不到这类脏页的刷写——这类设备的脏页同步要么由驱动自身逻辑触发,要么用户调用
msync()时直接触发硬件写入。你之前修改dirty_writeback_centisecs无效,就是因为这个参数只控制页缓存刷写线程,对MTD设备的直接写入逻辑不起作用。
3. 认为mmap()映射的文件直接从磁盘映射到进程虚拟地址空间,不经过页缓存,msync()直接在映射内存和磁盘间完成刷写,这个理解是否正确?
不完全准确,取决于文件类型:
- 普通文件的mmap是映射页缓存的页,数据会经过页缓存;
- 对于
mtdblock这类无缓冲块设备(驱动标记BLK_NO_CACHE),mmap会直接将设备物理存储映射到进程虚拟地址空间,确实绕开页缓存,此时msync()会直接触发把映射内存的数据刷到设备硬件,没有中间缓存层。但不是所有设备文件都遵循这个逻辑,部分块设备仍会使用页缓存。
4. 当前方法不可行,还有哪些实现目标的方式?
给你几个可行方案:
- 改用MTD字符设备:直接操作
/dev/mtd0(字符设备),通过ioctl()调用完成擦写操作,完全绕开块设备的自动刷写逻辑,自己控制写入时机。进程1计算时仅在内存修改数据,完成后再用ioctl(MEMWRITE)这类接口批量写入设备。 - 添加进程间同步锁:用POSIX互斥锁(
pthread_mutex_t)或文件锁(flock()/fcntl()),进程1计算前加锁,进程2读取前先获取锁,从逻辑层面保证进程2只能读到计算完成后的最终状态。 - 私有映射+最终拷贝:进程1用
MAP_PRIVATE映射设备文件,此时修改的是私有内存副本,不会同步到设备;计算完成后,再将私有映射里的最终数据通过write()或msync(MAP_SHARED)写入设备,或者让进程2重新映射最新的设备数据。 - 临时禁用MTD设备写权限:通过
ioctl()调用MTD驱动接口,临时将设备设为只读模式,计算完成后再恢复可写。比如使用MEMLOCK相关ioctl,或临时修改设备节点权限(需root权限,注意并发问题)。
内容的提问来源于stack exchange,提问作者Pavankumar S V
相关产品推荐
相关产品推荐

