#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);
}
/*
* 读写请求处理函数
*/
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);
}
}
}
/*
* Transfer a single BIO.
*/
static int blk_xfer_bio(struct blk_dev *dev, struct bio *bio)
{
int i;
struct bio_vec *bvec;
sector_t sector = bio->bi_sector;
/* Do each segment independently. */
bio_for_each_segment(bvec, bio, i)
{
char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);
blk_transfer(dev, sector, bio_cur_bytes(bio) >> 9 /* in sectors */,
buffer, bio_data_dir(bio) == WRITE);
sector += bio_cur_bytes(bio) >> 9; /* in sectors */
__bio_kunmap_atomic(bio, KM_USER0);
}
return 0; /* Always "succeed" */
}
/*
* Transfer a full request.
*/
static int blk_xfer_request(struct blk_dev *dev, struct request *req)
{
struct bio *bio;
int nsect = 0;
__rq_for_each_bio(bio, req)
{
blk_xfer_bio(dev, bio);
nsect += bio->bi_size / sect_size;
}
return nsect;
}
/*
* The device operations structure.
*/
static struct block_device_operations blk_ops =
{
.owner = THIS_MODULE,
};
/*
* Set up our internal device.
*/
static void setup_device()
{
//计算设备大小
dev->size = nsectors * sect_size;
dev->data = vmalloc(dev->size);
if (dev->data == NULL)
{
printk(KERN_NOTICE "vmalloc failure.\n");
return;
}
//把块设备放入请求队列中,blk_request用于指明处理这个请求的函数
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;
//分配gendisk结构
dev->gd = alloc_disk(1);
if (!dev->gd)
{
printk(KERN_NOTICE "alloc_disk failure\n");
goto out_vfree;
}
/*初始化alloc_disk*/
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)
{
/*
* 注册块设备,申请主设备号
*/
major = register_blkdev(major, "blk");
if (major <= 0)
{
printk(KERN_WARNING "blk: unable to get major number\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)
{
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);
nregister_blkdev(major, "blk");
kfree(dev);
}
module_init(blk_init);
module_exit(blk_exit);
- これは、プログラムのモジュールは、それはいくつかのことをやったblk_initモジュールの初期化機能、内部を見ています:
- 図1に示すように、ブロック・デバイス登録register_blkdev、いかなる数がマスタ印刷エラーメッセージに割り当てられていない場合
- 2、[デバイス情報ブロックを保持するために使用されている構造を適用し、各ブロックデバイスはいません
- 3、その後、デバイスのインストールsetup_deviceを、この機能はカスタマイズ可能です
- 3.1完全なコンピューティングデバイスサイズのブロック
- リクエストキューに3.2高速デバイス(パラメータ要求キューに要求へのIOスケジューリング・レベルの順序blk_requestが要求を処理するために使用する機能を示すための関数です)
- 3.3セクタサイズ指定されたデバイス
- 3.4次にalloc_disk(いくつかのブロックについてgendiskと区別するためのデバイスを駆動することができる)gendisk構造の機能を割り当てます
- 次のように3.5は、この構造体を初期化する必要性が続きます。
-
/*初始化alloc_disk*/
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));//扇区数
- 3.6ブロックデバイスを登録します
- 第二の重要な機能は、読み取りおよび書き込み要求を、読み、によって達成されるblk_request機能要求を記述し処理することです。
- 図1に示すように、使用blk_fetch_requestキューから要求を処理するために取らを
- 図2は、使用blk_transferのような読み取りおよび書き込みなどの対応するセクタのハードウェアの動作を、ブロック、それはmemcpy関数が使用されているアナログ記憶装置があるべきです
- 図3は、使用__blk_end_request_cur全く出口が存在しない場合、要求キューも処理すべき要求かどうかを判断し、処理を継続します。