一. 什么是块设备、

1.1. 一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性读到缓冲区。可以随机访问,块设备的访问位置必须能够在介质的不同区间前后移动

1.2. 块设备与字符设备差异

1.2.1. 块和字符是两种不同的访问设备的策略

1.2.2. 同一个设备可以同时支持块和字符两种访问策略

1.2.3. 块设备本身驱动层支持缓冲区,而字符设备驱动层没有缓冲

1.2.4. 块设备驱动最适合存储设备

1.3. 与块设备相关的几个单位

1.3.1. 扇区(Sectors):概念来自于早期磁盘,在硬盘、DVD中还有用,在Nand/SD中已经没意义了,但为了设备的统一,扇区是任何块设备硬件对数据处理的基本单位。通常,1个扇区的大小为512byte或512的整数倍。(对设备而言)

1.3.2. 块 (Blocks):由Linux制定对内核或文件系统等数据处理的基本单位。通常,1个块由1个或多个扇区组成。(对Linux操作系统而言)

1.3.3. 段(Segments):由若干个相邻的块组成。是Linux内存管理机制中一个内存页或者内存页的一部分。

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

二. 块设备的驱动框图

2.1. 框图从宏观分为三层

2.1.1. 虚拟文件系统层(VFS)

a. VFS是linux系统内核的软件层,由内核开发者已经编写完成。

b. VFS是文件系统和Linux 内核的接口,VFS以统一数据结构管理各种逻辑文件系统,接受用户层对文件系统的各种操作

c. 向上,对应用层提供一个标准的文件操作接口;

d. 对下,对文件系统提供一个标准的接口,以便其他操作系统的文件系统可以方便的移植到Linux上;

2.1.2. 内核空间层

2.1.2. 内核空间层又细分为三层

a. 通用块层(generic Block Layer)

负责维持一个I/O请求在上层文件系统与底层物理磁盘之间的关系。在通用块层中,通常用一个bio结构体来对应一个I/O请求

b. IO调度层

当多个请求提交给块设备时,执行效率依赖于请求的顺序。如果所有的请求是同一个方向(如:写数据),执行效率是最大的。内核在调用块设备驱动程序例程处理请求之前,先收集I/O请求并将请求排序,然后,将连续扇区操作的多个请求进行合并以提高执行效率(内核算法会自己做,不用你管),对I/O请求排序的算法称为电梯算法(elevator algorithm)。电梯算法在I/O调度层完成。内核提供了不同类型的电梯算法,电梯算法有

  1 noop(实现简单的FIFO,基本的直接合并与排序),

  2 anticipatory(延迟I/O请求,进行临界区的优化排序),

  3 Deadline(针对anticipatory缺点进行改善,降低延迟时间),

  4 Cfq(均匀分配I/O带宽,公平机制)

  PS:其实IO调度层(包括请求合并排序算法)是不需要用户管的,内核已经做好。

  映射层(Mapping Layer):起映射作用,将文件访问映射为设备的访问。

  VFS:对各种文件系统进行统一封装,为用户程序访问文件提供统一的接口,包含ext2,FAT,NFS,设备文件。

  磁盘缓存(Caches):将访问频率很高的文件放入其中。

  相关数据结构

  block_device:      描述一个分区或整个磁盘对内核的一个块设备实例

  gendisk:               描述一个通用硬盘(generic hard disk)对象。

  hd_struct:             描述分区应有的分区信息

  bio:                        描述块数据传送时怎样完成填充或读取块给driver

  request:                描述向内核请求一个列表准备做队列处理。

  request_queue:  描述内核申请request资源建立请求链表并填写BIO形成队列。

c. 块设备驱动

块设备驱动:在Linux中,驱动对块设备的输入或输出(I/O)操作,都会向块设备发出一个请求,在驱动中用request结构体描述。但对于一些磁盘设备而言请求的速度很慢,这时候内核就提供一种队列的机制把这些I/O请求添加到队列中(即:请求队列),在驱动中用request_queue结构体描述。在向块设备提交这些请求前内核会先执行请求的合并和排序预操作,以提高访问的效率,然后再由内核中的I/O调度程序子系统来负责提交  I/O 请求,调度程序将磁盘资源分配给系统中所有挂起的块 I/O  请求,其工作是管理块设备的请求队列,决定队列中的请求的排列顺序以及什么时候派发请求到设备。

三. 实例分析

3.1. 实例中用ram虚拟出一个块设备,并非真正的块设备

3.2. do_my_ramblock_request函数用于响应request

#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 = ; //实验用,打印出驱动读与写的调度方法
static int w_cnt = ; req = blk_fetch_request(q); while (NULL != req)
{
unsigned long start = blk_rq_pos(req) *;
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, ))
{
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 ;
}
static int blk_release(struct gendisk *gd , fmode_t no)
{
printk("11111blk umount succeed\n");
return ;
} 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(, "my_ramblock");
if (major < )
{
printk("fail to regiser my_ramblock\n");
return -EBUSY;
} // 实例化
my_ramblock_disk = alloc_disk(); //次设备个数 ,分区个数 +1 //分配设置请求队列,提供读写能力
my_ramblock_queue = blk_init_queue(do_my_ramblock_request, &my_ramblock_lock);
//设置硬盘属性
my_ramblock_disk->major = major;
my_ramblock_disk->first_minor = ;
my_ramblock_disk->fops = &my_ramblock_fops;
sprintf(my_ramblock_disk->disk_name, "my_ramblcok"); // /dev/name
my_ramblock_disk->queue = my_ramblock_queue;
set_capacity(my_ramblock_disk, RAMBLOCK_SIZE / );
/* 硬件相关操作 */
my_ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);
add_disk(my_ramblock_disk); // 向驱动框架注册一个disk或者一个partation的接口 return ;
} 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");

五. 实例实验

5.1. 模块安装(insmod)

[root@musk210 driver_test]# lsmod
Module Size Used by Not tainted
[root@musk210 driver_test]# insmod blkdev.ko
[root@musk210 driver_test]# lsmod
Module Size Used by Not tainted
blkdev
[root@musk210 driver_test]#

5.2. 查看信息

5.2.1. cat /proc/devices

[root@musk210 driver_test]# cat /proc/devices
Character devices:
mem
pty
ttyp
/dev/vc/
tty
/dev/tty
/dev/console
/dev/ptmx
vcs
misc
input
sound
sg
fb
video4linux
i2c
mtd
ppp
alsa
ptm
pts
usb
usb_device
s3c2410_serial
hidraw
s3c_bc
pvrsrvkm
rtc Block devices:
ramdisk
blkext
loop
sd
mtdblock
sd
sd
sd
sd
sd
sd
sd
sd
sd
sd
sd
sd
sd
sd
sd
mmc
my_ramblock
device-mapper
[root@musk210 driver_test]#

5.2.2. cat /proc/partitions

[root@musk210 driver_test]# cat /proc/partitions
major minor #blocks name mmcblk0
mmcblk0p1
mmcblk0p2
mmcblk0p3
mmcblk0p4
mmcblk1
mmcblk1p1
my_r

5.2.3. ls /dev/my*

[root@musk210 driver_test]# ls /dev/my*
/dev/my_ramblcok
[root@musk210 driver_test]#

5.2.4. lsmod

[root@musk210 driver_test]# lsmod
Module Size Used by Not tainted
blkdev

5.3. 挂载测试

5.3.1. 挂载前要先格式化

a. 格式化:mkfs.ext2 /dev/my_ramblock

[root@musk210 driver_test]# mkfs.ext2 /dev/my_ramblcok
[ 5587.367230] 11111blk mount succeed
Filesystem label=[ 5587.372541] do_my_ramblock-request read times
[ 5587.376912] do_my_ramblock-request read times
[ 5587.381302] do_my_ramblock-request read times
[ 5587.385774] do_my_ramblock-request read times
[ 5587.390276] do_my_ramblock-request read times
[ 5587.394779] do_my_ramblock-request read times
[ 5587.399285] do_my_ramblock-request read times
[ 5587.403796] do_my_ramblock-request read times
[ 5587.408303] do_my_ramblock-request read times
[ 5587.412854] do_my_ramblock request write times
[ 5587.417321] do_my_ramblock request write times
[ 5587.421906] do_my_ramblock request write times
[ 5587.426498] do_my_ramblock request write times
[ 5587.431089] do_my_ramblock request write times
[ 5587.435684] do_my_ramblock request write times
[ 5587.440277] do_my_ramblock request write times
[ 5587.444868] do_my_ramblock request write times
[ 5587.449462] do_my_ramblock request write times
[ 5587.454133] 11111blk umount succeed OS type: Linux
Block size= (log=)
Fragment size= (log=)
inodes, blocks
blocks (%) reserved for the super user
First data block=
Maximum filesystem blocks=
block groups
blocks per group, fragments per group
inodes per group
[root@musk210 driver_test]#

5.3.2. 挂载到/tmp目录下

a. 挂载:  mount -t ext2 /dev/my_ramblcok /tmp

[root@musk210 driver_test]# mount -t ext2 /dev/my_ramblcok /tmp/
[ 5695.893226] 11111blk mount succeed
[ 5695.895247] do_my_ramblock-request read times
[ 5695.899752] do_my_ramblock-request read times
[ 5695.904346] do_my_ramblock-request read times
[ 5695.908912] do_my_ramblock request write times

5.3.3. 去/tmp目录

[root@musk210 tmp]# ls
[ 5757.874625] do_my_ramblock-request read times
[ 5757.877941] do_my_ramblock-request read times
lost+found
[root@musk210 tmp]# touch a.txt
[ 5768.346032] do_my_ramblock-request read times

参考《朱老师.块设备驱动介绍》

参阅文献:http://www.51testing.com/html/42/n-3710242.html

块设备驱动——ramblock的更多相关文章

  1. Linux块设备驱动_WDS

    推荐书:<Linux内核源代码情景分析> 1.字符设备驱动和使用中等待某一事件的方法①查询方式②休眠唤醒,但是这种没有超时时间③poll机制,在休眠唤醒基础上加一个超时时间④异步通知,异步 ...

  2. linux块设备驱动之实例

    1.注册:向内核注册个块设备驱动,其实就是用主设备号告诉内核这个代表块设备驱动 sbull_major  =  register_blkdev(sbull_major, "sbull&quo ...

  3. FLASH驱动之-块设备驱动系统构架

    一.  块设备是只能以块为单位进行访问的设备,块的大小一般是512个字节的整数倍,常见的块设备包括硬件,SD卡,光盘,flash等.驱动程序是块的整数倍从设备读写得到数据.块设备的最小访单位为块,不同 ...

  4. Linux 块设备驱动 (一)

    1.块设备的I/O操作特点 字符设备与块设备的区别: 块设备只能以块为单位接受输入和返回输出,而字符设备则以字符为单位. 块设备对于I/O请求有对应的缓冲区,因此它们可以选择以什么顺序进行响应,字符设 ...

  5. linux下的块设备驱动(二)

    上一章主要讲了请求队列的一系列问题.下面主要说一下请求函数.首先来说一下硬盘类块设备的请求函数. 请求函数可以在没有完成请求队列的中的所有请求的情况下就返回,也可以在一个请求都不完成的情况下就返回. ...

  6. Linux块设备驱动(一) _驱动模型

    块设备是Linux三大设备之一,其驱动模型主要针对磁盘,Flash等存储类设备,本文以3.14为蓝本,探讨内核中的块设备驱动模型 框架 下图是Linux中的块设备模型示意图,应用层程序有两种方式访问一 ...

  7. Linux块设备驱动(二) _MTD驱动及其用户空间编程

    MTD(Memory Technology Device)即常说的Flash等使用存储芯片的存储设备,MTD子系统对应的是块设备驱动框架中的设备驱动层,可以说,MTD就是针对Flash设备设计的标准化 ...

  8. 【转】 bio 与块设备驱动

    原文地址: bio 与块设备驱动      系统中能够随机访问固定大小数据片(chunk)的设备被称作块设备,这些数据片就称作块.块设备文件都是以安装文件系统的方式使用,此也是块设备通常的访问方式.块 ...

  9. 乾坤合一~Linux设备驱动之块设备驱动

    1. 题外话 在蜕变成蝶的一系列学习当中,我们已经掌握了大部分Linux驱动的知识,在乾坤合一的分享当中,以综合实例为主要讲解,在一个月的蜕茧成蝶的学习探索当中,觉得数据结构,指针,链表等等占据了代码 ...

随机推荐

  1. HTML5基础——笔记

    HTML5基础——笔记 近几年来,互联网+.大数据.云计算‘物联网‘虚拟现实‘人工智能.机器学习.移动互联网等IT相关新名词.新概念层出不穷,相关产业发展如火如荼.互联网+移动互联网已经深入到人民日常 ...

  2. MySQL报错:Cause: java.sql.SQLException: Incorrect string value: '\xE6\x9D\xA8","...' for column 'obj_value' at row 1

    1.插入MySQL表时,报错:Cause: java.sql.SQLException: Incorrect string value: '\xE6\x9D\xA8","...' ...

  3. TeamViewer的替代品:realVNC

    TeamViewer的替代品:realVNC official web: realvnc: https://www.realvnc.com/ steps: 在需要被控制的PC上装上realVNC的服务 ...

  4. ClustrixDB安装配置

    前提条件 在安装ClustrixDB之前,需要: ClustrixDB安装程序和许可证密钥. 运行CentOS或RHEL 7.4的服务器(本地或云中). 具有root或sudo特权来安装Clustri ...

  5. Python爬虫十六式 - 第三式:Requests的用法

    Requests: 让 HTTP 服务人类 学习一时爽,一直学习一直爽   Hello,大家好,我是Connor,一个从无到有的技术小白.今天我们继续来说我们的 Python 爬虫,上一次我们说到了 ...

  6. IT界须知的故事——仙童八叛徒

    原文:http://blog.sina.com.cn/s/blog_457012450100vnbl.html 许多电脑史学家都认为,要想了解美国硅谷的发展史,就必须了解早期的仙童半导体公司.这家公司 ...

  7. [BZOJ1195]:[HNOI2006]最短母串(AC自动机+BFS)

    题目传送门 题目描述 给定n个字符串(S1,S2,…,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,…,Sn)都是T的子串. 输入格式 第一行是一个正整数n,表示给定的字符串的个数 ...

  8. Linux shell - shift命令用法(转载)

    位置参数可以用shift命令左移.比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1.$2.$3丢弃,$0不移动.不带参数的shift命令相当于shift 1. 非常 ...

  9. 省市区,级联查询,ajaxgird,ajaxfrom

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  10. Linux_LVM、RAID_RHEL7

    目录 目录 LVM逻辑卷管理 把物理分区初始化为物理卷 创建卷组 建立逻辑卷 格式化 挂载 vg拓展操作 lv扩展操作 RAID RAID 类型 RAID0条带化 RAID1镜像 RAID5条带冗余 ...