Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

137199
1107
135865


[리눅스커널][가상파일시스템] 프로세스는 파일객체 자료구조를 어떻게 관리할까? 13. 가상 파일 시스템

프로세스는 파일객체 자료구조를 어떻게 관리할까?

이전 절에서 파일을 오픈하면 프로세스가 파일 디스크립터와 파일 객체를 관리한다고 언급했습니다. 이번 소절에서는 프로세스 입장에서 파일 디스크립터와 파일 객체를 어떻게 관리하는지 살펴보겠습니다

패치 코드 소개
이해를 돕기 위해 다음 어플리케이션 코드를 소개합니다.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <signal.h>
6 #include <string.h>
7 #include <fcntl.h>
8
9 #define FILENAME_NAME "/home/pi/sample_text.text"
10
11 int main() 
12 {
13    int fd = 0;
14    ssize_t read_buf_size;
15    off_t new_file_pos;
16
17    char buf[256];
18    char string[] = "Raspbian Linux!\n";
19    
20    fd = open(FILENAME_NAME, O_RDWR);
21    
22    read_buf_size = read(fd, buf, 256);
23    printf("%s", buf);
24    
25    memset(buf, 0x0, sizeof(buf));
26
27    write(fd, string, strlen(string));
28    
29    new_file_pos = lseek(fd, (off_t)0, SEEK_SET);
30    
31    read_buf_size = read(fd, buf, 256);
32    printf("read again \n");
33    printf("[+]read buffer: %s \n", buf);
34
35    close(fd);
36
37   return 0;
38 }

먼저 20번째 줄 코드를 봅시다.

open() 함수를 호출하면 "/home/pi/sample_text.txt" 파일에 대한 핸들 정보인 파일 디스크립터를 반환합니다.
20    fd = open(FILENAME_NAME, O_RDWR);

파일 디스크립터는 정수형 타입입니다.

이후 파일 디스크립터를 write(), read() 그리고 lseek() 함수를 호출할 때 인자로 전달합니다.
22    read_buf_size = read(fd, buf, 256);
23    printf("%s", buf);
24    
25    memset(buf, 0x0, sizeof(buf));
26
27    write(fd, string, strlen(string));

여기서 한 가지 의문이 생깁니다. 유저 어플리케이션은 fd란 정수형 인자로 손쉽게 파일 관리를 합니다. 파일 상세 내용은 모르는 대신 정수형 인자 하나로 파일을 핸들링하는 것입니다. 누가 이 정수형 파일 디스크립터를 관리할까요? 그 주인공은 프로세스입니다. 

파일을 오픈하고 난 다음 읽고 쓰고 닫을 때 프로세스가 파일 디스크립터를 어떻게 관리하는지 3단계로 분류하겠습니다.
1 단계: 파일 객체 및 파일 디스크립터 생성 후 프로세스 파일 디스크립터 테이블에 등록
2 단계: 프로세스 파일 디스크립터 테이블에서 파일 디스크립터와 파일 객체 로딩
3 단계: 프로세스 파일 디스크립터 테이블에서 파일 디스크립터와 파일 객체 삭제

이번 소절에선 파일 디스크립터와 파일 객체를 프로세스가 어떻게 관리하는지 상세히 살펴봅니다.

파일 객체 파일 디스크립터 테이블 등록
먼저 1단계를 알아보겠습니다.

다음 그림을 보면서 1단계 동작에 대해 살펴봅시다.
 


위 그림은 복잡한 자료구조를 쉽게 이해하도록 재구성한 것입니다. 


위 그림에서 유저 공간에서 open() 함수를 호출해서 획득한 정수형 값인 파일 디스크립터는 커널 공간 파일 디스크립터 테이블 배열 인덱스를 의미합니다. 각 프로세스 마다 파일 객체를 관리하는 파일 디스크립터 테이블이 있는 겁니다.

위 그림에서 파일 디스크립터는 3번인데 커널 공간에서 파일 디스크립터 테이블 배열 3번을 의미합니다. 유저 공간에서 파일에 대한 핸들링은 3으로 관리하는데, 커널 공간에서는 3번 배열에 해당하는 파일 객체로 파일을 관리합니다.

파일 디스크립터로 파일 객체 로딩

다음 그림을 보면서 2단계 동작을 살펴보겠습니다.
 
유저 공간에서 3번 파일 디스크립터로 파일을 읽고 쓰고 파일 포인터를 설정합니다. 이 때 커널 공간에서는 파일 디스크립터 테이블에서 3번 배열에 해당하는 파일 객체(0xBE59EA20)로 파일을 읽고 쓰고 파일 포인터를 설정 동작을 관리합니다.

파일 디스크립터 해제

이번에 다음 그림을 보면서 마지막 3단계 동작을 확인합시다.
 

파일을 닫을 때 유저 공간에서 close() 함수를 호출하는데 이 때 정수형 파일 디스크립터를 인자로 전달합니다.

이 때 커널 공간에서 파일 디스크립터 테이블에 접근해서 3번 파일 디스크립터 테이블에 있는 파일 객체를 0x0으로 초기화합니다.

정리하면 유저 공간에서 파일을 관리하는 파일 디스크립터(정수형)는 커널 프로세스에서 파일 디스크립터 테이블 배열 인덱스에 대응합니다. 

만약 close() 함수를 호출해서 파일 디스크립터를 해제한 후 다시 해당 파일 디스크립터로 write(), read() 그리고 lseek() 함수를 호출하면 어떤 동작을 할까요?

가상 파일시스템에서 등록된 파일디스크립터가 아니므로 매크로를 반환하며 동작을 멈출 것입니다.

이번에 다른 관점으로 프로세스가 관리하는 파일 객체에 대해 생각해 봅시다.
같은 파일을 두 개 프로세스가 비슷한 시간에 오픈하고 읽고 쓰고 있다고 가정합시다. 이 때 프로세스는 어떻게 파일 디스크립터를 관리할까요? 프로세스 별로 파일 디스크립터를 생성합니다. 즉 2개 파일 객체와 파일 디스크립터가 존재하는 것입니다.

파일 객체는 이렇게 파일을 오픈하고 읽고 쓸 때 동작을 표현합니다. 파일에 대응하는 유일한 객체는 아이노드 객체입니다. 파일 객체와 아이노드 객체의 차이점은 아이노드 소절에서 다룹니다.


"혹시 궁금한 점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답변 올려드리겠습니다!" 

Thanks,
Austin Kim(austindh.kim@gmail.com)


Reference(가상 파일시스템)

가상 파일시스템 소개
파일 객체
파일 객체 함수 오퍼레이션 동작
프로세스는 파일객체 자료구조를 어떻게 관리할까?
슈퍼블록 객체
아이노드 객체
덴트리 객체
가상 파일시스템 디버깅

핑백

덧글

댓글 입력 영역