Char Driver Linux: file_operations读写的正确实现是什么?需要进行哪些抵消检查?
Char Driver Linux: What is the correct implementation of file_operations read and write? What are the offset checks needs to be made?
我正在尝试读取和写入字符驱动程序。当我使用 C 程序打开设备文件并读写时,它会出现 SEG 错误。当我对设备文件使用猫时,它会进入无限循环。
1) 我错过了什么,file_operations 中读写的正确实现是什么?
2) 我在原型 read/write 中知道:read(struct file *fp, char *ch, size_t count, loff_t *lofft)
计数是指 read/write 请求的字节数。但是最后一个参数offset是做什么用的,offset需要做哪些检查呢?
3) 对于像 cat /dev/chardriver
这样的多次读取调用,每次读取都会增加偏移量吗?就像计数 = 100 时从 1 到 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;
}
(写操作代码如下)
offset的答案可以参考这里:Understanding loff_t *offp for file_operations
关于偏移的一些要点:
所以,是的,每个连续读取调用的偏移量都需要
在读取功能中调整。
下一个读取偏移量应该从last_offset +
count_of_no_of_bytes_read_in_last_function_call
读取应该return0,如果offset超过kernel的大小
缓冲区.
已编辑:
读取所需的有效检查可以参考link(@Tsyvarev 建议):
编辑:增加写入功能的改进版本[=14=]
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;
}
我正在尝试读取和写入字符驱动程序。当我使用 C 程序打开设备文件并读写时,它会出现 SEG 错误。当我对设备文件使用猫时,它会进入无限循环。
1) 我错过了什么,file_operations 中读写的正确实现是什么?
2) 我在原型 read/write 中知道:read(struct file *fp, char *ch, size_t count, loff_t *lofft)
计数是指 read/write 请求的字节数。但是最后一个参数offset是做什么用的,offset需要做哪些检查呢?
3) 对于像 cat /dev/chardriver
这样的多次读取调用,每次读取都会增加偏移量吗?就像计数 = 100 时从 1 到 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;
}
(写操作代码如下)
offset的答案可以参考这里:Understanding loff_t *offp for file_operations
关于偏移的一些要点:
所以,是的,每个连续读取调用的偏移量都需要 在读取功能中调整。
下一个读取偏移量应该从last_offset + count_of_no_of_bytes_read_in_last_function_call
读取应该return0,如果offset超过kernel的大小 缓冲区.
已编辑:
读取所需的有效检查可以参考link(@Tsyvarev 建议):
编辑:增加写入功能的改进版本[=14=]
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;
}