How the Unix Kernel Represents Open Files
리눅스 파일은 여러 가지 방법으로 공유할 수 있다. 커널이 열린 파일을 어떻게 나타내는지 명확하게 파악하지 못하면 파일 공유에 개념이 혼란스러울 수 있다. 커널은 세 가지 관련 데이터 구조를 사용하여 열린 파일을 나타낸다.
Decriptor table
각 프로세스에는 프로세스의 열린 file discriptor에 의해 인덱싱되는 항목이 있는 고유한 decriptor table이 있다.
열려 있는 각 dicriptor entry는 file table의 entry를 가리킨다.
File table
열려 있는 file set은 모든 프로세스에서 공유되는 file table로 나타난다. 각 file table 항목은 현재 파일 위치, 현재 파일 위치를 가리키는 descriptor의 수 v-node table의 항목에 대한 포인터로 구성된다. descriptor를 닫으면 연관된 file table entry의 참조 count가 감소한다. 참조 count가 0이 될 때까지 커널은 file table 항목을 삭제하지 않는다.
v-node table
v-node table은 file table과 마찬가지로 모든 프로세스에서 공유된다. 각 entry에는 st_mode 및 st_size 멤버를 포함한 stat구조 내의 대부분의 정보가 포함된다.
Example - Typical Kernel data structures for open files
descriptor 1과 4가 서로 다른 2개의 파일을 별개의 file table entry를 통해 참조하는 예이다.
파일이 공유되지 않고 각 descriptor가 개별 파일에 대응된다. -> No sharing.
Example - File Sharing
여러 descriptor가 다른 file table entry를 통해서 같은 파일을 참조할 수도 있다.
옐르 들어, 같은 파일명으로 open 함수를 두 번 호출했을 때 이 문제가 발생할 수 있다.
각 descirptor마다 고유한 파일 위치가 있기 때문에 decriptor마다 다른 읽기가 파일 내의 다른 위치에서 데이터를 가져올 수 있다.
Example - fork
자식 프로세스는 부모 프로세스의 descriptor table을 모두 복사한다. 커널이 대응하는 file table entry를 삭제하기 전에 부모와 자식 모두 descriptor를 닫아야 한다.
I/O Redirection
Linux 쉘은 사용자가 표준 입출력을 disk file과 연결할 수 있는 I/O 리다이렉션 연산자를 제공한다.
ls > foo.txt
예를 들어 위 명령어 라인을 터미널에 입력하면 쉘이 ls 프로그램을 로드하고 실행하며 표준 출력이 디스크 파일 foo로 redirect된다.
dup2
#include <unistd.h>
int dup2(int oldfd, int newfd);
Returns: nonnegative descriptor if OK, −1 on error
dup2 함수는 discriptor table entry인 oldfd를 descriptor table entry newfd에 복사하고 newfd의 이전 내용을 덮어쓴다. newfd가 이미 열려 있는 경우 dup2는 oldfd를 복사하기 전에 newfd를 닫는다.
Example
1. stdout으로 redirect되는 파일을 open한다.
2. dup2(4, 1)을 호출한다. -> fd 1이 fd 4를 참조한다.