`
sunzixun
  • 浏览: 75982 次
  • 性别: 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,
};

 

 

 

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

 

分享到:
评论

相关推荐

    List转Json

    return mapper.readValue(jsonString, new TypeReference&lt;List&lt;Object&gt;&gt;(){}); } catch (Exception e) { e.printStackTrace(); } return null; } ``` 7. **注意事项**: - 对象中的字段需要有对应的getter...

    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

    在Java开发中,数据对象(通常称为Bean)之间的转换是一个常见的任务。...通过深入阅读给出的博文链接,开发者可以进一步掌握如何在实际项目中利用BeanMapper优化代码,提高代码的可维护性和可读性。

    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;

    Linux系统内核中的DeviceMapper机制

    本文结合具体代码对Linux内核中的devicemapper映射机制进行了介绍。Devicemapper是Linux2.6内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要制定实现存储资源的...

    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通用mapper笔记

    &lt;artifactId&gt;mapper&lt;/artifactId&gt; &lt;version&gt;4.0.3&lt;/version&gt; &lt;/dependency&gt; &lt;!-- MySQL驱动 --&gt; &lt;dependency&gt; &lt;groupId&gt;mysql&lt;/groupId&gt; &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;version&gt;8.0.12&lt;/...

    eclipse的maven项目中,通过mybatisgenerator工具自动生成实体类和Mapper

    &lt;javaClientGenerator type="XMLMAPPER" targetPackage="com.example.mapper" targetProject="src/main/java"&gt; &lt;property name="enableSubPackages" value="true"/&gt; &lt;/javaClientGenerator&gt; &lt;!-- 表配置 --&gt; ...

    搭建Mybatis框架环境.pdf

    &lt;/mapper&gt; ``` namespace是Mapper接口的全限定名,id对应Mapper接口中的方法名。 四、mybatis-config.xml配置文件 mybatis-config.xml是Mybatis的全局配置文件,包含数据库连接、事务管理、插件等配置。基础配置...

    spring-boot-mybatis-mapper包含SpringBoot集成mybatis自动分页

    PageInfo&lt;User&gt; pageInfo = new PageInfo&lt;&gt;(users); return pageInfo; } } ``` 在Controller中,你可以将分页信息传递给前端: ```java @RestController @RequestMapping("/users") public class ...

    mybatis自动生成Dao、Mapper和Domain工具

    MyBatis Generator(MBG)是MyBatis的一个配套工具,用于自动生成MyBatis的DAO、Mapper和Domain(实体类)文件,极大地提高了开发效率,减少了手动编写这些基础代码的工作量。 MyBatis Generator通过XML配置文件...

    Spring boot集成Mybatis通用mapper

    &lt;artifactId&gt;mapper-spring-boot-starter&lt;/artifactId&gt; &lt;version&gt;3.4.6&lt;/version&gt; &lt;/dependency&gt; &lt;/dependencies&gt; ``` 接下来,我们需要配置数据库连接。在`application.properties`文件中设置MySQL的相关属性:...

    Spring+Mybatis+BoneCP配置实例

    &lt;bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"&gt; &lt;property name="basePackage" value="com.example.mapper"/&gt; &lt;property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/&gt; &lt;/...

    springboot专栏 006 springboot整合mybatis-plus 增删改查 ModelAndView jsp

    &lt;/mapper&gt; ``` 然后,我们需要一个Service来处理业务逻辑,如`UserService.java`: ```java @Service public class UserService { @Autowired private UserMapper userMapper; public User getUserById(Long ...

    mybatis-3-mapper.dtd

    例如,它定义了`&lt;select&gt;`, `&lt;insert&gt;`, `&lt;update&gt;`, `&lt;delete&gt;`等元素,这些都是在执行SQL查询和更新时常用的操作。这些元素通常包含SQL语句,并且可以有参数绑定、结果映射等高级特性。 在编写mapper.xml文件时,...

    Java EE企业级应用开发教程(SSM)(第2版) 课后习题及答案

    * MyBatis 映射文件中的常用元素包括:&lt;mapper&gt;、&lt;cache&gt;、&lt;cache-ref&gt;、&lt;resultMap&gt;、&lt;sql&gt;、&lt;insert&gt;、&lt;delete&gt;、&lt;update&gt; 和 &lt;select&gt; 等。 * &lt;mapper&gt; 元素是映射文件的根元素,具有 namespace 属性,用于区分...

    基于Maven搭建Spring+Mybatis项目的简单示例

    &lt;bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"&gt; &lt;property name="basePackage" value="com.yourcompany.petstore.mapper"/&gt; &lt;property name="sqlSessionFactoryBeanName" value=...

    mybatis/ibatis自动生成SQLMapper脚本

    &lt;configurationFile&gt;src/main/resources/generatorConfig.xml&lt;/configurationFile&gt; &lt;overwrite&gt;true&lt;/overwrite&gt; &lt;verbose&gt;true&lt;/verbose&gt; &lt;/configuration&gt; &lt;/plugin&gt; &lt;/plugins&gt; &lt;/build&gt; ``` 6. **生成...

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

    springboot_demo-1.rar

    &lt;/mapper&gt; ``` 最后,在Spring Boot的启动类中,可以使用`@Autowired`注解注入Mapper接口,并进行数据库操作: ```java @SpringBootApplication public class Application { @Autowired private UserMapper ...

Global site tag (gtag.js) - Google Analytics