LDD3块设备代码分析

整个块设备抽象的数据结构

struct sbull_dev {

        int size;                       /* Device size in sectors */

        u8 *data;                       /* The data array */

        short users;                    /* How many users */

        short media_change;             /* Flag a media change? */

        spinlock_t lock;                /* For mutual exclusion */

        struct request_queue *queue;    /* The device request queue */请求队列

        struct gendisk *gd;             /* The gendisk structure */              /块设备数据结构

        struct timer_list timer;        /* For simulated media changes */

};

//模块初始化函数

static int __init sbull_init(void)

{

int i;

/*

* Get registered.

*/

sbull_major = register_blkdev(sbull_major, "sbull");//自动分配主设备号

if (sbull_major <= 0) {

printk(KERN_WARNING "sbull: unable to get major number/n");

return -EBUSY;

}

/*

* Allocate the device array, and initialize each one.

*/

Devices = kmalloc(ndevices*sizeof (struct sbull_dev), GFP_KERNEL);//分配每个块设备的数据结构

if (Devices == NULL)

goto out_unregister;

for (i = 0; i < ndevices; i++) 

setup_device(Devices + i, i);

 

return 0;

 

  out_unregister:

unregister_blkdev(sbull_major, "sbd");

return -ENOMEM;

}

 

static void setup_device(struct sbull_dev *dev, int which)

{

/*

* Get some memory.

*/

memset (dev, 0, sizeof (struct sbull_dev));

dev->size = nsectors*hardsect_size;

dev->data = vmalloc(dev->size);

if (dev->data == NULL) {

printk (KERN_NOTICE "vmalloc failure./n");

return;

}

spin_lock_init(&dev->lock);

 

/*

* The timer which "invalidates" the device.

*/

init_timer(&dev->timer);

dev->timer.data = (unsigned long) dev;

dev->timer.function = sbull_invalidate;//初始化超时定时器

 

/*

* The I/O queue, depending on whether we are using our own

* make_request function or not.

*/

switch (request_mode) {

   case RM_NOQUEUE:

dev->queue = blk_alloc_queue(GFP_KERNEL);

if (dev->queue == NULL)

goto out_vfree;

blk_queue_make_request(dev->queue, sbull_make_request);

break;

 

   case RM_FULL:

dev->queue = blk_init_queue(sbull_full_request, &dev->lock);

if (dev->queue == NULL)

goto out_vfree;

break;

 

   default:

printk(KERN_NOTICE "Bad request mode %d, using simple/n", request_mode);

         /* fall into.. */

 

   case RM_SIMPLE:

dev->queue = blk_init_queue(sbull_request, &dev->lock);//向系统动态申请请求队列

if (dev->queue == NULL)                                                    //sbull_request为个人实习的请求队列处理函数

goto out_vfree;

break;

}

blk_queue_hardsect_size(dev->queue, hardsect_size);

dev->queue->queuedata = dev;

/*

* And the gendisk structure.

*/

dev->gd = alloc_disk(SBULL_MINORS);//申请块设备数据结构

if (! dev->gd) {

printk (KERN_NOTICE "alloc_disk failure/n");

goto out_vfree;

}

dev->gd->major = sbull_major;

dev->gd->first_minor = which*SBULL_MINORS;

dev->gd->fops = &sbull_ops;

dev->gd->queue = dev->queue;//将请求队列与块设备绑定

dev->gd->private_data = dev;

snprintf (dev->gd->disk_name, 32, "sbull%c", which + 'a');

set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));

add_disk(dev->gd);//最后添加到系统

return;

 

  out_vfree:

if (dev->data)

vfree(dev->data);

}

 

 

static void sbull_exit(void)

{

int i;

 

for (i = 0; i < ndevices; i++) {

struct sbull_dev *dev = Devices + i;

 

del_timer_sync(&dev->timer);

if (dev->gd) {

del_gendisk(dev->gd);

put_disk(dev->gd);

}

if (dev->queue) {

if (request_mode == RM_NOQUEUE)

blk_put_queue(dev->queue);

else

blk_cleanup_queue(dev->queue);//返回请求队列

}

if (dev->data)

vfree(dev->data);

}

unregister_blkdev(sbull_major, "sbull");//返回设备号

kfree(Devices);

}

最简单的处理请求队列模型

static void sbull_request(request_queue_t *q)

{

struct request *req;

 

while ((req = elv_next_request(q)) != NULL) {//elv_next_request获得请求队列中的下一个请求

struct sbull_dev *dev = req->rq_disk->private_data;

if (! blk_fs_request(req)) {

printk (KERN_NOTICE "Skip non-fs request/n");

end_request(req, 0);

continue;

}

    //     printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx/n",

    //     dev - Devices, rq_data_dir(req),

    //     req->sector, req->current_nr_sectors,

    //     req->flags);

    //req->sector 要传输的下一个缓冲区

    //req->current_nr_sectors 当前要传输的扇区数目

    //req->buffer 数据应当从这个缓冲区来或者去

    //rq_data_dir 可获得这个请求的数据传送方向

sbull_transfer(dev, req->sector, req->current_nr_sectors,

req->buffer, rq_data_dir(req));

end_request(req, 1);

}

}

//传输数据

static void sbull_transfer(struct sbull_dev *dev, unsigned long sector,

unsigned long nsect, char *buffer, int write)          

{

                          //此次传输的偏移量

unsigned long offset = sector*KERNEL_SECTOR_SIZE;     //req->sector 要传输的下一个扇区

unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;//nsect = req->current_nr_sectors 当前要传输的扇区数目

                       //nbytes 此次要传输的字节数目

 

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);

}

 

每一个块设备的IO请求数据都是通过bio结构体表示,每个请求包含一个或者多个块(即是struct bio 中的数组)

块设备IO请求由结构体 struct request表示,因为一个请求可能包含多个连续磁盘块,所以可能包含多个struct bio结构体。

多个struct request 再链接成 struct request_queue。request_queue再与每个磁盘的gendisk捆绑在一起。

 

struct bio{

struct bio_vec *bi_io_vec;//指向数组的首地址

unsigned short bi_idx;//数组的标号

unsigned short bi_vcnt;//总共的片段数量

.......

}

struct bio_vec{//一个数据结构代表一个缓存片段

struct page *bv_page;//被缓存的内存页

unsigned int bv_len;//数据长度

unsigned int bv_offset;//页内偏移

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值