/dev/mem同步写不能使用msync的MS_SYNC选项探究

问题

做了个测试板子的程序,里面有一项写铁电的功能,要求写入之后立即断电,重启后校验数据准确性;铁电设计是通过内存地址直接映射的,于是,使用mmap直接映射了/dev/mem文件,自然地写入之后使用msync进行同步,最后使用munmap解映射;

然而,当我运行这段程序的时候,发现msync的MS_SYNC选项进行同步的时候会返回错误,错误码是EINVAL;这就奇怪了;

查原因

1. 查看MAN手册,如下:当地址不是页的整数倍,或者参数传递错误时才返回这个结果;

反复验证,发现地址没问题,而且将MS_SYNC换成MS_ASYNC就没问题了,所以怀疑是内核不支持这个同步选项;为了求证,查看内核代码:

2. sys_msync这个系统调用,在校验参数时,如果不合法会返回-EINVAL,这点如上述MAN手册所描述;

3. 继续往下看代码,有这么一句,如果有MS_SYNC标记的话,会执行do_fsync(),出错会返回error;

4. 在do_fsync函数中,会对file_operations和里面的fsync函数做校验,如果没有,则返回-EINVAL,基本上可以确定,正是因为该文件没有实现file_operations里面的fsync函数,所以返回参数错误了;

5. 我们来看看内存设备是在什么时候初始化的,如下代码,在device_create函数调用中会对一系列的内存设备进行初始化,其中包括/dev/mem;

6. 这个/dev/mem对应着一个操作函数,如下代码中的mem_fops:

7. 看看这个mem_fops的实现,如下,可见其并没有实现fsync函数;

到这,问题总算水落石出了;

8. 再来看看mmap函数的实现,里面调用了这个函数phys_mem_access_prot;

9. 上面提到的这个函数,如下,其中有个是否支持不缓存的方式判断,uncached_access;

10. 进入uncached_access非缓存访问函数,可见其内部根据文件的O_SYNC选项来判断是否支持不缓存的写;

好了,分析完毕;

解决办法

在打开/dev/mem时,使用如下方式,即open增加O_SYNC选项,这个选项即上面uncached_access函数使用的判断标记,表示每次写操作都要等到数据和文件属性都同步到物理存储才返回;

 

参考文章:

https://blog.csdn.net/wlp600/article/details/6893636

http://www.armadeus.org/wiki/index.php?title=FPGA_registers_access_from_Linux_userspace

https://stackoverflow.com/questions/20750176/how-to-get-writes-via-an-mmap-mapped-memory-pointer-to-flush-immediately

https://blog.csdn.net/tiantao2012/article/details/52168383?locationNum=2&fps=1

本文链接:/dev/mem同步写不能使用msync的MS_SYNC选项探究

转载声明:转载请注明来源:Linux TCP/IP Stack,谢谢!


发表评论

电子邮件地址不会被公开。 必填项已用*标注