网站被挂马原因,站长工具域名备案查询,蓝杉互动网站建设,汉中建设工程招投标信息网Linux字符设备#xff1a;read、write和poll函数实现及完整代码
1. read函数
原型
ssize_t read(struct file *file, char __user *buf, size_t count, loff_t *pos);实现步骤
检查用户缓冲区#xff1a;使用copy_to_user将数据从内核空间复制到用户空间。返回已读取的字…Linux字符设备read、write和poll函数实现及完整代码
1. read函数
原型
ssize_t read(struct file *file, char __user *buf, size_t count, loff_t *pos);实现步骤
检查用户缓冲区使用copy_to_user将数据从内核空间复制到用户空间。返回已读取的字节数 如果数据长度少于请求长度返回实际读取的字节数。如果到达文件末尾返回0。
注意事项
确保对用户缓冲区的访问是安全的。返回值必须是已成功读取的字节数或错误码如-EFAULT。考虑多线程情况下的并发访问适当加锁。
示例代码
static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{char data[] Hello, World!\n;size_t datalen strlen(data);if (*pos datalen)return 0;if (count datalen - *pos)count datalen - *pos;if (copy_to_user(buf, data *pos, count))return -EFAULT;*pos count;return count;
}2. write函数
原型
ssize_t write(struct file *file, const char __user *buf, size_t count, loff_t *pos);实现步骤
验证用户数据使用copy_from_user将数据从用户空间复制到内核空间。处理写入数据通常会将数据存储到设备的内存区域或触发硬件操作。
注意事项
确保处理的是合法数据。如果设备有缓冲区需检查空间是否足够。同样需要考虑多线程并发访问的问题。
示例代码
static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{char kernel_buf[128];if (count sizeof(kernel_buf) - 1)count sizeof(kernel_buf) - 1;if (copy_from_user(kernel_buf, buf, count))return -EFAULT;kernel_buf[count] \0;printk(KERN_INFO Received from user: %s\n, kernel_buf);*pos count;return count;
}3. poll函数
原型
unsigned int poll(struct file *file, struct poll_table_struct *wait);实现步骤
注册等待队列使用poll_wait将设备的等待队列添加到wait。返回设备状态返回一个位掩码指示设备的可读性、可写性等状态。
注意事项
确保等待队列正确唤醒。返回值可以是POLLIN可读、POLLOUT可写等。处理阻塞和非阻塞模式。
示例代码
static unsigned int my_poll(struct file *file, struct poll_table_struct *wait)
{unsigned int mask 0;poll_wait(file, my_wait_queue, wait);if (data_available)mask | POLLIN | POLLRDNORM; // 可读if (space_available)mask | POLLOUT | POLLWRNORM; // 可写return mask;
}4. 完整代码示例
#include linux/init.h
#include linux/module.h
#include linux/kernel.h
#include linux/fs.h
#include linux/uaccess.h
#include linux/poll.h
#include linux/wait.h
#include linux/sched.h#define DEVICE_NAME my_device
#define BUFFER_SIZE 128static int major;
static char device_buffer[BUFFER_SIZE];
static size_t buffer_len 0;static wait_queue_head_t my_wait_queue; // 声明等待队列
static int data_available 0; // 标志是否有数据可供读取// read 实现
static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{if (buffer_len 0) {if (file-f_flags O_NONBLOCK)return -EAGAIN;// 等待数据可用wait_event_interruptible(my_wait_queue, data_available);if (buffer_len 0) // 防止被中断唤醒但没有数据return -EINTR;}if (count buffer_len)count buffer_len;if (copy_to_user(buf, device_buffer, count))return -EFAULT;buffer_len 0; // 数据被读取后清空缓冲区data_available 0;return count;
}// write 实现
static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{if (count BUFFER_SIZE - 1)count BUFFER_SIZE - 1;if (copy_from_user(device_buffer, buf, count))return -EFAULT;device_buffer[count] \0;buffer_len count;// 数据写入后唤醒等待的进程data_available 1;wake_up_interruptible(my_wait_queue);return count;
}// poll 实现
static unsigned int my_poll(struct file *file, struct poll_table_struct *wait)
{unsigned int mask 0;poll_wait(file, my_wait_queue, wait);if (buffer_len 0)mask | POLLIN | POLLRDNORM; // 数据可读if (buffer_len BUFFER_SIZE)mask | POLLOUT | POLLWRNORM; // 可写入更多数据return mask;
}// 文件操作结构
static struct file_operations my_fops {.owner THIS_MODULE,.read my_read,.write my_write,.poll my_poll,
};// 模块初始化
static int __init my_init(void)
{major register_chrdev(0, DEVICE_NAME, my_fops);if (major 0) {printk(KERN_ALERT Failed to register character device\n);return major;}init_waitqueue_head(my_wait_queue); // 初始化等待队列printk(KERN_INFO Device registered with major number %d\n, major);return 0;
}// 模块退出
static void __exit my_exit(void)
{unregister_chrdev(major, DEVICE_NAME);printk(KERN_INFO Device unregistered\n);
}module_init(my_init);
module_exit(my_exit);MODULE_LICENSE(GPL);
MODULE_AUTHOR(Your Name);
MODULE_DESCRIPTION(A simple character device with wait queue.);