如果设备操作中缺少 llseek 方法,则内核中的默认实现通过修改 filp->f_pos 来执行查找
但是我有一个字符设备,其驱动程序没有实现 lseek。以下是此设备类型的文件操作定义: https://github.com/Xilinx/dma_ip_drivers/blob/master/XDMA/linux-kernel/xdma/cdev_ctrl.c
但尝试在此设备上执行 lseek 时会返回 ESPIPE:
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
int main(int argc, char** argv) {
uint32_t val=0x12345678;
int fid=open("/dev/xdma0_user", O_RDWR);
off_t lseek_ret=lseek(fid, 0x8ul, SEEK_SET);
if (lseek_ret <0)
fprintf(stderr, "Seek result: %d, errno: %s (%d)\n", lseek_ret, strerror(errno), errno );
unsigned int c=write(fid, &val, sizeof(val));
printf("written %u bytes\n", c);
close(fid);
return (0);
}
输出:
Seek result: -1, errno: Illegal seek (29)
written 4 bytes
我不明白这是怎么发生的。它不可能来自驱动程序:ESPIPE 甚至没有在任何地方提及,因此它一定来自内核,这与上面的引述相矛盾。
默认行为是否已被改变?能否以某种方式进行配置?如何查看内核实际执行的操作(理想情况下是源代码)?
内核版本是 5.10(Debian 11)。
Linux 设备驱动程序第三版于 2005 年发布,
llseek
此后内核的处理方式发生了几次变化。我不会详细介绍历史,但如果您感兴趣,可以从“ llseek:自动添加 .llseek fop ”和 Jason Donenfeld 的llseek
系列文章开始,最后是“ fs:删除 no_llseek ”(合并于 5.19,因此与您感兴趣的内核版本无关)。在 5.10 中,默认操作是
no_llseek
;参见vfs_llseek
:由于
xdma
驱动程序未设置.llseek
,调用最终由处理no_llseek
,并返回ESPIPE
。