[英]UIO and msync: Why does msync return "invalid argument" even though the address is a multiple of PAGESIZE
Linux version: 4.19 Linux 版本:4.19
Platform: Xilinx Ultrascale+ Zynq平台:Xilinx Ultrascale+ Zynq
In the programmable logic I've created a memory mapped device located at physical address 0xA0001000.在可编程逻辑中,我创建了一个位于物理地址 0xA0001000 的内存映射设备。 I'm using uio_pdrv_genirq as my device driver.
我使用 uio_pdrv_genirq 作为我的设备驱动程序。 The device shows up as uio0 and I'm ready to read and write to it, using mmap.
该设备显示为 uio0,我已准备好使用 mmap 对其进行读写。 I want to be able to guarantee that any writes that I make get written to the device right away instead of waiting for Linux to flush the dirty pages on its own.
我希望能够保证我所做的任何写入都会立即写入设备,而不是等待 Linux 自行刷新脏页。 For that I should use msync according to all my research.
为此,我应该根据我所有的研究使用 msync。 But I keep getting an error when I do that.
但是当我这样做时,我不断收到错误消息。 Here's my test program:
这是我的测试程序:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
void main() {
int fid;
int rval;
char *data;
int idx;
printf("Open UIO Device \n");
fid= open("/dev/uio0", O_RDWR | O_SYNC);
data= mmap(NULL, 0x1000, PROT_WRITE|PROT_READ, MAP_SHARED, fid, 0);
if(MAP_FAILED == data) {
printf("Error code when mapping! %s", strerror(errno));
}
printf("addr= 0x%8X\n", data);
printf("pagesize= 0x%4X\n", getpagesize());
printf("Write some data\n");
data[11]= 0xDE;
data[10]= 0xC0;
data[ 9]= 0xDE;
data[ 8]= 0xAD;
rval= msync(data, 0x1000, MS_SYNC);
if(-1 == rval) {
printf("Error on msync! %s\n", strerror(errno));
}
if(munmap(data, 0x1000) < 0) {
printf("munmap error! %s\n", strerror(errno));
}
printf("Close UIO device\n");
rval= close(fid);
if(rval != 0) {
printf("UIO device close Error!\n");
}
}
And here's the program output:这是程序输出:
mylinux:~/test-apps$ ./a.out
Open UIO Device
addr= 0xABA05000
pagesize= 0x1000
Write some data
Error on msync! Invalid argument
Close UIO device
I'm not understanding the source of this error.我不明白这个错误的来源。 The msync man pages states that this error can occur if the address is not a multiple of PAGESIZE.
msync 手册页指出,如果地址不是 PAGESIZE 的倍数,则会发生此错误。 But as you can see from the example above, it is a multiple.
但是正如您从上面的示例中看到的那样,它是一个倍数。 Even the physical address is a multiple of the PAGESIZE.
甚至物理地址也是 PAGESIZE 的倍数。
A few other notes:其他一些注意事项:
Thanks for any insights folks can provide.感谢人们提供的任何见解。
I believe the EINVAL
error is because the kernel's handler for the msync
syscall (in " mm/msync.c ") calls vfs_fsync_range
:我相信
EINVAL
错误是因为内核的msync
系统调用处理程序(在“ mm/msync.c ”中)调用vfs_fsync_range
:
error = vfs_fsync_range(file, fstart, fend, 1);
and vfs_fsync_range
(in " fs/sync.c ") is returning -EINVAL
here:并且
vfs_fsync_range
(在“ fs/sync.c ”中)在此处返回-EINVAL
:
if (!file->f_op->fsync)
return -EINVAL;
because the UIO driver core (in " drivers/uio/uio.c " does not set the fsync
file operation handler.因为 UIO 驱动核心(在“ drivers/uio/uio.c ”中没有设置
fsync
文件操作处理程序。
The physical memory you have mmap
ed is mapped as non-cached memory in the page tables, so writes do not need to be flushed.您拥有
mmap
ed 的物理内存在页表中映射为非缓存内存,因此不需要刷新写入。 However, you should probably use volatile
accesses to the memory mapped I/O registers.但是,您可能应该使用对内存映射 I/O 寄存器的
volatile
访问。 The register access functions such as readb
and writeb
in the kernel are architecture-specific, but invariably convert the address to a pointer to a volatile
integer type (eg volatile unsigned char *
, volatile unsigned short *
, or volatile unsigned int *
depending on the width of the register access) before accessing the memory location.内核中的
readb
和writeb
等寄存器访问函数是特定于体系结构的,但总是将地址转换为指向volatile
整数类型的指针(例如volatile unsigned char *
、 volatile unsigned short *
或volatile unsigned int *
取决于访问内存位置之前的寄存器访问宽度)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.