Я новичок в разработке модулей ядра Linux. Я пишу модуль, который создает файл устройства, в который я могу записывать и читать данные.
Я могу использовать echo для успешной записи в него данных, но когда я использую cat для печати данных с него, ничего не происходит.
Однако, если я использую системный вызов read() для чтения этого файла устройства из приложения пользовательского пространства, он работает как шарм!
Насколько я понимаю, cat открывает, читает и закрывает файл, поэтому его поведение не должно отличаться от поведения моего пользовательского приложения.
Есть ли у кого-нибудь представление о проблеме? Спасибо.
Вот часть моего кода модуля:
static uint64_t my_data_value;
uint8_t *kernel_buffer;
/* Some variables & function prototypes ignored */
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release,
};
static int device_open(struct inode *inode, struct file *file)
{
if ((kernel_buffer = kmalloc(1024, GFP_KERNEL)) == 0)
{
return -1;
}
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
kfree(kernel_buffer);
return 0;
}
static ssize_t device_read(struct file *file, char __user *buf, size_t len, loff_t *off)
{
size_t ret;
snprintf(kernel_buffer, 1024, "%016llX", my_data_value);
ret = copy_to_user(buf, kernel_buffer, strlen(kernel_buffer);
return ret;
}
static ssize_t device_write(struct file *file, const char __user *buf, size_t len, loff_t *off)
{
size_t i;
my_data_value = 0;
copy_from_user(kernel_buffer, buf, len);
for(i=0;i<(len-1);i++)
{
if ((kernel_buffer[i] < '0' || kernel_buffer[i] > '9') \
&& (kernel_buffer[i] < 'A' || kernel_buffer[i] > 'Z'))
{
return -1;
}
}
for(i=0; i<(len-1);i++)
{
my_data_value <<=4;
if (kernel_buffer[i] >= '0' && kernel_buffer[i] <='9')
{
my_data_value |= (uint64_t)(kernel_buffer[i] - '0');
}
else if (kernel_buffer[i] >= 'A' && kernel_buffer[i] <= 'Z')
{
my_data_value |= (uint64_t)(kernel_buffer[i] - 'A' + 10);
}
else
{
return -1;
}
}
return len;
пример команды
echo 1234567A > /dev/my_device # write successfully
cat /dev/my_device # nothing happens
и мое пользовательское приложение:
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int8_t read_buff[1024];
int main()
{
int fd;
fd = open("/dev/my_device", O_RDWR);
if (fd < 0)
{
printf("Cannot open device file\n");
return 0;
}
read(fd, read_buf, 1024);
printf("Data = %s\n", read_buf);
close(fd);
}
Нет, не нужно разбираться в реализации cat. Ваша функция device_read должна следовать соглашениям для обратного вызова .read: функция должна возвращать количество прочитанных байтов. В EOF он должен вернуть 0. Обратите внимание, что .read должен интерпретировать свой аргумент off как смещение в файле, см. Этот вопрос для получения дополнительной информации: stackoverflow.com/questions/31563107/….
Да я вижу. Я думаю, что simple_read_from_buffer (), который обновляет для нас loff_t *offp, намного полезнее, чем copy_to_user (). Хотя я уже читал исходный код cat.





Спасибо. Основываясь на этом посте, я понял, что мне следует изучить реализацию исходного кода cat.