文件操作

到现在,我们已经保留了一些设备编号给我们使用,但是我们还没有连接任何我们设备操作到这些编号上. file_operation结构是一个字符驱动如何建立这个连接.这个结构,定义在,是一个函数指针的集合.每个打开文件(内部用一个file结构来代表,稍后我们会查看)与它自身的函数集合相关连(通过包含一个称为f_op的成员,它指向一个file_operations结构).这些操作大部分负责实现系统调用,因此,命名为open, read,等等.我们可以认为文件是一个"对象"并且其上的函数操作称为它的"方法",使用面向对象编程的术语来表示一个对象声明的用来操作对象的动作.这是我们在Linux内核中看到的第一个面向对象编程的现象

一个file_operation结构或者其一个指针称为fops(或者它的一些变体).结构中的每个成员必须指向驱动中的函数,这些函数实现一个特别的操作,或者对于不支持的操作留置为NULL

struct module *owner

第一个file_operations成员根本不是一个操作;它是一个指向拥有这个结构的模块的指针.这个成员用来在它的操作还在被使用时阻止模块被卸载.几乎所有时间中,它被简单初始化为THIS_MODULE,一个在中定义的宏.

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.[]

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,};

这个声明使用标准的C标记式结构初始化语法.这个语法是首选的,因为它使驱动在结构定义的改变之间更加可移植,并且,有争议地,使代码更加紧凑和可读.标记式初始化允许结构成员重新排序;在某种情况下,真实的性能提高已经实现,通过安放经常使用的成员的指针在相同硬件高速存储行中.

文件结构

struct file,定义于,是设备驱动中第二个最重要的数据结构.文件结构代表一个打开的文件. (它不特定给设备驱动;系统中每个打开的文件有一个关联的struct file在内核空间).它由内核在open时创建,并传递给在文件上操作的任何函数,直到最后的关闭.在文件的所有实例都关闭后,内核释放这个数据结构.

mode_t f_mode;

文件模式确定文件是可读的或者是可写的(或者都是),通过位FMODE_READ和FMODE_WRITE.你可能想在你的open或者ioctl函数中检查这个成员的读写许可,但是你不需要检查读写许可,因为内核在调用你的方法之前检查.当文件还没有为那种存取而打开时读或写的企图被拒绝,驱动甚至不知道这个情况.

loff_t f_pos;

当前读写位置. loff_t在所有平台都是64位(在gcc术语里是long long ).驱动可以读这个值,如果它需要知道文件中的当前位置,但是正常地不应该改变它;读和写应当使用它们作为最后参数而收到的指针来更新一个位置,代替直接作用于filp->f_pos.这个规则的一个例外是在llseek方法中,它的目的就是改变文件位置.

unsigned int f_flags;

这些是文件标志,例如O_RDONLY, O_NONBLOCK,和O_SYNC.驱动应当检查O_NONBLOCK标志来看是否是请求非阻塞操作(我们在第一章的"阻塞和非阻塞操作"一节中讨论非阻塞I/O );其他标志很少使用.特别地,应当检查读/写许可,使用f_mode而不是f_flags.所有的标志在头文件中定义.

struct file_operations *f_op;

和文件关联的操作.内核安排指针作为它的open实现的一部分,接着读取它当它需要分派任何的操作时. filp->f_op中的值从不由内核保存为后面的引用;这意味着你可改变你的文件关联的文件操作,在你返回调用者之后新方法会起作用.例如,关联到主编号1 (/dev/null, /dev/zero,等等)的open代码根据打开的次编号来替代filp->f_op中的操作.这个做法允许实现几种行为,在同一个主编号下而不必在每个系统调用中引入开销.替换文件操作的能力是面向对象编程的"方法重载"的内核对等体.

void *private_data;

open系统调用设置这个指针为NULL,在为驱动调用open方法之前.你可自由使用这个成员或者忽略它;你可以使用这个成员来指向分配的数据,但是接着你必须记住在内核销毁文件结构之前,在release方法中释放那个内存. private_data是一个有用的资源,在系统调用间保留状态信息,我们大部分例子模块都使用它.

struct dentry *f_dentry;

关联到文件的目录入口( dentry )结构.设备驱动编写者正常地不需要关心dentry结构,除了作为filp->f_dentry->d_inode存取inode结构.

inode结构

inode结构由内核在内部用来表示文件.因此,它和代表打开文件描述符的文件结构是不同的.可能有代表单个文件的多个打开描述符的许多文件结构,但是它们都指向一个单个inode结构.

inode结构包含大量关于文件的信息.作为一个通用的规则,这个结构只有2个成员对于编写驱动代码有用:

dev_t i_rdev;

对于代表设备文件的节点,这个成员包含实际的设备编号.

struct cdev *i_cdev;

struct cdev是内核的内部结构,代表字符设备;这个成员包含一个指针,指向这个结构,当节点指的是一个字符设备文件时.

linux内核 猪头 作用,Linux内核驱动之一些重要数据结构相关推荐

  1. linux内核 猪头 作用,漫谈Linux内核哈希表(1)

    关于哈希表,在内核里设计两个很重要的数据结构:哈希链表节点: 点击(此处)折叠或打开 /*Kernel Version:3.4.x[include/linux/types.h]*/ struct hl ...

  2. Linux C try 头文件,linux c 头文件

    //1.Linux中一些头文件的作用: #include //ANSI C.提供断言,assert(表达式) #include //GCC.GTK,GNOME的基础库,提供很多有用的函数,如有数据结构 ...

  3. linux各种挂载点作用,Linux 挂载点目录及其作用

    Linux 挂载点目录及其作用 Linux 挂载点目录及其作用 什么是挂载点? Linux 使用字母和数字的组合来指代磁盘分区 Linux 是一切皆文件,整个系统都是当做文件来管理,在Windows中 ...

  4. linux pushd 不起作用,Linux命令行导航提示:pushd和popd命令的基础

    在本系列的第一部分中,我们通过讨论cd- command的用法来关注Linux中的命令行导航方面. 还讨论了一些其他相关点/概念. 进一步讨论,在本文中,我们将讨论如何使用pushd和popd命令在L ...

  5. linux非标准头文件,Linux学习:unix的标准化的实现(Linux中各种限制-数据类型-各种标准化头文件介绍)...

    作为Linux的前身,unix标准化是十分重要的.我在这里挑几个重要的点说明. 1:Linux中各种限制.Linux中限制有编译时限制和运行时限制,另外有一些限制是由于我们的实现不同而不同,因此我们需 ...

  6. linux 系统pwd的作用,linux系统pwd命令的作用

    在Linux系统中有很多命令,用户可以用这些命令创建新目录或者转换到目录.但是用户在转换目录之后,系统没有给出相应提示,所以经过几次转换后用户可能不知道自己所在的目录是哪里.而pwd命令的作用就在这里 ...

  7. linux uniq不起作用,linux之uniq用法

    Linux命令uniq的作用是过滤重复部分显示文件内容,这个命令读取输入文件,并比较相邻的行.在正常情况下,第二个及以后更多个重复行将被删去,行比较是根据所用字符集的排序序列进行的.该命令加工后的结果 ...

  8. linux内核 sin头文件,Linux内核中中断request_irq详解--中断共享问题解决

    .函数原型如下: 2.4 内核 int request_irq (unsignedintirq,void (*handler)(int,void*,structpt_regs*),unsignedlo ...

  9. Linux中kobject的作用,Linux设备驱动模型-- 数据结构Kset/KObject

    前言 Kset和kobject是Linux设备驱动模型中的核心数据结构,其主要作用是将系统中的设备抽象出来,以树状结构组织,方便系统统一管理. 而这个统一管理的地方,就是sysfs,先放一张示例图,阐 ...

最新文章

  1. JS(JavaScript)的深入了解1(更新中···)
  2. 零基础Java学习之final关键字
  3. python 人气高的项目_给大家推荐:五个Python小项目,Github上的人气很高的
  4. 数据挖掘 —— 探索性数据分析
  5. mac easyconnect不能双击打开_轻松解决Mac上「应用程序“xxx”不能打开」的问题
  6. php根据单词截取英文语句,php按单词截取字符串的方法
  7. mysql8.0云时代_8.0.22Mysql的详细安装
  8. 【转】QT布局QGridLayout QHBoxLayout QVBoxLayout简要分析!!
  9. android实现qq修改密码底部弹出框_易查分强大的“可修改列”功能:轻松实现填表、留言和信息核对...
  10. -bash:fork:Resource temporarily unavailable
  11. UI设计实用素材|寻找一种新的方法来设计网站,单页网站
  12. 你在闲鱼捡过最大的漏是什么?
  13. sysoper在oracle是什么意思,oracle用户 sysdba 与system,sysoper的区别
  14. HTML学习笔记(七)
  15. 面试必会 HashMap抄底不再怕
  16. fatal: unable to access ‘https://github.com/abseil/abseil-cpp.git/‘: Failed connect to github.com:44
  17. JavaWeb房屋租赁管理系统(servlet+jsp+mysql)
  18. 吉比特无源光纤说明书_光纤上网是如何实现的?
  19. Maven使用 | 多模块下的打包问题
  20. 一条SQL语句在MySQL中执行过程全解析

热门文章

  1. 老虎证券赴美IPO:3年交易破万亿,5年9轮融资“众星捧月”...
  2. 【Spark分布式内存计算框架——Structured Streaming】3. Structured Streaming —— 入门案例:WordCount
  3. 用C#与数据库实现吃货联盟订餐系统
  4. JSP Web学习心得
  5. java 报文长度_关于报文长度的理解
  6. 在线身份证号码提取生日工具
  7. 课题三 数控机床的坐标系及编程规则
  8. LUA 和 JAVA 的区别
  9. vue结合饿了么_饿了么基于Vue2.0的通用组件开发之路(分享会记录)
  10. AspectJ 学习笔记:Aspect的生命周期