03 Linux内核中几个重要数据结构

1、file_operations
定义:
#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);
    .....
    .....    //其中包含了一组函数指针,详细信息请参考内核源码
};
实例:(我看内核里面大家经常这么用)

说明:
(1)个人理解:file_operations中的函数实际是应用程序操作文件open、close、read、write等一系列函数的底层实现。
(2)此处例证了Linux内核中的面向对象编程思想:文件是一个”对象“,而操作他的函数是”方法“;
(3)read、write函数中参数 __user字符串表示指针是一个用户空间地址,不能被直接引用;
(4)书上Page 54,55,56对其中每个函数进行了详细说明
(5)简要列出几个常用函数说明
.owner = THIS_MODULE,   //几乎所有情况,该成员都这样初始化,避免在模块的操作正在被使用时,卸载该模块。
.open = my_open,              //对应应用程序中open函数的实现,并不是必须要声明,如果这个入口为NULL,设备永远打开成功。
.release = my_realease,     //我认为应该是close的对应,也可设置为NULL
.write = my_write,              //对应write,实现时,可以与应用程序对照理解,如果无定义,应用程序调用会出现-EINVAL错误
.read = my_read,               //对应read,与write类似
.ioctl = my_ioctl,                //这是个很美丽的函数,对设备的很多操作,可以通过命令来实现,个人比较喜欢,但认为也比较复杂。
(6)这些函数在真正用到的时候,就会有深刻理解,先基本了解一下就可以了。
2、file
定义:
#include <linux/fs.h>
      struct file {
 /*
  * fu_list becomes invalid after file_free is called and queued via
  * fu_rcuhead for RCU freeing
  */
 union {
  struct list_head fu_list;
  struct rcu_head fu_rcuhead;
 } f_u;
 struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
 const struct file_operations *f_op;
 spinlock_t f_lock;  
.......
........//详细信息请参考内核源码
};
说明:
(1)你在file_operations中一系列的函数参数中,可能会看到struct file *,那就是我们的file结构体咯
(2)file结构代表一个打开的文件(并不仅仅限定于设备驱动程序,系统中每个打开的文件在内核空间都有一个对应的file结构,所以我将本节题目改成了Linux的数据结构)。
(3)他的生命周期是:open时内核创建,对文件的所有操作内核中都要传递该参(可参考file_operations中的函数参数),close时,内核释放该数据结构。
(4)我是这样理解的:应用程序中open一个文件,会返回一个文件描述符fd,而同时内核中会创建一个指针filp,指向该结构,该结构体中的各变量就是文件打开后的各种属性如文件读写权限,打开位置,是否阻塞等,具体信息可以查看Page57,58
(5)关于file中定义了const struct file_operations *f_op;在open操作时会给该指针赋值,以后需要处理这些操作时,就会读取该指针。书上说”这种技巧允许相同主设备号下的设备实现多种操作行为,而不会增加系统调用的负担。这种替换文件操作的能力在面向对象编程技术中称为”方法重载““。而我也是云里雾里,好吧,这里加粗,慢慢理解吧。
3、inode
定义:
#include <linux/fs.h>
struct inode {
 umode_t i_mode;
 unsigned short i_opflags;
 kuid_t i_uid;
 kgid_t i_gid;
 unsigned int i_flags;
 ......//详细信息请参考内核源码
};
说明:
(1)内核用inode结构在内部表示文件,包含了大量有关文件的信息。与file不同的是,后者表示打开的文件描述符。
(2)这样一来,对于单个文件,可能会同时有很多个file结构,但都指向一个inode。
(3)可以通过以下两行获得主设备号、次设备号。
unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode);

我知道我总结的也不是很明白,对于这些神秘的概念,可能都是通过慢慢积累形成的,每个人都有不同的理解,因此描述出来都不甚相同。随着后面的深入,相信你会对他们有更深入的理解。
最后,附上一张最开始接触驱动时,某大神为了给我理清这些概念画的一张图,里面也涉及了一些字符设备的概念。当时我怎么看也不明白,现在似乎明白了一点,因为对于这些,有了自己的理解。

猜你喜欢

转载自blog.csdn.net/aysa_bear/article/details/51578803
今日推荐