一、linear源码分析

1.核心数据结构:struct linear_c

struct linear_c{                                                      
	struct dm_dev *dev;    //对应物理设备的dm_dev结构指针            
	sector_t start;       //在该物理设备中以扇区为单位的偏移地址start 
} 

2.核心函数:linear_map

static sector_t linear_map_sector(struct dm_tatget *ti, sector_t bi_sector)                                                            
{                                                                     
	//偏移值计算函数                                                  
	struct linear_c *lc = ti ->private;                               
	                                                                  
	return lc ->start + dm_target_offset(ti, bi_sector);              
/*  根据target device的起始地址和该bio请求在mapped device设备上的偏移值改变IO请求开始的扇区号bi_sector,从而完成IO请求的重定向      
	*/                                                                
                                                                      
}                                                                     
                                                                      
static void linear_map_bio(struct dm_target *ti, struct bio *bio)     
{                                                                     
	/* 指针重定向函数                                                  
	该映射方法就是将发送给逻辑设备mapped device的bio请求,根据映  射关系以线性的方式重新定向到linear target device所表示物理设备的相应位置                                                                    
    */                                                                
	struct linear_c *lc = ti ->private;                               
	                                                                   
	bio_set_dev(bio,lc->dev->bdev);                                   
	//修改bio的bi_bdev设备指针为target device对应的设备指针        
                                                                      
	if (bio_sector(bio) || op_is_zone_mgmt(bio_op(bio)))              
		bio->bi_iter.bi_sector =                                       
			linear_map_sector(ti, bio->bi_iter.bi_sector); //计算偏移值
}                                                                     
                                                                      
static int linear_map(struct dm_target *ti, struct bio *bio)          
{                                                                     
	//linear_map为核心函数                                            
linear_map_bio(ti, bio);      //指针重定向函数                        
	                                                                   
	return DM_MAPIO_REMAPPED;                                         
}   

二、linear图表解释
本部分介绍Device mapper的线性映射关系。
Target device 表示的是 mapped device 所映射的物理空间段,对 mapped device 所表示的逻辑设备来说,就是该逻辑设备映射到的一个物理设备。Device mapper 中这三个对象和 target driver 插件一起构成了一个可迭代的设备树。在该树型结构中的顶层根节点是最终作为逻辑设备向外提供的 mapped device,叶子节点是target device所表示的底层物理设备。最小的设备树由单个 mapped device和target device组成。每个target device都是mapped device独占的,只能被一个mapped device使用。一个mapped device可以映射到一个或者多个target device上,而一个mapped device又可以作为它上层 mapped device的target device被使用,该层次在理论上可以在 device mapper 架构下无限迭代下去。
在这里插入图片描述

在上图中我们可以看到mapped device 1通过映射表和 a、b、c 三个 target device 建立了映射关系,而 target device a 又是通过 mapped device 2 演化过来,mapped device 2 通过映射表和 target device d 建立映射关系。

三、linear举例说明
用户空间中最主要的工作就是构建并保存映射表,下面给出linear映射表的例子:

0    512   linear /dev/sda 1101                                      
512  1024  linear /dev/sdb 888                                       
1536 128   linear /dev/sdc 0    

本例子中将逻辑设备0-511扇区、512-1535扇区以及1536-1663三个地址范围分别以线形映射的方式映射到/dev/sda设备第1101号扇区、/dev/sdb设备第888号扇区和/dev/sdc设备的第0号扇区开始的区域。

在这里插入图片描述
在这里插入图片描述
映射表确定后,创建、删除逻辑设备的操作就相对简单,通过dmsetup如下命令就可以完成相应的操作。

dmsetup create 设备名 映射表文件    /* 根据指定的映射表创建一个逻辑设备 */                                                                 
                                                                      
dmsetup reload  设备名 映射表文件 /*  为指定设备从磁盘中读取映射文件,重新构建映射关系    */                                                
                                                                      
dmsetup remove  设备名 /* 删除指定的逻辑设备 */    

四、stripe源码分析
1.核心数据结构:struct stripe_c

struct stripe.c{
	uint32_t stripes;
	int stripes_shift;

	//条带数组大小
	sector_t stripe_width;
	
	uint32_t chunk_size;
	int chunk_size_shift;

	//处理事件所需
	struct dm_target *ti;

	//用于触发事件的工作结构
	struct work_struct trigger_event;

	struct stripe stripe[];  //条带数组
};

2.核心函数:stripe_map

static int stripe_map(struct dm_target *ti,struct bio *bio)

  	{
		//创建了自定义的struct stripe_c结构sc,并记录在ti->private上
struct stripe_c *sc = ti->private;
		uint32_t stripe;
		unsigned target_bio_nr;
	//如果bio是REQ_PREFLUSH或bi_opf,只需绕过stripes

		if (bio->bi_opf & REQ_PREFLUSH) {
			target_bio_nr = dm_bio_get_target_bio_nr(bio);
			BUG_ON(target_bio_nr >= sc->stripes);
          //设置bio参数
			bio_set_dev(bio, sc->stripe[target_bio_nr].dev->bdev);
			return DM_MAPIO_REMAPPED;
		}
		if (unlikely(bio_op(bio) == REQ_OP_DISCARD) ||
		    unlikely(bio_op(bio) == REQ_OP_SECURE_ERASE) ||
		    unlikely(bio_op(bio) == REQ_OP_WRITE_ZEROES)) {
			target_bio_nr = dm_bio_get_target_bio_nr(bio);
			BUG_ON(target_bio_nr >= sc->stripes);
			return stripe_map_range(sc, bio, target_bio_nr);
		}
	  //计算条带偏移值函数

		stripe_map_sector(sc, bio->bi_iter.bi_sector,
				  &stripe, &bio->bi_iter.bi_sector);
	//计算偏移值

		bio->bi_iter.bi_sector += sc->stripe[stripe].physical_start;
    //设置bio参数
		bio_set_dev(bio, sc->stripe[stripe].dev->bdev);
	

		return DM_MAPIO_REMAPPED;
	}

Stripe_map_sector函数

Static void stripe_map_sector(struct stripe_c *sc, sector_t sector, unit32_t *stripe, sector_t *result)

				      uint32_t *stripe, sector_t *result)
	{
		sector_t chunk = dm_target_offset(sc->ti, sector);
		sector_t chunk_offset; //偏移量
	

		if (sc->chunk_size_shift < 0) //增量小于零
     //直接赋值
			chunk_offset = sector_div(chunk, sc->chunk_size);
		else {
        //否则偏移量增加一个块长度
			chunk_offset = chunk & (sc->chunk_size - 1);
			chunk >>= sc->chunk_size_shift;  //右移位
		}
	

		if (sc->stripes_shift < 0) //条带偏移值小于零
      //直接赋值
			*stripe = sector_div(chunk, sc->stripes);
		else {
     //否则偏移量增加一个条带长度
			*stripe = chunk & (sc->stripes - 1);
			chunk >>= sc->stripes_shift;
		}
	

		if (sc->chunk_size_shift < 0)
			chunk *= sc->chunk_size;    //p偏移量赋值
		else
			chunk <<= sc->chunk_size_shift; //移位
	

		*result = chunk + chunk_offset;  //计算最终偏移量结果
	}

五、stripe举例说明

0   2048    striped 2   64  /dev/sda    1024    /dev/sdb    0

该例子中将逻辑设备从0号扇区开始的,长度为2048个扇区的段以条带的方式映射的到/dev/sda设备的第1024号扇区以及/dev/sdb设备的第0号扇区开始的区域。同时告诉内核这个条带类型的target driver存在2个条带设备与逻辑设备做映射,并且条带的大小是64个扇区,使得驱动可以该值来拆分跨设备的IO请求。

六、stripe图表解释
这里给出stripe映射的图解。
在这里插入图片描述

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐