[입 개발] EXT4 에서 달라진 부분들 #2 – 데이터 영역의 관리

EXT4가 들어오면서 크게 달라진 부분 그 두 번째는, 데이터 영역을 관리하는 방법입니다. 일단 기존에서 사용하던 방식을 알아보도록 하겠습니다. 파일시스템의 특성을 볼때는, 그 시기에 있던 기술의 한계를 알면 도움이 되는데, 최초에 ext가 나오던 시기는 그렇게 큰 파일이 많지는 않던 시기입니다. 즉 엄청 큰 파일을 처리할 일이 많지는 않던 시기입니다. 그리고 기본적으로 ext2~3 까지는 하나의 파일의 최대 크기는 4 bytes 변수를 사용하기 때문에 최대 4기가 한계입니다.(블럭의 크기와 상관없이 일단 최대한 가졌을 때 표현할 수 있는 한계가 4기가입니다. 파일 크기를 나타내는 변수가 4 bytes 이기 때문이죠.)

여기서 보통 파일의 종류에 따라서 File/Directory 에서 File이면, 실제 데이터 영역에 파일의 내용이 있고, 디렉토리면, 해당 디렉토리에 있는 파일 목록에 대한 정보가 데이터 영역에 관리가 되게 됩니다. 즉, “I am a boy” 라는 내용을 가진 파일이 있다면, 그 파일의 크기는 10이고, block 크기가 4k라면, 한 개의 block만 할당이 되어있을것입니다. 그래서 데이터 영역에 가면 처음 10바이트가 “I am a boy”가 들어있게 됩니다. 이걸 관리하는 정보는 EXT는 inode에 있고, ext2~3에서는 그 크기는 총 60바이트입니다. 그리고 블럭을 가리키는 정보는 하나가 4 bytes 입니다. 즉, 60바이트의 공간이 할당되어 있는데, 한 칸이 4 bytes 면 총 15개의 정보를 저장하는 공간이 들어갈 수 있습니다.(FAT32 를 안다면 Fat Table 을 생각하시면 쉽습니다.)

그림1

그런데 여기서 잘 생각해보면, 그림1 처럼 한칸이 4 bytes라 하나의 블럭을 가리키면… 60바이트로는 총 15개… 한 칸이 하나의 블럭을 가리키므로, block 크기가 4k면 4k * 15 = 60k 밖에 안됩니다.(아까는 4기가가 최고라며!!!) 어떻게 된 것일까요? 사실 EXT2/3의 특징 중에 하나가 direct, indirect block, double indirect block, triple indirect block 으로 구성이 된다는 것입니다.

먼저 시작하기 전에 inode에 들어있는 15 개의 칸은… 12개의 direct와 각각 하나씩의 indirect, double indirect, triple indirect 로 구성이 되어있습니다. 먼저 direct 는 그 칸 하나가 그림2처럼 실제 디스크의 블럭하나를 가리키는 것입니다. direct 로는 최대 60k 밖에 파일이 가질 수가 없으므로, 이 사이즈를 더 크게 사용하기 위한 것들이 위한 indirect, double indirect, triple indirect 방식입니다.

그림2

12개니 각 블럭이 4k면 48k의 공간을 지정할 수 있습니다. 그렇다면 13번째 칸의 indirect 는 뭐냐, indirect 가 가리키는 블럭으로 가면, 아까 12개의 direct block을 가리키는 정보가 있던 것과 같은 형태로 실제 디스크를 가리키는 블럭이 direct block이 나옵니다. 블럭 크기가 4k면 여기에 실제 디스크의 블럭을 가리킬 수 있는 정보가 각각 4 byte니 1024개가 들어가게 됩니다. 즉, indirect block은 실제로 direct 블럭 1024개를 가리키므로 4M의 공간을 지정할 수 있습니다. 그림3을 참고합시다.

그림3

그럼 이제 슬슬 이해가 가기 시작할 것입니다. indirect 블럭은 해당 블럭이 direct block을 어드레싱 하는 주소 정보가 들어가 있고, double indirect 블럭이 가리키는 정보는 indirect 블럭을 가리키는 블럭 1024개를 가리키는 블럭에 대한 정보가 됩니다. 그림4를 참고하면, 실제로 double indirect 블럭의 내용은 indirect block 정보들입니다.

그림4

여기서는 4M 짜리 1024개를 가리키므로 4G 의 디스크 정보를 가리킬 수 있습니다. 이쯤되면 이제 triple indirect 의 성격도 눈치 채실 껍니다.
triple indirect block이 가리키는 정보는 double indirect block 1024개를 가리키는 정보입니다. 그림5를 참고하면 됩니다. 그런데 여기서
의아한 것은 사실 double indirect block 만으로도… 실제 파일의 최대 크기인 4G가 넘어간다는 것입니다.(물론 블럭 크기가 4K 일 경우입니다. 1K로 설정되면 이 마지막 블럭을 사용하게 되겠지만… 블럭 크기가 4k면… 마지막 triple indirect 는 사용할 이유가 없습니다.)

블럭 크기가 4k 일때, triple indirect block은 4G * 1024 = 4TB 의 데이터 영역을 가리킬 수 있습니다. 그림5를 참고합시다.

그림5

그런데 ext4로 가면서 왜 이런 구조를 버리는 것일까요? 간단하게 생각해보면 해당 구조는 낭비가 너무 심합니다. 혹시나 FAT32에서 NTFS로 가면서 내부구조가 어떻게 바뀌었는지 이해한다면, 실제로 EXT4의 extend를 이해하는 것은 굉장히 수월합니다.

먼저 간단하게 생각해봅시다. 1000, 1001, 1002, 1003 4개의 블럭이 있다고 할 때 이걸 가리키는 방법으로 ext2에서의 기존 방식은 하나에 한칸을 가리켜야 하므로 총 4칸 16 바이트가 필요합니다. 그런데 이렇게 표현할 수 있지 않을까요? (시작위치, 블럭 개수), 이런 형태면 다음과 같은 (1000, 4) 형태로, 표현이 가능해집니다. 데이터 공간도 각각 4 바이트를 쓴다고 하더라도 8바이트면 줄어듭니다. 물론 매번 필요한 공간이 Fragmentation 이 발생한다면 (1000, 1), (1001, 1), (1002, 1), (1003, 1) 형태로 공간을 낭비하게 됩니다. 즉 연속된 공간이 많이 필요할 수록, 새로운 표현 방법이 공간을 절약할 수 있습니다. 또한 추가 분석할 필요 없이도 쉽게 뒤에 얼마만큼 읽어야 할지도 알 수 있게 됩니다.

이런 방식을 적용한것이, ntfs의 cluster runs 나, ext4의 extent 라는 구조입니다. 그런데 extent는 (시작위치, 블럭 개수) 의 구조에서 블록 개수에는 2 byte만 할당되어 있습니다. 그래서 block 크기가 4k 기준일 때 무조건 32768 즉 4k * 32768 = 128MB 이상되면 아무리 디스크에 연속적으로 할당된 공간이 있더라도 extend가 추가로 생기게 됩니다. 즉 1GB 파일이면 8개는 extent가 생겨야 합니다.

그런데 extent구조를 보면 헤더가 일단 12 바이트이고, 리프 노드(실제 파일의 정보를 가리키는)냐, 인덱스 노드(리프 노드나 다른 인덱스 노드의 정보를 가지는)냐에 따라 가지는 정보들이 각각 12 bytes입니다. 즉… 60바이트에서 헤더를 빼고나면 일단 inode 안에는 4개의 리프 노드만 들어갈 수 있습니다. 즉 512MB 보다 파일 사이즈가 커지거나 fragmentation 이 많이 나면… 결국 tree 형태로 관리되는 정보가 실제 다른 블럭에 들어가야만 합니다.

그림6

그래서 실제 구조는 그림6처럼 되게 됩니다. 그리고 이 extent도 실제로는 해당 파일의 inode의 flag에 USE_EXTENT 가 설정되어 있어야 사용하게 됩니다. 즉 ext4 내에 있는 파일이 어떤 건 extent 형태로, 어떤건 옛날 방식으로도 주소 지정이 가능하다라는 것입니다. 다음번에는 기존에 왜 한 디렉토리에 파일이 많으면, 파일 열기등이 느려지는지, ext4에서는 어떻게 풀고 있는지 가볍게 살펴보도록 하겠습니다.

Advertisements