`
sunzixun
  • 浏览: 74788 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

<linux> Device Mapper 和 Multiple Devices

阅读更多

 

 

 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->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 接口 这里看到如果你想修改一些限制,主要就是

 

 写道
enum blk_default_limits{}

blk_set_default_limits()
 

 

 

都知道 dm 有对应的设备树 ,层层转发

 

 

我们知道

 

 

dm_request(struct request_queue *q, struct bio *bio) -> _split_and_process_bio(md, bio)-> __clone_and_map(&ci); 

->__map_bio(ti, clone, tio);  

 

 

交给对于策略的 dm_type 处理map(ti, clone, &tio->info);

 

后就会根据 DM_MAPIO_REMAPPED 标志 ,继续 generic_make_request(clone);

 

代码如下: 

 

 

 

static void __map_bio(struct dm_target *ti, struct bio *clone,
		      struct dm_target_io *tio)
{
	int r;
	sector_t sector;
	struct mapped_device *md;

	clone->bi_end_io = clone_endio;
	clone->bi_private = tio;


	atomic_inc(&tio->io->io_count);
	sector = clone->bi_sector;
       /*如果是liner策略就是:linear_map*/
	r = ti->type->map(ti, clone, &tio->info);
     
	if (r == DM_MAPIO_REMAPPED) {
	 /* the bio has been remapped so dispatch it 这里又去调用
         * */
       
		generic_make_request(clone);
	} else if (r < 0 || r == DM_MAPIO_REQUEUE) {
		/* error the io and bail out, or requeue it if needed */
		md = tio->io->md;
		dec_pending(tio->io, r);
		clone->bi_private = md->bs;
		bio_put(clone);
		free_tio(md, tio);
	} else if (r) {
		//...
	}
}
 

 

 

 

回来看一下 

 

我们希望一次执行只调用 一个 q->make_request_fn  ,

但是对于基于栈的设备 就用 current->bio_list来维护 反复make_request_fn 提交的请求

 

同样 current->bio_list 也作为一个标志来表明是否 generic_make_request  当前激活。

 

如果 bio_list == null 说明没有激活 generic_make_request , 所以新的请求需要加入到bio_list队尾

 

 

下面的函数是一个明显的递归 ,一起来看看

 

 

void generic_make_request(struct bio *bio)/*szx:__make_request*/
{
	struct bio_list bio_list_on_stack;
       /*第一次先不会进入:如果进入了这个时候gen_m_r 已经激活了, 
         *不断的把bio_list 里面放入要处理的bio 直到不需要remap 这次递归结束不会进gen_m_r了 */
	if (current->bio_list) {
		/* make_request is active */
		bio_list_add(current->bio_list, bio);
		return;
	}
        /*调用者要保证 bio->bi_next 为空*/
	BUG_ON(bio->bi_next);
	bio_list_init(&bio_list_on_stack);
	current->bio_list = &bio_list_on_stack;static int raid_map(struct dm_target *ti, struct bio *bio, union map_info *map_context)
{
	struct raid_set *rs = ti->private;
	mddev_t *mddev = &rs->md;

	mddev->pers->make_request(mddev, bio);

	return DM_MAPIO_SUBMITTED;
}
  do { /*第一次会从这里进入开始dm_requst这样的fn*/ __generic_make_request(bio); /*如果是从这个调用返回了,说明current->bio_list 里面有料了, *就开始用真正需要的下层block device 处理*/ bio = bio_list_pop(current->bio_list); } while (bio); current->bio_list = NULL; /* deactivate 去激活gn_m_r*/ }

  我不知道到这里 你明白没有。。

 

 

 

对于raid 策略的 target_device 。dm_request --->....->

 

 到了dm_raid.c对应的 target_driver 之后就会调用事先注册的_map_io 

 

 

 

 

 

 

static int raid_map(struct dm_target *ti, struct bio *bio, union map_info *map_context)
{
	struct raid_set *rs = ti->private;
	mddev_t *mddev = &rs->md;
/*这里就会去调用对应的  raid 级别(策略)*/
	mddev->pers->make_request(mddev, bio);

	return DM_MAPIO_SUBMITTED;
}
 

 

然后就会调用自己管理的所有 raid_type 的make_request 方法。

 

static struct mdk_personality raid1_personality =
{
	.name		= "raid1", 
	.level		= 1,
	.owner		= THIS_MODULE,
	.make_request	= make_request,
	.run		= run,
	.stop		= stop,
	.status		= status,
	.error_handler	= error,
	.hot_add_disk	= raid1_add_disk,
	.hot_remove_disk= raid1_remove_disk,
	.spare_active	= raid1_spare_active,
	.sync_request	= sync_request,
	.resize		= raid1_resize,
	.size		= raid1_size,
	.check_reshape	= raid1_reshape,
	.quiesce	= raid1_quiesce,
	.takeover	= raid1_takeover,
};

 

 

 

然后就会回到 上面的递归流程。

 

分享到:
评论

相关推荐

    mapper-4.1.5.jar

    tk.mabatis的jar包 4.1.5版本。可参考以下方式使用 &lt;properties&gt; &lt;tk-mapper.version&gt;4.1.5&lt;/... &lt;artifactId&gt;mapper&lt;/artifactId&gt; &lt;version&gt;${tk-mapper.version}&lt;/version&gt; &lt;/dependency&gt; &lt;/dependencies&gt;

    深度转换Bean<->Bean的Mapper

    NULL 博文链接:https://vernonchen163.iteye.com/blog/1879387

    Maven项目逆向生成工具 自动生成数据库表的pojo对象以及mapper文件 可以免费下载无需付费

    需要在项目pom文件的插件节点里面加上逆向生成插件 将配置文件... &lt;configurationFile&gt;GeneratorMapper.xml&lt;/configurationFile&gt; &lt;verbose&gt;true&lt;/verbose&gt; &lt;overwrite&gt;true&lt;/overwrite&gt; &lt;/configuration&gt; &lt;/plugin&gt;

    SpringMVC中json转换所需要的Maven仓库的jar包

    &lt;artifactId&gt;jackson-mapper-asl&lt;/artifactId&gt; &lt;version&gt;1.9.13&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt; &lt;artifactId&gt;jackson-annotations&lt;/artifactId&gt; ...

    Mybatis Generator配置详解.md

    &lt;sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"&gt; &lt;property name="enableSubPackages" value="true"/&gt; &lt;/sqlMapGenerator&gt; &lt;!-- 生成DAO的包名和位置--&gt; ...

    计算机端口监控

    Fport can be&lt;br&gt;used to quickly identify unknown open ports and their associated applications.&lt;br&gt;&lt;br&gt;Usage: &lt;br&gt;C:\&gt;fport&lt;br&gt;FPort v2.0 - TCP/IP Process to Port Mapper&lt;br&gt;Copyright 2000 by ...

    自己整理的Mybatis必须掌握的知识。从原生方式的使用再到常用的Mapper文件的使用解析,共48页

    一、 概述 1.1 简介 1.2 传统JDBC存在的问题 1.3 框架的好处 1.4 历史 二、 配置文件 2.1 核心配置文件 ...9.1 &lt;mapper&gt;根标签 9.2 &lt;resultMap&gt; 9.3 &lt;insert&gt; 9.4 &lt;sql&gt; 十、动态SQL 十一、逆向工程 十二、关联查询

    基于SpringBoot的图书馆管理系统项目源码+数据库+项目说明(课程设计).zip

    | mapper:数据库SQL语句mapper文件&lt;br&gt; &emsp;&emsp;| static:静态文件&lt;br&gt; &emsp;&emsp;&emsp;&emsp;| css:css文件&lt;br&gt; &emsp;&emsp;&emsp;&emsp;| js:JavaScript文件&lt;br&gt; &emsp;&emsp;&emsp;&emsp;| images:...

    基于SpringBoot的图书馆管理系统源码+数据库+项目说明(毕设).zip

    | mapper:数据库SQL语句mapper文件&lt;br&gt; &emsp;&emsp;| static:静态文件&lt;br&gt; &emsp;&emsp;&emsp;&emsp;| css:css文件&lt;br&gt; &emsp;&emsp;&emsp;&emsp;| js:JavaScript文件&lt;br&gt; &emsp;&emsp;&emsp;&emsp;| images:...

    Fport

    在命令行下使用,请看例子: &lt;br&gt;&lt;br&gt;C:\&gt;fport&lt;br&gt;FPort v2.0 - TCP/IP Process to Port Mapper&lt;br&gt;Copyright 2000 by Foundstone, Inc.&lt;br&gt;http://www.foundstone.com&lt;br&gt;&lt;br&gt;Pid Process Port Proto Path&lt;br&gt;1296...

    TKmapper配置文件

    &lt;dependency&gt; &lt;groupId&gt;tk.mybatis&lt;/groupId&gt; &lt;artifactId&gt;mapper&lt;/artifactId&gt; &lt;version&gt;4.1.5&lt;/version&gt; &lt;/dependency&gt;

    atlas-project.rar

    &lt;artifactId&gt;mapper&lt;/artifactId&gt; &lt;version&gt;3.4.0&lt;/version&gt; &lt;/dependency&gt; 用了这个通用Mapper后,很多基础的方法,如:selectByPrimaryKey()等等,都不用写了,也不用自动生成了,等于自带了这些方法; 还用...

    SSM框架的学习与应用-Java EE企业级应用开发学习记录(第三天)Mybatis的深入学习(动态sql的操作)

    介绍了动态SQL常用元素:&lt;if&gt;、&lt;choose&gt;、&lt;where&gt;、&lt;trim&gt;、&lt;set&gt;、&lt;foreach&gt;等。 通过&lt;if&gt;元素示例演示了根据输入参数动态构建查询条件。 通过&lt;choose&gt;元素示例演示了多条件选择动态查询。 通过&lt;where&gt;、&lt;trim&gt;元素...

    MapInfo Professional用户指南(精简版)

    &lt;br&gt;在 Web 地图服务客户端中包含的众多新特性之中,集成了 Vertical Mapper 这一新的 3D 图像制图引&lt;br&gt;擎,并对 Universal Translator 作出了重要改进。第8 页“MapInfo Professional 7.5 新增特性” 提供&lt;br&gt;了...

    MyBatisTest

    这是个完整的例子 呵呵 看看适合你不 &lt;?xml version="1.0" encoding="UTF-8" ?&gt; &lt;!DOCTYPE configuration PUBLIC "-/... &lt;mapper resource="com/sdzn/mybatis/mapper/UserMapper.xml" /&gt; &lt;/mappers&gt; &lt;/configuration&gt;

    jsoup jar包

    b.&lt;decorator:title/&gt;这个标签会找到被装饰页面的title(&lt;title&gt;&lt;/title&gt;标签内)内容填入, &lt;decorator:head/&gt;找到被装饰页面的head(&lt;head&gt;&lt;/head&gt;标签内)内容填入,&lt;decorator:body/&gt;找到被装饰页面的body(&lt;body&gt;&lt;/...

    FieldMapper:一个将地图列表转换为对象列表的库

    FieldMapper和ResultMap 一个将映射List&lt;Map&gt;&gt;转换为对象列表的库。 它可以与数据库访问库一起使用... &lt;id&gt;FieldMapper Repo&lt;/id&gt; &lt;url&gt;https://raw.github.com/rizvn/FieldMapper/mvn-repo/&lt;/url&gt; &lt;/repository

    MybatisPageHelper分页插件

    &lt;value&gt;classpath:mapper/*.xml&lt;/value&gt; &lt;/array&gt; &lt;/property&gt; --&gt; &lt;property name="typeAliasesPackage" value="org.jd.domain" /&gt; &lt;property name="plugins"&gt; &lt;array&gt; &lt;bean class=...

    Linux device-mapper-udev-CRS-ASM_v3.6.pdf

    Linux device-mapper-udev-CRS-ASM

    MyBatis SonarQube Plugin自定义规则用于检查 MyBatis Mapper 文件中的风险 SQL.zip

    在XML文件中,&lt;if&gt;标签通常被嵌套在其他标签内,如&lt;select&gt;、&lt;insert&gt;和&lt;update&gt;等标签内,用于控制生成的SQL语句的结构和内容。 &lt;if&gt;标签通常包含一个test属性,该属性被用于指定条件表达式。如果表达式的结果为...

Global site tag (gtag.js) - Google Analytics