本文结合具体代码对Linux内核中的devicemapper映射机制进行了介绍。Devicemapper是Linux2.6内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要制定实现存储资源的管理策略,当前比较流行的Linux下的逻辑卷管理器如LVM2(LinuxVolumeManager2version)、EVMS(EnterpriseVolumeManagementSystem)、dmraid(DeviceMapperRaidTool)等都是基于该机制实现的。理解该机制是进一步分析、理解这些卷管理器的实现及设计的基础。通过本文也可以进一步理解Linux系统块一级IO的设计和实现。
DeviceMapper是Linux2.6内核中支持逻辑卷管理的通用设备映射机制,它为实现用于存储资源管理的块设备驱动提供了一个高度模块化的内核架构,如图1。
图1DeviceMapper的内核体系架构在内核中它通过一个一个模块化的targetdriver插件实现对IO请求的过滤或者重新定向等工作,当前已经实现的targetdriver插件包括软raid、软加密、逻辑卷条带、多路径、镜像、快照等,图中linear、mirror、snapshot、multipath表示的就是这些targetdriver。Devicemapper进一步体现了在Linux内核设计中策略和机制分离的原则,将所有与策略相关的工作放到用户空间完成,内核中主要提供完成这些策略所需要的机制。Devicemapper用户空间相关部分主要负责配置具体的策略和控制逻辑,比如逻辑设备和哪些物理设备建立映射,怎么建立这些映射关系等等,而具体过滤和重定向IO请求的工作由内核中相关代码完成。因此整个devicemapper机制由两部分组成--内核空间的devicemapper驱动、用户空间的devicemapper库以及它提供的dmsetup工具。在下文中,我们分内核和用户空间两部分进行介绍。
内核部分
Devicemapper的内核相关代码已经作为Linux2.6内核发布版的一部分集成到内核源码中了,相关代码在内核源码的driver/md/目录中,其代码文件可以划分为实现devicemapper内核中基本架构的文件和实现具体映射工作的targetdriver插件文件两部分。文章下面的分析结果主要是基于上述源码文件得到的。
重要概念
Devicemapper在内核中作为一个块设备驱动被注册的,它包含三个重要的对象概念,mappeddevice、映射表、targetdevice。Mappeddevice是一个逻辑抽象,可以理解成为内核向外提供的逻辑设备,它通过映射表描述的映射关系和targetdevice建立映射。从Mappeddevice到一个targetdevice的映射表由一个多元组表示,该多元组由表示mappeddevice逻辑的起始地址、范围、和表示在targetdevice所在物理设备的地址偏移量以及target类型等变量组成(这些地址和偏移量都是以磁盘的扇区为单位的,即512个字节大小)。Targetdevice表示的是mappeddevice所映射的物理空间段,对mappeddevice所表示的逻辑设备来说,就是该逻辑设备映射到的一个物理设备。Devicemapper中这三个对象和targetdriver插件一起构成了一个可迭代的设备树。在该树型结构中的顶层根节点是最终作为逻辑设备向外提供的mappeddevice,叶子节点是targetdevice所表示的底层物理设备。最小的设备树由单个mappeddevice和targetdevice组成。每个targetdevice都是被mappeddevice独占的,只能被一个mappeddevice使用。一个mappeddevice可以映射到一个或者多个targetdevice上,而一个mappeddevice又可以作为它上层mappeddevice的targetdevice被使用,该层次在理论上可以在devicemapper架构下无限迭代下去。
图2Devicemapper内核中各对象的层次关系在图2中我们可以看到mappeddevice1通过映射表和a、b、c三个targetdevice建立了映射关系,而targetdevicea又是通过mappeddevice2演化过来,mappeddevice2通过映射表和targetdeviced建立映射关系。
我们进一步看一下上述三个对象在代码中的具体实现,dm.c文件定义的mapped_device结构用于表示mappeddevice,它主要包括该mappeddevice相关的锁,注册的请求队列和一些内存池以及指向它所对应映射表的指针等域。Mappeddevice对应的映射表是由dm_table.c文件中定义的dm_table结构表示的,该结构中包含一个dm_target结构数组,dm_target结构具体描述了mapped_device到它某个targetdevice的映射关系。而在dm_table结构中将这些dm_target按照B树的方式组织起来方便IO请求映射时的查找操作。Dm_target结构具体记录该结构对应targetdevice所映射的mappeddevice逻辑区域的开始地址和范围,同时还包含指向具体targetdevice相关操作的target_type结构的指针。Target_type结构主要包含了targetdevice对应的targetdriver插件的名字、定义的构建和删除该类型targetdevice的方法、该类targetdevice对应的IO请求重映射和结束IO的方法等。而表示具体的targetdevice的域是dm_target中的private域,该指针指向mappeddevice所映射的具体targetdevice对应的结构。表示targetdevice的具体结构由于不同的target类型而不同,比如最简单的线性映射target类型对应targetdevice的结构是dm-linear.c文件中定义的linear_c结构。其定义如下:
structlinear_c{
structdm_dev*dev;
sector_tstart;
};
|
该targetdevice的定义相当简单,就只包括了表示对应物理设备的dm_dev结构指针和在该物理设备中以扇区为单位的偏移地址start。上述几个数据结构关系如图3所示:
图3devicemapper中几个重要数据结构的关系内核中建立过程
在下面我们结合具体的代码简要介绍下在内核中创建一个mappeddevice的过程:
1、根据内核向用户空间提供的ioctl接口传来的参数,用dm-ioctl.c文件中的dev_create函数创建相应的mappeddevice结构。这个过程很简单,主要是向内核申请必要的内存资源,包括mappeddevice和为进行IO操作预申请的内存池,通过内核提供的blk_queue_make_request函数注册该mappeddevice对应的请求队列dm_request。并将该mappeddevice作为磁盘块设备注册到内核中。
2、调用dm_hash_insert将创建好的mappeddevice插入到devicemapper中的一个全局hash表中,该表中保存了内核中当前创建的所有mappeddevice。
3、用户空间命令通过ioctl调用table_load函数,该函数根据用户空间传来的参数构建指定mappeddevice的映射表和所映射的targetdevice。该函数先构建相应的dm_table、dm_target结构,再调用dm-table.c中的dm_table_add_target函数根据用户传入的参数初始化这些结构,并且根据参数所指定的target类型,调用相应的target类型的构建函数ctr在内存中构建targetdevice对应的结构,然后再根据所建立的dm_target结构更新dm_table中维护的B树。上述过程完毕后,再将建立好的dm_table添加到mappeddevice的全局hash表对应的hash_cell结构中。
4、最后通过ioctl调用do_resume函数建立mappeddevice和映射表之间的绑定关系,事实上该过程就是通过dm_swap_table函数将当前dm_table结构指针值赋予mapped_device相应的map域中,然后再修改mapped_device表示当前状态的域。
通过上述的4个主要步骤,devicemapper在内核中就建立一个可以提供给用户使用的mappeddevice逻辑块设备。
IO流
Devicemapper本质功能就是根据映射关系和targetdriver描述的IO处理规则,将IO请求从逻辑设备mappeddevice转发相应的targetdevice上。Devicemapper处理所有从内核中块一级IO子系统的generic_make_request和submit_bio接口[两个接口具体的描述可以查看参考文献[1]和[2],这两本书对内核中的块IO层有比较详尽的讲解。]中定向到mappeddevice的所有块读写IO请求。IO请求在devicemapper的设备树中通过请求转发从上到下地进行处理。当一个bio请求在设备树中的mappeddeivce向下层转发时,一个或者多个bio的克隆被创建并发送给下层targetdevice。然后相同的过程在设备树的每一个层次上重复,只要设备树足够大理论上这种转发过程可以无限进行下去。在设备树上某个层次中,targetdriver结束某个bio请求后,将表示结束该bio请求的事件上报给它上层的mappeddevice,该过程在各个层次上进行直到该事件最终上传到根mappeddevice的为止,然后devicemapper结束根mappeddevice上原始bio请求,结束整个IO请求过程。
Bio在devicemapper的设备树进行逐层的转发时,最终转发到一个或多个叶子target节点终止。因为一个bio请求不可以跨多个targetdevice(亦即物理空间段),因此在每一个层次上,devicemapper根据用户预先告知的mappeddevice的target映射信息克隆一个或者多个bio,将bio进行拆分后转发到对应的targetdevice上。这些克隆的bio先交给mappeddevice上对应的targetdriver上进行处理,根据targetdriver中定义的IO处理规则进行IO请求的过滤等处理,然后再提交给targetdevice完成。上述过程在dm.c文件中的dm_request函数中完成。Targetdriver可以对这些bio做如下处理:
1、将这些bio在本驱动内部排队等待以后进行处理;
2、将bio重新定向到一个或多个targetdevice上或者每个targetdevice上的不同扇区;
3、向devicemapper返回error状态。
IO请求就按照上文中描述的过程在图2中所示的设备树中逐层进行处理,直到IO请求结束。
小结
Devicemapper在内核中向外提供了一个从逻辑设备到物理设备的映射架构,只要用户在用户空间制定好映射策略,按照自己的需要编写处理具体IO请求的targetdriver插件,就可以很方便的实现一个类似LVM的逻辑卷管理器。Devicemapper以ioctl的方式向外提供接口,用户通过用户空间的devicemapper库,向devicemapper的字符设备发送ioctl命令,完成向内的通信。它还通过ioctl提供向往的事件通知机制,允许targetdriver将IO相关的某些事件传送到用户空间。
用户空间部分
Devicemapper在用户空间相对简单,主要包括devicemapper库和dmsetup工具。Devicemapper库就是对ioctl、用户空间创建删除devicemapper逻辑设备所需必要操作的封装,dmsetup是一个提供给用户直接可用的创建删除devicemapper设备的命令行工具。因为它们的功能和流程相对简单,在本文中对它们的细节就不介绍了,用户空间主要负责如下工作:
1、发现每个mappeddevice相关的targetdevice;
2、根据配置信息创建映射表;
3、将用户空间构建好的映射表传入内核,让内核构建该mappeddevice对应的dm_table结构;
4、保存当前的映射信息,以便未来重新构建。
以下我们主要通过实例来说明dmsetup的使用,同时进一步说明devicemapper这种映射机制。用户空间中最主要的工作就是构建并保存映射表,下面给出一些映射表的例子:
1)
01024linear/dev/sda204
1024512linear/dev/sdb766
1536128linear/dev/sdc0
2)02048striped264/dev/sda1024/dev/sdb0
3)04711mirrorcore264nosync2/dev/sda2048/dev/sdb1024
例子1中将逻辑设备0~1023扇区、1024~1535扇区以及1536~1663三个地址范围分别以线形映射的方式映射到/dev/sda设备第204号扇区、/dev/sdb设备第766号扇区和/dev/sdc设备的第0号扇区开始的区域。
例子2中将逻辑设备从0号扇区开始的,长度为2048个扇区的段以条带的方式映射的到/dev/sda设备的第1024号扇区以及/dev/sdb设备的第0号扇区开始的区域。同时告诉内核这个条带类型的targetdriver存在2个条带设备与逻辑设备做映射,并且条带的大小是64个扇区,使得驱动可以该值来拆分跨设备的IO请求。
例子3中将逻辑设备从0号扇区开始的,长度为4711个扇区的段以镜像的方式映射到/dev/sda设备的第2048个扇区以及/dev/sdb设备的第1024号扇区开始的区域。
映射表确定后,创建、删除逻辑设备的操作就相对简单,通过dmsetup如下命令就可以完成相应的操作。
dmsetupcreate设备名映射表文件/*根据指定的映射表创建一个逻辑设备*/
dmsetupreload设备名映射表文件/*为指定设备从磁盘中读取映射文件,重新构建映射关系*/
dmsetupremove设备名/*删除指定的逻辑设备*/
图4根据例子1中映射表在内核中建立的逻辑设备当用户空间根据映射表下达创建逻辑设备命令后,devicemapper在内核中就根据传入的参数和映射关系建立逻辑地址到物理地址的映射关系。根据映射表例子1中的映射关系建立的设备如图4所示,图中的下半部分就抽象地描绘出了按照该映射表在内核中建立的逻辑地址到物理地址的映射关系。
Devicemapper的用户空间部分对开发者要实现自己的存储管理工具来说是可选的,事实上,很多我们常见的逻辑卷管理器,比如LVM2、dmraid等工具都利用devicemapper的提供的devicemapper用户空间库,根据自己的管理需求建立独立的一套管理工具,而并没有使用它提供的dmsetup工具,甚至IBM的开源项目企业级的逻辑卷管理系统-EVMS,在实现中都没有采用devicemapper的用户空间库,完全根据内核中的ioctl定义实现了一套自己的函数库。
TargetDriver
Devicemapper提供了一个统一的架构,通过targetdriver插件的方式允许用户根据实际的需要指定自己的IO处理规则,因此targetdriver充分体现了devicemapper的灵活性。在上文中我们已经不止一次的提到过targetdriver,也描述过targetdriver的功能,在这里我们结合最简单的lineartargetdriver具体介绍targetdriver的实现。
Targetdriver主要定义对IO请求的处理规则,在devicemapper中对targetdriver的操作已定义好了统一的接口,在实现中该接口由我们上文提到的target_type结构中定义,它定义了以下targetdriver的方法:
1、构建targetdevice的方法;
2、删除targetdevice的方法;
3、Target的映射IO请求的方法;
4、Target结束IO请求的方法;
5、暂停targetdevice读写的方法;
6、恢复targetdevice读写的访问;
7、获取当前targetdevice状态的访问;
8、Target处理用户消息的方法;
用户可以根据具体需求选择性地实现上述方法,但一般最少要实现前3种方法,否则在devicemapper下不能够正常的工作。lineartargetdriver就只实现了前3种方法和方法7,它完成逻辑地址空间到物理地址空间的线性映射,可以将多个物理设备以线性连接的方式组成一个逻辑设备,就如图4中描述的那样,通过lineartargetdriver将/dev/sda、/dev/sdb、/dev/sdc的三段连续空间组成了一个大的逻辑块设备。Lineartarget的实现很简单,它的创建和删除方法主要完成申请和释放描述lineartargetdevice所用结构的内存资源;IO映射处理方法的实现更是简单,如下代码所示:
staticintlinear_map(structdm_target*ti,structbio*bio,
unionmap_info*map_context)
{
structlinear_c*lc=(structlinear_c*)ti->private;
bio->bi_bdev=lc->dev->bdev;
bio->bi_sector=lc->start+(bio->bi_sector-ti->begin);
return1;
}
|
该映射方法就是将发送给逻辑设备mappeddevice的bio请求,根据映射关系以线性的方式重新定向到lineartargetdevice所表示物理设备的相应位置,如代码所示具体实现方法就是修改bio的bi_bdev设备指针为targetdevice对应的设备指针,并根据targetdevice的起始地址和该bio请求在mappeddevice设备上的偏移值改变IO请求开始的扇区号bi_sector,从而完成IO请求的重定向。其他targetdriver的实现也都大同小异,按照devicemapper所定义的接口规范,结合自己需要的功能进行实现即可,这里就不一一介绍了,有兴趣的读者可以看内核中具体的targetdriver代码。
总结
DeviceMapper是Linux操作系统中块设备一级提供的一种主要映射机制,现在已被多数Linux下的逻辑卷管理器所采用。在该机制下,实现用户自定义的存储资源管理策略变得极其方便。理解devicemapper所提供的映射机制,也是进一步理解Linux下一些常见逻辑卷管理器实现的基础。
分享到:
相关推荐
本文结合具体代码对Linux内核中的devicemapper映射机制进行了介绍。Devicemapper是Linux2.6内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要制定实现存储资源的...
前言 在新主机首次安装 Docker Engine-Community...Device Mapper 是 Linux2.6 内核中支持逻辑卷管理的通用设备映射机制,它为实现用于存储资源管理的块设备驱动提供了一个高度模块化的内核架构。 LVM LVM(Logical Vo
最初Docker仅能在支持Aufs文件系统的Linux发行版上运行,但是由于Aufs未能加入Linux内核,为了寻求兼容性、扩展性,Docker在内部通过graphdriver机制这种可扩展的方式来实现对不同文件系统的支持。目前,Docker支持...
device-mapper-1.00.19-2.i386.rpm,这个是linux内核升级的软件包,希望对大家有用。
解压 内核升级工具.tar会出现device-mapper-1.00.19-2.i386 lvm2-2.00.25-1.01.i386 mkinitrd-4.1.18-2.i386 module-init-tools-3.2.tar这四个就是升级内核所需要的工具 不然会出错 其中内核源码可以去...
linux 内核升级需要组件,包括device-mapper-1.02.17-3.0.1.el4.i386.rpm,lvm2-2.02.39-4.i386.rpm,mkinitrd-4.1.18-2.i386.rpm,module-init-tools-3.2.tar.bz2
| |-- device-mapper-1.00.19-2.i386.rpm | |-- lvm2-2.00.25-1.01.i386.rpm | |-- mkinitrd-4.2.0.3.tar.tar | |-- module-init-tools-3.2.2.tar.bz2 | `-- modutils-2.4.5-1.src.rpm |-- 04 | |-- 内核模块参数...
Linux内核从2.4升级到2.6所需的软件包 包括:device-mapper-1.00.19-2.i386 lvm2-2.00.25-1.01.i386 mkinitrd-4.1.18-2.i386
该文件时虚拟机下linux内核升级工具,其中包括四个压缩包:module-init-tools-3.2.tar;mkinitrd-4.1.18-2.i386;lvm2-2.00.25-1.01.i386;device-mapper-1.00.19-2.i386
| |-- device-mapper-1.00.19-2.i386.rpm | |-- lvm2-2.00.25-1.01.i386.rpm | |-- mkinitrd-4.2.0.3.tar.tar | |-- module-init-tools-3.2.2.tar.bz2 | `-- modutils-2.4.5-1.src.rpm |-- 04 | |-- 内核模块参数...
| |-- device-mapper-1.00.19-2.i386.rpm | |-- lvm2-2.00.25-1.01.i386.rpm | |-- mkinitrd-4.2.0.3.tar.tar | |-- module-init-tools-3.2.2.tar.bz2 | `-- modutils-2.4.5-1.src.rpm |-- 04 | |-- 内核模块参数...
linux内核2.4->2.6需要使用到的工具集合。包括: > module-init-tools-3.2.tar.bz2 > mkinitrd-4.1.18-2.i386.rpm > lvm2-2.00.25-1.01.i386.rpm > device-mapper-1.00.19-2.i386.rpm
其中包括升级内核需要的工具软件,还有详细的安装步骤,只要按文章中的介绍的顺序安装即可成功升级内核。当然那你可以下载更高版本的内核,那安装步骤一致,只是在设计到版本号的时候把文中提到的版本号换成自己的...
linux内核升级使用,Device Mapper依赖该包。
module-init-tools-3.2.tar.gz mkinitrd-4.1.18-2.i386.rpm device-mapper-1.00.19-2.i386.rpm lvm2-2.00.25-1.01.i386.rpm 有以上四个包打包到一起方便大家下载,由于只有15M的空间有限,内核包就不打包在一起了,
module-init-tools.tar;mkinitrd-4.2.0.3.tar;lvm2.2.00.25.tar;device-mapper.1.02.08.tar
device-mapper lvm2-2.00 mkinitrd module-init-tools 升级的方法: 请看 Linux Kernel 内核升级过程详解.doc 建议: 1.一定要按照 详解.doc 的步骤升级,就万无一失了,特别是红字标注的,所以一定要...
dm-crypt系统之所以具有这些优点,主要得益于该技术是建立在2.6版本内核的device-mapper特性之上的。 device-mapper是设计用来为在实际的块设备之上添加虚拟层提供一种通用灵活的方法,以方便开发人员实现镜像、快照...