Drivers de dispositivo Linux, 3ª edição afirma:
se o método llseek estiver faltando nas operações do dispositivo, a implementação padrão no kernel executa buscas modificando filp->f_pos
No entanto, tenho um dispositivo de caractere para o qual o driver não implementa lseek. Aqui estão as definições de op de arquivo para esse tipo de dispositivo: https://github.com/Xilinx/dma_ip_drivers/blob/master/XDMA/linux-kernel/xdma/cdev_ctrl.c
Mas tentar lseek neste dispositivo retorna 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);
}
Saída:
Seek result: -1, errno: Illegal seek (29)
written 4 bytes
Não consigo entender como isso acontece. Não pode vir do driver: ESPIPE nem é mencionado em lugar nenhum, então deve vir do kernel, o que contradiz a citação acima.
O comportamento padrão foi alterado? Ele pode ser configurado de alguma forma? Como pode ser visto o que o kernel realmente faz (idealmente código fonte)?
A versão do kernel é 5.10 (Debian 11).
A terceira edição do Linux Device Drivers foi publicada em 2005, e
llseek
o manuseio no kernel mudou algumas vezes desde então. Não vou entrar em detalhes sobre o histórico, mas se você estiver curioso, pode começar em torno de “ llseek: automatically add .llseek fop ” e da série de Jason Donenfeldllseek
, culminando em “ fs: remove no_llseek ” (mesclado no 5.19, então não é relevante para a versão do kernel em que você está interessado).Em 5.10, a operação padrão é
no_llseek
; vejavfs_llseek
:Como o
xdma
driver não define.llseek
, as chamadas acabam sendo manipuladas porno_llseek
, que retornaESPIPE
.