LVM(Logical Volume Manager) Disk Dump 를 통한 LVM 구조 정의

2024/06/06 LVM 총 6569 자,약 19 문장

LVM (Logical Volume Manager) 은 LVM은 기존의 물리적인 디스크 파티션 구조의 방식에서 더 유연한 스토리지 관리 기능을 제공합니다. 파일시스템이 블록장치에 직접 접근해서 읽기,쓰기를 했다면 LVM은 파일시스템이 LVM이 만든 가상의 블록장치에 읽기, 쓰기를 수행합니다. 이것을 논리 볼륨이라고 하는데, 필요에 따라 크기를 조정하거나 관리할 수 있습니다.

LVM은 다음과 같은 주요 구성 요소로 구성됩니다:

  • Physical Volumes (PV): 하나 이상의 물리적인 디스크 또는 파티션으로 구성된 스토리지 공간입니다. 이러한 물리적인 디스크 또는 파티션은 LVM의 기본 구성 요소입니다.
  • Volume Groups (VG): 하나 이상의 Physical Volumes(PV)를 물리적 또는 가상적으로 그룹화한 것입니다. Volume Group은 논리 볼륨을 생성하고 할당하는 데 사용됩니다.
  • Logical Volumes (LV): Volume Group 내에서 생성되며, 논리적인 블록 장치로 사용되는 가상의 스토리지 공간입니다. 논리 볼륨은 필요에 따라 크기를 조정하거나 다른 논리 볼륨과 병합할 수 있습니다.

이러한 LVM 이 디스크에서는 어떻게 표현되고 관리되는 지 살펴봅시다!


LVM 디스크 덤프


    +--------------------------+
    | thick_vol | thick_snap | |  LV
    +--------------------------+
    | thick                    |  VG            
    +--------------------------+
    | /dev/sdd    | /dev/sde   |  PV
    +--------------------------+


위 그림과 같이 구성된 LVM 에서 /dev/sdd/dev/sde 의 덤프를 해보면 어떻게 나올까요?


# pvs
  PV         VG        Fmt  Attr PSize   PFree
  /dev/sdd   thick     lvm2 a--  <50.00g  48.98g
  /dev/sde   thick     lvm2 a--  <50.00g <50.00g

# vgs
  VG        #PV #LV #SN Attr   VSize  VFree
  thick       2   2   1 wz--n- 99.99g 98.98g

# lvs
  LV         VG        Attr       LSize  Pool Origin    Data%  Meta%  Move Log Cpy%Sync Convert
  thick_snap thick     swi-a-s--- 12.00m      thick_vol 0.00
  thick_vol  thick     owi-a-s---  1.00g


덤프를 하고, 알아보기 쉽도록 hex 데이터로 바꿔봅시다.


# dd if=/dev/sdd of=/root/sdd_dump bs=1020k count=1
# dd if=/dev/sde of=/root/sde_dump bs=1020k count=1

# xxd sdd_dump > sdd_hex
# xxd sde_dump > sde_hex

# cat sdd_hex | head -n 656

...
0000200: 4c41 4245 4c4f 4e45 0100 0000 0000 0000  LABELONE........
0000210: a982 7799 2000 0000 4c56 4d32 2030 3031  ..w. ...LVM2 001
0000220: 4a6f 6c4f 5177 7833 4466 5033 756a 6e75  JolOQwx3DfP3ujnu
0000230: 776e 6435 4342 4735 6230 6747 5975 3874  wnd5CBG5b0gGYu8t


LABELONE 등등 여러가지 문자 들이 뚜렷하게 보이네요! :smile:

/dev/sde 은 어떻게 되어 있을까요?


# cat sde_hex | head -n 656

...
0000200: 4c41 4245 4c4f 4e45 0100 0000 0000 0000  LABELONE........
0000210: 1d8e 939d 2000 0000 4c56 4d32 2030 3031  .... ...LVM2 001
0000220: 4647 5a33 4d45 6150 4c68 394e 784f 724f  FGZ3MEaPLh9NxOrO
0000230: 6e39 7a38 4172 6459 7071 4f33 6a35 6c52  n9z8ArdYpqO3j5lR


뭔가 알 것 같으면서도 아직은 어떤 데이터가 있는지 모르겠네요. 어떻게 구성되어 있는 걸까요?


LVM 디스크에 쓰여진 데이터 해석

LVM 소스 코드를 통해서 디스크에 어떻게 작성하고 있는지 엿볼 수 있습니다. 다음 구조체를 보면 라벨이 찍혀있고 그 뒤의 여러 정보들이 있습니다.


$ cat lib/label/label.h

35 /* On disk - 32 bytes */
36 struct label_header {
37 >---int8_t id[8];>-->---/* LABELONE */
38 >---uint64_t sector_xl;>/* Sector number of this label */
39 >---uint32_t crc_xl;>---/* From next field to end of sector */
40 >---uint32_t offset_xl;>/* Offset from start of struct to contents */
41 >---int8_t type[8];>>---/* LVM2 001 */
42 } __attribute__ ((packed));


주석을 살펴보니 라벨, 섹터정보, crc 정보, offset 정보, LVM 타입 등이 보이네요.

LVM 이 사용하고 있는 디스크이고, 어디서부터 정보를 저장하고 있는지 간략하게 파악할 수 있었습니다.

그 다음 내용은 뭘까요?


# cat sde_hex | head -n 656

...
0000220: 4647 5a33 4d45 6150 4c68 394e 784f 724f  FGZ3MEaPLh9NxOrO
0000230: 6e39 7a38 4172 6459 7071 4f33 6a35 6c52  n9z8ArdYpqO3j5lR
0000240: 0000 0080 0c00 0000 0000 1000 0000 0000  ................
0000250: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000260: 0000 0000 0000 0000 0010 0000 0000 0000  ................
0000270: 00f0 0f00 0000 0000 0000 0000 0000 0000  ................
0000280: 0000 0000 0000 0000 0200 0000 0100 0000  ................
0000290: 0000 0000 0000 0000 0000 0000 0000 0000  ................



$ cat lib/format_text/layout.h

40 /* Fields with the suffix _xl should be xlate'd wherever they appear */
41 /* On disk */
42 struct pv_header {
43 >---int8_t pv_uuid[ID_LEN];
44
45 >---/* This size can be overridden if PV belongs to a VG */
46 >---uint64_t device_size_xl;>---/* Bytes */
47
48 >---/* NULL-terminated list of data areas followed by */
49 >---/* NULL-terminated list of metadata area headers */
50 >---struct disk_locn disk_areas_xl[0];>-/* Two lists */
51 } __attribute__ ((packed));
52
53 /*
54 * Ignore this raw location. This allows us to


pvcreate 시에 pvuuid 의 정보에 대해서 저장을 해뒀나 보네요. pv 의 uuid 와 디바이스의 정보를 포함하고 있습니다.

disk_areas_xl 에는 각각 데이터 영역 정보와 메타데이터 영역 정보를 포함하고 있습니다. 영역 정보는 리스트로 들어갈 수 있는데, 리스트가 끝났다면 zero 값으로 offsetsize 를 채워넣습니다.


$ cat lib/format_text/format-text.h

67 /* On disk */
68 struct disk_locn {
69 >---uint64_t offset;>---/* Offset in bytes to start sector */
70 >---uint64_t size;>->---/* Bytes */
71 } __attribute__ ((packed));


아래에서 보면 0000 1000 0000 0000 값이 데이터 영역의 offset, 0000 0000 0000 0000 이 데이터 영역의 size 임을 확인할 수 있습니다.

offset, size 등은 bswap 을 사용하여 저장하고 읽습니다. 위의 0000 1000 0000 0000는 그러므로 x100000 값으로 읽을 수 있습니다.


0000240: 0000 0080 0c00 0000 0000 1000 0000 0000  ................
0000250: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000260: 0000 0000 0000 0000 0010 0000 0000 0000  ................
0000270: 00f0 0f00 0000 0000 0000 0000 0000 0000  ................
0000280: 0000 0000 0000 0000 0200 0000 0100 0000  ................


데이터 영역의 위치로 가면 아직 아무것도 작성을 하지 않아서 그런지 아무것도 없습니다.


0100000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0100010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0100020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0100030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0100040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0100050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0100060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0100070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0100080: 0000 0000 0000 0000 0000 0000 0000 0000  ................


하지만 메타데이터 영역의 위치(x10 00) 으로 가면 메타데이터의 헤더가 있는 것을 확인할 수 있죠.


0001000: 2af4 634e 204c 564d 3220 785b 3541 2572  *.cN LVM2 x[5A%r
0001010: 304e 2a3e 0100 0000 0010 0000 0000 0000  0N*>............
0001020: 00f0 0f00 0000 0000 00a0 0100 0000 0000  ................
0001030: 0007 0000 0000 0000 a181 917c 0000 0000  ...........|....
0001040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0001050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0001060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0001070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0001080: 0000 0000 0000 0000 0000 0000 0000 0000  ................


메타데이터 헤더는 어떻게 구성되어 있을까요?


$ cat lib/format_text/layout.h

 71 /* On disk */
 72 /* Structure size limited to one sector */
 73 struct mda_header {
 74 >---uint32_t checksum_xl;>--/* Checksum of rest of mda_header */
 75 >---int8_t magic[16];>--/* To aid scans for metadata */
 76 >---uint32_t version;
 77 >---uint64_t start;>>---/* Absolute start byte of mda_header */
 78 >---uint64_t size;>->---/* Size of metadata area */
 79
 80 >---struct raw_locn raw_locns[0];>--/* NULL-terminated list */
 81 } __attribute__ ((packed));

 60 /* On disk */
 61 struct raw_locn {
 62 >---uint64_t offset;>---/* Offset in bytes to start sector */
 63 >---uint64_t size;>->---/* Bytes */
 64 >---uint32_t checksum;
 65 >---uint32_t flags;
 66 } __attribute__ ((packed));


메타데이터 헤더는 헤더 정보의 유효성을 검증하고 메타데이터의 위치를 가리키고 있습니다. 실제로 메타데이터는 mda_header->start + raw_locns->offset 에서 확인이 가능합니다.

이제 주소를 계산하는 것도 어렵지 않습니다!

  • x1000 + x1a000 = x1b000


001b000: 7468 6963 6b20 7b0a 6964 203d 2022 3266  thick {.id = "2f
001b010: 7559 4431 2d48 5856 792d 315a 3275 2d76  uYD1-HXVy-1Z2u-v
001b020: 797a 332d 7765 4530 2d6c 6553 4a2d 716e  yz3-weE0-leSJ-qn
001b030: 6d79 784f 220a 7365 716e 6f20 3d20 3333  myxO".seqno = 33
001b040: 0a66 6f72 6d61 7420 3d20 226c 766d 3222  .format = "lvm2"
001b050: 0a73 7461 7475 7320 3d20 5b22 5245 5349  .status = ["RESI
001b060: 5a45 4142 4c45 222c 2022 5245 4144 222c  ZEABLE", "READ",
001b070: 2022 5752 4954 4522 5d0a 666c 6167 7320   "WRITE"].flags.
001b080: 3d20 5b5d 0a65 7874 656e 745f 7369 7a65  = [].extent_size


이렇게 LVM 이 디스크에 어떻게 정보를 저장하고 활용하는지 살펴보았습니다. 만약 LVM 으로 구성한 서비스를 사용하다가 메타데이터가 깨진 오류가 나온다면 이곳에 문제가 있는지 없는지 살펴볼 수 있겠네요 :smile:



참고

  • lvm: https://github.com/lvmteam/lvm2
HeonJe Lee | 선임연구원
게이트웨이 On-promise 제품 팀에서 시스템 모니터링 및 관리를 쉽게 다가갈 수 있도록 하기 위한 업무를 하고 있습니다.

Contact: lhjnano@gmail.com

Search

    Table of Contents