1.块设备概念
块设备是指只能以块(512Byte)为单位进行访问的设备,
块大小一般是512个字节的整数倍。常见的块设备包括硬件,SD卡,光盘等。
2.快速体验
-
insmod simple-blk.ko
-
ls /dev/simp_blkdev0
-
mkfs.ext3 /dev/simp_blk0
-
mkdir –p /mnt/blk
-
mount /dev/simp_blk0 /mnt/blk
-
cp /etc/init.d/* /mnt/blk
-
ls /mnt/blk
-
umount /mnt/blk
-
ls /mnt/blk
3.块设备驱动系统架构
VFS是对各种具体文件系统的一种封装 ,为
用户程序访问文件提供统一的接口。
4.系统架构-Cache
当用户发起文件访问请求的时候,首先会到Disk Cache中寻找文件是否被缓存了,如果在cache中,则直接从cache中读取。
如果数据不在缓存中,就必须要到具体的文件系统中读取数据了。
5.Mapping Layer(映射层、FS文件系统)
1. 首先确定文件系统的block size,然后计算所请求的数据包含多少个block。
2. 调用具体文件系统的函数来访问文件的
inode结构,确定所请求的数据在磁盘上的地址。
6. Generic Block Layer
Linux内核把把块设备看作是由若干个扇区组
成的数据空间。上层的读写请求在通用块层被构造成一个或多个bio结构。
7. I/O Scheduler Layer
I/O调度层负责采用某种算法(如:电梯调度
算法)将I/O操作进行排序。
8. I/O Scheduler Layer
电梯调度算法的基本原则:如果电梯现在朝
上运动,如果当前楼层的上方和下方都有请求,则先响应所有上方的请求,然后才向下响应下方的请求;如果电梯向下运动,则刚好相反。
9.块设备驱动
在块系统架构的最底层,由块设备驱动根据
排序好的请求,对硬件进行数据访问。
10.块设备驱动实例分析
-
#include <linux/module.h>
-
#include <linux/moduleparam.h>
-
#include <linux/init.h>
-
-
#include <linux/sched.h>
-
#include <linux/kernel.h> /* printk() */
-
#include <linux/slab.h> /* kmalloc() */
-
#include <linux/fs.h> /* everything... */
-
#include <linux/errno.h> /* error codes */
-
#include <linux/timer.h>
-
#include <linux/types.h> /* size_t */
-
#include <linux/fcntl.h> /* O_ACCMODE */
-
#include <linux/hdreg.h> /* HDIO_GETGEO */
-
#include <linux/kdev_t.h>
-
#include <linux/vmalloc.h>
-
#include <linux/genhd.h>
-
#include <linux/blkdev.h>
-
#include <linux/buffer_head.h> /* invalidate_bdev */
-
#include <linux/bio.h>
-
-
MODULE_LICENSE("Dual BSD/GPL");
-
-
static int major = 0;
-
-
static int sect_size = 512;
-
-
static int nsectors = 1024;
-
-
/*
-
* The internal representation of our device.
-
*/
-
struct blk_dev{
-
int size; /* Device size in sectors */
-
u8 *data; /* The data array */
-
struct request_queue *queue; /* The device request queue */
-
struct gendisk *gd; /* The gendisk structure */
-
};
-
-
struct blk_dev *dev;
-
-
-
/*
-
* Handle an I/O request, in sectors.
-
*/
-
static void blk_transfer(struct blk_dev *dev, unsigned long sector,
-
unsigned long nsect, char *buffer, int write) //扇区访问函数
-
{
-
unsigned long offset = sector*sect_size;
-
unsigned long nbytes = nsect*sect_size;
-
-
if ((offset + nbytes) > dev->size) {
-
printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
-
return;
-
}
-
if (write)
-
memcpy(dev->data + offset, buffer, nbytes); //对内存读写
-
else
-
memcpy(buffer, dev->data + offset, nbytes);
-
}
-
-
/*
-
* The simple form of the request function.
-
*/
-
static void blk_request(struct request_queue *q) //实现读写请求处理函数
-
{
-
struct request *req;
-
-
req = blk_fetch_request(q); //从队列中取出一个请求
-
while (req != NULL) {
-
struct blk_dev *dev = req->rq_disk->private_data;
-
-
blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));
-
-
if(!__blk_end_request_cur(req, 0)) //判断请求队列是否为空
-
{
-
req = blk_fetch_request(q); //嵌套处理
-
}
-
}
-
}
-
-
/*
-
* The device operations structure.
-
*/
-
static struct block_device_operations blk_ops = {
-
.owner = THIS_MODULE,
-
};
-
-
-
/*
-
* Set up our internal device.
-
*/
-
static void setup_device()
-
{
-
/*
-
* Get some memory.
-
*/
-
dev->size = nsectors*sect_size; //获取设备大小
-
dev->data = vmalloc(dev->size); //获取数据指针
-
if (dev->data == NULL) {
-
printk (KERN_NOTICE "vmalloc failure.\n");
-
return;
-
}
-
-
dev->queue = blk_init_queue(blk_request, NULL); //请求队列初始化,blk_request是处理上层传下来的请求的
-
if (dev->queue == NULL)
-
goto out_vfree;
-
-
blk_queue_logical_block_size(dev->queue, sect_size); //指明扇区大小
-
dev->queue->queuedata = dev;
-
/*
-
* And the gendisk structure.
-
*/
-
dev->gd = alloc_disk(1); //为块设备分配gendisk结构,并初始化
-
if (! dev->gd) {
-
printk (KERN_NOTICE "alloc_disk failure\n");
-
goto out_vfree;
-
}
-
dev->gd->major = major;
-
dev->gd->first_minor = 0;
-
dev->gd->fops = &blk_ops;
-
dev->gd->queue = dev->queue;
-
dev->gd->private_data = dev;
-
sprintf (dev->gd->disk_name, "simp_blk%d", 0);
-
set_capacity(dev->gd, nsectors*(sect_size/sect_size));
-
add_disk(dev->gd); //注册块设备
-
return;
-
-
out_vfree:
-
if (dev->data)
-
vfree(dev->data);
-
}
-
-
static int __init blk_init(void)
-
{
-
/*
-
* Get registered.
-
*/
-
major = register_blkdev(major, "blk"); //注册块设备驱动,major若为0会自动分配
-
if (major <= 0) {
-
printk(KERN_WARNING "blk: unable to get major number\n");
-
return -EBUSY;
-
}
-
-
dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL); //分配一个blk_dev空间
-
if (dev == NULL)
-
goto out_unregister;
-
-
setup_device(); //调用函数
-
-
return 0;
-
-
out_unregister:
-
unregister_blkdev(major, "sbd");
-
return -ENOMEM;
-
}
-
-
static void blk_exit(void)
-
{
-
-
if (dev->gd) {
-
del_gendisk(dev->gd);
-
put_disk(dev->gd);
-
}
-
if (dev->queue)
-
blk_cleanup_queue(dev->queue);
-
if (dev->data)
-
vfree(dev->data);
-
-
unregister_blkdev(major, "blk");
-
kfree(dev);
-
}
-
-
module_init(blk_init);
-
module_exit(blk_exit);
11、简单块设备驱动设计
-
#include <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/errno.h>
-
#include <linux/blkdev.h>
-
#include <linux/bio.h>
-
#include <linux/string.h>
-
#include <asm/uaccess.h>
-
#include <linux/kernel.h>
-
#include <linux/types.h>
-
#include <linux/genhd.h>
-
-
MODULE_LICENSE("GPL");
-
-
static int major = 0;
-
-
static int sect_size = 512;
-
static int nsectors = 1024;
-
-
struct blk_dev {
-
int size;
-
u8 *data;
-
struct request_queue *queue;
-
struct gendisk *gd;
-
};
-
-
struct blk_dev *dev;
-
-
static void blk_transfer(struct blk_dev *dev, unsigned long sector, unsigned long nsect,char *buffer, int write)
-
{
-
unsigned long offset = sector * sect_size;
-
unsigned long nbyte = nsect * sect_size;
-
-
if((offset + nbyte) > dev->size)
-
{
-
printk(KERN_NOTICE"Beyond-end write (%ld %ld)\n", offset, nbyte);
-
return;
-
}
-
-
if(write)
-
{
-
memcpy(dev->data + offset, buffer, nbyte);
-
}
-
else
-
{
-
memcpy(buffer, dev->data + offset, nbyte);
-
}
-
}
-
-
void blk_request(struct request_queue *q)
-
{
-
struct request *req;
-
req = blk_fetch_request(q);
-
-
while(req != NULL)
-
{
-
struct blk_dev *dev = req->rq_disk->private_data;
-
//处理该请求
-
blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));
-
-
if(!__blk_end_request_cur(req, 0))
-
req = blk_fetch_request(q);
-
}
-
-
}
-
-
static struct block_device_operations blk_ops = {
-
.owner = THIS_MODULE,
-
};
-
-
static void setup_device(void)
-
{
-
dev->size = nsectors * sect_size;
-
dev->data = vmalloc(dev->size);
-
if(dev->data == NULL) {
-
printk(KERN_NOTICE "vmalloc failure.\n");
-
return;
-
}
-
-
dev->queue = blk_init_queue(blk_request, NULL);
-
if(dev->queue == NULL)
-
{
-
goto out_vfree;
-
}
-
-
blk_queue_logical_block_size(dev->queue, sect_size);
-
dev->queue->queuedata = dev;
-
-
dev->gd = alloc_disk(1);
-
if(!dev->gd)
-
{
-
printk(KERN_NOTICE "alloc_disk failure\n");
-
goto out_vfree;
-
}
-
-
dev->gd->major = major;
-
dev->gd->first_minor = 0;
-
dev->gd->fops = &blk_ops;
-
dev->gd->queue = dev->queue;
-
dev->gd->private_data = dev;
-
sprintf(dev->gd->disk_name, "simp_blk%d", 0);
-
-
set_capacity(dev->gd, nsectors);
-
add_disk(dev->gd);
-
return;
-
-
out_vfree:
-
if(dev->data)
-
vfree(dev->data);
-
}
-
-
static int __init blk_init(void)
-
{
-
major = register_blkdev(0, "blk");
-
if(major <= 0)
-
{
-
printk(KERN_WARNING "register blk dev fail!\n");
-
return -EBUSY;
-
}
-
-
dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);
-
if(dev == NULL)
-
goto out_unregister;
-
-
setup_device();
-
-
return 0;
-
out_unregister:
-
unregister_blkdev(major, "sbd");
-
return -ENOMEM;
-
}
-
-
static void blk_exit(void)
-
{
-
del_gendisk(dev->gd);
-
blk_cleanup_queue(dev->queue);
-
vfree(dev->data);
-
unregister_blkdev(major, "blk");
-
kfree(dev);
-
}
-
-
module_init(blk_init);
-
module_exit(blk_exit);
错误总结:一开始写的时候,编译完加载进内核。直接死机,因为代码有点长。就从逻辑处一点一点注释掉来分析,果然有好多错误。
第一次遇到的问题,内核中常用goto跳转处理错误情况。如果跳转处前面没有return就坑爹了,第一次遇到找了好久
阅读(696) | 评论(0) | 转发(0) |