块设备驱动介绍

以下内容源于朱有鹏《物联网大讲堂》课程的学习,如有侵权,请告知删除。


一、正确理解块设备驱动的概念

1、块设备和字符设备的差异

  • 块和字符是两种不同的访问设备的策略
  • 同一个设备可以同时支持块和字符两种访问策略;
  • 设备本身的物理特性决定了哪一种访问策略更适合;
  • 块设备本身驱动层支持缓冲区,而字符设备驱动层没有缓冲;
  • 块设备驱动最适合存储设备。

2、块设备驱动的特点

  • 字符设备只能顺序访问(如串口发送数据顺序),而块设备可以随机访问(不连续块访问);
  • 传统的机械式块设备(如硬盘、DVD)可以随机访问,但是连续访问效率更高,因此块设备驱动中有排序逻辑将用户的随机访问重新调整成尽量连续访问以提升效率;
  • 电磁设备Nand、SD卡等随机访问效率等同于顺序访问;
  • 块设备驱动和字符设备驱动不同,应用层对块设备驱动的访问一般不是直接操作设备文件(/dev/block/xxx,或者/dev/sdax),而是通过文件系统来简洁操作。(思考裸机阶段时刷机烧录SD卡时说过的对SD卡的2种访问:文件系统下访问和扇区级访问)

3、块设备相关的几个单位

(1)扇区(Sector)

  • 概念来自于早期磁盘,在硬盘、DVD中还有用,在Nand/SD中已经没意义了。
  • 扇区是块设备本身的特性,大小一般为512的整数倍,因为历史原因很多时候都向前兼容定义为512。

(2)块(block)

  • 概念来自于文件系统,是内核对文件系统数据处理的基本单位,大小为若干个扇区,常见有512B、1KB、4KB等

(3)段(Section)

  • 概念来自于内核,是内核的内存管理中一个页或者部分页,由若干个连续为块组成。

(4)页(Page)

  • 概念来自于内核,是内核内存映射管理的基本单位。linux内核的页式内存映射名称来源于此。

(5)总结:块设备驱动对下以Sector为单位管理块设备,对上以Block为单位和文件系统交互。


二、块设备驱动框架简介

1、块设备驱动框图


(1)VFS

  • 虚拟文件系统,是文件系统的抽象,对上可以接各种文件系统,是一对多的关系,是分层理论。

(2)通用块层

  • 对所有块设备都适用,屏蔽了不同硬件的差异。类似于字符设备驱动框架的第一部分。

(3)IO调度层(电梯算法)

  • 有别于其他设备的地方。这里提供了合并、排序等机制。
  • 读写相当于电梯上、下的操作。

(4)块设备驱动层(真正硬件操作部分)

2、重点结构体

(1)struct request对设备的每一次操作(譬如读或者写一个扇区)

(2)struct request_queuerequest,队列

(3)struct bio通用块层用bio来管理一个请求

(4)struct gendisk表示一个磁盘设备或一个分区


三、块设备驱动案例分析

1、块设备驱动案例演示

(1)驱动简单介绍

(2)编译

(3)模块安装

(4)查看信息cat /proc/devices(查看字符和块设备),cat /proc/partitions(查看磁盘及分区),ls /dev/,lsmod

(5)挂载测试

2、块设备驱动简单分析

(1)如何证明块设备驱动真的工作了:格式化、挂载

  • 格式化:mkfs.ext2 /dev/my_ramblock
  • 挂载:mount -t ext2 /dev/my_ramblcok /tmp,之后在/tmp进行的操作(创建文件,写内容),都是在此块设备进行操作
  • 卸载:umount /tmp,卸载之后,/tmp没有之前的文件

(2)注意各种打印信息

(3)体会块设备驱动的整体工作框架

3、源码分析

(1)register_blkdev(kernel/block/genhd.c)

  • 内核提供的注册块设备驱动的注册接口,在块设备驱动框架中的地位,等同于register_chrdev在字符设备驱动框架中的地位。

(2)blk_init_queue 

  • 用来实例化产生一个等待队列,将来应用层对本块设备所做的所有的读写操作,都会生成一个request然后被加到这个等待队列中来。

(3)blk_init_queue

  • 函数接收2个参数,第一个是等待队列的回调函数,这个函数是驱动提供的用来处理等待队列中的request的函数(IO调度层通过电梯算法从等待队列中取出一个request,就会调用这个回调函数来处理这个请求),第二个参数是一个自旋锁,这个自旋锁是要求我们驱动提供给等待队列去使用的。

(4)blk_fetch_request

  • 函数是IO调度层提供的接口,作用是从request_queue中(按照电梯算法)取出一个(算法认为当前最应该去被执行的一个请求,是被算法排序、合并后的)请求,取出的请求其实就是当前硬件(块设备)最应该去执行的那个读写操作。


#include <linux/module.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/dma.h>#define RAMBLOCK_SIZE (1024*1024)   			// 1MB,2048扇区static struct gendisk *my_ramblock_disk;		// 磁盘设备的结构体
static struct request_queue *my_ramblock_queue;	// 等待队列
static DEFINE_SPINLOCK(my_ramblock_lock);
static int major;
static unsigned char *my_ramblock_buf;			// 虚拟块设备的内存指针static void do_my_ramblock_request(struct request_queue *q)
{struct request *req;static int r_cnt = 0; 			//实验用,打印出驱动读与写的调度方法static int w_cnt = 0;req = blk_fetch_request(q);while (NULL != req){unsigned long start = blk_rq_pos(req) *512;unsigned long len = blk_rq_cur_bytes(req);if(rq_data_dir(req) == READ){// 读请求memcpy(req->buffer, my_ramblock_buf + start, len); 	//读操作,printk("do_my_ramblock-request read %d times\n", r_cnt++);}else{// 写请求memcpy( my_ramblock_buf+start, req->buffer, len); 	//写操作printk("do_my_ramblock request write %d times\n", w_cnt++);}if(!__blk_end_request_cur(req, 0)) {req = blk_fetch_request(q);}}
}static int blk_ioctl(struct block_device *dev, fmode_t no, unsigned cmd, unsigned long arg)
{return -ENOTTY;
}static int blk_open (struct block_device *dev , fmode_t no)
{printk("11111blk mount succeed\n");return 0;
}
static int blk_release(struct gendisk *gd , fmode_t no)
{printk("11111blk umount succeed\n");return 0;
}static const struct block_device_operations my_ramblock_fops =
{.owner 		= THIS_MODULE,.open 		= blk_open,.release 	= blk_release,.ioctl 		= blk_ioctl,
};static int my_ramblock_init(void)
{major = register_blkdev(0, "my_ramblock");if (major < 0){printk("fail to regiser my_ramblock\n");return -EBUSY;}// 实例化my_ramblock_disk = alloc_disk(1);		//次设备个数 ,分区个数 +1//分配设置请求队列,提供读写能力my_ramblock_queue = blk_init_queue(do_my_ramblock_request, &my_ramblock_lock);//设置硬盘属性 my_ramblock_disk->major = major;my_ramblock_disk->first_minor = 0;my_ramblock_disk->fops = &my_ramblock_fops;sprintf(my_ramblock_disk->disk_name, "my_ramblcok");		// /dev/namemy_ramblock_disk->queue = my_ramblock_queue;set_capacity(my_ramblock_disk, RAMBLOCK_SIZE / 512);/* 硬件相关操作 */my_ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);add_disk(my_ramblock_disk);				// 向驱动框架注册一个disk或者一个partation的接口return 0;
}static void my_ramblock_exit(void)
{unregister_blkdev(major, "my_ramblock");del_gendisk(my_ramblock_disk);put_disk(my_ramblock_disk);blk_cleanup_queue(my_ramblock_queue);kfree(my_ramblock_buf); 
}module_init(my_ramblock_init);
module_exit(my_ramblock_exit);MODULE_LICENSE("GPL"); 



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461197.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java中有scoreframe类型嘛_java构造函数的三种类型总结

我们说构造函数能处理参数的问题&#xff0c;但其实也要分三种情况进行讨论。目前有三种类型&#xff1a;无参、有参和默认。根据不同的参数情况&#xff0c;需要我们分别进行构造函数的讨论。这里重点是无参构造函数的初始化也要分两种方法进行分析。下面我们就这三种不同的构…

netbeans搭建安卓开发环境

2019独角兽企业重金招聘Python工程师标准>>> NetBeans 上开发 Android 应用程序需要安装一个 Android SDK 和针对 NetBeans 的 Android 开发插件 下载并安装 Android SDK 下载 Android SDK 解压后运行 tools\android.bat update sdk 进行升级&#xff0c;根据所选内…

VS2010皮肤控件介绍

在我们平时使用的各种工具中&#xff0c;如QQ&#xff0c;迅雷&#xff0c;以及各种空间等&#xff0c;都提供了一些换肤功能&#xff0c;可以让我们选择各种我们喜欢的界面。本文就对VS中常用的窗口程序做一个简单的换肤&#xff0c;利用一个dll文件来进行实现。 首先我们要加…

MySQL和Mariadb都启动不了了_linux centos7mariadb安装成功启动不了 解决思路

查看系统日志/var/log/mariadb/mariadb.log190313 14:31:03 InnoDB: Database was not shut down normally!InnoDB: Starting crash recovery.InnoDB: Reading tablespace information from the .ibd files...InnoDB: Restoring possible half-written data pages from the dou…

java 线程转储_获取Java线程转储的常用方法(推荐)

1. 线程转储简介线程转储(Thread Dump)就是JVM中所有线程状态信息的一次快照。线程转储一般使用文本格式, 可以将其保存到文本文件中, 然后人工查看和分析, 或者使用工具/API自动分析。Java中的线程模型, 直接使用了操作系统的线程调度模型, 只进行简单的封装。线程调用栈, 也称…

Oracle conn 协议适配器错误解决

Oracle conn 协议适配器错误 --解决方法C:\Documents and Settings\administrator>set oracle_sidmyoracleC:\Documents and Settings\administrator>sqlplus /nologSQL*Plus: Release 10.2.0.1.0 - Production on 星期三 12月 26 09:47:16 2012Copyright (c) 1982, 2005…

python给定一个整数n、判断n是否为素数_输入一个大于3的整数n,判断它是否为素数...

#include //让n被i除(i的值从2到n-1)int main(){int n,i;printf("please enter a integer number,n?");scanf("%d",&n);for(i2;i<n-1;i)if(n%i0) break;if(i",n);else printf("%d is a prime number.",n);return 0;}**************…

编译Ngnix遇到的问题,查看程序依赖的库文件

要点:ldd 可以读取每个可以运行的程序依赖的 so 文件。 编译的时候提示需要Openssl库. 查看本机,已经安装了openssl 查看编译报错文件,查找Openssl所依赖的库 more objs/autoconf.err 查看openssl所依赖的库文件 ldd /usr/bin/openssl ldd –u /usr/bin/openssl objdump -x ob…

[JavaWeb修行之路 Day1] 安装、配置、部署Tomcat

一、相关软件下载 Tomcat下载地址&#xff1a;http://tomcat.apache.org 。选择Tomcat 6或者Tomcat 7。Eclipse下载地址&#xff1a;http://www.eclipse.org/downloads/ 。选择Eclipse IDE for Java EE Developers进行下载。当然&#xff0c;也可以使用MyEclipse&#xff0c;收…

应用层为何不能设置分辨率

以下内容源于朱有鹏《物联网大讲堂》课程的学习&#xff0c;如有侵权&#xff0c;请告知删除。 5、在应用程序中设置分辨率 &#xff08;1&#xff09;可视分辨率&#xff08;即实际分辨率&#xff09;、虚拟分辨率 &#xff08;2&#xff09;实验及结果 vinfo.xres 1024; …

Vagrant 快速入门

1. Vagrant功能: Vagrant uses Oracle’s VirtualBox to build configurable, lightweight, and portable virtual machines dynamically.. 【Vagrant 使用Oracle VM VirtualBox 动态创建和配置轻量级的&#xff0c;可重现的&#xff0c;便携的虚拟机环境。】 2. Vagrant下载: …

各种分页存储过程 (转)

在项目中&#xff0c;我们经常遇到或用到分页&#xff0c;那么在大数据量&#xff08;百万级以上&#xff09;下&#xff0c;哪种分页算法效率最优呢&#xff1f;我们不妨用事实说话。 测试环境 硬件&#xff1a;CPU 酷睿双核T5750 内存&#xff1a;2G 软件:Windows server 20…

ViewBag 找不到编译动态表达式所需的一种或多种类型,是否缺少引用?

症状&#xff1a; 类似上面的警告提示&#xff0c;运行程序不会有任何错误&#xff0c;但若干地方都提示警告&#xff0c;并且明明dll的引用都是正确的。 解决方案&#xff1a; 删除&#xff1a;C:\Users\{your computer name}\AppData\Local\Temp\Temporary ASP.NET Files 该目…

framebuffer驱动详解4——framebuffer驱动分析2(probe函数讲解)

以下内容源于朱有鹏《物联网大讲堂》课程的学习&#xff0c;如有侵权&#xff0c;请告知删除。 主要在填充fbdev这个结构体。 二、framebuffer驱动分析2 1、probe函数分析 &#xff08;1&#xff09;struct s3c_platform_fb 这个结构体是fb的platform_data结构体&#xff1…

XenDesktop 5 SQL Server Mirror事务日志比较大的原因分析

在实施XenDesktop5项目过程中&#xff0c;发现XenDesktop5版本的数据库镜像事务日志很大&#xff0c;在XenDesktop4和XenApp版本中不存在该问题&#xff1b;于是我根据该现象探究XenDesktop5及以上版本镜像数据库事务日志为何如此之大以及我们今后实施的过程中该如何来维护这么…

input子系统详解1——input子系统简介

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 转载博客&#xff1a;input输入子系统 - 涛少& - 博客园​​​​​​​ 前言 Linux系统支持的输入设备繁多&#xff0c;例如键盘、鼠标、触摸屏、手柄等等&#xff0c;Linux系统是如何管理如此…

【04】Effective Java - 类和接口

为什么80%的码农都做不了架构师&#xff1f;>>> 1、使类和成员的可访问性最小化 封装是软件设计的基本原则之一&#xff0c;它的好处就是解除组成系统的各个模块之间的耦合关系&#xff0c;使得这些模块可以独立地开发、测试、优化、使用、理解 修改&#xff0c;同…

input子系统详解3——input子系统框架核心层分析

以下内容源于朱有鹏嵌入式课程的学习&#xff0c;如有侵权请告知删除。 一、前言 由input子系统简介可知&#xff0c;input子系统分为三层&#xff1a; 1、上层输入事件驱动层 涉及的文件有x210_kernel\drivers\input\evdev.c、mousedev.c 和 joydev.c文件&#xff0c;分别对应…

Gitlab Merge Request Builder Plugin 配置小记

2019独角兽企业重金招聘Python工程师标准>>> 以前在给一些开源项目贡献代码的时候&#xff0c;在github上一提交pull request或者提交的分支代码更新了的时候&#xff0c;jenkins就会自动把代码进行merge并且运行单元测试&#xff0c;当时看了心里就2个字&#xff1…

IOS:屏幕旋转与Transform

IOS&#xff1a;屏幕旋转与Transform iTouch&#xff0c;iPhone&#xff0c;iPad设置都是支持旋转的&#xff0c;如果我们的程序能够根据不同的方向做出不同的布局&#xff0c;体验会更好。 如何设置程序支持旋转呢&#xff0c;通常我们会在程序的info.plist中进行设置Supporte…