详解 file_operations 结构体

2023-01-03 19:18:43 浏览数 (1)

写过 Linux 驱动的小伙伴,一定对 file_operations 结构体不陌生,我们常常实现其中的 open、read、write、poll 等函数,今天为大家讲解其中每个函数的作用。

Linux4.14/include/linux/fs.h

代码语言:javascript复制
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 *);
 unsigned int (*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 *);
 int (*open) (struct inode *, struct file *);
 int (*flush) (struct file *, fl_owner_t id);
 int (*release) (struct inode *, struct file *);
 int (*fsync) (struct file *, loff_t, loff_t, 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 **, void **);
 long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);
 void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
 unsigned (*mmap_capabilities)(struct file *);
#endif
 ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,loff_t, size_t, unsigned int);
 int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,u64);
 ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,u64);
} __randomize_layout;

1、struct module *owner;

这不是一个操作,它是一个指向拥有这个结构的模块的指针。用来在它的操作还在被使用时阻止模块被卸载。一般情况下, 它被简单初始化为 THIS_MODULE, 一个在<linux/module.h> 中定义的宏。

2、loff_t (*llseek)

llseek 方法用作改变文件中的当前【读/写】位置, 并且新位置作为(正的)返回值。错误返回负值。

3、ssize_t (*read)

从设备中同步读取数据,也就是读节点。读取成功返回读取的字节数。

4、ssize_t (*write)

向设备同步发送数据,也就是写节点。

5、ssize_t (*read_iter)

初始化一个异步读。可能在函数返回前不结束的读操作。如果这个方法是 NULL,所有的操作会由 read 代替进行(同步)。

6、ssize_t (*write_iter)

初始化一个异步写。

7、int (*iterate)

迭代

8、int (*iterate_shared)

共享迭代

9、unsigned int (*poll)

poll 方法是 3 个系统调用的后端:poll, epoll, 和 select, 都用作查询对一个或多个文件描述符的读或写是否会阻塞。poll 方法应当返回一个位掩码指示是否非阻塞的读或写是可能的,并且提供给内核信息用来使调用进程睡眠直到可以进行读写。如果一个驱动的 poll 方法为 NULL,设备假定为不阻塞地可读可写。

10、long (*unlocked_ioctl)

kernel-2.6 以前,使用的是 ioctl;kernel-2.6 以后,使用 unlocked_ioctl。

11、long (*compat_ioctl)

兼容性的 ioctl,为了让 32-bit 的 process 可以在 64-bit 上的 system 来执行 ioctl()

12、int (*mmap)

用来请求将设备内存映射到进程的地址空间。一般涉及到图像方面,会使用此函数,比如 framebuffer。如果这个方法是 NULL,mmap 系统调用返回 -ENODEV。

13、int (*open)

打开文件,尽管这常常是对设备文件进行的第一个操作,不要求驱动声明一个对应的方法。如果这个项是 NULL,设备打开一直成功,但是你的驱动不会得到通知。

14、int (*flush)

flush 操作在进程关闭它的设备文件描述符的拷贝时调用; 它应当执行(并且等待)设备的任何未完成的操作。我们很少使用 flush,SCSI 磁带驱动使用它,为确保所有写的数据在设备关闭前写到磁带上。如果 flush 为 NULL,内核简单地忽略用户应用程序的请求。

15、int (*release)

在文件结构被释放时引用这个操作。

16、int (*fsync)

这个方法是 fsync 系统调用的后端, 用户调用来刷新任何挂着的数据. 如果这个指针是 NULL, 系统调用返回 -EINVAL.

17、int (*fasync)

通知设备 FASYNC 标志发生变化,如果设备不支持异步通知,该字段可以为NULL

18、int (*lock)

lock 方法用来实现文件加锁; 加锁对常规文件是必不可少的特性, 但是设备驱动几乎从不实现它.

19、ssize_t (*sendpage)

它由内核调用来发送数据, 一次一页,到对应的文件。设备驱动实际上不实现 sendpage。

20、unsigned long (*get_unmapped_area)

这个方法的目的是在进程的地址空间找一个合适的位置来映射在底层设备上的内存段中. 这个任务通常由内存管理代码进行; 这个方法存在为了使驱动能强制特殊设备可能有的任何的对齐请求. 大部分驱动可以置这个方法为 NULL。

21、int (*check_flags)

这个方法允许模块检查传递给 fnctl(F_SETFL...) 调用的标志.

22、int (*flock)

为解决多进程对同一文件的读写冲突,在 Linux 系统中,提供了 flock 这一系统调用,用来实现对文件的读写保护,即文件锁的功能。

23、ssize_t (*splice_write)

类似于 write,splice 用于在两个文件描述符之间移动数据,是一种重要零拷贝技术。

24、ssize_t (*splice_read)

类似于 read,splice 用于在两个文件描述符之间移动数据,是一种重要零拷贝技术。

25、int (*setlease)

设置租约?

26、long (*fallocate)

快速创建文件。

27、void (*show_fdinfo)

展示 fd 文件描述符的信息。

28、unsigned (*mmap_capabilities)

mmap 的权限限制信息。

29、ssize_t (*copy_file_range)

Copy a range of data from one file to another.

30、int (*clone_file_range)

将一系列的数据从一个文件复制到另一个文件,希望在这一过程中能以比较优化的方式来完成。

31、ssize_t (*dedupe_file_range)

用于将文件一定范围内的重复数据消除。

一般情况下,大家只需要实现最常见几个就可以,比如 llseek、open、read、write、poll 、unlocked_ioctl、mmap、flush 等。

0 人点赞