linux系统下块设备驱动程序
顾名思义,块设备驱动程序就是支持以块的方式进行读写的设备。块设备和字符设备最大的区别在于读写数据的基本单元不同。块设备读写数据的基本单元为块,例 如磁盘通常为一个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系统下块设备驱动程序的更多相关文章
- 深入理解Linux内核-块设备驱动程序
扇区: 1.硬盘控制器将磁盘看成一大组扇区2.扇区就是一组相邻字节3.扇区按照惯例大小设置位512字节4.存放在块设备中的数据是通过它们在磁盘上的位置来标识,即首个扇区的下标和扇区的数目.5.扇区是硬 ...
- 【驱动】linux系统下nand flash驱动程序框架
linux操作系统下nand flash驱动框架 当我们需要在操作系统上读写普通文件的时候,总是需要一层层往下,最终到达硬件相关操作,当然底层设备大多数都是块设备 NAND FLASH就作为一个最底层 ...
- python基础——Linux系统下的文件目录结构
单用户操作系统和多用户操作系统 单用户操作系统:指一台计算机在同一时间只能由一个用户使用,一个用户独自享用系统的全部硬件和软件资源. 多用户操作系统:指一台计算机在同一时间可以由多个用户使用,多个用户 ...
- Linux中块设备驱动程序分析
基于<Linux设备驱动程序>书中的sbull程序以对Linux块设备驱动总结分析. 開始之前先来了解这个块设备中的核心数据结构: struct sbull_dev { i ...
- 【DSP开发】【Linux开发】Linux下PCI设备驱动程序开发
PCI是一种广泛采用的总线标准,它提供了许多优于其它总线标准(如EISA)的新特性,目前已经成为计算机系统中应用最为广泛,并且最为通用的总线标准.Linux的内核能较好地支持PCI总线,本文以Inte ...
- 最全最详细:ubuntu16.04下linux内核编译以及设备驱动程序的编写(针对新手而写)
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...
- linux 系统下有sda和hda的硬件设备分别代表什么意思
linux 系统下有sda和hda的硬件设备分别代表什么意思/dev/sda1 # SCSI设备,sda,sdb,sdc,三块盘,1,2,3代表分区(PV)/dev/sda2/dev/sdb1/dev ...
- Linux下PCI设备驱动程序开发 --- PCI驱动程序实现(三)
三.PCI驱动程序实现 1. 关键数据结构 PCI设备上有三种地址空间:PCI的I/O空间.PCI的存储空间和PCI的配置空间.CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给 ...
- (linux)块设备驱动程序
1.4.1 Linux块设备驱动程序原理(1) 顾名思义,块设备驱动程序就是支持以块的方式进行读写的设备.块设备和字符设备最大的区别在于读写数据的基本单元不同.块设备读写数据的基本单元为块,例如 ...
随机推荐
- .NET 在序列化时使用全小写的属性名
基于某些奇怪的需求,需要将一些对象序列化后输出,而且属性名又必须为小写形式. 解决过程 说到在 .NET 平台上序列化操作,那么第一个想到的应该就是 Json.NET 家的 Newtonsoft.Js ...
- JSP_内置对象_session
session表示客户端与服务器的一次会话. Web中的session指的是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间. 从上述定义中可以看到,s ...
- h5调用app中写好的的方法
做h5页面的时候,总会遇到些不能解决的问题于是就要与app做一些交互, app那边编辑好的方法后我们怎么用js语法去调用app编写好的方法 if(this.$winInfo.shebei == 1){ ...
- BZOJ 3319: 黑白树 树+并查集+未调完+神题
Code: #include<bits/stdc++.h> #define maxn 1000003 using namespace std; char *p1,*p2,buf[10000 ...
- Android 性能测试初探(六)
书接前文 Android 性能测试初探之功耗(五) 本节聊聊性能测试的最后一项- 流量,当然我所指的性能测试是针对大部分应用而言的,可能还有部分应用会关注网速.弱网之类的测试,但本系列文章都不去一一探 ...
- eoLinker GoKu Gateway 开源版 V2.1发布,加入UI管理系统等
GoKu API Gateway 是eoLinker旗下的开源版接口网关,支持OpenAPI与微服务管理,支持私有云部署,实现API转发.请求参数转换.数据校验等功能,提供图形化界面管理,能够快速管理 ...
- 【剑指Offer】43、左旋转字符串
题目描述: 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S ...
- node环境变量配置,npm环境变量配置
引言:很久没有在windows上配过node, 记得以前node环境变量是要加 NODE_PATH 到用户变量,再在系统变量引入NODE_PATH的,而npm install的全局包目录会存放在C:/ ...
- CentOS6.2上安装Oracle10g报ins_emdb.mk错误处理方法
oracle安装过程报ins_emdb.mk错误,此时继续点击“continue”即可,待Oracle完成安装后,再手工执行相应脚本完成链接即可 在CentOS6.2操作系统上,安装Oracle10g ...
- 论文WAN Optimized Replication of Backup Datasets Using Stream-Informed Delta Compression
这是EMC的备份小组发表在FAST12上的论文,主要是结合重删和差量数据压缩的方法,达到更高的数据压缩率.并且作者使用了一种基于数据流的差量数据压缩,消除了对索引的需求.通过测试达到的压缩效 ...