块设备是需要分扇区的
(req->sector + req->current_nr_sectors) <<9:每个扇区是512个字节所以需要左移9位算出扇区的大小
RAMDISK,取内存中的一块出来模拟块设备的卡的读写操作
#define SIMP_BLKDEV_DEVICEMAJOR COMPAQ_SMART2_MAJOR
#define SIMP_BLKDEV_DISKNAME "simp_blkdev"
#define SIMP_BLKDEV_BYTES 16*1024*1024
static struct request_queue * simp_blkdev_queue;
static struct gendisk * simp_blkdev_disk;
unsigned char simp_blkdev_data[SIMP_BLKDEV_BYTES];
static void simp_blkdev_do_request(struct request_queue *q)
{ Struct request *req;
While((req=elv_next_request(q)) != NULL){
If((req->sector + req->current_nr_sectors) <<9) > SIMP_BLKDEV_TYTES{
Printk(KERN_ERR_SIMP_BLKDEV_DISKNAME”:bad request :block=%11u,count=%u\n”,
(unsigned long long)req->sector,req->current_ar_sectors);
End_request(req,0)
Continue;
}
Switch(rq_data_dir(req)){
Case READ:
Memcpy(req->buffer, simp_blkdev_data + (req->sector <<9),
req->current_nr_sectors<<9);
End_request(req,1);
Break;
Case WRITE:
Memcpy(simp_blkdev_data + (req->sector <<9),
req->buffer,req->current_nr_sectors<<9);
End_request(req,1);
Break;
Default:
Break;
}
}
}
struct block_device_operations simp_blkdev_fops = {
.owner = THIS_MODULE,
};
static int __init simp_blkdev_init(void)
{
int ret;
simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request,NULL);
if(!simp_blkdev_queue){
ret = -ENOMEM;
goto err_init_queue;
}
simp_blkdev_disk = alloc_disk(1);
if(!simp_blkdev_disk){
ret = -ENOMEM;
goto err_alloc_disk;
}
strcpy(simp_blkdev_disk->disk_name, SIMP_BLKDEV_DISKNAME);
simp_blkdev_disk->major = SIMP_BLKDEV_DEVICEMAJOR;
simp_blkdev_disk->first_minor = 0;
simp_blkdev_disk->fops = &simp_blkdev_fops;
simp_bldkev_disk->queue = simp_blkdev_queue;
set_capacity(simp_blkdev_disk, SIMP_BLKDEV_BYTES >>9 );
add_disk(simp_blkdev_disk);
return 0;
err_alloc_disk:
blk_cleanup_queue(simp_blkdev_queue);
err_init_queue:
return ret;
}
static void __exit simp_blkdev_exit(void){
del_gendisk(simp_blkdev_disk);
put_disk(simp_blkdev_disk);
blk_cleanup_queue(simp_blkdev_queue);
}
module_init(simp_blkdev_init);
module_exit(simp_blkdev_exit);
应该考虑,frn和__make_request两个函数的关系
这里块设备I/O请求可以是,对某个扇区某块区域的请求
bi_io_vec更多是关于来自用户的信息内容
static int simp_blkdev_make_request(struct request_queue *q, struct bio * bio)
{
struct bio_vec *bvec;
int i;
void * dsk_mem;
if((bio->bi_sector<<9) + bio->bi_size>SIMP_BLKDEV_BYTES){
printk(KERN_ERR SIMP_BLKDEV_DISKNAME":bad request:block=%11u,count = %u\n"),
(unsigned long long )bio->bi_sector,bio->bi_size);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
bio_endio(bio,0,-EIO);
#else
bio_endio(bio,-EIO);
#endif
return 0;
}
dsk_mem = simp_blkdev_data + (bio->bi-sector <<9);
bio_for_each_segment(bvec, bio, i){
void * iovec_mem;
switch(bio_rw(bio)):{
case READ:
case READA:
iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset;//因为操作的是页指针所以需要映射
memcpy(iovec_mem, dsk_mem, bvec->bv_len);
kunmap(bvec->bv_page);
break;
case WRITE:
iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset;
memcpy(dsk_mem, iovec_mem, bvec->bv_len);
kunmap(bvec->bv_page);
break;
default:
printk(KERN_ERR SIMP_BLKDEV_DISKNAME) ":unknown value bio_rw :%
lu\n",bio_rw(bio));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
bio_endio(bio,0,-EIO);
#else
bio_endio(bio,-EIO);
#endif
return 0;
}
}
}
static int __init simp_blkdev_init(void)
{
int ret;
simp_blkdev_queue = blk_alloc_queue(GFP_KERNEL);
if(!simp_blkdev_queue){
ret = -ENOMEM;
goto err_init_queue;
}
blk_queue_make_request(simp_blkdev_queue,simp_blkdev_make,request); //这个和第一段程序不同的地方在于blk_init_queue内部先找到__make_request,然后再找到simp_blkdev_do_request;而这里是直接给队列分配处理函数simp_blkdev_make
simp_blkdev_disk = alloc_disk(1);
...
...
...
return ret;
}
几个代码树结构:
\blk_init_queue(rfn,lock)
\blk_init_queue_node(rfn,lock,-1)
\q->request_fn = rfn;
\blk_queue_make_request(q,__make_request)
\q->make_request_fn=__make_request;
blk_init_queue是和blk_cleanup_queue搭配使用的