关于linux驱动,file_operations 结构体详细说明

file_operations 是 Linux 内核中用于定义字符设备驱动与用户空间交互接口的核心结构体。它通过函数指针数组,将用户空间的系统调用(如 open()read()write() 等)映射到内核驱动的具体实现函数。以下是其详细说明:


1. 结构体定义

在较新的内核版本(如 5.x+)中,file_operations 定义在 <linux/fs.h> 中,典型成员如下:

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
    ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
    int (*iterate) (struct file *, struct dir_context *);
    int (*iterate_shared) (struct file *, struct dir_context *);
    __poll_t (*poll) (struct file *, struct poll_table_struct *);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    // ... 其他成员(根据内核版本可能不同)
};

2. 核心成员详解

(1) owner
  • 作用:指向模块所有者的指针,通常设为 THIS_MODULE
  • 用途:防止模块被卸载时仍有未释放的引用(通过 try_module_get() 和 module_put() 管理引用计数)。
  • 示例
    
    

    static struct file_operations fops = {
        .owner = THIS_MODULE,
        // 其他成员...
    };

(2) open
  • 触发条件:用户调用 open() 或 fopen()
  • 原型
    int (*open)(struct inode *inode, struct file *filp);
  • 参数
    • inode:设备文件的 inode 结构体,包含设备号等信息。
    • filp:文件对象,可通过 filp->private_data 存储驱动私有数据。
  • 典型操作
    • 初始化设备。
    • 分配资源(如内存、DMA 缓冲区)。
    • 设置 filp->private_data 指向驱动上下文。
(3) release
  • 触发条件:用户调用 close() 或 fclose()
  • 原型
    int (*release)(struct inode *inode, struct file *filp);
  • 用途
    • 释放 open() 中分配的资源。
    • 关闭硬件设备。
    • 清理 filp->private_data
(4) read / write
  • 触发条件:用户调用 read() 或 write()
  • 原型

    ssize_t (*read)(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
    ssize_t (*write)(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);

  • 参数
    • buf:用户空间缓冲区地址(需通过 copy_to_user()/copy_from_user() 访问)。
    • count:请求的字节数。
    • f_pos:文件偏移量(由驱动维护,如 *f_pos += ret)。
  • 返回值:成功时返回实际操作的字节数,错误返回负值(如 -EINVAL)。
(5) unlocked_ioctl / compat_ioctl
  • 触发条件:用户调用 ioctl()原型

    long (*unlocked_ioctl)(struct file *filp, unsigned int cmd, unsigned long arg);
    long (*compat_ioctl)(struct file *filp, unsigned int cmd, unsigned long arg);
    用途
    • 实现设备特定的控制命令(如配置寄存器、获取状态)。
    • compat_ioctl 用于 64 位内核处理 32 位用户的 ioctl 调用。
  • 实现要点
    • 使用 _IOC_* 宏定义命令(如 _IOC_READ_IOC_WRITE)。
    • 通过 copy_to_user()/copy_from_user() 传递参数。
(6) poll
  • 触发条件:用户调用 select()poll()epoll()
  • 原型
    __poll_t (*poll)(struct file *filp, struct poll_table_struct *wait);
  • 用途
    • 实现非阻塞 I/O。
    • 注册等待队列(poll_wait(filp, &queue, wait)),当数据就绪时唤醒进程。
  • 返回值:位掩码(如 POLLIN 表示可读,POLLOUT 表示可写)。
(7) mmap
  • 触发条件:用户调用 mmap()
  • 原型
    int (*mmap)(struct file *filp, struct vm_area_struct *vma);
  • 用途
    • 将设备内存映射到用户空间(如摄像头帧缓冲)。
    • 需设置 vma->vm_flags 并调用 remap_pfn_range()
(8) llseek
  • 触发条件:用户调用 lseek()
  • 原型
    loff_t (*llseek)(struct file *filp, loff_t offset, int whence);
  • 用途
    • 修改文件读写位置(如随机访问设备)。
    • 返回新位置,错误返回负值。

3. 同步与并发控制

  • 问题:多个进程同时访问设备可能导致数据竞争。
  • 解决方案
    • 使用互斥锁(mutex)保护共享资源。
    • 在 open() 中初始化锁,release() 中销毁。
    • 示例:

      static int my_open(struct inode *inode, struct file *filp) {
          struct my_dev *dev = container_of(inode->i_cdev, struct my_dev, cdev);
          mutex_lock(&dev->lock);
          filp->private_data = dev;
          // 初始化操作...
          mutex_unlock(&dev->lock);
          return 0;
      }

4. 示例:简单字符设备驱动

#include <linux/module.h>
#include <linux/fs.h>

static int dev_open(struct inode *inode, struct file *filp) {
    // 初始化设备
    return 0;
}

static ssize_t dev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
    // 从设备读取数据到用户空间
    return 0;
}

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = dev_open,
    .read = dev_read,
    // 其他成员...
};

static int __init my_init(void) {
    // 注册字符设备
    return 0;
}

static void __exit my_exit(void) {
    // 注销设备
}

module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

5. 注意事项

  1. 错误处理:所有函数需正确返回错误码(如 -EFAULT-EINVAL)。
  2. 资源管理:在 open() 中分配资源,release() 中释放。
  3. 内核版本兼容性:部分成员(如 read_iter/write_iter)用于替代传统 read/write,支持零拷贝。
  4. 文档参考:内核源码 Documentation/driver-model/ 和 Documentation/filesystems/vfs.txt

通过合理实现 file_operations,驱动可高效、安全地与用户空间交互。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值