一文读懂Linux内核中的Device mapper映射机制

一、 简介 

        本文总结Device mapper的映射机制。Device mapper是Linux2.6内核中提供的一种逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要指定实现存储资源的管理策略,当前比较流行的Linux的逻辑卷管理器比如:LVM2(Linux Volume Manager 2 version)、EVMS(Enterprise Volume Manager System)、dmraid(Device Mapper Raid Tool)等都是基于该机制实现的。理解该机制是进一步分析、理解这些卷管理器的实现及设计的基础。

        Device mapper 是 Linux2.6 内核中支持逻辑卷管理的通用设备映射机制,它为实现用于存储资源管理的块设备驱动提供了一个高度模块化的内核架构,如图 1:

        在内核中它通过一个一个模块化的 target driver 插件实现对 IO 请求的过滤或者重新定向等工作,当前已经实现的 target driver 插件包括软 raid、软加密、逻辑卷条带、多路径、镜像、快照等,图中 linear、mirror、snapshot、multipath 表示的就是这些 target driver。Device mapper 进一步体现了在 Linux 内核设计中策略和机制分离的原则,将所有与策略相关的工作放到用户空间完成,内核中主要提供完成这些策略所需要的机制。Device mapper 用户空间相关部分主要负责配置具体的策略和控制逻辑,比如逻辑设备和哪些物理设备建立映射,怎么建立这些映射关系等等,而具体过滤和重定向 IO 请求的工作由内核中相关代码完成。因此整个 Device mapper 机制由两部分组成--内核空间的 Device mapper 驱动、用户空间的Device mapper 库以及它提供的 dmsetup 工具。在下文中,我们分内核和用户空间两部分进行介绍 。

二、内核部分

        Device mapper 的内核相关代码已经作为 Linux 2.6 内核发布版的一部分集成到内核源码中了,相关代码在内核源码的 driver/md/ 目录中,其代码文件可以划分为实现 Device mapper 内核中基本架构的文件和实现具体映射工作的 target driver 插件文件两部分。文章下面的分析结果主要是基于上述源码文件得到的。

重要概念:

        Device mapper 在内核中作为一个块设备驱动被注册的,它包含三个重要的对象概念,mapped device、映射表、target device。Mapped device 是一个逻辑抽象,可以理解成为内核向外提供的逻辑设备,它通过映射表描述的映射关系和 target device 建立映射。从 Mapped device 到一个 target device 的映射表由一个多元组表示,该多元组由表示 mapped device 逻辑的起始地址、范围、和表示在 target device 所在物理设备的地址偏移量以及target 类型等变量组成(这些地址和偏移量都是以磁盘的扇区为单位的,即 512 个字节大小)。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 架构下无限迭代下去,如图2:

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

        我们进一步看一下上述三个对象在代码中的具体实现,dm.c 文件定义的 mapped_device 结构用于表示 mapped device,它主要包括该 mapped device 相关的锁,注册的请求队列和一些内存池以及指向它所对应映射表的指针等域。Mapped device 对应的映射表是由 dm_table.c 文件中定义的 dm_table 结构表示的,该结构中包含一个 dm_target结构数组,dm_target 结构具体描述了 mapped_device 到它某个 target device 的映射关系。而在 dm_table 结构中将这些 dm_target 按照 B 树的方式组织起来方便 IO 请求映射时的查找操作。Dm_target 结构具体记录该结构对应 target device 所映射的 mapped device 逻辑区域的开始地址和范围,同时还包含指向具体 target device 相关操作的 target_type 结构的指针。Target_type 结构主要包含了 target device 对应的 target driver 插件的名字、定义的构建和删除该类型target device的方法、该类target device对应的IO请求重映射和结束IO的方法等。而表示具体的target device的域是dm_target中的private域,该指针指向mapped device所映射的具体target device对应的结构。表示target device的具体结构由于不同的target 类型而不同,比如最简单的线性映射target类型对应target device的结构是dm-linear.c文件中定义的linear_c结构。其定义如下:

struct linear_c {
	struct dm_dev *dev;
	sector_t start;
};

         该target device的定义相当简单,就只包括了表示对应物理设备的dm_dev结构指针和在该物理设备中以扇区为单位的偏移地址start。上述几个数据结构关系如图3所示:

 内核中建立过程:

1、 根据内核向用户空间提供的ioctl 接口传来的参数,用dm-ioctl.c文件中的dev_create函数创建相应的mapped device结构。这个过程很简单,主要是向内核申请必要的内存资源,包括mapped device和为进行IO操作预申请的内存池,通过内核提供的blk_queue_make_request函数注册该mapped device对应的请求队列dm_request。并将该mapped device作为磁盘块设备注册到内核中。

2、 调用dm_hash_insert将创建好的mapped device插入到device mapper中的一个全局hash表中,该表中保存了内核中当前创建的所有mapped device。

3、 用户空间命令通过ioctl调用table_load函数,该函数根据用户空间传来的参数构建指定mapped device的映射表和所映射的target device。该函数先构建相应的dm_table、dm_target结构,再调用dm-table.c中的dm_table_add_target函数根据用户传入的参数初始化这些结构,并且根据参数所指定的target类型,调用相应的target类型的构建函数ctr在内存中构建target device对应的结构,然后再根据所建立的dm_target结构更新dm_table中维护的B树。上述过程完毕后,再将建立好的dm_table添加到mapped device的全局hash表对应的hash_cell结构中。

4、 最后通过ioctl调用do_resume函数建立mapped device和映射表之间的绑定关系,事实上该过程就是通过dm_swap_table函数将当前dm_table结构指针值赋予mapped_device相应的map域中,然后再修改mapped_device表示当前状态的域。

通过上述的4个主要步骤,Device mapper在内核中就建立一个可以提供给用户使用的mapped device逻辑块设备。

IO流:

Device mapper本质功能就是根据映射关系和target driver描述的IO处理规则,将IO请求从逻辑设备mapped device转发相应的target device上。Device mapper处理所有从内核中块一级IO子系统的generic_make_request和submit_bio接口[两个接口具体的描述可以查看参考文献[1]和[2],这两本书对内核中的块IO层有比较详尽的讲解。] 中定向到mapped device的所有块读写IO请求。IO请求在device mapper的设备树中通过请求转发从上到下地进行处理。当一个bio请求在设备树中的mapped deivce向下层转发时,一个或者多个bio的克隆被创建并发送给下层target device。然后相同的过程在设备树的每一个层次上重复,只要设备树足够大理论上这种转发过程可以无限进行下去。在设备树上某个层次中,target driver结束某个bio请求后,将表示结束该bio请求的事件上报给它上层的mapped device,该过程在各个层次上进行直到该事件最终上传到根mapped device的为止,然后device mapper结束根mapped device上原始bio请求,结束整个IO请求过程。

Bio在device mapper的设备树进行逐层的转发时,最终转发到一个或多个叶子target节点终止。因为一个bio请求不可以跨多个target device(亦即物理空间段), 因此在每一个层次上,device mapper根据用户预先告知的mapped device 的target映射信息克隆一个或者多个bio,将bio进行拆分后转发到对应的target device上。这些克隆的bio先交给mapped device上对应的target driver上进行处理,根据target driver中定义的IO处理规则进行IO请求的过滤等处理,然后再提交给target device完成。上述过程在dm.c文件中的dm_request函数中完成。Target driver可以对这些bio做如下处理:

1、 将这些bio在本驱动内部排队等待以后进行处理;

2、 将bio重新定向到一个或多个target device上或者每个target device上的不同扇区;

3、 向device mapper返回error 状态。

IO请求就按照上文中描述的过程在图2中所示的设备树中逐层进行处理,直到IO请求结束。

小结

Device mapper在内核中向外提供了一个从逻辑设备到物理设备的映射架构,只要用户在用户空间制定好映射策略,按照自己的需要编写处理具体IO请求的target driver插件,就可以很方便的实现一个类似LVM的逻辑卷管理器。Device mapper以ioctl的方式向外提供接口,用户通过用户空间的device mapper库,向device mapper的字符设备发送ioctl命令,完成向内的通信。它还通过ioctl提供向往的事件通知机制,允许target driver将IO相关的某些事件传送到用户空间。

三、用户空间部分 

        Device mapper在用户空间相对简单,主要包括device mapper库和dmsetup工具。Device mapper库就是对ioctl、用户空间创建删除device mapper逻辑设备所需必要操作的封装,dmsetup是一个提供给用户直接可用的创建删除device mapper设备的命令行工具。因为它们的功能和流程相对简单,在本文中对它们的细节就不介绍了,用户空间主要负责如下工作:

1、 发现每个mapped device相关的target device;

2、 根据配置信息创建映射表;

3、 将用户空间构建好的映射表传入内核,让内核构建该mapped device对应的dm_table结构;

4、 保存当前的映射信息,以便未来重新构建。

        以下我们主要通过实例来说明dmsetup的使用,同时进一步说明device mapper这种映射机制。用户空间中最主要的工作就是构建并保存映射表,下面给出一些映射表的例子:

1)
0 1024 linear /dev/sda 204
1024 512 linear /dev/sdb 766

1536 128 linear /dev/sdc 0

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

3) 0 4711 mirror core 2 64 nosync 2 /dev/sda 2048 /dev/sdb 1024

        例子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号扇区开始的区域。同时告诉内核这个条带类型的target driver存在2个条带设备与逻辑设备做映射,并且条带的大小是64个扇区,使得驱动可以该值来拆分跨设备的IO请求。

        例子3中将逻辑设备从0号扇区开始的,长度为4711个扇区的段以镜像的方式映射到/dev/sda设备的第2048个扇区以及/dev/sdb设备的第1024号扇区开始的区域。

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

dmsetup create 设备名 映射表文件 /* 根据指定的映射表创建一个逻辑设备 */

dmsetup reload 设备名 映射表文件 /* 为指定设备从磁盘中读取映射文件,重新构建映射关系 */

dmsetup remove 设备名 /* 删除指定的逻辑设备 */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/404846.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

轻松打造智能化性能测试监控平台:【JMeter+Grafana+Influxdb】的优化整合方案

在当前激烈的市场竞争中,创新和效率成为企业发展的核心要素之一。在这种背景下,如何保证产品和服务的稳定性、可靠性以及高效性就显得尤为重要。 而在软件开发过程中,性能测试是一项不可或缺的环节,它可以有效的评估一个系统、应…

igolang学习3,golang 项目中配置gin的web框架

1.go 初始化 mod文件 go mod init gin-ranking 2.gin的crm框架 go get -u github.com/gin-gonic/gin 3.go.mod爆红解决

渗透测试之RCE漏洞

RCE(remote command execute)远程命令执行。应用程序的某些功能需要调用可以执行的系统命令的函数,如果这些函数或者函数的参数被用户控制,就可能通过命令连接符将恶意的命令拼接到函数中,从而执行系统命令。 常见的命…

WordPress使用

WordPress功能菜单 仪表盘 可以查看网站基本信息和内容。 文章 用来管理文章内容,分类以及标签。编辑文章以及设置分类标签,分类和标签可以被添加到 外观-菜单 中。 分类名称自定义;别名为网页url链接中的一部分,最好别设置为中文…

mybatis 集成neo4j实现

文章目录 前言一、引入jar包依赖二、配置 application.properties三、Mybatis Neo4j分页插件四、Mybatis Neo4j自定义转换器handler五、MybatisNeo4j代码示例总结 前言 MyBatis是一个基于Java语言的持久层框架,它通过XML描述符或注解将对象与存储过程或SQL语句进行…

【C++私房菜】面向对象中的多重继承以及菱形继承

文章目录 一、多重继承1、多重继承概念2、派生类构造函数和析构函数 二、菱形继承和虚继承2、虚继承后的构造函数和析构函数 三、has-a 与 is-a 一、多重继承 1、多重继承概念 **多重继承(multiple inheritance)**是指从多个直接基类中产生派生类的能力…

Open CASCADE学习|绘制砂轮

今天绘制一个砂轮,其轮廓由两条直线段和两段圆弧构成,圆弧分别与直线相切,两条圆弧之间相交而非相切。建模思路是:先给定两条直线段的起始点及长度,画出直线段,然后给定其中一圆弧的半径及圆心角&#xff0…

Elastic Stack--02--核心概念、倒排索引

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1.核心概念1.1 索引1.2 类型1.3 文档1.4 字段 2.倒排索引此处ID是唯一标识 具体拆解的案例 1.核心概念 mysqlESDatabases 数据库索引 indicesTable 数据表类型 Type…

探索D咖智能饮品机器人的工作原理:科技、材料与设计的相互融合

智能饮品机器人是近年来随着人工智能和自动化技术的发展而崭露头角的一种创新产品。它将科技、材料和设计相互融合,为消费者带来了全新的饮品体验。下面D咖来探索智能饮品机器人的工作原理,以及科技、材料和设计在其中的作用。 首先,智能饮品…

抖音小店无货源真的靠谱吗?发展前景如何?2024年值得做吗?

大家好,我是电商花花。 我们通常说的抖音小店无货源就是利用产品之间的信息差、利润差来赚取商品的差价。 无货源模式就是即使没有货源,也能做抖音小店,前期店铺起店,我们需要大量的出单量和数据,我们才能快速把店铺…

Spring Boot应用集成Actuator端点自定义Filter解决未授权访问的漏洞

一、前言 我们知道想要实时监控我们的应用程序的运行状态,比如实时显示一些指标数据,观察每时每刻访问的流量,或者是我们数据库的访问状态等等,需要使用到Actuator组件,但是Actuator有一个访问未授权问题,…

QT基本组件

四、基本组件 Designer 设计师(重点) Qt包含了一个Designer程序,用于通过可视化界面设计开发界面,保存文件格式为.ui(界面文件)。界面文件内部使用xml语法的标签式语言。 在Qt Creator中创建文件时&#xf…

蓝桥杯C++竞赛常用库函数介绍

文章目录 前言一、二分查找1. 二分查找的前提2.binary_search函数3.lower_bound函数和upper_bound函数4.蓝桥杯例题 二、最值查找1. min和max函数2.min_element和max_element函数3.nth_element函数4.蓝桥杯例题 三、排序1.sort函数2.sort自定义比较函数,或lambda表达式(匿名函数…

金和OA UploadFileBlock接口任意文件上传漏洞

声明 本文仅用于技术交流,请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任 1. 产品简介 金和数字化智能办公平台(简称JC6)是…

运维SRE-06 阶段性复习软件管理体系

那些年运维必会操作-第一弹 操作 文件:增删改查 增:touch,vim,>,>>,cp删除:rm修改:内容:vi/vim,>,>> 文件名:mv查看:内容:cat/vim/less/more/head/tail/sed/awk/…

编写LLVM Pass的一个小问题

在阅读官方文档时发现一个很有趣的细节,官方给出了一个测试用例,此处有一个小问题(%无法复制)。但是我在使用自己编译的ll文件时,我发现该pass无法正常使用。最后经过测试发现是利用-O0编译产生的ll文件有optnone的fla…

学生成绩管理系统(C语言课设 )

这个学生成绩管理系统使用C语言编写,具有多项功能以方便管理学生信息和成绩。首先从文件中读取数据到系统中,并提供了多种功能(增删改查等)选项以满足不同的需求。 学生成绩管理系统功能: 显示学生信息增加学生信息删除学生信息…

Spring Security 重点解析

Spring Security 重点解析 文章目录 Spring Security 重点解析1. 简介2. 依赖3. 登录认证3.1 登录校验流程3.2 Spring Security 默认登录的原理3.2.1 Spring Security 完整流程3.2.2 登录逻辑探究 3.3 自定义改动3.3.1 自定义用户密码校验3.3.2 自定义 UserDetails 获取方式 F1…

C++多线程同步(上)

多线程同步 引言总述详情互斥锁示例运行结果分析条件变量示例一实现分析优化运行结果示例二实现代码运行结果示例三实现代码运行结果读写锁示例实现代码注意分析运行结果附言实现运行结果运行结果个人心得引言 项目中使用多线程,会遇到两种问题,一种是对共享资源的访问时需要…

kafka和ZK的关系

zk相当于是kafka的一个基础设施 Kafka是一种高吞吐量、可扩展的分布式发布订阅消息系统,ZooKeeper是一个分布式协调服务,用于管理和协调分布式系统中的各种资源 Zookeeper:管理broker,consumer 创建broker后,向zk注册…