본문

리눅스에서 프로세스-파일간의 연결에 대해 알아보자 #1

리눅스는 다양한 파일시스템을 지원하며, 그 파일시스템 위의 파일이 동일하게 보이게 하기 위하여 VFS(Virtual File System)을 사용한다. 사용자 프로세스는 커널을 통하여 디스크의 파일에 접근한다. Process-FDT(File Descriptor Table)-FT(File Table)-VFSIT(VFS inode Table)-FS(File System)으로 이어지는 전송과정을 거친다. 밑줄 친 부분에 대해 자세히 알아보자
 
* VFS inode Table
리눅스에서는 하나의 파일이 파일데이터와 그 데이터에 관련된 inode(속성정보)로 구성된다. inode 테이블은 현재 시스템 상에 존재하는 프로세스들이 열어서 사용하고 있는 파일들의 inode정보를 갖는 테이블이다. 프로세스가 파일을 열면 커널은 inode 테이블에 빈 엔트리를 할당하고 디스크로부터 그 파일의 속성정보를 가져와 저장한다. 하나의 파일에 대해서 하나의 inode 테이블 엔트리만 존재할 수 있기 때문에 하나의 파일을 두번 이상 동시에 열 때에는 이미 할당된 inode 엔트리를 공유한다. inode 정보에는 다음과 같은 것들이 있다.
 
장치 번호 - 이 파일이 있는 디스크의 장치번호
inode번호 - inode를 식별하기 위한 번호로 한 디스크내의 모든 inode들의 번호는 고유하다.
모드 - 파일종류(파일,디렉토리등)과 접근권한(rwx)
uid, gid - 소유자와 그룹의 id
실제 장치 번호 - 파일 종류가 장치파일인 경우 실제 장치 번호
파일 크기 - 파일에 저장된 데이터의 바이트
파일 접근 시간- 최종접근, 데이터변경, 속성변경시간
i_count(참조 카운터) - 이 inode를 가리키는 파일 테이블 엔트리의 수.

* 파일 테이블
현재 열려있는 파일의 읽기/쓰기 동작을 지원하기 위한 자료구조. open()이나 creat()시스템 콜에 의해 파일이 열릴 때마다 하나씩 할당되고 close()시스템 콜에 의해 닫을 때 해제된다. 따라서 하나의 파일에 대해 동시의 여러개의 파일테이블 엔트리가 존재할 수 있다. 테이블 엔트리에는 다음과 같은 정보가 들어간다
 
열기모드 - 읽기전용(O_RDONLY), 읽기/쓰기(O_RDWR), 쓰기전용(O_WROnLY)등의 모드
플래그 - 부가적 특성(O_ASYNC, O_NONBLOCK 등)
읽기/쓰기 위치(f_pos) - 현재 읽기/쓰기 위치
f_count(참조 카운터) - 이 엔트리를 가리키는 파일 디스크립터 테이블 엔트리의 수
 
* 파일 디스크립터 테이블
이 테이블은 프로세스마다 하나씩 가지는 것으로 프로세스가 사용중인 파일을 관리하기 위한 테이블이다. 크기가 256이고 파일 테이블에 대한 포인터를 저장하는 배열이다. 프로세스가 open(), creat(), dup() 등의 시스템 호출을 할 때마다 하나의 빈 엔트리가 할당되고 해당하는 파일테이블에 대한 포인터가 들어간다. open(), creat(). dup()에 의해 반환되는 파일 디스크립터는 이 배열의 인덱스이다. close() 시스템 콜에 의해 엔트리가 제거된다
 

* 예를 들어 "file1"이라는 파일을 열기위한 fd1=open("file1", O_RDONLY) 시스템 콜은 커널 내에서 다음과 같은 일을 한다.
 
1. 디스크에서 파일(file1)을 찾아 그 inode 정보를 가져와 inode 테이블의 빈 엔트리를 채우고 참조 카운터(i_count)를 1로 한다. 그 파일의 inode 정보가 이미 테이블에 있으면 새로운 엔트리를 할당하지 않고 참조 카운터만 증가시킨다.
2. inode에 있는 접근 권한이 열기 모드를 허용하는지 조사한다.
3. 파일테이블 엔트리를 할당하고 읽기/쓰기위치(f_pos)를 0으로 한다. (만약 열기모드에 O_APPEND가 있으면 f_pos를 파일 크기와 같게 한다.) 그리고 참조 카운터(f_count)를 1로 한다.
4. fd 테이블을 처음부터 탐색해서 사용되지 않는 영역에 파일 테이블 엔트리의 포인터를 기록하고, 그 인덱스를 반환한다.

응용 프로세스가 파일을 열거나 생성하게 되면 정수로 된 파일 디스크립터를 얻게 되는데 이 파일 디스크립터는 이후에 일어나는 모든 파일 동작 즉, 읽기(read()), 쓰기(write()). 파일 동작제어(fcntl()), 파일 닫기(close())등의 동작에서 그 파일을 가리키는데 사용된다. 대부분의 리눅스 프로세스에서 파일디스크립터 0은 표준입력, 1은 표준출력, 2는 표준 오류장치를 나타내도록 미리 열려 있다. 이중 표준 입력 장치는 키보드, 표준 출력/오류장치는 모니터를 나타낸다
 
파일 테이블 엔트리파일을 열 때마다 새로 할당되고 파일 디스크립터 테이블의 엔트리는 파일 디스크립터가 새로 생성될 때마다 새로 할당된다. 한편 파일 닫기 동작 close()는 open()의 반대 과정을 수행한다. 먼저 디스크립터 테이블에서 해당 포인터를 지우고 파일테이블의 f_count를 감소시킨다. f_count가 0이 되면 이 엔트리를 해제하고 다시 inode 테이블의 i)count를 감소시킨다. inode테이블의 i_count가 0이되면 이 엔트리를 해제한다



========================
아주 오랜만에, 리눅스에 대해서 다시 공부할 일이 생겨버렸다. 예전에 다 배우고 써먹던 거지만 간만에 보는거라 아예 다시보는게 낫겠다 싶어 블로그에 정리를 해본다. 운영체제론등을 들었을때의 그 감동이 다시 몰려오는 중이다. 그때는 과제와 시험에 떠밀려 파도타기를 하던때라 이런 감흥을 즐길 수 없었는데 지금은 그런 부담이 없으니 이런 공부가 마냥 좋다.

댓글

Holic Spirit :: Tistory Edition

design by tokiidesu. powerd by kakao.