2014년 12월 18일 목요일

디스크 파티션 분석

MBR(Master Boot Record)은 블록장치의 첫512바이트로 부팅 가능한 파티션을 찾는 짧은 코드와 블록장치의 파티션 정보를 가지고 있다. 기본적으로 MBR에는 총 4개의 파티션 정보를 저장할 수 있으며, 이 4개의 파티션 정보 영역에 Primary 파티션 혹은 Extended 파티션에 대한 정보를 저장할 수 있다.

MBR에 적재되어 있는 작은 코드는 MBR 뒷부분에 포함되어 있는 파티션 테이블의 정보를 사용하여 부팅 가능한 파티션이 있는지 확인 후 해당 파티션의 VBR (Volume Boot Record)을 로드하고 실행한다. VBR의 코드는 해당 파티션에 설치된 OS를 메모리에 로드하고 실행하는 역할을 한다. 만일 블록장치 전체를 파티션 생성없이 통으로 포맷하여 사용할 경우 MBR없이 MBR자리에 VBR이 생성될 것이다.  VBR이 저장되어 있는 영역을 흔히 부트섹터(boot sector)라고 부른다.

파티션 테이블은 64바이트 크기로 4개의 파티션 정보가 16바이트씩 기록되며 이 16 바이트에는 각 파티션의 시작과 끝 위치, 크기(# of sector)등이 기록되어 있다. 이 4개의 파티션은 Primary 혹은 Extended 파티션이 될 수 있다. Primary 파티션은 부팅 가능한 파티션이므로 별다른 이유(4개 이상의 파티션 필요등)가 없다면 굳이 (부팅 불가능한) Extended 파티션을 사용할 필요가 없다. Extended 파티션은 하위 파티션을 담고 있는 껍데기 파티션으로 역시 MBR에 시작과 끝 위치, 전체 파티션 총 크기(# of sector)가 기록되어 있다.  Extended 파티션 안에는 한개 이상의 Logical 파티션이 들어 있으므로,  각각의 Logical 파티션의 시작, 끝 위치, 크기를 파악하기 위해서는  Extended 파티션의 첫 512바이트의 EBR (Extended Boot Record )을 읽어야 한다.  EBR은 MBR/VBR과 동일한 구조를 가지기 때문에 4개의 파티션 저장을 위한 공간이 있으나, 이중 첫 2개의 파티션 정보만 사용한다.

MBR/VBR/EBR 의 구조                                    offset
---------------------------------------------------- 0x0000
부트 코드 :
  MBR: 부팅 가능한 파티션을 찾아 VBR을 메모리로 로드하고 실행
  VBR: OS를 메모리에 로드하고 실행.
  EBR: empty ?
---------------------------------------------------- 0x01BE
파티션 테이블:                            0x01BE ~ 0x01FD    
Signature (0xAA 0x55)                  0x01FE ~ 0x01FF
-----------------------------------------------------0x0200


EBR의 첫번째 파티션 정보에는 첫 Logical 파티션에 대한 시작위치와 끝위치가 기록되어 있으며, 두번째 파티션 정보는 다음 EBR에 대한 위치를 가지고 있다.  따라서 Logical 파티션의 갯수만큼 EBR이 존재하게 되며, 각 EBR은 1개의 logical 파티션에 대한 정보와 다음 EBR에대한 정보를 가지고 있게 된다.  (Linked List를 생각하면 된다.)

정확한 이해를 위해 QNX Neutrino OS상에서 간단한 실험을 통하여 MBR/EBR의 구조를 확인해 보자. 먼저 아래와같이 테스트를 위한 램디스크를 생성한다.

분석 편의를 위해서 24KB(48개의 512 Byte 블럭)의 작은 램 디스크를 만들었다.
# devb-ram disk name=notuse ram capacity=1,nodinit blk ramdisk=24k

참고: 리눅스에서 테스트를 한다면 램디스크 대신 루프백 장치를 사용하여 동일한 테스트를 진행할 수 있다. "루프백 장치"를  참고한다. 

생성 내용 확인 - 48개의 512Byte 블럭이 생성 되었다.
# df -P /dev/ram0    
Filesystem            512-blocks      Used Available Capacity  Mounted on      
/dev/ram0                     48        48         0     100%                  

생성된 가상의 램 디스크가 어떻게 물리 장치를 시뮬레이트하는지 보자. fdisk가 보여주는 정보에 따르면,  6개의 실린더,  8개의 sector(block), 1개의 track을 가진 물리 장치를 시뮬레이트하고 있는 것으로 보인다. 실린더당 크기는 8x512=4096=4KB이다.  

# mount -e /dev/ram0
참고: QNX Neutrino에서의 mount -e 명령은 리눅스에서 partprobe 정도에 해당한다. 



# fdisk -z /dev/ram0

FDISK
Ignore Next Prev Change Delete Boot Unboot Restore Loader Save Quit

        _____OS_____     Start      End     ______Number_____    Size    Boot  
        name    type    Cylinder  Cylinder  Cylinders  Blocks                  

    1.  ______ (___)    _______   _______   _______   _________  _____
    2.  ______ (___)    _______   _______   _______   _________  _____
    3.  ______ (___)    _______   _______   _______   _________  _____
    4.  ______ (___)    _______   _______   _______   _________  _____


 Choose a partition by typing the partition number OR moving the pointer
 with the UP/DOWN arrows.
 Then, choose one of the actions on the top line of the screen.
          


Drive : /dev/ram0                   Config:     1 Heads
Size  : 0 Mbytes                                8 Sectors/track
Loader: None                                    6 Cylinders
Blocks: 48                                    512 Block Size


최종 목적은 24KB의 작은 디스크를 아래와 같이 파티션 하는 것이다. 

------------------------------------------------- 0x0000   ---  A
cy0 : MBR    (0x0000~0x01FF)
              Boot Code       (0x0000~0x01BD)
              Partition Table (0x01BE~0x01FF)
      Unused (0x0200~0x0FFF)
------------------------------------------------- 0x1000   ---- B
cy1 : 1st Primary Partition
      VBR                     (0x1000~0x11FF)      
                              (0x1200~0x1FFF)
------------------------------------------------- 0x2000   ---- C
cy2 : EBR    (0x2000~0x21FF)
              Boot Code       (0x2000~0x21BD)
              Partition Table (0x21BE~0x21FF)
      Unused (0x2200~0x2FFF)
------------------------------------------------- 0x3000   ---- D
cy3 : 1st Logical Partition      
      VBR                     (0x3000~0x31FF)
                              (0x3200~0x3FFF)
------------------------------------------------- 0x4000   ---- E
cy4 : EBR    (0x4000~0x41FF)
              Boot Code       (0x4000~0x41BD)
              Partition Table (0x41BE~0x41FF)
      Unused (0x4200~0x4FFF)
------------------------------------------------- 0x5000   ---- F
cy5 : 2nd Logical Partition
      VBR                     (0x5000~0x51FF)
                              (0x5200~0x5FFF)
------------------------------------------------- 0x6000   ---- G

(주의!! - 실제로 Primary파티션이나 Logical 파티션은 생성 후 생성 시 지정한 파일시스템으로 포맷해야 해당 파티션을 사용할 수 있게 된다. 하지만 파일시스템별로 필요한 최소 크기가 있으므로 위와 같은 크기로 파티션하면 실제로 포맷은 불가능하게 된다. 실제 포맷까지 테스트 하려면 fdisk시 해당 파티션의 크기 - 실린더 갯수를 늘려야 한다.  위와 같은 크기로 파티션시에는 포맷시 에러가 발생할 것이다. )

이제 첫번째 파티션을 Primary파티션으로 생성해 보자. QNX Neutrino의 fdisk utility는 실린더 경계에서만 파티션이 가능하다. 첫번째 실린더(0번 실린더)에 MBR이 있고, 이 크기가 비록 512바이트 이지만, 첫 파티션을 실린더 경계에 만들려면 1번 실린더에서 시작하여야 한다. 따라서 0번 실린더는 대부분(8개 sector중 7개 sector) 낭비된다 (리눅스의 fdisk는 실린더가 아닌 섹터 단위로 파티션 경계를 설정할 수 있으므로 이러한 낭비 없이 파티션 생성이 가능하다) . 파티션의 크기 또한 실린더 크기의 배수가 되므로 최소 크기인 실린더 1개로 지정하기 위하여 시작 위치 끝위치 모두 1번 실린더로 설정한다. (-c1,1)  따라서 이 파티션은 1번 실린더 전체를 차지하며 4KB가 된다. QNX Neutriono fdisk 사용 시  파일 시스템 타입을 지정하지 않으면 기본 값인 type 77( QNX 4 file system)으로 생성된다. 

# fdisk /dev/ram0 add -s1 -c1,1 
# fdisk /dev/ram0 show

     _____OS_____     Start      End     ______Number______   Size    Boot  
     name    type    Cylinder  Cylinder  Cylinders   Blocks                 

1.   QNX       77          1          1         1          8      0 MB
2.   ------   ---   --------   --------   -------  --------  -----          
3.   ------   ---   --------   --------   -------  --------  -----          
4.   ------   ---   --------   --------   -------  --------  -----          



방금 Primary파티션을 생성한 것이므로 MBR에 해당 내용이 모두 기록되었을 것이다. 아래와 같이 od 명령으로 내용을 확인해 보자. 

# od -Ax -tx1 -v /dev/ram0 | less 
0000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
0000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
...
00001B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00001C0 01 01 4d 00 08 01 08 00 00 00 08 00 00 00 00 00 
00001D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00001E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00001F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa 

512바이트의 마지막 2바이트는 55 aa로 끝나며, 이는 해당 512바이트 정보가 valid함을 의미한다. 이는 MBR뿐만 아니라 EBR이나 VBR에도 동일하게 존재한다.

파티션 정보의 시작은 0x01BE부터 이며, 각 파티션당 16바이트이다. 
따라서 첫번째 Primary파티션의 정보는 아래와 같다. 

00 00 01 01 4D 00 08 01 08 00 00 00 08 00 00 00

비트별 정보는 다음 사이트를 참조하여 해석가능하다. (http://en.wikipedia.org/wiki/Master_boot_record)

해석해보면 아래와 같다.  파티션 시작 위치 및 끝 위치는 little endian을 고려하여 해석해야 한다. 

00                    :  80이면 부팅 가능한 파티션
00 01 01          :  파티션 시작 위치 (CHS표기):  1번 실린더 1번 sector
4D                   :  filesystem type : 0x4D, QNX 4 filesystem
00 08 01          :  파티션 끝위치 (CHS표기): 1번 실린더, 8번 sector
08 00 00 00     :  파티션 시작위치 (sector단위,디스크 시작부터 8번째 sector이후 시작),  위 그림에서 A~B
08 00 00 00     :  파티션 크기 (sector단위) 8개 sector, 위 그림에서 B~C

이제 나머지 공간(실린더 2,3,4,5) 전체에 extended 파티션(-t5)을 생성한다. 

# fdisk /dev/ram0 add -s2 -t5 -c2,5 
# fdisk /dev/ram0 show

     _____OS_____     Start      End     ______Number______   Size    Boot  
     name    type    Cylinder  Cylinder  Cylinders   Blocks                 

1.   QNX       77          1          1         1          8      0 MB
2.   Extd'd     5          2          5         4         32      0 MB
2.1  Unused     0          3          5         3         24      0 MB
3.   ------   ---   --------   --------   -------  --------  -----          
4.   ------   ---   --------   --------   -------  --------  -----          

MBR을 확인하면 아래와 같이 내용이 추가된다. 

# od -Ax -tx1 -v /dev/ram0 | less 
0000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
0000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
...
00001B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00001C0 01 01 4d 00 08 01 08 00 00 00 08 00 00 00 00 00 
00001D0 01 02 05 00 08 05 10 00 00 00 20 00 00 00 00 00 
00001E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00001F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa 

추가된 내용
00 00 01 02 05 00 08 05 10 00 00 00 20 00 00 00


해석해보면 아래와 같다. 
00                    :  80이면 부팅 가능한 파티션
00 01 02          :  파티션 시작 위치 (CHS표기):  2번 실린더 1번 sector
05                    :  filesystem type : extended 파티션 
00 08 05          :  파티션 끝위치 (CHS표기): 5번 실린더, 8번 sector
10 00 00 00     :  파티션 시작위치 (sector단위, MBR 시작부터 16번 sector이후 시작) ,  위 그림에서 A~C
20 00 00 00     :  파티션 크기 (sector단위)  32개 sector,  위 그림에서 C~G

앞서 설명한바와 같이 Extended 파티션의 경우 껍데기 파티션이고, 이 안에 한개 이상의 실제 파티션이 존재하며, 이 각각의 실제 파티션에 대한 정보는 EBR이라는 곳에 저장된다.  EBR은 논리 파티션의 개수만큼 생기는데, 아직 logical 파티션을 생성하지 않았으므로 EBR이 존재하지 않아야 하지만, 위에서 보듯이 Extended 파티션 생성시 Unused라는 name을 가지는 dummy logical 파티션이 자동으로 생성되어 있다.  그럼 여기에 해당하는 dummy EBR이 생성되었는지 확인해 보자. 첫번째 EBR은 Extended 파티션 시작(2번 cyliander 1번 sector) 첫 512바이트에서 찾을 수 있다.  cyliander당 크기가 4KB이므로 2번 cliandaer의 시작 위치는 8KB, 즉 0x2000이 된다.  

00021A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa 

보는바와 같이 아직 모든 data가 00이며 MBR/EBR임을 나타내는 signature "55 aa" 만 확인할 수 있다. 

그럼 실제로 첫번째 logical 파티션을 생성해보자. -s2는 MBR의 두번째 파티션, -t3는 FAT파일 시스템,  -e1은 첫번째 logical 파티션, -n1은 실린더 1개 할당을 뜻한다. 

# fdisk /dev/ram0 add -s2 -t3 -e1 -n1
# fdisk /dev/ram0 show

     _____OS_____     Start      End     ______Number______   Size    Boot  
     name    type    Cylinder  Cylinder  Cylinders   Blocks                 

1.   QNX       77          1          1         1          8      0 MB
2.   Extd'd     5          2          5         4         32      0 MB
2.1  nonQNX     3          3          3         1          8      0 MB
2.2  Unused     0          5          5         1          8      0 MB
3.   ------   ---   --------   --------   -------  --------  -----          
4.   ------   ---   --------   --------   -------  --------  -----          


첫번째 logical 파티션(2.1 nonQNX로 표기됨)에 대한 EBR은 아래와 같다. 
00021B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021C0 01 03 03 00 08 03 08 00 00 00 08 00 00 00 00 00 
00021D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa 

해석해보면 아래와 같다. 
00                    :  80이면 부팅 가능한 파티션
00 01 03          :  파티션 시작 위치 (CHS표기):  3번 실린더 1번 sector
03                   :  filesystem type : 3 (FAT 파일 시스템)
00 08 03          :  파티션 끝위치 (CHS표기): 3번 실린더, 8번 sector
08 00 00 00     :  파티션 시작위치 (sector단위, 이 EBR 시작부터 8번 sector이후 시작),  위 그림에서 C~D
08 00 00 00     :  파티션 크기 (sector단위)  8개 sector,  위 그림에서 D~E

3번 실린더까지 사용하였으므로 이제 4번, 5번 실린더가 미사용인 상태이고, logical파티션을 추가 생성하면 4번 실린더의 첫 512바이트에 다음 EBR이 기록될 것임을 추측할 수 있다.  실제 사용 가능한 파티션은 5번 실린더 하나가 될 것이다. 

실제로 두번째 logical 파티션 추가해보자. (-e2)

# fdisk /dev/ram0 add -s2 -t3 -e2 -n1 
# fdisk /dev/ram0 show                

     _____OS_____     Start      End     ______Number______   Size    Boot  
     name    type    Cylinder  Cylinder  Cylinders   Blocks                 

1.   QNX       77          1          1         1          8      0 MB
2.   Extd'd     5          2          5         4         32      0 MB
2.1  nonQNX     3          3          3         1          8      0 MB
2.2  nonQNX     3          5          5         1          8      0 MB
3.   ------   ---   --------   --------   -------  --------  -----          
4.   ------   ---   --------   --------   -------  --------  -----         



먼저 첫번째 EBR에 새로운 logical 파티션을 위한 두번째 ERD 위치 정보 추가되는 것을 확인할 수 있다. 
00021B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021C0 01 03 03 00 08 03 08 00 00 00 08 00 00 00 00 00 
00021D0 01 04 05 00 08 05 10 00 00 00 10 00 00 00 00 00 
00021E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00021F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa 


해석해보면 아래와 같다. 
00                    :  80이면 부팅 가능한 파티션
00 01 04          :  파티션 시작 위치 (CHS표기):  4번 실린더 1번 sector
05                   :  filesystem type : 5 (extended partition)
00 08 05          :  파티션 끝위치 (CHS표기): 5번 실린더, 8번 sector
10 00 00 00     :  파티션 시작위치 (sector단위, 첫번째 EBR 시작부터 16번 sector이후 시작),  위 그림에서 C~E
10 00 00 00     :  파티션 크기 (sector단위)  16개 sector,  위 그림에서 E~G


4번 실린더에 있는 두번째 EBR을 확인해 보자, 4번 실린더의 시작 주소는  16KB(0x4000)이다. 

00041B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00041C0 01 05 03 00 08 05 08 00 00 00 08 00 00 00 00 00 
00041D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00041E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00041F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa 

해석해보면 아래와 같다. 
00                    :  80이면 부팅 가능한 파티션
00 01 05          :  파티션 시작 위치 (CHS표기):  5번 실린더 1번 sector
05                   :  filesystem type : 3 (FAT 파일 시스템)
00 08 05          :  파티션 끝위치 (CHS표기): 5번 실린더, 8번 sector
08 00 00 00     :  파티션 시작위치 (sector단위, 두번째 EBR 시작부터 8번 sector이후 시작),  위 그림에서 E~F
08 00 00 00     :  파티션 크기 (sector단위)  8개 sector,  위 그림에서 F~G

참고 : 더 알기 쉽게 정리되어 있는 사이트
http://cappleblog.co.kr/131