在vmem_disk驱动中,通过模块参数request_mode
的方式来支持3种不同的请求处理模式,如下为vmem_disk设备驱动的请求处理代码。
Handle an I/O request
该函数完成真正的硬件I/O操作(对于本例子而言,就是一个memcpy)
static void vmem_disk_transfer(struct vmem_disk_dev *dev,unsigned long sector,unsigned long nsect,char *buffer, int write)
{
unsigned long offset = sector *KERNEL_SECTOR_SIZE;
unsigned long nbytes = nsect *KERNEL_SECTOR_SIZE;
if((offser + nbyte) > dev->size)
{
printk(KERNEL_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);
}
}
Transfer a single BIO
vmem_disk_xfer_bio()
函数调用它来完成一个于bio对应的硬件操作。
在完成的过程中,通过bio_for_each_segment()
展开了该bio
中的每个segment
。
static int vmem_disk_xfer_bio(struct vmem_disk_dev *dev,struct bio *bio)
{
struct bio_vec bvec;
struct bvec_iter iter;
sector_t sector = bio->bi_iter.bi_sector;
bio_for_each_segment(bvec,bio,iter)
{
char *buffer = __bio_kmap_atomic(bio,iter);
vmem_disk_transfer(dev,sector,bio_cur_byte(bio) >> 9,buffer,bio,bio_data_dir(bio) == WRITE);
__bio_kunmap_atomic(buffer);
}
return 0;
}
The request_queue version
vmem_disk_request()通过blk_peek_request()先从request_queue拿出一个请求,之后调用__rq_for_each_bio()从该请求中取出一个bio,然后调用vmem_disk_xfer_bio(),来完成该I/O请求。
static void vmem_disk_request(struct request_queue *q)
{
struct request *req;
struct bio *bio;
while((req = blk_peek_request(q)) != NULL)
{
struct vmem_disk_dev *dev = req->rq_disk->private_data;
if(req->cmd_type != REQ_TYPE_FS)
{
printk(KERNEL_NOTICE "Skip non-fs request\n");
blk_start_request(req);
__blk_end_request_all(req,-EIO);
continue;
}
blk_start_request(req);
__rq_for_each_bio(bio,req);
vmem_disk_xfer_bio(dev,bio);
__blk_end_request_all(req,0);
}
}
The direct make request version
vmem_disk_make_request直接调用vmem_disk_xfer_bio来完成一个bio操作。
static void vmem_disk_make_request(struct request_queue *q,struct bio *bio)
{
struct vmem_disk_dev *dev = q->queuedata;
int status;
status = vmem_disk_xfer_bio(dev,bio);
bio_endio(bio,status);
}