日期:2014-05-16 浏览次数:20726 次
?
?
?DM 和 MD 。。。 一个用于逻辑卷 一个用于软RAID 。都是虚拟的。。。
?
?
?开始我也很好奇,如果同时启用2个设备,bio 是如何分发的。 现在有了点眉目。
?
先说一下iscsi 的理解。 简单的看了一下iscsi mod。我的理解就是
?
网络过来的数据包组织成了 struct tio
?
然后经过 ?block_io.c 的
?
static int blockio_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->li