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代码中嵌入汇编代码两种方式使用同一个系统调用
系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...
随机推荐
- jquery输入框自动提示
1. 下载jar包:jquery.autocomplete.js 2. 页面内容:<script type="text/javascript" src="../jq ...
- Leetcode703.Kth Largest Element in a Stream数据流中的第K大元素
设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中 ...
- golang数据类型二
字符类型 3.14基本数据类型的相互转换 3.15基本数据类型和string的转换 FormatInt // FormatUint 将 int 型整数 i 转换为字符串形式// base:进位制(2 ...
- 模板内置函数(HTML)
模板内置函数 注意:1.html书写避免多余的空格,否则可能无法被识别 2.模板是用来渲染的不要用来处理逻辑 后台ctime=datetime.datatime.now() {{ctime|date: ...
- SSM框架用JSON进行前后端数据传输
一个根据用户id查找用户信息的简单功能,使用JSON进行数据的传输 前端代码 这里用bootstrap做简单的样式美化,中间留了个div用来异步的显示查询结果,ajax进行前端的数据传输(class内 ...
- 阿里云区块链共创会:BaaS正式商业化 广邀合作伙伴共建生态
摘要: 阿里云宣布区块链服务Hyperledger Fabric版正式商业化,并发布生态合作伙伴计划. 2019年3月29日,阿里云区块链于深圳召开正式商业化共创会,宣布区块链服务Hyperledge ...
- mysql操作手册
开启日志:https://segmentfault.com/a/1190000003072237 常用词: Mysql:一种免费的跨平台的数据库系统 E:\mysql:表示是在dos 命令窗口下面 ...
- PHP实现打印出库单,有没有实现过?
https://mp.weixin.qq.com/s/X3JldplICRq7KR0HNFcpuw 背景 有时候你在实现一个出库订单之类的功能模块,这里也有可能要你的站点也实现相应的打印出库单预览,今 ...
- hdu2044 dp
/* 每一种情况都可以由周围2个点得出 */ #include<stdio.h> int main() { __int64 dp[]; int i,t,l,r; dp[]=; dp[]=; ...
- HDU 5572 An Easy Physics Problem【计算几何】
计算几何的题做的真是少之又少. 之前wa以为是精度问题,后来发现是情况没有考虑全... 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5572 题意: ...