Linux中字符设备驱动程序的主要功能是实现设备的读写和控制接口。对于字符设备驱动程序,最核心的就是file_operations结构,这个结构实际上是VFS(虚拟文件系统)的文件接口,它的每一个成员函数一般都对应一个系统调用。用户进程利用系统调用对设备文件进行诸如读和写等操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,并调用相应的驱动程序函数。file_operations结构定义如下:

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 (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);  
int (*readdir) (struct file *, void *, filldir_t); 
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
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 *); 
int (*open) (struct inode *, struct file *);  
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);  
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync); 
int (*fasync) (int, struct file *, int); 
int (*lock) (struct file *, int, struct file_lock *); 
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);  
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);  
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);  
int (*setlease)(struct file *, long, struct file_lock **);  
}; 
struct module *owner
第一个 file_operations 成员根本不是一个操作; 它是一个指向拥有这个结构的模块的指针. 这个成员用来在它的操作还在被使用时阻止模块被卸载. 几乎所有时间中, 它被简单初始化为 THIS_MODULE, 一个在 <linux/module.h> 中定义的宏.
loff_t (*llseek) (struct file *, loff_t, int);
llseek 方法用作改变文件中的当前读/写位置, 并且新位置作为(正的)返回值. loff_t 参数是一个"long offset", 并且就算在 32位平台上也至少 64 位宽. 错误由一个负返回值指示. 如果这个函数指针是 NULL, seek 调用会以潜在地无法预知的方式修改 file 结构中的位置计数器( 在"file 结构" 一节中描述).
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
用来从设备中获取数据. 在这个位置的一个空指针导致 read 系统调用以 -EINVAL("Invalid argument") 失败. 一个非负返回值代表了成功读取的字节数( 返回值是一个 "signed size" 类型, 常常是目标平台本地的整数类型).
ssize_t (*aio_read)(struct kiocb *, char __user *, size_t, loff_t);
初始化一个异步读 -- 可能在函数返回前不结束的读操作. 如果这个方法是 NULL, 所有的操作会由 read 代替进行(同步地).
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
发送数据给设备. 如果 NULL, -EINVAL 返回给调用 write 系统调用的程序. 如果非负, 返回值代表成功写的字节数.
ssize_t (*aio_write)(struct kiocb *, const char __user *, size_t, loff_t *);
初始化设备上的一个异步写.
int (*readdir) (struct file *, void *, filldir_t);
对于设备文件这个成员应当为 NULL; 它用来读取目录, 并且仅对文件系统有用.
unsigned int (*poll) (struct file *, struct poll_table_struct *);
poll 方法是 3 个系统调用的后端: poll, epoll, 和 select, 都用作查询对一个或多个文件描述符的读或写是否会阻塞. poll 方法应当返回一个位掩码指示是否非阻塞的读或写是可能的, 并且, 可能地, 提供给内核信息用来使调用进程睡眠直到 I/O 变为可能. 如果一个驱动的 poll 方法为 NULL, 设备假定为不阻塞地可读可写.
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
ioctl 系统调用提供了发出设备特定命令的方法(例如格式化软盘的一个磁道, 这不是读也不是写). 另外, 几个 ioctl 命令被内核识别而不必引用 fops 表. 如果设备不提供 ioctl 方法, 对于任何未事先定义的请求(-ENOTTY, "设备无这样的 ioctl"), 系统调用返回一个错误.
int (*mmap) (struct file *, struct vm_area_struct *);
mmap 用来请求将设备内存映射到进程的地址空间. 如果这个方法是 NULL, mmap 系统调用返回 -ENODEV.
int (*open) (struct inode *, struct file *);
尽管这常常是对设备文件进行的第一个操作, 不要求驱动声明一个对应的方法. 如果这个项是 NULL, 设备打开一直成功, 但是你的驱动不会得到通知.
int (*flush) (struct file *);
flush 操作在进程关闭它的设备文件描述符的拷贝时调用; 它应当执行(并且等待)设备的任何未完成的操作. 这个必须不要和用户查询请求的 fsync 操作混淆了. 当前, flush 在很少驱动中使用; SCSI 磁带驱动使用它, 例如, 为确保所有写的数据在设备关闭前写到磁带上. 如果 flush 为 NULL, 内核简单地忽略用户应用程序的请求.
int (*release) (struct inode *, struct file *);
在文件结构被释放时引用这个操作. 如同 open, release 可以为 NULL.
int (*fsync) (struct file *, struct dentry *, int);
这个方法是 fsync 系统调用的后端, 用户调用来刷新任何挂着的数据. 如果这个指针是 NULL, 系统调用返回 -EINVAL.
int (*aio_fsync)(struct kiocb *, int);
这是 fsync 方法的异步版本.
int (*fasync) (int, struct file *, int);
这个操作用来通知设备它的 FASYNC 标志的改变. 异步通知是一个高级的主题, 在第 6 章中描述. 这个成员可以是NULL 如果驱动不支持异步通知.
int (*lock) (struct file *, int, struct file_lock *);
lock 方法用来实现文件加锁; 加锁对常规文件是必不可少的特性, 但是设备驱动几乎从不实现它.
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
这些方法实现发散/汇聚读和写操作. 应用程序偶尔需要做一个包含多个内存区的单个读或写操作; 这些系统调用允许它们这样做而不必对数据进行额外拷贝. 如果这些函数指针为 NULL, read 和 write 方法被调用( 可能多于一次 ).
ssize_t (*sendfile)(struct file *, loff_t *, size_t, read_actor_t, void *);
这个方法实现 sendfile 系统调用的读, 使用最少的拷贝从一个文件描述符搬移数据到另一个. 例如, 它被一个需要发送文件内容到一个网络连接的 web 服务器使用. 设备驱动常常使 sendfile 为 NULL.
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
sendpage 是 sendfile 的另一半; 它由内核调用来发送数据, 一次一页, 到对应的文件. 设备驱动实际上不实现 sendpage.
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
这个方法的目的是在进程的地址空间找一个合适的位置来映射在底层设备上的内存段中. 这个任务通常由内存管理代码进行; 这个方法存在为了使驱动能强制特殊设备可能有的任何的对齐请求. 大部分驱动可以置这个方法为 NULL.[10]
int (*check_flags)(int)
这个方法允许模块检查传递给 fnctl(F_SETFL...) 调用的标志.
int (*dir_notify)(struct file *, unsigned long);
这个方法在应用程序使用 fcntl 来请求目录改变通知时调用. 只对文件系统有用; 驱动不需要实现 dir_notify.

scull 设备驱动只实现最重要的设备方法. 它的 file_operations 结构是如下初始化的:
struct file_operations scull_fops = {.owner =  THIS_MODULE, .llseek =  scull_llseek, .read =  scull_read, .write =  scull_write, .ioctl =  scull_ioctl, .open =  scull_open, .release =  scull_release,
};  

其中struct file代表一个打开的文件,在执行file_operation中的open操作时被创建。假设驱动程序中定义的file_operation是fops,图1-4是应用层系统调用与驱动层fops的调用关系图。

 
(点击查看大图)图1-4  应用层与驱动层的调用关系

struct inode被内核用来表示一个文件结点。文件结点的操作结构定义如下:

  1. struct inode_operations {
  2. int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
  3. struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
  4. int (*link) (struct dentry *,struct inode *,struct dentry *);
  5. int (*unlink) (struct inode *,struct dentry *);
  6. int (*symlink) (struct inode *,struct dentry *,const char *);//创建软链接
  7. int (*mkdir) (struct inode *,struct dentry *,int);//创建目录
  8. int (*rmdir) (struct inode *,struct dentry *);//删除结点
  9. int (*mknod) (struct inode *,struct dentry *,int,dev_t);//创建结点
  10. int (*rename) (struct inode *, struct dentry *,struct inode *, struct dentry *);
  11. int (*readlink) (struct dentry *, char __user *,int);
  12. void * (*follow_link) (struct dentry *, struct nameidata *);
  13. void (*put_link) (struct dentry *, struct nameidata *, void *);
  14. void (*truncate) (struct inode *);
  15. int (*permission) (struct inode *, int);//权限管理
  16. int (*check_acl)(struct inode *, int);
  17. int (*setattr) (struct dentry *, struct iattr *);
  18. int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
  19. int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
  20. ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
  21. ssize_t (*listxattr) (struct dentry *, char *, size_t);
  22. int (*removexattr) (struct dentry *, const char *);
  23. void (*truncate_range)(struct inode *, loff_t, loff_t);
  24. long (*fallocate)(struct inode *inode, int mode, loff_t offset,loff_t len);
  25. int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,u64 len);
  26. };

file_operations结构相关推荐

  1. linux 内核 file_operations结构体各项解析

    struct module *owner 第一个 file_operations 成员根本不是一个操作; 它是一个指向拥有这个结构的模块的指针. 这个成员用来在它的操作还在被使用时阻止模块被卸载. 几 ...

  2. Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析

    前面在 Linux 字符设备驱动开发基础 (三)-- 字符设备驱动结构(中) ,我们已经介绍了两种重要的数据结构 struct inode{...}与 struct file{...} ,下面来介绍另 ...

  3. file_operations结构体分析 (设备文件的操作)

    linux设备驱动中file_operations结构体分析  struct module *owner 第一个 file_operations 成员根本不是一个操作; 它是一个指向拥有这个结构的模块 ...

  4. 驱动注册的两种方式(一)——file_operations结构体

    使用file_operations结构体进行字符驱动设备的注册/注销: #include <linux/module.h> //module_init() & module_exi ...

  5. file_operations结构体介绍

    内核中file_operations源码 linux-2.6.22.6 /include/linux/fs.h 具体内容在最后 //code from : linux2.6.22.6 /** NOTE ...

  6. file_operations结构体

    以下读书笔记内容,摘自宋宝华<Linux设备驱动开发详解>一书. (1)llseek()函数 用来修改一个文件的当前读写位置,并将新位置返回,在出错时,这个函数返回一个负值. (2)rea ...

  7. Linux驱动程序中的file,inode,file_operations三大结构体

    本文允许转载,但请标明出处:http://blog.csdn.net/u010944778/article/details/45077565 file_operations:     该结构是将系统调 ...

  8. linux 内核 数据结构 file_operations、file、inode

    文件操作结构 将驱动程序操作连接到设备编号,结构定义在<linux/fs.h>,其中包含一组函数指针,每个打开的文件(在内部由一个file结构表示)和一组函数关联(通过包含指向一个file ...

  9. linux存储--文件描述符fd与FILE结构体(二)

    文件描述符fd 对于linux而言,所有对设备(对于linux而言,一切皆文件)和文件的操作都使用文件描述符来进行的. 文件描述符是一个非负的整数,它是一个索引值,指向内核中每个进程打开文件的记录表. ...

最新文章

  1. 关于学习Python的一点学习总结(27->关键字参数和默认值)
  2. KMP算法的详细解释及实现
  3. electron 两个窗口如何通信_关于 Electron 进程间通信的一个小小实践
  4. LeetCode 21 合并两个有序链表
  5. WebKit DOM Event (一)
  6. python最常用的版本、也称为classic_2021年中国大学《创新思维与创业》单元测试答案...
  7. matlab ifft频率分辨率,[FFT] matlab中关于FFT的使用(理解频率分辨率、补零问题)
  8. 自学python需要安装什么-Python学习需要安装的工具
  9. 末学者笔记--Jenkins+Git+Gitlab+Ansible实现持续集成自动化部署静态网站
  10. BZOJ1176[Balkan2007] Mokia
  11. 深度学习:图像识别(匹配)方法|室内定位|论文与方法整理
  12. 锂电池欧姆内阻和极化内阻
  13. 看漫画用什么软件最好?另外,好看的百合漫画有哪些?
  14. centos lvm管理2t以上硬盘
  15. 【coq】函数语言设计 笔记 07 - indProp
  16. php 在文本域中添加qq表情 createelement,仿微信在对话框文字中插入Emoji表情包
  17. 小红书年货热潮|品牌场景营销新套路
  18. openstack的部署与云主机实例
  19. 元胞自动机模拟森林火灾--matlab实现
  20. EasyExcel 批量添加批注

热门文章

  1. boost::process::search_path相关的测试程序
  2. boost::mp11::mp_iota相关用法的测试程序
  3. boost::hana::back用法的测试程序
  4. boost::enable_current_exception用法测试程序
  5. ITK:创建Image
  6. DCMTK:OFOptional的单元测试
  7. VTK:Rendering之Model
  8. VTK:隐式函数之BooleanOperationImplicitFunctions
  9. VTK:Filtering之SelectionSource
  10. Qt Creator管理会议