Linux 为什么这些特殊设备文件读取的最小页面大小为字节?

Linux 为什么这些特殊设备文件读取的最小页面大小为字节?,linux,kernel,Linux,Kernel,我正在编写我的第二个内核模块。作为演示,我试图提供对固件核心的用户空间访问。该演示是在petalinux(专门为Zynq或Microblaze定制的嵌入式操作系统)下进行的。我在用户空间和内核模块之间添加了虚拟文件系统挂钩,它似乎在读写两方面都起作用。唯一的问题是,在我的用户应用程序和内核模块之间的某个地方,操作系统将我请求的大小膨胀到页面大小(4096) 一位同事评论说,我可能将模块安装为块设备,而不是字符设备。这很有道理。我的模块上游肯定有人在缓存我的结果(如果我对块驱动程序的理解准确的话,

我正在编写我的第二个内核模块。作为演示,我试图提供对固件核心的用户空间访问。该演示是在petalinux(专门为Zynq或Microblaze定制的嵌入式操作系统)下进行的。我在用户空间和内核模块之间添加了虚拟文件系统挂钩,它似乎在读写两方面都起作用。唯一的问题是,在我的用户应用程序和内核模块之间的某个地方,操作系统将我请求的大小膨胀到页面大小(4096)

一位同事评论说,我可能将模块安装为块设备,而不是字符设备。这很有道理。我的模块上游肯定有人在缓存我的结果(如果我对块驱动程序的理解准确的话,这对硬盘驱动器来说是非常有意义的),但是我们被绑定到一个易失性设备上,所以这是不合适的。但我能找到的所有诊断都表明它是作为一个字符设备安装的

mknod /dev/myModule **c** (Dynamically specified Major Number) (Zero)
ls -la /dev/myModule
   **c**rw-r--r--     1   root    root 252, -    Jan 1 01:05 myModule
这是我用来注册虚拟文件IO挂钩的模块源

alloc_chrdev_region (&moduleMajorNumber, 0, 1, "moduleLayerCDMA");
register_chrdev_region  (&moduleMajorNumber,    1, "moduleLayerCDMA");    
cdevP = cdev_alloc();
cdevP->ops = &moduleLayerCDMA_fileOperations;
cdevP->owner = THIS_MODULE;
cdev_add(cdevP, moduleMajorNumber, 1);

有什么线索吗?

您的问题来自这样一个事实:标准C库缓冲I/O例程(
fopen
fclose
fread
fgetch
&他们的朋友)为每个打开的文件/设备保留一个用户空间缓冲区,当您的程序尝试从该文件/设备读取时,库例程尝试进行预读,为以后的读调用做准备,以提高I/O的效率。类似地,使用
fwrite
进行的写入将通过写入缓冲区进行,并且只有在缓冲区已满或关闭文件/设备或显式执行
fflush
时,才会通过系统调用刷新到系统

有两种方法可以解决这个问题:

  • 更简单的方法可能是简单地将用户空间程序转换为使用非缓冲I/O(
    打开
    关闭
    读取
    写入
    &他们的朋友),它们只是在1:1的基础上进行相应的系统调用
  • 或者在内核模块中处理这个问题:如果
    读取中请求的字节数大于您希望在单个系统调用中返回的字节数,则忽略该字节数。您可以将该值视为调用者提供的缓冲区长度,而不必完全填满它。当然,在返回值中,您必须指出实际读取了多少字节

您是否在用户应用程序中使用类似于
fread()
的东西从设备读取数据?我是。你的直觉是对的,这就是问题所在;从命令行使用dd可以解决这个问题。