linux scull 中的读写代码
读和写方法都进行类似的任务, 就是, 从和到应用程序代码拷贝数据. 因此, 它们的原型 相当相似, 可以同时介绍它们:
ssize_t read(struct file *filp, char user *buff, size_t count, loff_t *offp); ssize_t write(struct file *filp, const char user *buff, size_t count, loff_t *offp);
对于 2 个方法, filp 是文件指针, count 是请求的传输数据大小. buff 参数指向持有被 写入数据的缓存, 或者放入新数据的空缓存. 最后, offp 是一个指针指向一个"long offset type"对象, 它指出用户正在存取的文件位置. 返回值是一个"signed size type"; 它的使用在后面讨论.
让我们重复一下, read 和 write 方法的 buff 参数是用户空间指针. 因此, 它不能被内 核代码直接解引用. 这个限制有几个理由:
- · 依赖于你的驱动运行的体系, 以及内核被如何配置的, 用户空间指针当运行于内核 模式可能根本是无效的. 可能没有那个地址的映射, 或者它可能指向一些其他的随 机数据.
- 就算这个指针在内核空间是同样的东西, 用户空间内存是分页的, 在做系统调用时 这个内存可能没有在 RAM 中. 试图直接引用用户空间内存可能产生一个页面错, 这 是内核代码不允许做的事情. 结果可能是一个"oops", 导致进行系统调用的进程死 亡.
- · 置疑中的指针由一个用户程序提供, 它可能是错误的或者恶意的. 如果你的驱动盲 目地解引用一个用户提供的指针, 它提供了一个打开的门路使用户空间程序存取或 覆盖系统任何地方的内存. 如果你不想负责你的用户的系统的安全危险, 你就不能 直接解引用用户空间指针.
显然, 你的驱动必须能够存取用户空间缓存以完成它的工作. 但是, 为安全起见这个存取 必须使用特殊的, 内核提供的函数. 我们介绍几个这样的函数(定义于 <asm/uaccess.h>), 剩下的在第一章"使用 ioctl 参数"一节中. 它们使用一些特殊的, 依赖体系的技巧来确保 内核和用户空间的数据传输安全和正确.
scull 中的读写代码需要拷贝一整段数据到或者从用户地址空间. 这个能力由下列内核函 数提供, 它们拷贝一个任意的字节数组, 并且位于大部分读写实现的核心中.
unsigned long copy_to_user(void user *to,const void *from,unsigned long count); unsigned long copy_from_user(void *to,const void user *from,unsigned long count);
尽管这些函数表现象正常的 memcpy 函数, 必须加一点小心在从内核代码中存取用户空间. 寻址的用户也当前可能不在内存, 虚拟内存子系统会使进程睡眠在这个页被传送到位时. 例如, 这发生在必须从交换空间获取页的时候. 对于驱动编写者来说, 最终结果是任何存 取用户空间的函数必须是可重入的, 必须能够和其他驱动函数并行执行, 并且, 特别的, 必须在一个它能够合法地睡眠的位置. 我们在第 5 章再回到这个主题.
这 2 个函数的角色不限于拷贝数据到和从用户空间: 它们还检查用户空间指针是否有效. 如果指针无效, 不进行拷贝; 如果在拷贝中遇到一个无效地址, 另一方面, 只拷贝部分数 据. 在 2 种情况下, 返回值是还要拷贝的数据量. scull 代码查看这个错误返回, 并且如 果它不是 0 就返回 -EFAULT 给用户.
用户空间存取和无效用户空间指针的主题有些高级, 在第 6 章讨论. 然而, 值得注意的是 如果你不需要检查用户空间指针, 你可以调用 copy_to_user 和 copy_from_user 来 代替. 这是有用处的, 例如, 如果你知道你已经检查了这些参数. 但是, 要小心; 事实上, 如果你不检查你传递给这些函数的用户空间指针, 那么你可能造成内核崩溃和/或安全漏洞.
至于实际的设备方法, read 方法的任务是从设备拷贝数据到用户空间(使用 copy_to_user), 而 write 方法必须从用户空间拷贝数据到设备(使用 copy_from_user). 每个 read 或 write 系统调用请求一个特定数目字节的传送, 但是驱动可自由传送较少数 据 -- 对读和写这确切的规则稍微不同, 在本章后面描述.
不管这些方法传送多少数据, 它们通常应当更新 *offp 中的文件位置来表示在系统调用成 功完成后当前的文件位置. 内核接着在适当时候传播文件位置的改变到文件结构. pread 和 pwrite 系统调用有不同的语义; 它们从一个给定的文件偏移操作, 并且不改变其他的 系统调用看到的文件位置. 这些调用传递一个指向用户提供的位置的指针, 并且放弃你的 驱动所做的改变.
read 和 write 方法都在发生错误时返回一个负值. 相反, 大于或等于 0 的返回值告知调 用程序有多少字节已经成功传送. 如果一些数据成功传送接着发生错误, 返回值必须是成 功传送的字节数, 错误不报告直到函数下一次调用. 实现这个传统, 当然, 要求你的驱动 记住错误已经发生, 以便它们可以在以后返回错误状态.
尽管内核函数返回一个负数指示一个错误, 这个数的值指出所发生的错误类型( 如第 2 章 介绍 ), 用户空间运行的程序常常看到 -1 作为错误返回值. 它们需要存取 errno 变量来 找出发生了什么. 用户空间的行为由 POSIX 标准来规定, 但是这个标准没有规定内核内部 如何操作.
linux scull 中的读写代码的更多相关文章
- linux scull 中的设备注册
在内部, scull 使用一个 struct scull_dev 类型的结构表示每个设备. 这个结构定义为: struct scull_dev { struct scull_qset *data; ...
- linux scull 中的缺陷
让我们快速看一段 scull 内存管理代码. 在写逻辑的深处, scull 必须决定它请求的内 存是否已经分配. 处理这个任务的代码是: if (!dptr->data[s_pos]) { dp ...
- 【转】 Linux内核中读写文件数据的方法--不错
原文网址:http://blog.csdn.net/tommy_wxie/article/details/8193954 Linux内核中读写文件数据的方法 有时候需要在Linuxkernel--大 ...
- Android 怎样在linux kernel 中读写文件
前言 欢迎大家我分享和推荐好用的代码段~~ 声明 欢迎转载,但请保留文章原始出处: CSDN:http://www.csdn.net ...
- Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁
在上一篇博文中笔者讨论了关于原子操作和自旋锁的相关内容,本篇博文将继续锁机制的讨论,包括内存屏障.读写自旋锁以及顺序锁的相关内容.下面首先讨论内存屏障的相关内容. 三.内存屏障 不知读者是是否记得在笔 ...
- Linux内核中锁机制之信号量、读写信号量
在上一篇博文中笔者分析了关于内存屏障.读写自旋锁以及顺序锁的相关内容,本篇博文将着重讨论有关信号量.读写信号量的内容. 六.信号量 关于信号量的内容,实际上它是与自旋锁类似的概念,只有得到信号量的进程 ...
- 大话Linux内核中锁机制之信号量、读写信号量
大话Linux内核中锁机制之信号量.读写信号量 在上一篇博文中笔者分析了关于内存屏障.读写自旋锁以及顺序锁的相关内容,本篇博文将着重讨论有关信号量.读写信号量的内容. 六.信号量 关于信号量的内容,实 ...
- 大话Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁
大话Linux内核中锁机制之内存屏障.读写自旋锁及顺序锁 在上一篇博文中笔者讨论了关于原子操作和自旋锁的相关内容,本篇博文将继续锁机制的讨论,包括内存屏障.读写自旋锁以及顺序锁的相关内容.下面首先讨论 ...
- linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...
随机推荐
- POJ1485 Sumdiv
Sumdiv Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 22680 Accepted: 5660 Descripti ...
- PHP学习(数据类型)
PHP中,支持8种原始类型,其中包括四种标量类型.两种复合类型和两种特殊类型.PHP是一门松散类型的语言,不必向PHP声明变量的数据类型,PHP会自动把变量转换为自动的数据类型,一定程度降低了学习PH ...
- linux awk命令详解,使用system来内嵌系统命令, awk合并两列
linux awk命令详解 简介 awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分 ...
- c# 日期函数
DateTime dt = DateTime.Now;Label1.Text = dt.ToString();//2005-11-5 13:21:25Label2.Text = dt.ToFileTi ...
- python 并发之线程
一.什么是线程 #指的是一条流水线的工作过程,关键的一句话:一个进程内最少自带一个线程,其实进程根本不能执行,进程不是执行单位,是资源的单位,分配资源的单位 #线程才是执行单位 #进程:做手机屏幕的工 ...
- 你在用 JWT 代替 Session?
现在,JSON Web Tokens (JWT) 是非常流行的.尤其是 Web 开发领域. 流行 安全 稳定 易用 支持 JSON 所有这些因素,令 JWT 名声大振. 但是,今天我要来说说使用 JW ...
- BZOJ1085 luogu2324骑士精神题解
没有什么特别好的办法,只好用搜索去做 因为一次移动最多归位一个骑士 所以可以想到用IDA*,为了简化状态 我们用k,x,y,sum来表示移动了k步,空格在x,y,还用sum个没有归位的情况 然后枚举转 ...
- 洛谷1758 BZOJ1566 管道取珠题解
题目链接 一道人类智慧的dp题 首先我们可以将∑ai^2转化为求取两次,两次一样的方案数 然后用f[i][j][k][l]表示第一个人在第一个串中取到i第二个串中取到j 第二个人在一个串中取到k第二个 ...
- sql select时增加常量列
阅读更多 string sql="select a,b,'常量' as c from table" 注:单引号' ' 很重要,否则编译时会把其看成查询参数,从而提示参数未指定错误. ...
- @bzoj - 2395@ [Balkan 2011]Timeismoney
目录 @description@ @solution@ @accepted code@ @details@ @description@ 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n ...