4. inode 구조
예전 리눅스에서 사용했던 ext2파일시스템의 inode 파일의 최대 크기에 대하여 계산을 해보도록 하겠습니다. 만약, 4KB 인덱스 블록을 이용할 경우 4Byte로 주소를 표현한다고 할 때 총 1024개의 포인터를 갖습니다. 이때 직접 블록은 12개로 12*4KB이고, 단일 간접 블록은 210*4(KB)로 4MB , 이중 간접 블록은 210*210*4(KB)로 4GB, 삼중 간접 블록은 210*210*210*4(KB)로 4TB를 이론적으로 표현할 수 있습니다. 하지만 ext2(3)에선 실제로 4GB 정도만을 지원합니다. 새롭게 도입된 ext4에선 이러한 제한을 해결하였습니다.
ext2_dir_entry자료구조에 대해서 알아보겠습니다.
inode | Inode Number |
rec_len | Directory Entry Length |
name_len | name length |
name | file name |
5. ext2 파일 시스템
ext2에 저널링(Journaling) 기능을 추가한 것이 ext3 파일 시스템입니다. 파일 시스템은 디스크를 관리합니다. 각 디스크는 /dev 디렉터리에서 확인할 수 있으며 IDE 방식의 경우 "hd"의 이름으로 시작하고 디스크가 둘 이상일 경우 "had", "hdb"로 생성됩니다. SCSI 방식의 경우 "sd"로 생성됩니다.
리눅스에선 최대 64개의 파티션으로 구분될 수 있고 hda1, hda2로 넘버링 됩니다. 파일 시스템은 각 파티션당 하나씩 만들어집니다.
ext2 파일 시스템은 파티션을 여러 개의 블록 그룹으로 나눕니다. 또한 디스크의 성능을 높이기 위해 관련된 inode와 디스크 블록을 인접한 실린더에 유지하려 합니다. ext2로 파일 시스템을 구축하면 부트 스트랩 코드가 존재하는 부트 블록과 여러 개의 블록 그룹들로 구성됩니다. 여기서 블록 그룹은 수퍼 블록, 블록 그룹 디스크립터, 디스크 블록을 위한 bitmap, inode를 위한 bitmap, inode table 영역, data blocks 등 6가지 부분으로 구분됩니다.
이 6가지 부분 중 inode table은 파일 시스템 구축 당시에 계산된 값으로 결정되어 고정된 값을 유지합니다. inode table과 데이터 블록 내에서 빈 공간을 관리하는 비트맵이 존재합니다. root 디렉터리의 경우 inode 2번을 일반 파일이 생성되기 시작하는 최초의 inode 번호로 11번을 지정해 두었습니다. 수퍼 블록과 블록 그룹 디스크립터의 경우 매우 중요하기 때문에 각 블록 그룹마다 중복해서 가지고 있습니다.
6. ext3 파일 시스템과 ext4 파일 시스템
ext2 설계에 신뢰성과 성능 향상을 위해 ext3에 도입한 기술에 대해 알아보겠습니다.
- 빠른 디렉터리 탐색을 위한 해쉬 기반의 HTree 기술 도입
- 총 세 가지 저널링 모드 지원 , Journal, Ordered, Writeback
- 시스템 가용시간 향상. online-resizing, LVM(Logical Volume Manager)
2008년 stable된 ext4 는
- 선할당 : 파일 시스템의 일관성을 높이고 동시에 속도 향상, 파일 생성시 미리 블록할당
지연할당 : 자유 블록 카운트만 갱신하고 실제 할당은 뒤로 미룸 - extent 기반 데이터 블록 유지 -> 메타데이터 줄임
+a ext3의 저널링 기능 성능 향상 저널링 체크섬, 대용량 파일 시스템과 큰 용량의 파일 지원, 온라인 단편화 제거 지원
7. 가상파일 시스템 VFS
리눅스에선 각 파일 시스템마다 각자의 함수로 파일에 접근하는 것이 아닌 하나의 가상 layer를 주어 각 파일 시스템(UFS, ext2, ext3, NFS 등등)의 함수 호출을 쉽게 연결해 관리합니다.
만약 사용자의 open 요청이 오면 VFS가 해당 파일이 어떤 파일 시스템에 속해있는지 판단하고 구조체를 하나 생성해 그 파일 시스템 내부의 고유한 open 함수를 호출합니다.
이를 위해 리눅스는 VFS 내에 4개의 객체를 도입하였습니다.
수퍼 블록 | 현재 사용 중인 파일 시스템 당 하나 씩 |
아이노드 객체 | 특정 파일과 관련된 정보를 담는 구조체, 메타 데이터를 읽어 아이노드 객체에 채움 |
파일 객체 | 태스크가 open한 파일과 연관된 정보, 두 태스크가 접근하는 위치 정보는 다르게 유지할 수 있도록 관리된다. |
디엔트리 객체 | 태스크가 파일에 접근하려면 해당 파일의 아이노드 객체를 자신의 태스크와 연관된 객체인 파일 객체에 연결해 사용해야 함. 일종의 캐시 역할 |
8. 태스크 구조와 VFS 객체
VFS와 task_struct 연결에 대해서 알아보겠습니다.
태스크가 ext2를 마운트 하는 경우에 대해서 알아보겠습니다.
태스크가 ext2를 마운트 하는 경우엔 VFS가 ext2의 마운트 함수 호출을 하면서 비어있는 수퍼블록 객체를 넘깁니다. ext2에서는 자체 구현 파일 시스템 내부 함수를 이용해 넘어온 수퍼블록 객체의 내용을 채워서 리턴합니다.
sys_open()를 호출하는 경우엔 VFS는 빈 아이노드 객체를 인자로 ext2의 내부 open 함수를 호출합니다. 내부 함수는 필요한 정보를 아이노드 객체에 채워서 리턴합니다. VFS는 아이노드 객체를 디엔트리 객체에 연결시켜 사용자의 태스크 구조와 연결합니다. 여기서 task_struct에는 files라는 이름의 변수가 files_struct 자료구조로 구현되어 있습니다. 이 자료구조의 fd_array 변수는 file descriptor가 fd_array 배열의 인덱스로 각 항들은 파일 객체를 가리킵니다.
파일 객체 중 중요한 것은 f_dentry 디엔트리 객체로 아이노드 객체를 가리킵니다. f_pos는 현재 파일에서 읽거나 쓸 위치를 나타냅니다. f_op는 각 파일 유형에 적합한 파일 연산을 등록하는데 이용됩니다.
파일당 하나씩 존재하는 아이노드 객체는 아래의 멤버들로 이루어져 있습니다.
i_dev | inode가 실제 존재하고 있는 파일 시스템의 위치 |
i_rdev | 장치 파일의 경우 드라이버의 주 번호를 나타냄 |
i_ino | inode 고유 번호 |
i_mode | inode가 관리하는 파일의 속성, 접근 제어 정보 유지 |
i_nlink | 이 inode를 가리키고 있는 파일의 수 |
i_size | 아이노드 객체에 해당되는 파일의 크기 |
i_op | f_op와 비슷하게 요청한 연산 파악 |
f_op, i_op는 함수 포인터들을 필드로 갖습니다.
9. 파일 시스템 제어 흐름 분석
sys_open()과 sys_read()의 제어흐름에 대해서 알아보겠습니다.
Ⅰ. sys_open()
- sys_open() 호출 시 요청된 파일에 대한 inode를 찾습니다.
- 태스크 구조와 VFS의 객체를 연결합니다.
- file_open()을 호출합니다.
- open_namei()를 호출해 아이노드 객체를 반환하고 f_op 변수를 초기화합니다.
f_op : struct file_operations로 각 변수에 실제 연산을 수행하는 함수의 시작 주소를 등록해
리눅스에선 각 파일시스템의 유형에 따라 서로 다른 파일 연산이 구현되므로 결국 파일 유형에 맞는 파일 연산을 진행할 수 있도록 f_op 변수에 등록합니다. - file->f_op->open() 호출, 특정 파일에 고유한 open()을 호출합니다.
- sys_open() 파일 디스크립터를 할당하고 이것이 파일 객체를 가리키도록 합니다.
sys_read()의 경우 sys_open()의 흐름과 비슷한 점이 조금 있습니다.
fd를 이용해 파일 객체를 찾고 이 구조의 f_op에 등록된 read 함수를 호출합니다. 이때 호출되는 함수는 generic_file_read로 해당 파일이 속한 파일 시스템에 맞는 디스크 연산 함수를 호출합니다. 이를 지원하는 자료구조가 struct inode_operations 입니다. 이때 f_op처럼 각 파일시스템에 고유한 연산들이 등록됩니다.
결국 f_op와 i_op가 각각 특정 파일에 고유한 연산으로 제어를 전달하는 진입점이라고 생각할 수 있습니다.
<새로운 파일 시스템을 리눅스와 연결하기>
register_filesystem() 함수로 커널에 등록해야합니다.
이 함수는 struct file_system_type 자료구조를 인자로 받습니다. 이 자료구조는 name, fs_flags, get_sb, 리스트, 모듈 정보로 이루어져 있습니다.
리눅스 커널에 존재하는 모든 file_system_type 구조들은 리스트로 연결됩니다. 이 리스트의 시작은 file_systems라는 커널 내부의 전역변수로 특정 파일 시스템에 대한 마운트 요청이 생기면 file_systems에서 시작되는 리스트를 검색해 요청된 파일 시스템의 file_system_type 자료구조를 찾습니다.
get_sb에 기록된 함수를 호출해 VFS의 수퍼블록 객체에 저장합니다.
결국 새로운 파일 시스템의 구현은 수퍼블록, 수퍼블록 연산, inode_operations 등등을 작성하는 것을 말합니다.
'리눅스 커널 Linux kernel' 카테고리의 다른 글
9장 네트워킹 - 1 (0) | 2013.07.30 |
---|---|
6장 인터럽트와 트랩 그리고 시스템 호출 (0) | 2013.07.30 |
우분투 vim 플러그인 설치 – nerd tree (0) | 2013.07.27 |
5장 파일 시스템과 가상 파일 시스템 - 1 (0) | 2013.07.25 |
4장 메모리관리 - 2 (0) | 2013.07.24 |