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. Tomat服务器学习

    Tomat服务器学习 使用的是Redhat版本的Tomcat 目录结构 bin:可执行文件 conf:配置文件 lib:tomcat运行时依赖的jar包 logs:日志文件 temp:临时文件 web ...

  2. JavaScript基本使用

    基本使用 1.JavaScript组成 ECMAScript+BOM+DOM BOM的思想(重点) DOM的思想(重点) 2.使用<script></script>标签 doc ...

  3. 原生js实现选项卡样式切换的几种方式。

    先分享一个不能实现的实例(因为es5没有块作用域) for(var i=0; i<list.length; i++ ) { list[i].onclick = function(){ tabch ...

  4. span元素

    <span>标签属于行内元素(inline),所以无法设置高度和宽度: 如果需要改变其宽高,就需要将其转变为块体元素(block)或行内块体元素(inle-block)

  5. 字节流、字符串、16进制字符串转换__java

    package com.dvn.li.main; /** * @Package: * @ClassName:TypeConversion * @Description:字节流.字符串.16进制字符串转 ...

  6. shell数组处理

    linux shell在编程方面比windows 批处理强大太多,无论是在循环.运算.已经数据类型方面都是不能比较的. 下面是个人在使用时候,对它在数组方面一些操作进行的总结.   1.数组定义   ...

  7. 底部版权时间自动变化,网页在线qq咨询

    <p><small>© 众筹网<script>document.write(new Date().getFullYear());</script> &l ...

  8. 关于单例模式getInstance()的使用

    /**  * 对象的实例化方法,也是比较多的,最常用的方法是直接使用new,而这是最普通的,如果要考虑到其它的需要,如单实例模式,层次间调用等等. * 直接使用new就不可以实现好的设计好,这时候需要 ...

  9. Centos7.4安装RabbitMQ

    1.1 安装RabbitMQ 1.1.1 系统环境 [root@rabbitmq ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 ( ...

  10. Python求均值,方差,标准差

    import numpy as nparr = [1,2,3,4,5,6]#求均值arr_mean = np.mean(arr)#求方差arr_var = np.var(arr)#求标准差arr_st ...