티스토리 뷰

세상에는 매우 다양한 형태의 저장장치들이 존재한다. 우리가 흔히 데스크톱이나 노트북에 장착하여 주 저장장치로 사용하는 하드 디스크, SSD 부터 시작하여 휴대가 간편한 USB도 있고, 음원과 같은 파일은 CD에 저장되기도 한다. 이러한 다양한 형태의 장치들은 각자의 파일들을 잘 유지하기 위해서 독자적인 파일시스템을 가지고 있다. 왜냐하면 각각의 장치들은 다른 방식으로 동작하고 있기 때문이다. 혹은 파일시스템이 워낙 다양하기 때문에 그렇다면 파일시스템이란 무엇일까?

 

 

 

파일시스템(FileSystem)

 

 

파일시스템은 간단하게 정의하면 '파일이나 자료를 쉽게 발견 및 접근할 수 있도록 보관 또는 조직하는 체제'이다. 즉 저장장치 내에 저장된 여러 개의 파일들을 고유하게 분류할 수 있는 체계가 필요하고 각각을 읽고 쓰기 위해서 특정한 약속을 정하는 것이다. 가장 쉽게 이 존재를 확인할 수 있는곳은 바로 각자의 Windows에 설치되어있는 파일 탐색기이다. 우리는 아무런 의심없이 폴더를 생성하고 거기에 문서파일을 넣을 수도 있으며, 필요 시 삭제도 할 수 있다. 이런 것들이 가능한 이유는 각각의 파일을 체계적으로 관리하고 분류해주는 파일시스템이 존재하기 때문이다.

 

대표적으로 대부분의 리눅스 배포판은 EXT4라는 파일시스템을 사용하고 있고, USB에서 많이 사용되는 FAT도 있고, MS 시스템에서 많이 사용되는 NTFS등의 파일시스템이 존재한다.

 

 

 

가상 파일시스템(VFS - Virtual FileSystem)

 

 

파일시스템이 저장장치 내의 파일을 체계적으로 관리해주는 역할을 하는 것은 어느정도 이해가 됐다. 그렇다면 이런 경우를 생각해보자. 어떤 우분투 PC에 USB를 꼽고 그 안에 파일을 넣는 작업을 할 때 우리는 어떠한 불편함도 느끼지 않는다. 하지만 가만히 생각해보면 그 둘은 다른 파일시스템을 사용하고 있으며, 각 파일시스템은 파일 관리방법과 읽기, 쓰기의 방식이 모두 다르다. 그러나 우리는 이러한 일들을 아무런 어려움 없이 해낸다.

 

이러한 일을 가능하게 해주는 것이 가상 파일시스템(이하 VFS)이다. 설명을 하기전에 아래 그림을 확인해 보자.

 

 

VFS를 통한 파일시스템 공존

 

 

VFS의 정의는 '파일시스템 관련 인터페이스를 사용자 공간 어플리케이션에 제공하는 커널 서브시스템'이다. 그림을 보면 어느정도 이해가 될 것이다. VFS는 다양한 파일시스템들이 공존할 수 있도록 공통된 인터페이스를 제공해준다. 즉 open(), read(), write() 등의 시스템콜을 호출했을 때, 각 파일시스템이나 물리적 매체의 종류와 상관없이 동작하게 해주는 역할을 한다.

 

아래의 그림은 사용자 공간에서 write()라는 시스템 콜이 발생했을 때, 실제 디바이스까지 어떻게 전달되는지를 보여준다.

 

 

 

 

1. 사용자가 write() 시스템 콜을 호출한다.

2. VFS는 sys_write() 함수를 호출하여 실제 파일시스템의 쓰기 함수를 호출된다.

3. 실제 파일시스템의 쓰기 함수가 실행된다.

4. 물리적 장치에 쓰여진다.

 

위와 같은 순서로 VFS는 사용자가 write()라는 함수를 호출해도 자체적으로 파일시스템에 알맞는 함수를 호출하여 쓰기를 진행하기 때문에 사용자는 연결된 파일시스템이 어떤 것이냐를 신경쓰지 않고도 읽고 쓰기를 자유롭게 할 수 있는 것이다. 이러한 추상화 기능을 제공하는 계층을 파일시스템 추상화 계층이라고 한다.

 

그렇다면 리눅스에서는 이러한 파일시스템을 추상화하기 위해서 어떤 구조를 사용하고 있을까? VFS의 주요한 네 가지 객체는 슈퍼블록(SuperBlock), 아이노드(Inode), 덴트리(Dentry), 파일(File)이 있다. 아래에서 자세하게 각각을 알아보자.

 

 

 

슈퍼블록(SuperBlock)

 

 

슈퍼블록 구조체는 linux-5.0.1/include/linux/fs.h 안에 정의되어 있다. linux-5.0.1은 버전에 따라서 폴더이름이 달라지므로 주의하자. 슈퍼블록은 각 파일시스템별로 구현하며, 본질적인 파일시스템 메타데이터이다. 여기에는 파일시스템의 유형과 크기, 상태, 다른 메타데이터 구조체(아이노드 등)의 정보가 들어있다. 슈퍼블록은 매우 중요하기 때문에 복사본을 여러 곳에 저장해 놓기도 한다. 

 

 

 

 

위 사진은 실제 linux-5.0.1 버전 커널 소스에 존재하는 struct super_block의 일부 모습이다. 위에서 '객체'라고 설명했지만, 실제로는 C코드로 만들어져 있어, 일반적으로 생각하는 객체의 모습은 아니다. 단지 struct에 함수 포인터와 멤버변수를 넣어 객체처럼 동작하도록 구현한 것으로 생각하면 되겠다. 상당히 많은 멤버들이 존재하지만 이 중 super_operations 구조체가 있는데, 이는 슈퍼블록에 대한 모든 동작에 대한 함수포인터가 멤버로 존재한다. 이 외의 대부분의 멤버들은 아이노드의 리스트, 파일시스템 유형 등의 정보를 가지고 있다.

 

아래 그림은 struct super_operation의 코드이다.

 

 

 

 

 

아이노드(Inode)

 

 

슈퍼블록이 파일시스템 전반에 걸친 메타데이터를 저장했다면, 아이노드파일 각각의 메타데이터를 유지한다. 슈퍼블록은 이 아이노드들의 리스트를 유지하여 각각의 파일에 대한 메타데이터를 유지한다. 아이노드는 파일의 주인(User, Group), 접근 권한, 파일 타입 등의 다양한 파일 정보를 유지한다.

 

리눅스 시스템의 경우에는 디스크에 아이노드를 유지하고 있어서 메모리에 읽어오기만 하면되지만, 특정 파일시스템의 경우에는 아이노드를 자체적으로 유지하고 있지 않은 파일시스템도 존재한다. 따라서 이러한 파일시스템들은 디스크에 아이노드가 저장되어 있지는 않지만, VFS에 마운트 되기 위해서는 반드시 메모리 상에 아이노드 객체를 구축해야한다.

 

struct inode는 슈퍼블록과 동일하게 linux-5.0.1/include/linux/fs.h에 정의되어 있다. 아래 그림은 아이노드 구조체의 일부 코드이다. 아이노드 역시 inode_operations 구조체가 아이노드 동작의 모든 함수포인터를 가지고 있다.

 

 

 

 

 

덴트리(Dentry)

 

 

덴트리(Dentry)는 디렉토리 엔트리(Directory Entry)의 약자이다. 덴트리는 아이노드의 번호와 파일 이름을 관련하여 파일과 아이노드를 연결시켜주는 역할을 한다. 또한 덴트리는 캐시를 유지하여 자주 접근되는 경로를 더 빠르게 접근할 수 있도록 도와준다. 또한 디렉토리와 그 디렉토리에 있는 파일들의 관계를 유지하기도 한다.

 

예를들어 /homw/yun/Document/hello.txt 라는 경로가 있다고 하면, 각각의 경로를 덴트리 객체로 유지한다. /, home, yun, Document, hello.txt와 같이 각각의 모든 경로들을 객체화시킨다. 왜냐하면 경로 탐색은 문자열 비교가 필요한 작업이기 때문에 상당히 비용이 큰 작업이다. 따라서 이러한 비교 작업을 계속해서 반복하는 것은 비효율적이므로 이를 객체화시켜 반복되는 작업을 없애는 것이다.

 

덴트리 객체는 슈퍼블록이나 아이노드와 같이 디스크에 저장되는 것이 아닌, 메모리에서 사용자 패턴에 동적으로 생기고 없어진다. 다음 사진은 struct dentry의 코드이다. 이 구조체는 linux-5.0.1/include/linux/dcache.h 에 정의되어 있다.

 

 

 

 

덴트리는 캐시에 유지된다고 위에서 언급했다. 그렇다면 어떤 기준으로 덴트리가 캐시에 쓰여지고 지워지게 되는지 알아보자. 덴트리 캐시는 세 가지 상태를 가진다.

 

사용 - 사용자가 한 명 이상있는 상태, 유효한 아이노드를 가리키는 상태

미사용 - 사용자가 없는 상태, 유효한 아이노드를 가리키는 상태

부정 - 사용자가 없는 상태, 유효한 아이노드를 가리키지 않는 상태

 

사용 상태의 덴트리는 캐시에서 절대 삭제되지 않는다.

미사용 상태의 덴트리는 유효한 객체를 가리키고 있기 때문에 캐시에 유지된다. 사용자가 사용하고 있지 않더라도 공간 지역성, 시간 지역성의 특성에 따라 다시 불릴 확률이 높기 때문이다. 만약 메모리가 부족해지면 폐기될 수는 있는 상태이다.

부정 상태의 덴트리는 사용되지도 않으면서 가리키는 아이노드도 유효하지 않은 상태이다. 이러한 부정 상태는 당연히 필요없어 보이지만, 파일이 존재하지 않는다는 정보도 유지할 의의가 있기에 캐시에 유지한다.

 

따라서 VFS는 경로명을 사용할 때마다 먼저 덴트리 캐시에서 찾고, 캐시에 없을 경우 직접 경로를 탐색한다.

 

덴트리 구조체에도 dentry_operations 구조체가 존재하여 동작을 유지한다.

 

 

 

파일(File)

 

 

파일 객체는 프로세스가 사용중인 파일을 표현하는 객체이다. 사용자 공간에서 가장 먼저 보이는 것이 파일 객체이다. 프로세스는 슈퍼블록, 아이노드, 덴트리가 아닌 파일을 직접 다룬다. 파일 객체는 파일이 어디에 저장되어 있는지, 어떤 프로세스들이 사용하고 있는지를 유지한다.

 

파일 객체는 linux-5.0.1/include/linux/fs.h 파일에 정의되어 있다. 아래는 struct file 객체 코드이다.

 

 

 

 

파일 객체의 file_operations 구조체는 파일 객체 관련 함수 포인터를 가지고 있는데, 우리에게 친숙한 read(), write(), seek(), open() 과 같은 함수로 구성되어 있다.

 

 

 

정리

 

 

지금까지 파일시스템이 무엇인지를 알아보고 그 파일시스템을 관리하기 위한 추상화 계층인 VFS, VFS의 내부 객체들을 알아보았다. 한 마디로 정리하자면, 각각의 파일시스템을 모두 수용하기 위해서 VFS라는 추상화 계층을 만들게 되었다는 것이다. 그리고 내부적으로 슈퍼블록, 아이노드, 덴트리, 파일 객체를 통해 동작이 이뤄진다.

 

1. 모든 파일시스템은 그 정보를 유지하는 슈퍼블록을 하나씩 가진다.

2. 슈퍼블록은 그 안에 속한 파일들의 아이노드들의 포인터를 가지고 있다.

3. 아이노드는 각각의 파일에 대한 정보를 가지고 있다.

3. 파일의 경로는 모두 덴트리 객체로 메모리상에 저장된다.

4. 파일 객체는 프로세스가 사용중인 객체이다.

 

 

 

참조

 

 

Linux Kernel Development (3rd Edition) - Robert Love

https://unix.stackexchange.com/questions/4402/what-is-a-superblock-inode-dentry-and-a-file

 

What is a Superblock, Inode, Dentry and a File?

From the article Anatomy of the Linux file system by M. Tim Jones, I read that Linux views all the file systems from the perspective of a common set of objects and these objects are superblock, ino...

unix.stackexchange.com

https://ko.wikipedia.org/wiki/%ED%8C%8C%EC%9D%BC_%EC%8B%9C%EC%8A%A4%ED%85%9C

 

파일 시스템 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 둘러보기로 가기 검색하러 가기 파일 시스템(file system, 문화어: 파일체계)은 컴퓨터에서 파일이나 자료를 쉽게 발견 및 접근할 수 있도록 보관 또는 조직하는 체제를 가리키는 말이다. 파일 시스템은 통상 하드 디스크나 CD-ROM 같은 실제 자료 보관 장치를 사용하여 파일의 물리적 소재를 관리하는 것을 가리키나 네트워크 프로토콜(NFS, SMB, 9P 등)을 수행하는 클라이언트를 통하여 파일 서버 상의 자료로의 접

ko.wikipedia.org

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함