read和write原型

read和write方法完成的任务是相似的,亦即,拷贝数据到应用程序空间,或者反过来从应用程序空间拷贝数据;因此,它们的原型很相似,如下:

 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

其中参数filp是文件指针,参数count是请求传输的数据长度,参数buff指向用户空间的缓冲区,这个缓冲区或者保存将要写入的数据,或者是一个存放新读入数据的空缓冲区;offp指明了用户在文件中进行存放操作的位置;

一般而言,调用read和write都应该更新*offp所指向的文件位置,以便反应新系统调用成功完成之后当前文件的位置;

返回值:

read-

n==count,说明所请求的字节数成功完成;

n>0 && n<count,说明只有部分数据传输成功,大部分情况下,程序会重新读取数据;如果用fread函数读取数据,则库函数会不断的调用系统调用,直至所有的数据传输完成;

n==0,到达了文件尾;

n<0,意味着发生了错误,该值指明了发生了什么错误;

write-

n==count,说明所请求数目的字节数成功完成;

n>0 && n<count,说明只有部分数据传输成功,程序很可能再次试图写入余下的数据;

n==0,意味着什么也没写入,这个结果不是错误,而且也没理由返回一个错误码,标准库会重复调用write;

n<0,意味着发生了错误,该值指明了发生了什么错误;

内核不能直接引用用户空间指针

因为read和write方法的buff参数是用户空间指针,所以,内核代码不能直接引用其中的内容,这种限制的原因如下:

1. 随着驱动程序所运行的架构的不同或者内核配置的不同个,在内核模式中运行时,用户空间的指针可能是无效的,该地址可能根本无法映射到内核空间,或者可能指向某些随机数据;

2. 即使该指针在内核空间代表相同的东西,但是用户空间的内存是分页的,而在系统调被调用时,涉及到的内存可能根本就不在RAM中,对用户空间内存的直接应用将导致页错误,而这对内核嗲吗来说是不允许发生的事情,其结果可能是oops,导致调用该系统调用的进程死亡;

3. 我们讨论的指针可能由用户程序提供,而改程序可能存在缺陷或者是个恶意程序,如果我们的驱动程序盲目的引用用户提供的指针,则将导致系统出现打开的后门,从而允许用户空间程序随意的访问或者覆盖系统中的内存;为了驱动程序的安全性,永远会不要直接引用用户空间指针;

大多数read和write代码要做的工作就是将用户地址空间和内核地址空间进行整段的数据拷贝,这种能力是由下面的内核函数提供的,它们用于拷贝任意一段字节序列;

 static __always_inline unsigned long __must_check
copy_from_user(void *to, const void __user *from, unsigned long n) static __always_inline unsigned long __must_check
copy_to_user(void __user *to, const void *from, unsigned long n)

虽然这些函数的行为很想通常的memcpy,但是当内核空间运行的代码访问用户空间时要多加小心,被寻址的用户空间页面可能当前并且不再内存中,于是虚拟内存子系统将该进程转入睡眠状态,知道该页面呗传送至期望的位置;例如,当页面必须从交换空间取回时,这样的情况就会发生,对于驱动程序编写人员来说,者带来的结果是访问用户空间的任何函数都必须是可重入的,并且必须能和其他驱动程序函数并发执行,更特别的是,必须处于能够合法休眠的状态;

这两个函数的作用并不限于在内核空间和用户空间之间拷贝数据,它们还检查用户空间的指针是佛有效,如果无效,则不会进行拷贝;另一方面,如果在拷贝过程中遇到无效地址,则仅仅会赋值部分数据;在这两种情况下,返回值是还需要拷贝的内存数量值;

如果并不需要检查用户空间指针,则建议调用__copy_to_user和__copy_from_user;在预先知道参数已经检查过时,这两个函数很有用,但是,如果并没有真正的检查传递给这些函数的用户空间指针,则可能导致内核崩溃或者建立安全漏洞;

Linux设备驱动程序 之 read和write的更多相关文章

  1. linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)

    原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...

  2. 【转】linux设备驱动程序中的阻塞机制

    原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...

  3. Linux设备驱动程序 第三版 读书笔记(一)

    Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...

  4. Linux设备驱动程序学习之分配内存

    内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...

  5. 教你写Linux设备驱动程序:一个简短的教程

    教你写Linux设备驱动程序:一个简短的教程 http://blog.chinaunix.net/uid-20799298-id-99675.html

  6. linux设备驱动程序_hello word 模块编译各种问题集锦

    在看楼经典书籍<linux设备驱动程序>后,第一个程序就是编写一个hello word 模块. 原以为非常easy,真正弄起来,发现问题不少啊.前两天编过一次,因为没有记录,今天看的时候又 ...

  7. Linux设备驱动程序学习----1.设备驱动程序简介

    设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介   Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...

  8. Linux设备驱动程序学习----2.内核模块与应用程序的对比

    内核模块与应用程序的对比 更多内容请参考Linux设备驱动程序学习----目录 1. 内核模块与应用程序的对比 内核模块和应用程序之间的不同之处: 大多数中小规模的应用程序是从头到尾执行单个任务,而模 ...

  9. Linux设备驱动程序学习----3.模块的编译和装载

    模块的编译和装载 更多内容请参考Linux设备驱动程序学习----目录 1. 设置测试系统 第1步,要先从kernel.org的镜像网站上获取一个主线内核,并安装到自己的系统中,因为学习驱动程序的编写 ...

  10. linux设备驱动程序-设备树(1)-dtb转换成device_node

    linux设备驱动程序-设备树(1)-dtb转换成device_node 本设备树解析基于arm平台 从start_kernel开始 linux最底层的初始化部分在HEAD.s中,这是汇编代码,我们暂 ...

随机推荐

  1. uni-app使用Canvas绘图

    最近公司项目在用uni-app做小程序商城,其中商品和个人需要生成图片海报,经过摸索记录后将一些重点记录下来.这里有两种方式来生成 1.后台控制生成 2.前端用canvas合成图片 这里我们只讲使用c ...

  2. UVA10140PrimeDistance题解--质数/技巧

    题目链接 https://www.luogu.org/problemnew/show/UVA10140 分析 \(L,R\)都很大,显然不能直接筛出\(L,R\)区间中的质数,这里需要一个结论 结论 ...

  3. JavaScript Basics_Fundamentals Part 1_Variables

    JavaScript Variables JavaScript 变量(Variables)是用于存储数据值的容器. 创建一个 JavaScript 变量,可以使用关键字 let. Example le ...

  4. vue学习(10)-vue-resource

    下载:cnpm i vue-resource --save 在main.js导入包:import VueResource from 'vue-resource' 安装:Vue.use(VueResou ...

  5. 微信小程序上传图片更新图像

    解决思路: 1. 调用wx.chooseImage 选择图片 2.wx.uploadFile 上传图片 3.调用后台接口进行修改操作 修改原来的头像 wx.chooseImage({ success: ...

  6. CHD-5.3.6集群上sqoop安装

    Sqoop(发音:skup)是一款开源的工具,主要用于在Hadoop(Hive)与传统的数据库(mysql.postgresql...)间进行数据的传递,可以将一个关系型数据库(例如 : MySQL ...

  7. Hadoop_28_MapReduce_自定义 inputFormat

    1. 自定义inputFormat 1.1.需求: 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件,此时就需要有相应解决方案; 1.2.分析: 小文件的优化 ...

  8. HDU 2897 bash 博弈变形

    一堆石子N个 每个人最少取P个 最多取Q个 最后取光的人输 问谁赢 X=N%(P+Q)  X=0则先手取Q个必胜 X<=P则后手胜 X>P则先手取P个必胜 #include <ios ...

  9. 修改文件属性与权限(鸟哥linux私房菜)

    chgrp:改变文件所属用户组 chown:改变文件所有者 chmod:改变文件的权限 chgrp [-R] dirname/filename ... chgrp users install.log( ...

  10. windows安装mysql(5.7.26版本)压缩包

    1.解压安装包,进入文件夹,并创建一个data文件夹! 2.修改 my-default.ini 文件 [mysql] default-character-set=utf8 [mysqld] port ...