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就坑爹了,第一次遇到找了好久
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(68) | 评论(0) | 转发(0) |
0
上一篇:LCD驱动程序架构和分析
下一篇:MTD系统架构和yaffs2使用、Nandflash驱动设计
相关热门文章
SHTML是什么_SSI有什么用...
查看linux中某个端口(port)...
卡尔曼滤波的原理说明...
shell中字符串操作
关于java中的“错误:找不到或...
给主人留下些什么吧!~~
评论热议