본문 바로가기

컴퓨터 공학 자료(학부)/Linux

MINIX(미니 리눅스) 함수 호출시 루틴

OPEN() 함수를 유저 프로세스에서 호출할때의 파일시스템 동작 상세는 다음과 같다

자잘한 함수호출은 생락하고 바로  syscall()부터 시작하자면


대략의 계층구조는 다음과 같다.
 _syscall()의 인자 FS는 File System의 약자로써 VFS(Virtual File System)와 더불어 MINIX 운영체제의 파일시스템 계층을 구축한다. 조금 더 상세히 설명 하자면, MINIX 파일시스템은 VFS-FS 의 이원화된 two level layered structure인데, 이렇게 나누어진 이유는 NTFS, minix, EXT2, EXT3 등등 다양한 파일 시스템을 사용할 수 있게 하기 위해서이다. 즉, 다시 말해 VFS는 실제 파일 시스템인 FS(File System)보다 한 단계 위에 존재하면서 프로세스로부터 요청이 들어왔을 때 파일시스템이 어떤 파일 시스템인지(FS인지, EXT2인지, EXT3 인지 등등) 을 파악하여 그에 맞는 파일 오퍼레이션을 호출하는 역할을 담당한다. 이런 이원화된 파일 시스템 structure 덕분에 한 운영체제에 여러가지 파일 시스템을 동시에 가지는 것이 허용된다.

그림에서 볼 수 있듯이 VFS 구조 덕분에 여러 가지 파일 시스템을 적용할 수 있다.

VFS는 모든 파일 시스템이 필요로 하는 일련의 펑션을 정의하고 있다. 이러한 인터페이스는 세 종류 대상과 관련된 일련의 동작으로 구성된다. 즉 파일시스템, 아이노드, 열린 파일이다. 또한 VFS는 커널에서 지원하는 파일시스템 타입을 알고 있다. 이는 커널 구성 동안에 만들어 지는 테이블을 사용한다. 이 테이블 내의 각 엔트리가 하나의 파일 시스템 타입을 정의한다. 즉 파일시스템 타입의 이름과 펑션에 대한 포인터이다. 어떤 파일 시스템이 마운트 될 때 그에 맞는 마운트 펑션이 불려 진다. 이 펑션이 디스크의 슈퍼블록을 읽는 것을 담당하며, 내부 변수를 초기화하고 VFS는 마운트된 파일시스템 디스크립터를 돌려 준다. 파일시스템이 마운트 된 후에 VFS는 펑션은 물리적인 파일시스템 루틴을 접근하는데 이 디스크립터를 사용한다. 마운트된 파일시스템 디스크립터는 모든 파일시스템 타입에 공통된 몇 가지의 데이터를 포함한다. 물리적 파일시스템 커널코드에 의해 제공되는 펑션에 대한 포인터와 물리적인 파일 시스템 코드에 필요한 고유정보이다. 파일시스템 디스크립터에 포함된 펑션 포인터는 VFS가 파일 시스템 내부 루틴을 접근하는 것을 허용한다. 두 가지의 다른 디스크립터가 VFS에 의해 사용된다. 아이노드 디스크립터와 열린 파일 디스크립터이다. 각 디스크립터는 사용 중인 파일에 관련된 정보와 물리적인 파일시스템 코드에 의해 제공되는 일련의 동작을 갖고 있다. 아이노드 디스크립터는 어떤 파일에 대해서도 사용되는 펑션에 대한 포인터를 포함하는데 비해 (e.g. create, unlink) 파일 디스크립터는 열린 파일에 대해서만 작동하는 펑션에 대한 포인터를 갖는다. 다시 본론으로 돌아가서, int _syscall(who, syscallnr, msgptr) 함수는 인자로 받은 who, syscallnr, msgptr 을 이용하여(이는 나중에 아이노드 번호를 찾아가는데 쓰일것이다) _sendrec(who, msgptr)함수를 내부에서 호출하여서 VFS로 request를 전송하고 VFS는 MFS(Minix File System)에게 파일을 open 하라는 메시지를 보낼 것이다. 요청을 받은 MFS는 오픈 메시지를 물리적 디스크 드라이브에 보낼 것이다. 이 모든 통신은 커널을 거쳐 진행된다. syscall의 리턴값은 int형인데 이는 현재 실행되고 있는 프로세서의 파일 테이블의 파일 디스크립터중에서 사용되지 않는 fd값의 반환값이다. 언제나 stdio와 stdout이 fd[1], fd[2] 번을 차지하기 때문에 리턴되는 fd 값은 계속 3번임을 확인할 수 있었다.

fd=open(“/usr/cse/lik/data.txt”,O_RRDONLY,0)가 실행되면 위의 함수호출 절차를 거쳐서 VFS에 이르게 된다. VFS는 우선 첫 번째로 자신에게 신호를 보낸 call이 어떤 종류의 시스템콜인지 먼저 파악한다. 이를 위해서 open()함수는 _syscall(FS, OPEN, &m)에게 두 번째 인자 OPEN을 전달하는데, 이를 미리 헤더파일에 정의해두어 VFS에게 신호를 보내는 syscall함수에게 자신이 open() 함수임을 알린다. 따라서 VFS가 open()함수로부터 전달받는 메시지 프로토콜 형식을 정확히 알기위해 찾아본 결과, ‘ipc.h’ 헤더파일에 메시지 프로토콜 structure의 원형이 있음을 알게되어서 직접 찾아보았다.

찾은 메시지 프로토콜 구조의 형식은 다음과 같다. 너무 복잡해서 메시지 프로토콜의 구조를

모두 정확히는 파악하지 못했지만, 대략적으로 주소의 길이, 호출형태, 유저id, 그룹

id, path(“/usr/cse/lik/data.txt”) 등이 인자로 전달됨을 파악 할 수 있었다.

이후에 VFS는 가장 먼저 루트 FS에 접근하여 request를 전송하고, 루트 FS는 다시 VFS에게 /usr 의 정보를 포함하고 있는 아이노드 넘버와 offset등의 정보를 전송한다. 이후 VFS는 다시 /usr FS에 접근하여 /cse 디렉토리의 정보를 포함하고 있는 아이노드의 정보를 얻고, 이를 반복하여 결국 data.txt에 접근하게 된다. 이를 어떻게 찾을 수 있을까 검색 끝에, 직접 MINIX내의 VFS 디렉토리로 접근하여 파일들을 살펴보기로 하였다.

다음에서 main.c를 vim으로 열어보았다.




main.c는 입력을 기다리면서 무한 루프를 돌면서 get_work() 함수를 실행한다.

get_work()함수는 main.c에 정의되어있고 실행 루틴은 다음 그림과 같다.



여기서 시간상 포기했다 아쉽게
대략적인 실행 루틴은 다음과 같다