|
沙发

楼主 |
发表于 2009-8-22 17:05:36
|
只看该作者
file_operation 结构体
file_operations 结构体定义在 include/linux/fs.h 中。2.4 内核的定义如下:
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char *, size_t, 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);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_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 *);
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);
}; 2.6 内核的定义如下(2.6.30):
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 **);
};
按照一般的惯例,一个 file_operations 结构体或其指针,都被称为 fops .
在结构体里面,除了 owner 域外,其它域都是函数的指针。假如结构体中对应的函数位置设为 NULL ,则表示不支持此操作。 另外,在这些方法的(操作函数)列表里,注意到不少函数的参数里包含字符串 __user 。这种注解是一种文档形式(a form of documentation)。注意,一个指针是一个不能被直接解引用的用户空间地址。对于正常情况下的编译,__user 没有影响,但它可以被外部检查软件用来找出对用户空间地址的滥用。
struct module *owner
一个指向拥有这个结构的模块指针(表示 file_operations 的拥有者)。2.4 内核中只有定义没有实际作用。这个成员的作用是,如果对设备的操作还在使用中,则阻止模块被卸载。它一般总是被简单的初始化为 THIS_MODULE --- 这是一个宏,定义在 <linux/module.h> 中。它的定义如下:
extern struct module __this_module;
#define THIS_MODULE (&__this_module) 2.6 内核因为内核直接管理设备驱动程序的使用次数,所以必须指定该域。
........... ............. ............. ............. ............. ............. ............. ............. ............. ............. .............
loff_t (*llseek) (struct file *, loff_t, int);
llseek() 函数用来修改一个文件的当前读写位置(文件指针),并将新位置返回,出错时返回一个负值。如果此处定义为 NULL,那么在调用 seek() 时会改变 file struct 这个结构体中位置计数器的值,那么可能带来潜在的且不可预知的错误!字符设备驱动程序的编译者可定义不同的文件指针。例如,对于控制内存的字符设备驱动程序可以定义成内存的地址。其中,loff_t 是一个 "长偏移 “(long offset) 类型,即使是在 32 位的平台上,它至少也是 64 位宽。
........... ............. ............. ............. .......................... ............. ............. ............. ..........................
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
定义设备驱动程序的读取函数。函数用来从设备中读取数据,成功时返回读取的字节数,出错时返回一个负值。如果这里被定义为 NULL,那么用户程序在调用 read() 时会导致失败,错误返回为 -EINVAL 。
........... ............. ............. ............. .......................... ............. ............. ............. ..........................
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
初始化一个异步读操作,在函数返回之前,这个读操作可能还没能完成。如果这里设为 NULL ,则所有的处理(同步处理)都由 read 取而代之。
........... ............. ............. ....................................... ............. ............. .......................................
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
写数据到设备。若此处设为 NULL ,那么在应用程序里调用 write() 时,则会返回 -EINVAL 。如果返回值为非负数,则代表写成功,并且表示成功写入的字节数。
........... ............. ............. ....................................... ............. ............. .......................................
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
在设备上初始化一个异步写操作。
........... ............. ............. ....................................... ............. ............. .......................................
int (*readdir) (struct file *, void *, filldir_t);
对于设备文件,这里应该设置为 NULL,此函数用来读取一个目录,这仅对文件系统有用。
........... ............. ............. ....................................... ............. ............. .......................................
unsigned int (*poll) (struct file *, struct poll_table_struct *);
poll 方法是 3 种系统调用 : poll() , epoll() 以及 select() 对应的后台程序,这 3 种系统调用都用来查询读写一个或多个的文件描述符是否会被阻塞。
poll 方法返回一个位掩码(bit mask),这个掩码表示一个非阻塞的读或写操作是否可能;或者是,提供给内核信息,用来把调用进程置于睡眠态直到 I/O 可用。如果此处设置为 NULL , 则设备假定为无阻塞的可读可写。
........... ............. .................................................... ............. ....................................................
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
ioctl 系统调用提供了一种可定制指定设备命令的方法。此外,少数的 ioctl 命令也能被内核直接识别,而无需与 fops 表相关联。如果设备没有提供一个 ioctl 方法,则对于任何非预定义的请求系统调用都返回错误信息。( -ENOTTY, "No such ioctl for device" )。
........... ............. .................................................... ............. ....................................................
int (*mmap) (struct file *, struct vm_area_struct *);
mmap 将设备内存映射到进程地址空间中。如果此处设为 NULL ,那 mmap 系统调用返回 -ENODEV 。这个函数对于帧缓冲等设备特别有意义。
........... ............. .................................................... ............. ....................................................
int (*open) (struct inode *, struct file *);
对设备文件来说,open 是第一步要做的操作,然而驱动并没有强制要求要对此操作方法来一个声明。如果这里为 NULL ,则打开设备操作永远都会提示成功,但是驱动不会被通知到它有被要求打开。
........... ............. .................................................... ............. ....................................................
int (*flush) (struct file *, fl_owner_t id);
在一个进程关闭了它对一个设备的文件描述符的拷贝后,flush 操作被调用;它执行(并等待)设备上任何一个仍未执行的操作。换句话说,它在应用程序关闭设备之前,将需要写入写入到设备程序内部的缓存内容全部运行到设备上。目前,flush 只用在极少数的设备上,如 SCSI 。例如,要在设备关闭之前确保所有的要写的数据都写往磁带上,则此时 flush 就有用了。如果 flush 被设置为 NULL , 那么内核会简单的忽略用户程序的请求。
........... ................................................................. .................................................................
int (*release) (struct inode *, struct file *);
当文件结构被释放时,此操作被调用。和 open 类似,release 也可以为 NULL 。注意,release 并不是每次调用 close() 时就会被调用。不论何时只要一个文件结构被共享着(比如在 fork() 或 dup() 后),而且在所有的拷贝未关闭之前,release 都不会被调用。
.............................................................................................................................................
int (*fsync) (struct file *, struct dentry *, int datasync);
此方法是 fsync() 系统调用的后端程序,用户用它来将婚存的数据全部写入到硬件上。如果此处被设置为 NULL ,则相应的系统调用返回 -EINVAL 。
.............................................................................................................................................
int (*aio_fsync) (struct kiocb *, int datasync);
这是 fsync 方法的异步版本。
.............................................................................................................................................
int (*fasync) (int, struct file *, int);
此操作用来通知设备它的 FASYNC 标志的改变。如果驱动不支持异步通知,则此处可设置为 NULL 。
.............................................................................................................................................
int (*lock) (struct file *, int, struct file_lock *);
lock 方法用来实现文件的锁定;锁定对于普通文件来说是一种必须的特性,但设备驱动几乎从不去实现它。
.............................................................................................................................................
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
sendpage 是 sendfile 的另一半;它被内核调用来发送数据到相应的文件,一次一个页(page),驱动程序一般不实现 sendpage 方法。
.............................................................................................................................................
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
此方法的目的是在用进程地址空间找出一个合适的位置并将其映射进底层设备上的内存段(memory segment)中。这个任务一般情况下由内存管理代码执行;此方法允许驱动程序强制一个特殊设备可能有的任一种对齐要求。大多数驱动程序对此留空。
.............................................................................................................................................
int (*check_flags)(int);
此方法允许一个模块检查传入 fcntl(F_SETFL...) 调用的标志。
.............................................................................................................................................
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
这两个方法实现 分散(scatter)/聚集(gather) 读写操作。应用程序偶尔需要对多个内存区域进行读写操作;上面的系统调用允许它们这么做而不需要额外的数据拷贝。如果此处的函数指针为 NULL ,则 read 和 write 方法被调用(可能多于一次)。 |
|