一:struct file:
1.struct file: 描述进程中打开的文件,进程中只要调用了open就有一个该对象。具体描述了打开文件的路径,权限,标志,内部偏移
file结构体是用来维护打开的文件的。每打开一次文件,内核空间里就会多增加一个file来维护,当文件关闭是释放。所以,在内核中可以存在同一个文件的多个file,因为该文件被应用程序打开被打开。struct file { struct path f_path; atomic_long_t f_count; unsigned int f_flags; fmode_t f_mode; loff_t f_pos; void *private_data; const struct file_operations *f_op }
在struct file中有几个重要的成员:
1)loff_t f_pos;
这是用来记录文件的偏移量。在应用程序中,打开文件时偏移量为0,每次的读写操作都会使偏移量增加。
从这个原因可以看出为什么每打开一次文件就新建一个file结构体了。不然的话,每个打开文件的读写操作都修改同一个偏移量,那读写岂不是乱套了吗?
2)void *private_data;
这是空类型的指针可以用于存放任何数据,我会用这个指针来存放待会要定义的结构体指针。
回想一下,文件操作结构体fops中所有的函数成员里面都有一个参数是file结构体,所以每个函数都可以在file->private_data中拿到我自己定义的结构体了。
3)struct file_operations *fops;
打开文件后,内核会把fops存放在这里,以后的操作就在这里在这里找函数了。
二:struct file_operations
file_operations是一个函数指针的集合,用于存放我们定义的用于操作设备的函数的指针,如果我们不定义,它默认保留为NULL。
内核源码中文件操作结构体的定义:
/* include/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 (*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 *); 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 *, 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 **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); };
三:struct cdev:
在Linux内核中,使用cdev结构体来描述一个字符设备,cdev结构体的定义如下:
- <include/linux/cdev.h>
- struct cdev {
- struct kobject kobj; //内嵌的内核对象.
- struct module *owner; //该字符设备所在的内核模块的对象指针.
- const struct file_operations *ops; //该结构描述了字符设备所能实现的方法,是极为关键的一个结构体.
- struct list_head list; //用来将已经向内核注册的所有字符设备形成链表.
- dev_t dev; //字符设备的设备号,由主设备号和次设备号构成.
- unsigned int count; //隶属于同一主设备号的次设备号的个数.
- };