그림 출처. http://e2fsprogs.sourceforge.net/ext2intro.html
파일 시스템은 자신의 관리영역에서 해당 정보를 아이노드 객체에 저장
# task_struct
: 프로세스는 자신이 사용하는 자원, 자원에서 수행되는 수행흐름으로 구성(resource + flow of control). 이를 관리하기 위해 각 프로세스마다 생성하는 자료구조.
- 프로세스, 스레드 마다 생성, 수행 이미지 공유여부 및 스레드 그룹정보를 통해 구분
- 리눅스에서는 프로세스와 쓰레드 모두 커널내부에서 태스크로 관리
fork(), clone(), pthread_create() --> sys_clone() --> do_fork() ,task_struct
vfork() --> sys_vfork() --> do_fork() ,task_struct
cf. task_struct 구조체 내부 필드 중
- pid : 태스크 별로 유일한 값
- tgid : 한 프로세스내의 쓰레드는 동일한 PID를 공유해야한다는 POSIX 표준에 따라 리눅스에서는 Thread Group ID라는 개념을 도입
- files : file_struct라는 자료구조를 가리킴(file_struct의 max_fds : 한 태스크가 오픈할 수 있는 파일의 최대 갯수를 나타내는 변수)
- fd_array : file_struct구조체의 file이라는 자료구조에 대한 포인터를 갖는 배열
유닉스 계열의 운영체제에서 일반적으로 fd, file descriptor라고 부름
fd는 함수의 리턴값을 받는 변수로, fd_array에서 해당되는 인덱스로 사용됨
일반적으로 fd_array[0]은 표준입력(stdin), fd_array[1]은 표준 출력(stdout), fd_array[2]는 표준 에러출력(stderr)으로 설정
# fd_array
: task_struct의 files변수가 가리키는 file_struct구조체내의 값으로 fd_array의 각 값들은 파일 객체를 가리킴
- 유닉스 운영체제에서는 파일 테이블이라고 부름
- 사용자 태스크에게 fd라는 정수로 파일에 접근할 수 있도록 하는 추상화 계층을 제공하는 변수
- f_dentry : 디엔트리 객체를 가리킴(해당 디엔트리 객체는 다시 연결되어있는 아이노드 객체를 가리킴)
- f_pos : 현재 피일에서 읽거나 쓸 위치를 저장(처음 파일을 오픈하였을 때는 값이 0), lseek호출을 통해 f_pos값을 바꿀 수 있음
- f_op : file_operations라는 자료구조를 가리키는 포인터(8장)
# file_operations와 inode_operations
- file_operations 구조체 : 가상적인 파일연산이 요청되면 커널에서는 요청된 파일의 유형정보 및 파일의 고유 함수를 사용하여 서비스를 제공해야하는데 이때 사용하는 구조
각 파일 유형에 적합한 파일 연산들이 저장되는 변수
각 파일시스템 유형에 적합한 파일시스템 연산들이 저장되는 변수
=> 리눅스가 다양한 파일과 파일시스템을 지원할 수 있는 비밀병기
# task_struct와 VFS
그림 출처. http://www.redirfs.org/docs/thesis/
- 파일의 이름을 인자로 시스템콜을 호출
- VFS가 아이노드 객체를 인자로 파일시스템 내부의 해당 함수를 호출
- 필요한 정보를 아이노드 객체에 채운 후 리턴
- VFS는 해당 아이노드 객체를 디엔트리 객체에 연결시킨 후 사용자 태스크 구조와 연결
# f_op
: 파일시스템마다 구현된 함수들이 다른데, 해당되는 파일 유형에 맞는 연산이 등록되는 변수
예. file -> f_op -> open()
- ext2 : ext2의 open(), linux/fs/ext2/file.c에 구현
- NFS : nfs_file_open()
- 파이프 : fifo_open()
- 장치파일 : chrdev_open() / blkdev_open(), linux/fs/device.c에 구현
# sys_open()
- 특정파일 각각의 open()함수들의 호출 후 filp_open()함수 리턴
: 태스크에서 현재 사용하지 않는 fd_array의 한 항을 할당
- 해당 항이 생성된 파일 객체를 가리키도록 설정
- 태스크 구조와 VFS이 연결됨
# sys_read()함수
: 인자로 전달된 fd를 이용해 파일 객체를 찾고 해당 f_op에 등록된 read함수를 호출, linux/fs/reead_write.c에 구현
- 우선 요청 데이터가 캐시에 있는지 찾음
- 캐시에 있으면 디스크에 안가고 바로 데이터를 사용자에게 전달, 없다면 디스크로 접근
- 이때 각 파일시스템은 서로 다른 방식으로 디스크를 관리하므로 각 파일시스템은 서로다른 디스크 연산함수를 사용하며 해당 처리가 필요함
-> 특정 파일시스템에 맞는 디스크 연산 함수를 호출할 수 있도록 inode_operations구조체를 사용
-> include/linux/fs.h에 정의
-> inode와 관련한 연산을 나타내는 변수로 구성(create, lookup, link, mkdir, mknod, readpage...)
-> 즉, 각 파일세스템에 고유한 연산들이 저장
# 파일의 사용과 파일시스템의 사용
- f_op와 i_op : 각 파일과 파일시스템에 고유한 연산을 제어를 전달하는 진입점 역할을 수행하는 변수
- 파일에 접근(새로운 장치를 위한 장치파일 연결)을 위해 디바이스 드라이버를 사용하여 새로운 file_operations 구조를 작성해 커널에 등록
- 파일시스템의 경우 file_operations구조 및 register_filesystem()이라는 커널내부함수를 사용하여 inode_operations구조도 작성하여 커널에 등록
# register_filesystem()
- linux/fs/filesystems.c에 구현
- struct_file_system_type 자료구조를 인자로 받음, include/linux/fs.h에 정의
<항목>
- name : 파일시스템을 나타내는 변수. ext2, ext3 ...
- fs_flags : 속성정보 저장 변수. 물리장치필요여부, 읽기전용여부...
- mount : 수퍼블록을 읽어 파티션을 마운트 하는 함수의 포인터 저장 변수
- 복수개의 file_system_type구조들의 연결을 위한 리스트와 모듈 정보 등
- ...
- register_filesystem()으로 커널에 등록된 파일시스템은 하나의 file_system_type 자료구조를 가짐
- 커널의 존재하는 모든 file_system_type은 리스트로 연결
- file_systems라는 커널 내의 전역변수가 file_system_type리스트의 시작을 가리킴
# File System의 마운트 요청,
- file_systems에서 검색하여 요청된 file_system_type 자료구조 찾기
- get_sb에 기록된 함수를 호출하여 파일시스템의 수퍼블럭정보를 얻어옴
- 얻어온 수퍼블럭정보를 VFS의 수퍼블럭 객체에 저장
- 수퍼블럭을 읽어 해당 파일시스템의 자세한 정보를 얻어옴
- 이 자세한 정보로 inode_operations, file_operations에 접근이 가능
# VFS의 내부구조
그림 출처. http://www.read.cs.ucla.edu/111/2006fall/notes/lec14
그림 출처. https://www.usenix.org/legacy/event/usenix01/full_papers/kroeger/kroeger_html/node8.html
- 태스크는 시스템 콜 인터페이스로 VFS와 통신
- 태스크가 원하는 내용은 커널내부의 페이지캐시(캐시역할)을 통할수도 있음
- 캐시에 없다면 실제 디스크와 I/O 수행
- 이때 디엔트리 객체와 아이노드 객체를 위한 캐시를 일반데이터블럭을 위한 캐시공간과 분리하여 성능향상을 도모
- VFS내에 존재하는 객체의 연결관계를 이용해 inode_operations, file_operations 구조체의 함수를 호출
- 가상계층과 물리는 실제 디스크와 I/O하는 부분에서는
커널내의 일반 블록 게층(Generic Block Layter)의 gendisk를 관리하는 블록 디바이스 드라이버에게 I/O 요청을 해야함
- 성능향상을 위해 리눅스는 자체적인 디스크 I/O 스케줄링 알고리즘(3가지 Elevator알고리즘)을 통해 요청을 보냄
참고.
리눅스 커널 내부구조(책)
'System > Linux Kernel' 카테고리의 다른 글
Device Tree, 리눅스 커널 4.0 (0) | 2015.08.29 |
---|---|
메모리관리 (0) | 2015.08.18 |
인터럽트 / 트랩 (0) | 2015.08.16 |
리눅스 부팅과정과 런레벨 (0) | 2015.08.13 |
Linux File System (0) | 2015.08.13 |