1. 字符设备与块设备的 I/O 操作主要有如下不同点:

(1)块设备只能以块为单位接受输入和返回输出,而字符设备则以字节为单位。大多数设备是字符设备,因为它们不需要缓冲而且不以固定块大小进行操作。

(2)块设备对于 I/O 请求有对应的缓冲区,因此它们可以选择以什么顺序进行响应,字符设备无须缓冲且被直接读写。对于存储设备而言调整读写的顺序作用巨大,因为在读写连续的扇区比分离的扇区更快。

(3)字符设备只能被顺序读写,而块设备可以随机访问。虽然块设备可随机访问,但是对于磁盘这类机械设备而言,顺序地组织块设备的访问可以提高性能,而对 SD 卡、RamDisk 等块设备而言,不存在机械上的原因,进行这样的调整没有必要。

2. 块设备例程

将ldd3(linxu device driver 3)中块设备驱动部分的代码在kerne 3.19.0 编译时,会出现很多问题,主要是由于ldd3示例代码使用的内核版本较低(2.6.10版本),对于块设备子系统,很多接口都已经发生了改变,修改后的驱动代码如下ramdisk.c(亲测可用):

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define RAMDISK_NAME "ramdisk"

#define RAMDISK_MAX_DEVICE 1

#define RAMDISK_MAX_PARTITIONS 4

#define RAMDISK_SECTOR_SIZE 512

#define RAMDISK_SECTORS 16

#define RAMDISK_HEADS 4

#define RAMDISK_CYLINDERS 256

#define RAMDISK_SECTOR_TOTAL (RAMDISK_SECTORS * RAMDISK_HEADS * RAMDISK_CYLINDERS * 50) //16383 sectors

#define RAMDISK_SIZE (RAMDISK_SECTOR_SIZE * RAMDISK_SECTOR_TOTAL) //8MB = 16383 x 512k

typedef struct {

unsigned char* data;

struct request_queue* queue;

struct gendisk* gd;

}RAMDISK_DEV;

static char* sdisk[RAMDISK_MAX_DEVICE] = {NULL};

static RAMDISK_DEV* rdev[RAMDISK_MAX_DEVICE] = {NULL};

static dev_t ramdisk_major;

static int ramdisk_space_init(void)

{

int i;

int err = 0;

for(i = 0; i < RAMDISK_MAX_DEVICE; i++){

sdisk[i] = vmalloc(RAMDISK_SIZE);

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

if(!sdisk[i]){

err = -ENOMEM;

return err;

}

memset(sdisk[i], 0, RAMDISK_SIZE);

}

return err;

}

static void ramdisk_space_clean(void)

{

int i;

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

for(i = 0; i < RAMDISK_MAX_DEVICE; i++){

vfree(sdisk[i]);

}

}

static int ramdisk_open(struct block_device* bdev, fmode_t mode)

{

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

return 0;

}

static void ramdisk_release(struct gendisk*gd, fmode_t mode)

{

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

return;

}

static int ramdisk_ioctl(struct block_device* bdev, fmode_t mode, unsigned int cmd, unsigned long arg)

{

int err;

struct hd_geometry geo;

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

switch(cmd)

{

case HDIO_GETGEO:

err = !access_ok(VERIFY_WRITE, arg, sizeof(geo));

if(err)

return -EFAULT;

geo.cylinders = RAMDISK_CYLINDERS;

geo.heads = RAMDISK_HEADS;

geo.sectors = RAMDISK_SECTORS;

geo.start = get_start_sect(bdev);

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

if(copy_to_user((void*)arg, &geo, sizeof(geo)))

return -EFAULT;

return 0;

}

return -ENOTTY;

}

static struct block_device_operations ramdisk_fops = {

.owner = THIS_MODULE,

.open = ramdisk_open,

.release = ramdisk_release,

.ioctl = ramdisk_ioctl,

};

static int ramdisk_make_request(struct request_queue* q, struct bio* bio)

{

char* pRHdata;

char* pBuffer;

struct bio_vec bvec;

int err = 0;

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

struct block_device* bdev = bio->bi_bdev;

RAMDISK_DEV* pdev = bdev->bd_disk->private_data;

if(((bio->bi_iter.bi_sector * RAMDISK_SECTOR_SIZE) + bio->bi_iter.bi_size) > RAMDISK_SIZE){

err = -EIO;

return err;

}

pRHdata = pdev->data + (bio->bi_iter.bi_sector * RAMDISK_SECTOR_SIZE);

bio_for_each_segment(bvec, bio, bio->bi_iter){

pBuffer = kmap(bvec.bv_page) + bvec.bv_offset;

switch(bio_data_dir(bio)){

case READ:

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

memcpy(pBuffer, pRHdata, bvec.bv_len);

flush_dcache_page(bvec.bv_page);

break;

case WRITE:

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

flush_dcache_page(bvec.bv_page);

memcpy(pRHdata, pBuffer, bvec.bv_len);

break;

default:

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

kunmap(bvec.bv_page);

goto out;

}

kunmap(bvec.bv_page);

pRHdata += bvec.bv_len;

}

out:

bio_endio(bio, err);

return 0;

}

static int alloc_ramdev(void)

{

int i;

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

for(i = 0; i < RAMDISK_MAX_DEVICE; i++){

rdev[i] = kzalloc(sizeof(RAMDISK_DEV), GFP_KERNEL);

if(!rdev[i]){

return -ENOMEM;

}

}

return 0;

}

static void clean_ramdev(void)

{

int i;

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

for(i = 0; i < RAMDISK_MAX_DEVICE; i++){

if(rdev[i])

kfree(rdev[i]);

}

}

static int __init ramdisk_init(void)

{

int i;

ramdisk_space_init();

alloc_ramdev();

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

ramdisk_major = register_blkdev(0, RAMDISK_NAME);

for(i = 0; i < RAMDISK_MAX_DEVICE; i++){

rdev[i]->data = sdisk[i];

rdev[i]->queue = blk_alloc_queue(GFP_KERNEL);

blk_queue_make_request(rdev[i]->queue, ramdisk_make_request);

rdev[i]->gd = alloc_disk(RAMDISK_MAX_PARTITIONS);

rdev[i]->gd->major = ramdisk_major;

rdev[i]->gd->first_minor = i * RAMDISK_MAX_PARTITIONS;

rdev[i]->gd->fops = &ramdisk_fops;

rdev[i]->gd->queue = rdev[i]->queue;

rdev[i]->gd->private_data = rdev[i];

sprintf(rdev[i]->gd->disk_name, "ramdisk%c", 'A' +i);

rdev[i]->gd->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;

set_capacity(rdev[i]->gd, RAMDISK_SECTOR_TOTAL);

add_disk(rdev[i]->gd);

}

return 0;

}

static void __exit ramdisk_exit(void)

{

int i;

printk(KERN_EMERG "%s*********Start*******%d \n", __FUNCTION__, __LINE__);

for(i = 0; i < RAMDISK_MAX_DEVICE; i++){

del_gendisk(rdev[i]->gd);

put_disk(rdev[i]->gd);

blk_cleanup_queue(rdev[i]->queue);

}

clean_ramdev();

ramdisk_space_clean();

unregister_blkdev(ramdisk_major, RAMDISK_NAME);

}

module_init(ramdisk_init);

module_exit(ramdisk_exit);

MODULE_AUTHOR("zkj");

MODULE_DESCRIPTION("block device");

MODULE_LICENSE("GPL");

Makefile参考:

KVERS = $(shell uname -r)

CURDIR = $(shell pwd)

# Kernel modules

obj-m += ramdisk.o

# Specify flags for the module compilation.

#EXTRA_CFLAGS=-g -O0

build: kernel_modules

kernel_modules:

#    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules

make -C ../linux-3.16 M=$(CURDIR) modules

clean:

#    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

make -C ../linux-3.16 M=$(CURDIR) clean

Terminal下编译(arm平台):ubuntu@ubuntu:~/WorkSpace/kernel-src/

ramdisk$ make CROSS_COMPILE=arm-linux- ARCH=arm

内核模块加载:

insmod ramdisk.ko

查看加载情况:

#sudo insmod ramdisk.ko

#

下面内容参考:http://blog.csdn.net/rocky_zhm/article/details/50372243用lsmod看看。

这里我们注意到,该模块的Used by为0,因为它既没有被其他模块使用,也没有被mount。

# lsmod

Module                  Size  Used by

simp_blkdev         16784008  0

...

#

如果当前系统支持udev,在调用add_disk()函数时即插即用机制会自动为我们在/dev/目录下建立设备文件。

设备文件的名称为我们在gendisk.disk_name中设置的simp_blkdev,主、从设备号也是我们在程序中设定的72和0。

如果当前系统不支持udev,那么很不幸,你需要自己用mknod /dev/simp_blkdev  b 72 0来创建设备文件了。

# ls -l /dev/ramdiskA

brw-rw---- 1 root disk 251, 0 12月 21 14:23 /dev/ramdiskA

创建块设备中的分区

sudo fdisk /dev/ramdiskA

Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel

Building a new DOS disklabel with disk identifier 0x7670efa4.

Changes will remain in memory only, until you decide to write them.

After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n // 创建一个新分区

Partition type:

p   primary (0 primary, 0 extended, 4 free)

e   extended

Select (default p): p //选择分区类型,主分区(p)

Partition number (1-4, default 1): 1 // 分区编号,默认为1

First sector (2048-819199, default 2048): 2048 //分区起始sector默认为2048

Last sector, +sectors or +size{K,M,G} (2048-819199, default 819199): 200000 //设定分区大小

Command (m for help): w //保存设定的分区信息

The partition table has been altered!

Calling ioctl() to re-read partition table.

Syncing disks.

在块设备中创建文件系统,这里我们创建常用的ext3。当然,作为通用的块设备,创建其他类型的文件系统也没问题。# mkfs.ext3 /dev/ramdiskAmke2fs 1.39 (29-May-2006)Filesystem label=OS type: LinuxBlock size=1024 (log=0)Fragment size=1024 (log=0)4096 inodes, 16384 blocks819 blocks (5.00%) reserved for the super userFirst data block=1Maximum filesystem blocks=167772162 block groups8192 blocks per group, 8192 fragments per group2048 inodes per groupSuperblock backups stored on blocks:        8193Writing inode tables: doneCreating journal (1024 blocks): doneWriting superblocks and filesystem accounting information: doneThis filesystem will be automatically checked every 38 mounts or180 days, whichever comes first.  Use tune2fs -c or -i to override.#如果这是第一次使用,建议创建一个目录用来mount这个设备中的文件系统。当然,这不是必需的。如果你对mount之类的用法很熟,你完全能够自己决定在这里干什么,甚至把这个设备mount成root。# mkdir -p /mnt/temp1#把建立好文件系统的块设备mount到刚才建立的目录中# mount /dev/ramdiskA /mnt/temp1#看看现在的mount表# mount.../dev/ramdiskA on /mnt/temp1 type ext3 (rw)#看看现在的模块引用计数,从刚才的0变成1了,原因是我们mount了。# lsmodModule                  Size  Used byramdiskA            16784008  1...#看看文件系统的内容,有个mkfs时自动建立的lost+found目录。# ls /mnt/temp1lost+found#随便拷点东西进去# cp /etc/init.d/* /mnt/temp1#再看看# ls /mnt/temp1acpid           conman              functions  irqbalance    mdmpd           NetworkManagerDispatcher  rdisc            sendmail        winbindanacron         cpuspeed            gpm        kdump         messagebus      nfs                       readahead_early  setroubleshoot  wpa_supplicantapmd            crond               haldaemon  killall       microcode_ctl   nfslock                   readahead_later  single          xfsatd             cups                halt       krb524        multipathd      nscd                      restorecond      smartd          xinetdauditd          cups-config-daemon  hidd       kudzu         netconsole      ntpd                      rhnsd            smb             ypbindautofs          dhcdbd              ip6tables  lost+found    netfs           pand                      rpcgssd          sshd            yum-updatesdavahi-daemon    dund                ipmi       lvm2-monitor  netplugd        pcscd                     rpcidmapd        syslogavahi-dnsconfd  firstboot           iptables   mcstrans      network         portmap                   rpcsvcgssd       vmwarebluetooth       frecord             irda       mdmonitor     NetworkManager  psacct                    saslauthd        vncserver#现在这个块设备的使用情况是# df文件系统               1K-块        已用     可用 已用% 挂载点.../dev/ramdiskA         15863      1440     13604  10% /mnt/temp1#再全删了玩玩# rm -rf /mnt/temp1/*#看看删完了没有# ls /mnt/temp1#好了,大概玩够了,我们把文件系统umount掉# umount /mnt/temp1#模块的引用计数应该还原成0了吧# lsmodModule                  Size  Used byramdiskA         16784008  0...#最后一步,移除模块# sudo rmmod ramdiskA#

linux 3.16内核下载,linux块设备驱动程序示例(适用于高版本内核3.16.0 - 3.19.0等,亲测可用)...相关推荐

  1. 写一个块设备驱动程序

    ----------------------- Page 1----------------------- 第 1章 +---------------------------------------- ...

  2. 深入理解 Linux 内核---块设备驱动程序

    块设备的处理 一个进程在某个磁盘文件上发出一个 read() 系统调用,内核对进程请求回应的一般步骤: read() 调用一个适当的 VFS 函数,将文件描述符和文件内的偏移量传递给它. 虚拟文件系统 ...

  3. Linux块设备驱动程序原理

    顾名思义,块设备驱动程序就是支持以块的方式进行读写的设备.块设备和字符设备最大的区别在于读写数据的基本单元不同.块设备读写数据的基本单元为块,例如磁盘通常为一个sector,而字符设备的基本单元为字节 ...

  4. 《Linux Device Drivers》第十六章 块设备驱动程序——note

    基本介绍 块设备驱动程序通过主传动固定大小数据的随机访问设备 Linux核心Visual块设备作为基本设备和不同的字符设备类型 Linux块设备驱动程序接口,使块设备最大限度地发挥其效用.一个问题 一 ...

  5. linux 安装不了高版本内核,Parallel Tools 高版本内核的安装失败的解决方法 | 国光...

    Parallesl Desktop 个人认为它是macOS平台上最强大的一个虚拟机软件,国光曾经用这个虚拟机甚至可以流畅的打守望先锋,不过随着一些高版本的Linux内核的发行,PD Tools的安装可 ...

  6. SD/MMC卡块设备驱动程序

    SD/MMC 卡组成的存储系统是许多嵌入设备的主要存储设备,相当于PC机的硬盘,在嵌入设备上的SD/MMC卡控制器通过MMC协议来解析命令控制SD/MMC卡的操作.SD/MMC卡上有一些寄存器来控制卡 ...

  7. IO子系统(一) — 块设备驱动程序

    VFS层(虚拟文件系统层): 由于内核需要跟不同的文件系统打交道,而每一个文件系统所实现的方式和数据结构也不尽相同,所以内核抽象了这一层,专门用来适配各种文件系统,对上提供统一的操作接口,对下层的诸多 ...

  8. 从零开始的Linux 802.11WiFi CSITool(AP和monitor模式均亲测可用)

    从零开始的Linux WiFi CSITool(AP和monitor模式均亲测可用) 主要参考 1.官方资料: 2.亲测可用安装教程: 零.Linux及CSI相关知识的学习 1.Linux相关 1.1 ...

  9. linux samba默认端口,Linux 指定端口挂载samba 亲测可用!

    我在云主机开启了445,,46端口 通过tcptraceroute可以看到,运营商屏蔽了访问445 samba 端口 chunli@ubuntu ~$ tcptraceroute 47.88.159. ...

  10. VBOX安装KALI LINUX亲测可用版

    VBOX安装KALI LINUX亲测可用版 一.新建虚拟机 二.选一个不能带中文的路径 三.Kali是Debian系的Linux 四.内存一般看情况,2G不卡就可以了 五.创建虚拟硬盘,固定70G,我 ...

最新文章

  1. JavaScript 立即执行函数的两种写法
  2. 2004-10-26+ 用户输入的安全问题
  3. 电脑怎样限制装软件 怎么限制软件运行
  4. 在tomcat下部署两个或多个项目时 log4j和web.xml配置webAppRootKey 的问题(转)
  5. 【转】【UNITY3D 游戏开发之五】Google-protobuf与FlatBuffers数据的序列化和反序列化...
  6. ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车黑线循迹实验 四驱
  7. 滴滴新规则明日起试行:将影响一大波人
  8. php做网页的流畅,Easying轻量流畅
  9. Java 获取日期间的日期 根据日期获取星期
  10. PHPExcel存放多个sheet报错:Invalid character found in sheet title
  11. World Wind入门
  12. VScode下载安装及使用教程
  13. 第十五课.K均值算法
  14. 人工智能之人工神经网络
  15. 如何提高idea运行的速度
  16. 巴比特 | 元宇宙每日必读:回顾数字藏品的2022,从高歌猛进到急速刹车,明年能否等到“风”来?...
  17. 2010互联网第一件大事件——谷歌退出中国内地
  18. 实现屏幕监控的大体思路
  19. python如何提取奇数_如何在数组中只获取奇数并使用numpy for python将其平方?
  20. 数据分析统计基础(三):差异性/相关性分析

热门文章

  1. RC电路延时公式推导
  2. VC编程中20种各种编程技巧和方法
  3. ISO9001、ISO14001和ISO45001体系审核时需要准备哪些资料?
  4. 企业为什么需要一套固定资产管理系统
  5. 16、单片机串口原理与应用
  6. Windows2012安装AppFabric失败返回1603错误的解决方案
  7. 手写体识别识别(pytorch):
  8. Hibernate拦截器字段加密解密
  9. OpenGL入门教程
  10. unity中Asset Store下载的资源保存位置