ldm教程(深度剖析LDM详解一文解决)

管理动态磁盘的子系统是LDM,与MS-DOS分区(即上节所探讨的基本分区)不同,LDM有专门的数据库记录在动态磁盘的最后1MB中,所以要基本盘转动态盘的话要记得留有足够空间

LDM子系统很大程度上提高了容错性,并且可以支持最多2000个卷,并且允许卷存在于不同的磁盘上。我们在动态磁盘中是对卷进行管理,而不是分区,这里要记住。卷分为简单卷(simple volume),跨区卷(spanned volume),带区卷(striped volume)。这里跨区卷顾名思义,可以扩展到另一个磁盘上,而带区卷的读写性能最佳,它将数据平均的分给磁盘的带区卷上,效率提高了几倍,大概类似于RAID-0(对RAID不了解的可以移步我转载的那篇博客上)。

这是我xp虚拟机上的一块动态磁盘,今天我们就详细研究下它

ldm教程(深度剖析LDM详解一文解决)(1)

ldm教程(深度剖析LDM详解一文解决)(2)

首先是一个很明显的MBR分区,但是这个MBR分区其实只是个幌子之所以在动态磁盘中保留MBR一方面是为了考虑一些磁盘管理工具和双系统环境的情况,另一方面是考虑到系统盘和引导盘在动态盘上,所以保留了一个MBR分区。

重点是那个6号扇区(从0计数),这里一律用LBA地址了,所以序号是0它的偏移量是0xC00,我们跳过去看一下:

ldm教程(深度剖析LDM详解一文解决)(3)

这里是动态磁盘的私有头,上面记录了一些很重要的信息,这个私有头在动态磁盘上还有两份拷贝,并且需要注意的是,LDM中采用的是Big-Endian ,这个一定要注意!!!

接下来我们分析一下它的结构,这里仅标注重要的地方

ldm教程(深度剖析LDM详解一文解决)(4)

LDM有个特点就是喜欢在一个特定的结构前面加一串固定值,这里是PRIVHEAD(Private Head)私有头的意思。

更多linux内核视频教程文档资料免费领取后台私信【内核】自行获取.

ldm教程(深度剖析LDM详解一文解决)(5)

ldm教程(深度剖析LDM详解一文解决)(6)

Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂

第二项是一个校验和,占四个字节

然后跳到offset为0xc20的地方,前面的地方不是很重要我们就不分析了,有兴趣的可以去msdn上找一找。0xc20这里表示私有头的第一备份地址,这里是0x7FF扇区。后面的8个字节是私有头的第二备份地址,这里是0x740扇区。

接下来三组每个64字节,分别表示磁盘ID,主机ID,磁盘组ID,后面的一个32字节是该磁盘组的名字。

然后我们跳到0xD1B这里,这里表示逻辑磁盘的起始地址,这里是0x3F。后面的一个八字节表示该逻辑磁盘的size,这里是0x13FE59A。可以看出这里已经扩展到8个字节了,也就是2PB的大小,可以表示的空间非常非常大了,足够满足现有的状况。

然后接着是LDM数据库的位置,这里是0x13FF800,后面一个是LDM数据库的size,这里是0x800。接着是TOC的数目,这里是1,下面一个则是TOC的size,这里是0x7FE。(TOC全称是table of content 我查了好久…百度居然木得,可以理解为是目录表,最重要的是记录着两个表的总体信息)最后是日志和配置的相关信息。顺序依次是配置信息数量,这里为1,日志数量,这里为1,配置信息的大小,这里为0x5c9字节大小,日志大小,这里为0xE0大小(好奇为啥不一个数量后面接一个size,真的好奇怪,明明前面都是这样的格局)。

然后我们跳到LDM数据库的位置看下LDM数据库的相关信息,LDM扇区地址是0x13FF800,跳转之后发现空空如也。不要惊讶,我们给出LDM数据库的结构

ldm教程(深度剖析LDM详解一文解决)(7)

果然,它第一个扇区规定为空

ldm教程(深度剖析LDM详解一文解决)(8)

跳到第二扇区

ldm教程(深度剖析LDM详解一文解决)(9)

看到了TOCBLOCK,config,log字样,是TOC没错了,下面说明一下TOC的结构。

ldm教程(深度剖析LDM详解一文解决)(10)

我们关注的主要是它的固定值,位图名,位图起始地址。这里我们需要制作一个模板,按照这样的样式来,想知道原理的自己搜一搜,这里就不提了,打开模板的快捷键是Crtl F12

ldm教程(深度剖析LDM详解一文解决)(11)

template "LDM Table of content Block" description "LDM Table of content Block" applies_to disk sector-aligned requires 0x00 "54 4F 43 42 4C 4F 43 4B" big-endian read-only hexadecimal begin { char [8] "Signature:TOCBLOCK" hex 4 "Sequence number" hex 4 "Zeros" hex 4 "Sequence Number (2)" hex 16 "Zeros" char [8] "Bitmap Name" hex 2 "Bitmap Flags 1" int64 "Bitmap Start (in Sectors)" int64 "Bitmap Size (in Sectors)" hex 8 "Bitmap Flags 2" char [8] "Bitmap Name" hex 2 "Bitmap Flags 1" int64 "Bitmap Start (in Sectors)" int64 "Bitmap Size (in Sectors)" hex 8 "Bitmap Flags 2" } end

注意这里是大端的方式,全部以十六进制的方式呈现分析的结果如下:

ldm教程(深度剖析LDM详解一文解决)(12)

首先是一个TOCBLOCK的固定ascill字符串,然后BitmapName是config,这是配置信息的总表(VMDB)的名称,它的所处扇区是0x11,相对于LDM的数据库而言的。第二个BitmapName是log,这是日志记录的地方,它所在的相对扇区是0x5DA。我们先看VMDB,结构如下。

ldm教程(深度剖析LDM详解一文解决)(13)

ldm教程(深度剖析LDM详解一文解决)(14)

仍然需要制作模板

VMDB信息

template "LDM VMDB Block" description "LDM VMDB Block" applies_to disk sector-aligned requires 0x00 "56 4D 44 42" read-only big-endian hexadecimal begin { char [4] "Signature:VMDB" uint32 "Sequence Number of last VBLK" uint32 "Size of VBLK" uint32 "Offset to first VBLK" uint16 "Update Status" hex 2 "Version Major (Always 0x04)" hex 2 "Version Minor (Always 0x0A)" char [31] "Disk Group Name (string, null padded)" hex 64 "Disk Group Id GUID (string, null padded)" int64 "Committed Sequence" int64 "Pending Sequence" uint32 "Number of Committed Volume VBLKs" uint32 "Number of Committed Component VBLKs" uint32 "Number of Committed Partition VBLKs" uint32 "Number of Committed Disk VBLKs" hex 12 "Unused" uint32 "Number of Pending Volume VBLKs" uint32 "Number of Pending Component VBLKs" uint32 "Number of Pending Partition VBLKs" uint32 "Number of Pending Disk VBLKs" hex 12 "Unused" filetime "Last Accessed Time" } end

ldm教程(深度剖析LDM详解一文解决)(15)

固定值VMDB开头,VBLK的个数是0x1724个,代表着VMDB后面的VMLK(配置记录)的数量是这么多,每个VMLK的一般来说是128字节大小,也就是0x80大小,OffsetToFirstVBLK是VBLK相对于VMDB的字节偏移,这里是512字节,也就是VMDB占了一个扇区的大小,DiskGroupName是磁盘组名,一般是你的计算机名 Dgx(x从1开始标)。比较重要是下面的四项

Number of Committed Volume VBLKs //提交的卷记录Number of Committed Component VBLKs //提交的组件记录Number of Committed Partition VBLKs //提交的分区记录Number of Committed Disk VBLKs //提交的磁盘记录之所以会有这四项,是因为一个卷的建立并不是只有一个卷记录而已的,不同的卷类型有着不同的逻辑结构用以尽可能详细的描述该卷的信息,其中v代表volume,c代表component,p代表partition,d代表disk。简单卷:

ldm教程(深度剖析LDM详解一文解决)(16)

跨区卷:

ldm教程(深度剖析LDM详解一文解决)(17)

镜像卷

ldm教程(深度剖析LDM详解一文解决)(18)

镜像跨区卷

ldm教程(深度剖析LDM详解一文解决)(19)

而我们这里是两个简单卷,并且在同一块磁盘上。

ldm教程(深度剖析LDM详解一文解决)(20)

所以,会有2个卷记录,2个组件记录,2个分区记录,因为没有扩展卷,所以一个卷一个分区,1个磁盘记录就足够了,因为在同一磁盘上。

ldm教程(深度剖析LDM详解一文解决)(21)

后面就是VBLK了,一个大小为0x80。

ldm教程(深度剖析LDM详解一文解决)(22)

VBLK的结构是一个动态的结构,对于V,C,P,D有不同的描述,但是这些结构有个相同的Header。另外一个动态磁盘会有一个磁盘组的记录,但是动态磁盘仅支持1个磁盘组。结构参考来自:https://www.oschina.net/translate/a-cross-platform-parser-of-the-dynamic-disks-struc?print

struct Vblk { uint8_t magic[4]; uint32_t sequenceNumber; uint32_t groupNumber; uint16_t recordNumber; uint16_t numberOfRecords; uint16_t updateStatus; uint8 types; uint8 flags uint32_t length; uint8_t otherData; //动态结构,大小视类型而定,这里仅用uint8代表之后有不定字节 };

magic是一个固定的ASCII值“VBLK”,sequenceNumber表示是配置记录的第几个,这是从4开始编制的,因为VMDB占了0-3。NumberOfRecords是所占的记录数,因为有时一个128字节并不能完全表示除某个类型的特征。flags是一个很重要的标志,用于标识这个是什么类型。otherData则是代表了后面的动态结构,具体我会再下面讲。

flags的不同取值 组件的VBLK:0x32 分区的VBLK:0x33 磁盘的VBLK:0x34 磁盘组的VBLK:0x35 卷的VBLK:0x51

先看第一个VBLK

ldm教程(深度剖析LDM详解一文解决)(23)

sequnence num为4,说明这是第一条记录,类型是0x34表明是一个磁盘的VBLK

ldm教程(深度剖析LDM详解一文解决)(24)

重点关注它的对象ID,磁盘ID是403,磁盘名是Disk1,全局ID是c0cfb0bc-a5b6-43c9-a170-7052ee232537

再看下一条的ID

ldm教程(深度剖析LDM详解一文解决)(25)

sequence num是5,说明是第2条记录。Flags是磁盘组的VBLK。

ldm教程(深度剖析LDM详解一文解决)(26)

重要的已经标了出来,磁盘组的对象ID是401 ,这个很重要

再看下一条有效VBLK

ldm教程(深度剖析LDM详解一文解决)(27)

Flags是0x51,说明是一个卷结构

ldm教程(深度剖析LDM详解一文解决)(28)

对象ID是406 ,卷名为Volume1,是一个普通卷,被分配的驱动器号是J,有一个独特的GUID,分区类型是07,表明是NTFS类型,也确实如此,卷大小是0x1c2000,换算一下大小,是900MB,因为LDM分去了1MB,所以可用的为899MB

ldm教程(深度剖析LDM详解一文解决)(29)

继续往下:

ldm教程(深度剖析LDM详解一文解决)(30)

Flags为分区类型,看一下分区结构。

ldm教程(深度剖析LDM详解一文解决)(31)

这块分区的对象ID是40A,名称为Disk1-01,动态磁盘的扇区相对位置为0,这个的绝对扇区地址应该为63,卷偏移为0,说明是这个简单卷的第一个分区,若卷偏移不是0,说明有扩展卷的存在,父对象的组件ID是408,磁盘对象ID是403,这个403正是我们我们这块磁盘的ID。所以到这里,我们不难看出,LDM区分不同的部件是根据对象ID来的,所以每个部件的对象ID是一个独特的ID值,并且非常重要。继续往下查找该卷的组件。flags的值为0x32,表明是一个组件。

ldm教程(深度剖析LDM详解一文解决)(32)

组件结构:

ldm教程(深度剖析LDM详解一文解决)(33)

组件的对象ID是408,正是分区的父对象ID,名称是Volume1-01,是一个基本组件,它的父ID(卷)为406,正是逻辑磁盘J。至此一个简单卷的分析就到此了。

最后给出卷,分区,组件,磁盘,VBLK头的模板,仅供参考,template标明这是啥,记得别看错,模板识别是根据现在的光标位置进行选择的

template "LDM VBLK Header" description "LDM VBLK Header" applies_to disk multiple requires 0x00 "56 42 4C 4B" big-endian begin { char [4] "Signature:VBLK" hexadecimal uint32 "Sequence Number" hexadecimal uint32 "Group Number" hexadecimal uint16 "Record Number " hexadecimal uint16 "Number of Records" hexadecimal uint16 "Update Status" hexadecimal uint8 "Type" hexadecimal uint8 "Flags" hexadecimal uint32 "Length" move 104 } end

template "动态磁盘 VBLK组件结构 0x32" description "VBLK,组件结构" big-endian applies_to disk requires 0x0 "56 42 4C 4B" requires 0x13 "32" begin char[4] "标志" hexadecimal uint32 "序列号" hexadecimal uint32 "参考号" hexadecimal uint16 "记录号" hexadecimal uint16 "记录数" section "组件结构(0x32)" hexadecimal uint24 "更新状态" hex 1 "记录类型和标志" hexadecimal uint32 "数据长度" uint8 "对象ID长度" //用ID长度来控制对象ID内容 IfEqual "对象ID长度" 1 hexadecimal int8 "对象ID" endif IfEqual "对象ID长度" 2 hexadecimal int16 "对象ID" endif IfEqual "对象ID长度" 3 hexadecimal int24 "对象ID" endif IfEqual "对象ID长度" 4 hexadecimal int32 "对象ID" endif //判断结束 uint8 "名称长度" char[名称长度] "名称" uint8 "卷状态(活动)长度" char[卷状态(活动)长度] "卷状态(活动)" hexadecimal uint8 "组件类型(1为条带,2为基本或跨区),3为RAID" hex 4 "0值" uint8 "子组件数量长度" IfEqual "子组件数量长度" 1 hexadecimal int8 "子组件数量" endif IfEqual "子组件数量长度" 2 hexadecimal int16 "子组件数量" endif IfEqual "子组件数量长度" 3 hexadecimal int24 "子组件数量" endif IfEqual "子组件数量长度" 4 hexadecimal int32 "子组件数量" endif hexadecimal int64 "日志提交ID" hex 8 "0值" uint8 "父ID(卷)长度" IfEqual "父ID(卷)长度" 1 hexadecimal int8 "父ID(卷)" endif IfEqual "父ID(卷)长度" 2 hexadecimal int16 "父ID(卷)" endif IfEqual "父ID(卷)长度" 3 hexadecimal int24 "父ID(卷)" endif IfEqual "父ID(卷)长度" 4 hexadecimal int32 "父ID(卷)" endif hex 1 "0值" uint8 "条带大小长度" IfEqual "条带大小长度" 1 hexadecimal int8 "条带大小" endif IfEqual "条带大小长度" 2 hexadecimal int16 "条带大小" endif IfEqual "条带大小长度" 3 hexadecimal int24 "条带大小" endif IfEqual "条带大小长度" 4 hexadecimal int32 "条带大小" endif uint8 "条带数量长度" IfEqual "条带数量长度" 1 hexadecimal int8 "条带数量" endif IfEqual "条带数量长度" 2 hexadecimal int16 "条带数量" endif IfEqual "条带数量长度" 3 hexadecimal int24 "条带数量" endif IfEqual "条带数量长度" 4 hexadecimal int32 "条带数量" endif end

template "动态磁盘 VBLK卷结构 0x51" description "VBLK,卷结构" big-endian applies_to disk requires 0x0 "56 42 4C 4B" requires 0x13 "51" begin char[4] "标志" hexadecimal uint32 "序列号" hexadecimal uint32 "参考号" hexadecimal uint16 "记录号" hexadecimal uint16 "记录数" section "卷结构(0x51)" hexadecimal uint24 "更新状态" hex 1 "记录类型和标志" hexadecimal uint32 "数据长度" uint8 "ID长度" //用ID长度来控制对象ID内容 IfEqual "ID长度" 1 hexadecimal int8 "对象ID" endif IfEqual "ID长度" 2 hexadecimal int16 "对象ID" endif IfEqual "ID长度" 3 hexadecimal int24 "对象ID" endif IfEqual "ID长度" 4 hexadecimal int32 "对象ID" endif //判断结束 uint8 "名称长度" char[名称长度] "名称" uint8 "应用类型长度" char[应用类型长度] "应用类型" hex 1 "0值" char[14] "卷状态(活动)" hexadecimal uint8 "卷类型(3为普通,4为RAID)" hexadecimal uint8 "总是1" hexadecimal uint8 "卷数量" hex 3 "0值" hex 1 "标志(0x11为普通,0x13为RAID)" hexadecimal uint8 "子单元数长度" hexadecimal uint8 "子单元数" hexadecimal int64 "日志提交ID" hexadecimal int64 "ID" uint8 "大小长度" IfEqual "大小长度" 1 hexadecimal int8 "大小" endif IfEqual "大小长度" 2 hexadecimal int16 "大小" endif IfEqual "大小长度" 3 hexadecimal int24 "大小" endif IfEqual "大小长度" 4 hexadecimal int32 "大小" endif hex 4 "0值" hex 1 "分区类型" hex 16 "卷GUID" uint8 "ID1长度" char[ID1长度] "ID1(驱动器号)" uint8 "ID2长度" char[ID2长度] "ID2(驱动器号)" end

template "动态磁盘 VBLK分区结构 0x33" description "VBLK,分区结构" big-endian applies_to disk requires 0x0 "56 42 4C 4B" requires 0x13 "33" begin char[4] "标志" hexadecimal uint32 "序列号" hexadecimal uint32 "参考号" hexadecimal uint16 "记录号" hexadecimal uint16 "记录数" section "分区结构(0x33)" uint24 "更新状态" hex 1 "记录类型和标志" hexadecimal uint32 "数据长度" uint8 "对象ID长度" //用ID长度来控制对象ID内容 IfEqual "对象ID长度" 1 hexadecimal int8 "对象ID" endif IfEqual "对象ID长度" 2 hexadecimal int16 "对象ID" endif IfEqual "对象ID长度" 3 hexadecimal int24 "对象ID" endif IfEqual "对象ID长度" 4 hexadecimal int32 "对象ID" endif //判断结束 uint8 "名称长度" char[名称长度] "名称" hex 4 "0值" hexadecimal int64 "日志提交ID" hexadecimal int64 "起始位置" hexadecimal int64 "卷偏移" uint8 "大小长度" IfEqual "大小长度" 1 hexadecimal int8 "大小" endif IfEqual "大小长度" 2 hexadecimal int16 "大小" endif IfEqual "大小长度" 3 hexadecimal int24 "大小" endif IfEqual "大小长度" 4 hexadecimal int32 "大小" endif uint8 "父对象ID(组件)长度" IfEqual "父对象ID(组件)长度" 1 hexadecimal int8 "父对象ID(组件)" endif IfEqual "父对象ID(组件)长度" 2 hexadecimal int16 "父对象ID(组件)" endif IfEqual "父对象ID(组件)长度" 3 hexadecimal int24 "父对象ID(组件)" endif IfEqual "父对象ID(组件)长度" 4 hexadecimal int32 "父对象ID(组件)" endif uint8 "磁盘对象ID长度" IfEqual "磁盘对象ID长度" 1 hexadecimal int8 "磁盘对象ID" endif IfEqual "磁盘对象ID长度" 2 hexadecimal int16 "磁盘对象ID" endif IfEqual "磁盘对象ID长度" 3 hexadecimal int24 "磁盘对象ID" endif IfEqual "磁盘对象ID长度" 4 hexadecimal int32 "磁盘对象ID" endif int64 "组件部分的索引" end

template "动态磁盘 VBLK磁盘组结构 0x35" description "VBLK,磁盘组结构" big-endian applies_to disk requires 0x0 "56 42 4C 4B" requires 0x13 "35" begin char[4] "标志" hexadecimal uint32 "序列号" hexadecimal uint32 "参考号" hexadecimal uint16 "记录号" hexadecimal uint16 "记录数" section "磁盘组结构(0x35)" hexadecimal uint24 "更新状态" hex 1 "记录类型和标志" hexadecimal uint32 "数据长度" uint8 "对象ID长度" //用ID长度来控制对象ID内容 IfEqual "对象ID长度" 1 hexadecimal int8 "对象ID" endif IfEqual "对象ID长度" 2 hexadecimal int16 "对象ID" endif IfEqual "对象ID长度" 3 hexadecimal int24 "对象ID" endif IfEqual "对象ID长度" 4 hexadecimal int32 "对象ID" endif //判断结束 uint8 "名称长度" char[名称长度] "名称" uint8 "磁盘组ID长度" char[磁盘组ID长度] "磁盘组ID" hex 4 "0值" int64 "日志提交ID" uint8 "可选域1长度" IfEqual "可选域1长度" 1 hex 1 "可选域1" endif IfEqual "可选域1长度" 2 hex 2 "可选域1" endif IfEqual "可选域1长度" 3 hex 3 "可选域1" endif IfEqual "可选域1长度" 4 hex 4 "可选域1" endif uint8 "可选域2长度" IfEqual "可选域2长度" 1 hex 1 "可选域1" endif IfEqual "可选域2长度" 2 hex 2 "可选域1" endif IfEqual "可选域2长度" 3 hex 3 "可选域1" endif IfEqual "可选域2长度" 4 hex 4 "可选域1" endif end

template "动态磁盘 VBLK磁盘结构 0x34" description "VBLK,磁盘结构" big-endian applies_to disk requires 0x0 "56 42 4C 4B" requires 0x13 "34" begin char[4] "标志" hexadecimal uint32 "序列号" hexadecimal uint32 "参考号" hexadecimal uint16 "记录号" hexadecimal uint16 "记录数" section "磁盘结构(0x34)" hexadecimal uint16 "更新状态" hexadecimal uint16 "记录类型和标志" hexadecimal uint32 "数据长度" hexadecimal uint8 "对象ID长度" IfEqual "对象ID长度" 1 hexadecimal int8 "对象ID" endif IfEqual "对象ID长度" 2 hexadecimal int16 "对象ID" endif IfEqual "对象ID长度" 3 hexadecimal int24 "对象ID" endif IfEqual "对象ID长度" 4 hexadecimal int32 "对象ID" endif uint8 "名称长度" char[名称长度] "名称" uint8 "磁盘ID长度" char[磁盘ID长度] "磁盘ID" uint8 "预备名称长度" char[预备名称长度] "预备名称" hex 4 "0值" hexadecimal int64 "日志提交ID" end

导读-最新发表 - 内核技术中文网 - 构建全国最权威的内核技术交流分享论坛

转载地址:深度剖析LDM详解,一文解决! - 圈点 - 内核技术中文网 - 构建全国最权威的内核技术交流分享论坛

ldm教程(深度剖析LDM详解一文解决)(34)

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页