sunzixun 发表于 2013-1-31 02:14:58

<linux> Device Mapper 和 Multiple Devices

 
 
 DM 和 MD 。。。 一个用于逻辑卷 一个用于软RAID 。都是虚拟的。。。
 
 
 开始我也很好奇,如果同时启用2个设备,bio 是如何分发的。 现在有了点眉目。
 
先说一下iscsi 的理解。 简单的看了一下iscsi mod。我的理解就是
 
网络过来的数据包组织成了 struct tio
 
然后经过  block_io.c 的
 
static intblockio_make_request(struct iet_volume *volume, struct tio *tio, int rw)  
处理生成bio 后 直接 submit_bio 到generic layer。
 
这里其实 iscsi mod 替代了VFS层注册了自己的方法直接去处理用户态数据
<这里可能丢失了page buffer 层,这里按照存储器山的设计是不是不合理 后面再研究>。(当然他也支持通过VFS 接口下去)
 
好了下面就来看看到了 G层 是如何处理的 : 
 
在 sched 的伟大的 task_struct 结构里面有一个这个
 
 
struct task_struct {//...struct bio_list *bio_list;//...}  
bio 结构里面有一个
bi_next :用于连接下一个bio ,把他们放到设备 request queue 中
这里把他们用 bio_list管理起来  。 首尾都快速访问。
 
 
在正常的情况下 (实际 设备)bio_alloc 被产生之后 ,就会去通过 
 
generic_make_request 进入 generic block 层 。通过一些检查 ,修改分区偏移 放入队列后 会去通过
request_queue  内的 make_request_fn(q, bio) 调用__make_request 。这个大家都知道,就不那代码解释了
 
 
现在就是  在 Multiple Devices driver 里面我们可以看到: 
 
 
 
static int md_alloc(dev_t dev, char *name){static DEFINE_MUTEX(disks_mutex);mddev_t *mddev = mddev_find(dev);struct gendisk *disk;int partitioned;int shift;int unit;int error;//...blk_queue_make_request(mddev->queue, md_make_request);/*注册函数*///...} 
所以 RAID 的bio 请求会到 md_make_request
 
 
而在  Device Mapper driver 里面,我们同样可以在初始化的地方看到
 
 
 
static struct mapped_device *alloc_dev(int minor){int r;struct mapped_device *md = kzalloc(sizeof(*md), GFP_KERNEL);void *old_md;//...dm_init_md_queue(md);//...}紧接着:
 
 
static void dm_init_md_queue(struct mapped_device *md){queue_flag_clear_unlocked(QUEUE_FLAG_STACKABLE, md->queue);md->queue->queuedata = md;md->queue->backing_dev_info.congested_fn = dm_any_congested;md->queue->backing_dev_info.congested_data = md;blk_queue_make_request(md->queue, dm_request);blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);//...} 所以LVM 的bio 请求会到 dm_request
 
 
对于一个 bio 普通的内核处理路线 就直接把它放入整合进一个request 然后传给对应设备的request queue,设备在软中断或者调度的时候处理这个队列。
 
但是对于我们上面说的虚拟设备 最好直接通过一个请求调用传递给虚拟设备 这样可以让他们立刻服务。
而让bio 知道自己要被谁服务的方法就是我们上面2个地方都看到的  
 
 blk_queue_make_request(struct request_queue *q, make_request_fn *mfn) 
 
函数。
 
 
void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn){/*请求队列的最多安置请求数 (128)*/q->nr_requests = BLKDEV_MAX_RQ;       /*这里就是bio 处理函数啦,generic_make_request调用的*/q->make_request_fn = mfn;blk_queue_dma_alignment(q, 511);/*和普通的设备一样对于direct的IO 也通过DMA直接处理,这里设置了对齐掩码*/       /*设置了 请求拥塞开关上下限 113-111*/blk_queue_congestion_threshold(q);      /*队列已满 仍可以作为一次提交的请求数*/q->nr_batching = BLK_BATCH_REQ;       /*都是经典的默认值利用插拔来提高合并率(我叫他逼尿法)*/q->unplug_thresh = 4;/* hmm */q->unplug_delay = msecs_to_jiffies(3);/* 3 milliseconds */if (q->unplug_delay == 0)q->unplug_delay = 1;       /*【kblockd】 线程处理*/q->unplug_timer.function = blk_unplug_timeout;q->unplug_timer.data = (unsigned long)q;         /*设置虚拟设备队列的相关限制*/blk_set_default_limits(&q->limits);/*请求队列里面能处理的最多量*/blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);/* * If the caller didn't supply a lock, fall back to our embedded * per-queue locks */if (!q->queue_lock)q->queue_lock = &q->__queue_lock;/*对于处在ZONE_HIGH的内存需要分配的mpool也设置限制 */blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);} 
 
因为没有提供proc 接口 这里看到如果你想修改一些限制,主要就是
 
<div class="quote_title"> 写道
页: [1]
查看完整版本: <linux> Device Mapper 和 Multiple Devices