[ 摘自yuanbor的博客 ] bio的转发

任何一个bio(块设备的io请求)都要映射到最终存储它的设备上的相应位置,Device Mappermap函数就要完成这一功能。该函数的原型如下:

int xxx_map(struct dm_target *ti, struct bio *bio, union map_info *map_context);

ti代表targetbio是发给这个targetio请求。一个bio有三个关键成员:bi_sector(位置)、bi_bdev(设备)、bi_io_vec(数据)。DM框架将bio发给map函数,使得target有机会来改变bio的这三个关键成员,从而实现两个目的:重定位和修改数据。map_context在许多情况下并没有许多作用。

如果map函数将bio赋值后又分发出去,那么就返回DM_MAPIO_SUBMITTED告诉DM不要再处理了;如果map函数修改了bio的内容,希望DMbio按照新内容再分发,那么就返回DM_MAPIO_REMAPPED即可;如果map函数将bio加入队列中等待后续处理,则返回DM_MAPIO_REQUEUEDM相应的处理代码可以在dm.c中的__map_bio()函数中找到。

stripe_map就很简单了,直接修改biobi_sectorbi_bdev,返回DM_MAPIO_REMAPPED通知DM再分发一次即可。stripe所扮演的角色就好比是一个邮件中转站,下辖N个子邮箱。所有邮件都按照规则被转发到对应子邮箱中,中转站的工作就是把每个邮件的地址和收件人改一改再让邮递员送一遍即可,接下来的bio传递路径分析将详细展示这一中转过程。


DM转发bio的过程

DM为每一个driver的实例创建一个md作为对外的接口,每一个md在内核中注册成为一个块设备,因此每一个driver的实例就是一个虚拟的块设备。

每一个md通过driver的实例管理一个或多个targetdriver的主要工作就是把每个提交给mdbio请求进行数据转换并转发给对应的targetmd实现了一个标准的块设备驱动,这里仅分析bio的转发过程。

每个块设备都有一个请求队列,请求队列包含一个make_request_fn指针指向原型为int make_request(struct request_queue *q, struct bio *bio);的函数,Linux内核中的void generic_make_request(struct bio *bio);函数就是通过bio找到对应的bi_bdev,然后找到该bdev对应的request_queue,并调用其make_request_fn函数:

block/blk_core.c 1484行:ret = q->make_request_fn(q, bio);

这就是bio从内核进入DM的起点。为什么这么说?因为在md创建的时候(通过dm.calloc_dev())将md->queuemake_request_fn指针设置为了dm_request

drivers/md/dm.c 1908行:blk_queue_make_request(md->queue, dm_request);

dm_request接收到bio之后有两种选择:如果q->queue_flags被设置了QUEUE_FLAG_STACKABLE,则对request进行排队处理,否则直接分发。alloc_dev中创建queue的时候按照QUEUE_FLAG_DEFAULT创建,包含了QUEUE_FLAG_STACKABLE,但是接着该标志被清除了:

drivers/md/dm.c 1889行:md->queue = blk_init_queue(dm_request_fn, NULL);

...

drivers/md/dm.c 1903行:queue_flag_clear_unlocked(QUEUE_FLAG_STACKABLE, md->queue);

因此dm_request()函数将走_dm_request()分支。以下是bio所走过的流程:

int dm_request(struct request_queue *q, struct bio *bio)

`-> _dm_request(q, bio);

`-> __split_and_process_bio(md, bio); // md 由 q->queue_data 获得

`-> __clone_and_map(&ci);  // mdbio等信息记录在 ci 结构体中

`-> __map_bio(ti, clone, tio);  // ti 由 ci->md 查表获得,cloneci->bio克隆获得

`-> ti->type->map(ti, clone, &tio->info);

最终,bio传递给了对应timap函数。

要说明的是,DM构架及其驱动一般不会是真实设备的驱动,因此只会对bio进行处理之后再转发出去。转发的方法就是修改bio->bi_bdevbio->bi_sector。其中bi_bdev必需是在内核中已注册的设备,这些块设备和dm的块设备一道在Linux内核中注册,在Linux看来是平等的。而一个md其实是将其他块设备的bdev记录在自己的映射表中,按照自身的逻辑规律对bio进行映射转发而已。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值