<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]