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. 【php设计模式】适配器模式

    适配器模式(对象适配器.类适配器): 将一个类的接口转换成客户希望的另一个接口.适配器模式让那些接口不兼容的类可以一起工作. 在适配器模式定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的 ...

  2. 关于微信小程序返回页面时刷新页面的实现

    在小程序开发中,我们通常会遇到这样的需求:提交某个表单成功后跳转该表单详情页面,但是返回时需要跳转回到首页(注意:我这里的首页是提交表单页的前一个页面),而不能再返回提交表单的页面,并且要在首页中刷新 ...

  3. vue项目中引入animate.css和wow.js

    本文转自:https://blog.csdn.net/liyunkun888/article/details/85003152 https://www.zhuimengzhu.com/content/ ...

  4. Eclipse创建Maven项目时,项目中只存在src/main/resources(没有src/main/java、src/test/java)的解决方法

      例:Maven项目(chapter11),发现只存在src/main/resources,缺少了src/main/java和src/test/java 解决方法: 1.eclipse->wi ...

  5. linux下安装db2

    最近研究了一下在 ubuntu下安装db2的过程,很快就完成安装,特贴出来供大家讨论,如有错误请多多指教. 注意:安装过程请使用root用户,否则会出现安装失败的情况: 安装过程: 准备工作: 准备安 ...

  6. navicat for mysql 下载安装教程

    Navicat是一套快速.可靠并价格相当便宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设.它的设计符合数据库管理员.开发人员及中小企业的需要.Navicat 是以直觉化的图形用户界面而 ...

  7. 说一下 HashSet 的实现原理?(未完成)

    说一下 HashSet 的实现原理?(未完成)

  8. LocalDateTime、LocalDate、Long、Date、String 相互转换

    DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); ...

  9. javascript弹出带文字信息的提示框效果

    // position of the tooltip relative to the mouse in pixel // <html><head><meta charse ...

  10. C#实现10进制转2进制

    这几天在复习计算机原理,看到二进制忽然想到二进制转10进制的公式,然后转念一想10进制转二进制的公式好像没印象,那索性自己写出来. 结果学渣的我发现,并不能写出来!什么数列,对数,xx函数忘得一干二净 ...