顾名思义,块设备驱动程序就是支持以块的方式进行读写的设备。块设备和字符设备最大的区别在于读写数据的基本单元不同。块设备读写数据的基本单元为块,例 如磁盘通常为一个sector,而字符设备的基本单元为字节。从实现角度来看,字符设备的实现比较简单,内核例程和用户态API一一对应,这种映射关系由 字符设备的file_operations维护。块设备接口则相对复杂,读写API没有直接到块设备层,而是直接到文件系统 层,然后再由文件系统层发起读写请求。

源代码(ramdisk.c)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h> #include <linux/fs.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/vmalloc.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h> #define RAMHD_NAME "ramhd"
#define RAMHD_MAX_DEVICE 2
#define RAMHD_MAX_PARTITIONS 4 #define RAMHD_SECTOR_SIZE 512
#define RAMHD_SECTORS 16
#define RAMHD_HEADS 4
#define RAMHD_CYLINDERS 256 #define RAMHD_SECTOR_TOTAL (RAMHD_SECTORS * RAMHD_HEADS *RAMHD_CYLINDERS)
#define RAMHD_SIZE (RAMHD_SECTOR_SIZE * RAMHD_SECTOR_TOTAL) //8mb typedef struct {
unsigned char* data;
struct request_queue* queue;
struct gendisk* gd;
}RAMHD_DEV; static char* sdisk[RAMHD_MAX_DEVICE] = {NULL};
static RAMHD_DEV* rdev[RAMHD_MAX_DEVICE] = {NULL}; static dev_t ramhd_major; static int ramhd_space_init(void)
{
int i;
int err = ;
for(i = ; i < RAMHD_MAX_DEVICE; i++){
sdisk[i] = vmalloc(RAMHD_SIZE);
if(!sdisk[i]){
err = -ENOMEM;
return err;
} memset(sdisk[i], , RAMHD_SIZE);
} return err;
} static void ramhd_space_clean(void)
{
int i;
for(i = ; i < RAMHD_MAX_DEVICE; i++){
vfree(sdisk[i]);
}
} static int ramhd_open(struct block_device* bdev, fmode_t mode)
{
return ;
} static int ramhd_release(struct gendisk*gd, fmode_t mode)
{
return ;
} static int ramhd_ioctl(struct block_device* bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
{
int err;
struct hd_geometry geo; switch(cmd)
{
case HDIO_GETGEO:
err = !access_ok(VERIFY_WRITE, arg, sizeof(geo));
if(err)
return -EFAULT; geo.cylinders = RAMHD_CYLINDERS;
geo.heads = RAMHD_HEADS;
geo.sectors = RAMHD_SECTORS;
geo.start = get_start_sect(bdev); if(copy_to_user((void*)arg, &geo, sizeof(geo)))
return -EFAULT; return ;
} return -ENOTTY;
} static struct block_device_operations ramhd_fops = {
.owner = THIS_MODULE,
.open = ramhd_open,
.release = ramhd_release,
.ioctl = ramhd_ioctl,
}; static int ramhd_make_request(struct request_queue* q, struct bio* bio)
{
char* pRHdata;
char* pBuffer;
struct bio_vec* bvec;
int i;
int err = ; struct block_device* bdev = bio->bi_bdev;
RAMHD_DEV* pdev = bdev->bd_disk->private_data; if(((bio->bi_sector * RAMHD_SECTOR_SIZE) + bio->bi_size) > RAMHD_SIZE){
err = -EIO;
return err;
} pRHdata = pdev->data + (bio->bi_sector * RAMHD_SECTOR_SIZE);
bio_for_each_segment(bvec, bio, i){
pBuffer = kmap(bvec->bv_page) + bvec->bv_offset;
switch(bio_data_dir(bio)){
case READ:
memcpy(pBuffer, pRHdata, bvec->bv_len);
flush_dcache_page(bvec->bv_page);
break; case WRITE:
flush_dcache_page(bvec->bv_page);
memcpy(pRHdata, pBuffer, bvec->bv_len);
break; default:
kunmap(bvec->bv_page);
goto out;
} kunmap(bvec->bv_page);
pRHdata += bvec->bv_len;
} out:
bio_endio(bio, err);
return ;
} static int alloc_ramdev(void)
{
int i;
for(i = ; i < RAMHD_MAX_DEVICE; i++){
rdev[i] = kzalloc(sizeof(RAMHD_DEV), GFP_KERNEL);
if(!rdev[i]){
return -ENOMEM;
}
} return ;
} static void clean_ramdev(void)
{
int i; for(i = ; i < RAMHD_MAX_DEVICE; i++){
if(rdev[i])
kfree(rdev[i]);
}
} static int __init ramhd_init(void)
{
int i; ramhd_space_init();
alloc_ramdev(); ramhd_major = register_blkdev(, RAMHD_NAME); for(i = ; i < RAMHD_MAX_DEVICE; i++){
rdev[i]->data = sdisk[i];
rdev[i]->queue = blk_alloc_queue(GFP_KERNEL);
blk_queue_make_request(rdev[i]->queue, ramhd_make_request); rdev[i]->gd = alloc_disk(RAMHD_MAX_PARTITIONS);
rdev[i]->gd->major = ramhd_major;
rdev[i]->gd->first_minor = i * RAMHD_MAX_PARTITIONS;
rdev[i]->gd->fops = &ramhd_fops;
rdev[i]->gd->queue = rdev[i]->queue;
rdev[i]->gd->private_data = rdev[i];
sprintf(rdev[i]->gd->disk_name, "ramhd%c", 'a' +i);
rdev[i]->gd->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
set_capacity(rdev[i]->gd, RAMHD_SECTOR_TOTAL);
add_disk(rdev[i]->gd);
} return ;
} static void __exit ramhd_exit(void)
{
int i;
for(i = ; i < RAMHD_MAX_DEVICE; i++){
del_gendisk(rdev[i]->gd);
put_disk(rdev[i]->gd);
blk_cleanup_queue(rdev[i]->queue);
} clean_ramdev();
ramhd_space_clean();
unregister_blkdev(ramhd_major, RAMHD_NAME);
} module_init(ramhd_init);
module_exit(ramhd_exit); MODULE_AUTHOR("dennis__chen@ AMDLinuxFGL");
MODULE_DESCRIPTION("The ramdisk implementation with request function");
MODULE_LICENSE("GPL");

Makefile文件

ifneq ($(KERNELRELEASE),)
obj-m := ramdisk.o else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.* Module.*
endif

操作步骤

先把Makefile 和ramdisk.c放在同一个文件夹下,然后make,

用ls命令看是否生成ramdisk.ko驱动模块

insmod ramdisk.ko //动态挂载驱动模块
lsmod  //查看是否多了个ramdisk 模块
ls /dev  //查看一下/dev目录下是否多了个block_dev节点(节点会自动创建)
mkfs.ext3 /dev/block_dev  //在虚拟磁盘上建立ext3文件系统
mount /dev/block_dev /mnt/test   //挂载到/mnt/test目录下,然后去看看mnt/test下面是不是多了lost+found文件夹
终端敲入mount,看一下mount的记录,是不是ext3格式
对它进行读写:
#cp *.c /mnt/test
#ls /mnt/test  看内容是否写过去了
#cp su.c /
#ls /su.c 看是否读OK

操作完之后就清除掉
umount /mnt/test
rmmod ramdisk.ko

linux系统下块设备驱动程序的更多相关文章

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

    扇区: 1.硬盘控制器将磁盘看成一大组扇区2.扇区就是一组相邻字节3.扇区按照惯例大小设置位512字节4.存放在块设备中的数据是通过它们在磁盘上的位置来标识,即首个扇区的下标和扇区的数目.5.扇区是硬 ...

  2. 【驱动】linux系统下nand flash驱动程序框架

    linux操作系统下nand flash驱动框架 当我们需要在操作系统上读写普通文件的时候,总是需要一层层往下,最终到达硬件相关操作,当然底层设备大多数都是块设备 NAND FLASH就作为一个最底层 ...

  3. python基础——Linux系统下的文件目录结构

    单用户操作系统和多用户操作系统 单用户操作系统:指一台计算机在同一时间只能由一个用户使用,一个用户独自享用系统的全部硬件和软件资源. 多用户操作系统:指一台计算机在同一时间可以由多个用户使用,多个用户 ...

  4. Linux中块设备驱动程序分析

    基于<Linux设备驱动程序>书中的sbull程序以对Linux块设备驱动总结分析. 開始之前先来了解这个块设备中的核心数据结构: struct sbull_dev {         i ...

  5. 【DSP开发】【Linux开发】Linux下PCI设备驱动程序开发

    PCI是一种广泛采用的总线标准,它提供了许多优于其它总线标准(如EISA)的新特性,目前已经成为计算机系统中应用最为广泛,并且最为通用的总线标准.Linux的内核能较好地支持PCI总线,本文以Inte ...

  6. 最全最详细:ubuntu16.04下linux内核编译以及设备驱动程序的编写(针对新手而写)

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

  7. linux 系统下有sda和hda的硬件设备分别代表什么意思

    linux 系统下有sda和hda的硬件设备分别代表什么意思/dev/sda1 # SCSI设备,sda,sdb,sdc,三块盘,1,2,3代表分区(PV)/dev/sda2/dev/sdb1/dev ...

  8. Linux下PCI设备驱动程序开发 --- PCI驱动程序实现(三)

    三.PCI驱动程序实现 1. 关键数据结构 PCI设备上有三种地址空间:PCI的I/O空间.PCI的存储空间和PCI的配置空间.CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给 ...

  9. (linux)块设备驱动程序

      1.4.1  Linux块设备驱动程序原理(1) 顾名思义,块设备驱动程序就是支持以块的方式进行读写的设备.块设备和字符设备最大的区别在于读写数据的基本单元不同.块设备读写数据的基本单元为块,例如 ...

随机推荐

  1. js-var变量作用域

    看代码: var a=10; function fn1(){ alert(a); var a=20; alert(a); } 运行结果:undefined 和 20 注意: 在函数内,变量如没用var ...

  2. 请不要继续使用VC6.0了!

    很多次和身边的同学交流,帮助同学修改代码,互相分享经验,却发现同学们依然在使用老旧的VC6.0作为编程学习的软件,不由得喊出:“请不要继续使用VC6.0了!”. VC6.0作为当年最好的IDE(集成开 ...

  3. MVC 数据传递

    public class HomeController : Controller { // GET: Home public ActionResult Index() //控制器名Home下默认的一个 ...

  4. 【Codeforces Round #519 by Botan Investments D】Mysterious Crime

    [链接] 我是链接,点我呀:) [题意] 相当于问你这m个数组的任意长度公共子串的个数 [题解] 枚举第1个数组以i为起点的子串. 假设i..j是以i开头的子串能匹配的最长的长度. (这个j可以给2. ...

  5. lucene_04_解析语法查询

    解析语法查询就是调用方法查询的原始查询 例如: 查询所有的查询器的语法为:*:*,因为lucene查询是根据term来做的,既是:key:value类型.*:*表示所有域中的所有值. api调用语法解 ...

  6. POJ 3762 The Bonus Salary!

    The Bonus Salary! Time Limit: 2000ms Memory Limit: 65536KB This problem will be judged on PKU. Origi ...

  7. 只读事务(@Transactional(readOnly = true))的一些概念

    念:从这一点设置的时间点开始(时间点a)到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!(查询中不会出现别人在时间点a之后提交的数据) 应用场合: 如果你一次执行单条查询语句,则没有必要 ...

  8. Spring MVC-表单(Form)标签-文本框(Text Box)示例(转载实践)

    以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_textbox.htm 说明:示例基于Spring MVC 4.1.6. 以下示例 ...

  9. 启动BIOS虚拟化

    启动BIOS虚拟化 学习了:https://jingyan.baidu.com/article/335530daa55d7e19cb41c3c2.html securable.exe下载地址:http ...

  10. hadoop1.0.4升级到hadoop2.2 具体流程步骤

     hadoop1.x 升级到hadoop2.2 本文參考了博客:http://blog.csdn.net/ajax_jquery/article/details/27311671,对一些地方做了改动. ...