c-Char驱动程序Linux:读取和写入文件操作的正确实现是什么?需要进行哪些抵销检查



我正在尝试读写一个char驱动程序。当我使用C程序打开设备文件并进行读写时,会出现SEG故障。当我对设备文件使用cat时,它会进入无限循环。

1( 我缺少什么?在文件操作中读写的正确实现是什么?

2( 我知道在原型读/写中:read(struct file *fp, char *ch, size_t count, loff_t *lofft)计数是指读/写请求的字节数。但是,最后一个参数偏移用于什么?需要对偏移进行哪些检查?

3( 对于像cat /dev/chardriver这样的多次读取调用,每次读取的偏移量会增加吗?就像第一次读取调用从1到100的偏移量(计数=100(一样,在下一次读取调用中,偏移量会从101开始吗?或者它会从任意一个随机数中产生?

这是我的代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
char kernelbuff[1024];
MODULE_LICENSE("GPL");
struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};

int device_open(struct inode *inode, struct file *fp)
{
printk("device_open called");
return 0;
}
static int device_release(struct inode *inode, struct file *fp)
{
printk("device_release called");
return 0;
}
static ssize_t device_read(struct file *fp, char *ch, size_t sz, loff_t *lofft)
{
printk("device_read called");      
copy_to_user(ch, kernelbuff, 1024);
return sz;
}
static ssize_t device_write(struct file *fp, const char *ch, size_t sz, loff_t *lofft)
{
printk("device_write called");
copy_from_user(kernelbuff, ch, 50);
return 1024;
}
static int hello_init(void)
{
printk("basicchardriver: module initialized");
register_chrdev(500, "chr_device", &fops);
return 0;
}
static void hello_exit(void)
{
printk("basicchardriver: module exited");
unregister_chrdev(500, "chr_device");
}
module_init(hello_init);
module_exit(hello_exit);
}

测试:

sudo mknod -m 666 /dev/chardev c 500 0
echo "Hello World" >> /dev/chardev    ===> Works fine
cat /dev/chardev     ===> Goes to infinite loop

如果我使用C程序调用驱动程序,它会给出SEG故障:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{
int fd;
char buff[500];
fd = open("/dev/chardev", O_RDWR);
write(fd, "Hello World", 13);
read(fd, buff, 500);
printf("Reading data from kernel: t");
puts(buff);
return 0;
}
raj@raj-VirtualBox:~/device-driver/chardriver/read-write$ ./a.out
Reading data from kernel: Hello World
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)

我想我的问题得到了正确的答案:(专家请随时添加您自己的答案/修改(

以下是正确的阅读方式:

static ssize_t device_read(struct file *fp, char *ch, size_t sz, loff_t *lofft)
{
printk("device_read called");
if (*lofft > 1024 || sz > 1024) 
{
return -EFBIF; // return 0 also works
}
if ((*lofft+sz) > 1024)
{
sz = 1024 - *lofft;
}
copy_to_user(ch, kernelbuff + *lofft, sz);
*lofft+=sz;
return sz;
}

(写入操作代码如下(。

偏移的答案可以从这里参考:了解文件操作的lof_t*offp

关于偏移的一些要点:

  1. 因此,是的,每个连续读取调用的偏移量需要在读取功能中进行调整。

  2. 下一个读取偏移量应从last_offset开始+count_of_of_bytes_read_in_last_function_call

  3. 如果偏移量超过内核大小,则读取应返回0缓冲器

编辑:阅读所需的有效检查可以在这个链接中参考(由@Tsyvarev建议(:在';中检查错误;。读取';内核模块中的函数

编辑:添加写入功能的改进版本

static ssize_t device_write(struct file *fp, const char *ch, size_t sz, loff_t *lofft)
{
printk("device_write called");
if (((*lofft) > sizeof(kernelbuff)) || (sz > sizeof(kernelbuff)))
{
printk("Error: Allocating more than kernel buffer size"); // pr_err( ) can also be used as pointed by @KamilCuk
return -EFBIG;
}
if ((*lofft + sz) > sizeof(kernelbuff))
{
printk("Error: Allocating more than kernel buffer size");
return -EFBIG;
}
copy_from_user(kernelbuff + *lofft, ch, sz);
*lofft+=sz;
return sz;
}

最新更新