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. Django rest-framework框架-CSRF验证

    settings.py里面有一个中间件 django.middleware.csrf.CsrfViewmiddleware  #如果注释掉全站不需要csrf验证  如果打开全站都要csrf验证 全局使 ...

  2. [转载]PyTorch中permute的用法

    [转载]PyTorch中permute的用法 来源:https://blog.csdn.net/york1996/article/details/81876886 permute(dims) 将ten ...

  3. Vue.prototype详解

    参考地址:Vue.prototype详解 如果需要设置 全局变量,在main.js中,Vue实例化的代码里添加. 不想污染全局作用域.这种情况下,你可以通过在 原型 上定义它们使其在每个Vue实例中可 ...

  4. Rabbitmq各方法的作用详解

    exchange_declare('direct_logs', 'direct', false, false, false);// 这个是申明交换器,如果没有申明就给默认队列的这个交换器,而且发送的类 ...

  5. shell数组处理

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

  6. Vue介绍:vue导读1

    一.什么是vue 二.如何在页面中使用vue 三.vue的挂载点 四.vue的基础指令 一.什么是vue 1.什么是vue vue.js十一个渐进式javascript框架 渐进式:vue从控制页面中 ...

  7. Hadoop_23_MapReduce倒排索引实现

    1.1.倒排索引  根据属性的值来查找记录.这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址.由于不是由记录来确 定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(invert ...

  8. LoadRunner(3)

    一.性能测试的策略 重要的:基准测试.并发测试.在线综合场景测试 递增测试.极限测试... 1.基准测试:Benchmark Testing 含义:就是单用户测试,单用户.单测试点.执行n次: 作为后 ...

  9. java线程基础巩固---如何实现一个自己的显式锁Lock

    拋出synchronized问题: 对于一个方法上了同锁如果被一个线程占有了,而假如该线程长时间工作,那其它线程不就只能傻傻的等着,而且是无限的等这线程工作完成了才能执行自己的任务,这里来演示一下这种 ...

  10. kotlin命令行交互式终端

    之前在http://www.cnblogs.com/webor2006/p/7532982.htmlKotlin的环境搭建篇提到过在开发Kotlin可以用最原始的挖掘机式的命令行去编译运行,这里学习一 ...