티스토리 뷰
안녕하세요 Pingu입니다.🐧
지난 글에서는 여러 개의 디스크를 한 번에 사용하여 더 빠르고, 용량도 더 크고 신뢰도도 향상하는 방법인 RAID에 대해 알아봤었습니다. 이번 글에서는 그러한 디스크에 저장하는 파일과 파일을 구분하는 디렉터리에 대해 알아보려고 합니다. 제가 공부할 때 참고하는 책인 OSTEP에서는 Chapter 39 - Files and Directories 부분입니다!
Files and Directories
지금까지 OS를 공부해 오면서 CPU를 가상화할 때 사용하던 프로세스, 메모리를 가상화할 때 사용한 가상 메모리를 통해 OS의 추상화를 살펴보았습니다. 이번 글에서는 컴퓨터 시스템에서 중요한 스토리지(저장 공간) 가상화에 대해 알아보려고 합니다. 저장공간에는 디스크, SSD 등이 있으며 메모리와는 다르게 영구적으로 정보를 저장할 수 있습니다. 이러한 저장공간을 안정적, 효율적으로 관리하는 방법에 대해 알아보고 UNIX 파일 시스템과 상호작용 하기 위해 필요한 인터페이스들에 대해 알아보도록 하겠습니다.
지금부터 알아볼 스토리지 가상화는 발전해오며 두 가지 핵심 개념이 생겨났는데요 이는 파일과 디렉터리입니다.
먼저 파일은 단순하게 보면 1차원 바이트 배열이고 각 바이트는 읽고 쓸 수 있습니다. 각 파일에는 하위 레벨의 이름이 존재하며 이러한 이름을 inode라고 부릅니다. inode에 대해서는 나중에 알아보도록 하고 지금은 그냥 파일에는 inode라는 것이 존재한다는 것만 알고 넘어가도록 하겠습니다.
두 번째 개념인 디렉터리도 파일이 갖고 있는 inode를 가지고 있지만 그 내용은 다릅니다. 디렉터리의 inode에는 사용자가 지정한 파일 이름과 inode가 쌍으로 존재합니다. 예를 들어 inode가 10이고 사용자가 지정한 파일 이름이 "pingu.txt"라면 "pingu.txt"가 존재하는 디렉터리에는 ("pingu.txt", 10)과 같은 쌍이 존재하는 것이죠. 디렉터리 안에 디렉터리가 존재하더라도 동일하게 표현할 수 있고 이러한 구조는 디렉터리 트리를 만들게 됩니다.
위의 그림과 같이 디렉터리 트리는 Root 디렉터리에서 시작하여 하위 디렉터리들을 표현할 수 있습니다. UNIX 시스템에서는 이러한 루트 디렉터리를 "/"로 표현하고 이를 사용한 파일의 절대경로는 "/dir1/pingu.txt"와 같은 구조를 가지게 됩니다. 이러한 구조로 파일 시스템의 모든 파일의 구조를 만들 수 있게 됩니다.
The File System Interface
그럼 파일 시스템 인터페이스로 이러한 파일과 디렉터리를 만들고, 접근하고, 삭제하는 방법을 알아보도록 하겠습니다. 인터페이스는 C언어로 알아보도록 할 예정입니다.
Creating Files
그럼 가장 먼저 파일을 한 번 만들어보겠습니다. 아래와 같이 open()을 호출하고 CREAT 플래그를 전달하면 프로그램이 새 파일을 만들게 됩니다.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("pingu.txt",O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
return 0
}
위와 같이 잘 만들어 지는 것을 볼 수 있습니다. open() 함수는 3가지 매개변수를 사용하는데, 첫 번째 매개변수는 직관적으로 이해할 수 있는 사용자가 지정한 파일 이름입니다. 두 번째 매개변수는 O_CREAT(파일이 없는 경우), O_WRONLY(Write, read만 가능하도록), O_TRUNC(만약 이미 pingu.txt가 존재한다면 기존의 파일 삭제 후 생성)와 같은 플래그를 사용합니다. 세 번째 매개변수는 파일 접근 권한을 설정하는 매개변수인데 S_IRUSR(User가 읽을 수 있음), S_IWUSR(User가 쓸 수 있음)을 나타냅니다.
open() 함수는 file descriptor라는 것을 반환하는데요, 이는 프로세스가 가지는 정수이며 UNIX 시스템에서 파일에 접근하는 데 사용됩니다. 파일을 연다는 것은 권한이 있다는 것을 의미하고 이는 file descriptor를 사용하여 파일을 읽거나 쓴다는 말이 됩니다. 이러한 file descriptor는 프로세스별로 OS가 관리합니다.
Reading And Writing Files
이렇게 파일을 만들게 되면 읽고 쓰기가 가능해집니다. 아까 만든 pingu.txt에 뭔가를 쓰는 작업을 해보겠습니다.
echo의 출력을 리다이렉션 하여 pingu.txt에 썼습니다. 그런 뒤에 cat을 사용하여 파일의 내용을 확인하니 아까 쓴 내용이 존재하는 것을 볼 수 있어요. cat이라는 명령어로 파일의 내용을 확인했는데 cat이 어떻게 작동하는지 궁금하니 살펴보도록 할게요. 이럴 땐 strace(mac에서는 dtruss) 명령어를 사용하면 됩니다. 직접 해보려고 했는데 mac으로 하려면 recovery 모드로 실행해야 해서 그냥 책의 예시로 대체하겠습니다.
위의 예가 cat 명령어가 실행하는 것들입니다. 제일 먼저 "foo"라는 파일을 여네요. 그러면 open 명령어가 3이라는 file descriptor를 반환하고 이는 세 개의 파일이 열려있다는 것을 의미합니다. 세 개의 파일은 standard input, standard output, standard error입니다. 그런 뒤 read()라는 시스템 콜을 사용하여 파일에서 일부 바이트를 읽는데 첫 번째 매개변수가 바로 file descriptor를 의미합니다. 아까 프로세스마다 이를 갖는다고 했는데 cat 프로세스의 file descriptor가 3이므로 3을 매개변수로 사용하는 것이죠. read()로 읽은 뒤엔 write() 시스템 콜로 이를 터미널에 출력합니다. 그런 뒤 read()를 한 번 더 호출하는데 read()는 읽을 것이 더 없을 경우엔 0을 반환합니다. 따라서 close()를 호출하여 파일이 닫히게 됩니다.
Reading And Writing, But Not Sequentially
방금 알아본 read(), write()는 연속적으로 읽고 쓰는 방법이었습니다. 하지만 어떤 특정 부분만 읽고 쓰는것이 유용할 수 있는데, 이럴 때 lseek()라는 시스템 콜을 사용하면 됩니다.
off_t lseek(int fildes, off_t offset, int whence);
위의 코드가 lseek의 함수 원형이며 3개의 매개변수를 갖는 것을 볼 수 있습니다. 첫 번째 매개변수는 이젠 익숙한 file descriptor를 의미합니다. 두 번째 매개변수가 offset으로 아래 그림과 같이 파일의 특정 위치를 가리키는 역할을 합니다.
세 번째 매개변수인 whence는 어디를 기준으로 offset을 설정할지에 대한 값으로 SEEK_SET, SEEK_CUR, SEEK_END를 가질 수 있습니다. SEEK_SET은 offset의 값만큼, SEEK_CUR은 지금 위치부터 offset을 더한 위치까지, SEEK_END는 끝에서부터 offset만큼을 더한 값만큼의 위치부터 작업을 수행하겠다는 의미가 됩니다. OS는 파일을 읽고 쓸 때 이러한 offset을 추적하여 읽고 쓰기를 시작할 위치를 결정합니다. offset을 설정하는 방법은 위와 같이 lseek()를 사용하여 설정하는 방법과 읽고 쓰기를 그냥 진행하면 마친 지점을 offset으로 설정합니다. 즉 100바이트 길이의 파일을 10바이트까지 읽었다면 다음 읽기는 10바이트부터 시작된다는 얘기가 됩니다.
몇 가지 예를 보며 offset에 대해 이해해볼까요?
위의 예는 300 바이트크기의 파일을 열어서 계속해서 100바이트씩 읽는 작업을 나타낸 표입니다. 제일 처음 파일을 열면 offset이 0입니다. 그런 뒤 100바이트를 읽을 때마다 offset이 100씩 증가하다가 300바이트를 모두 다 읽은 시점부터는 계속해서 300에 머무르는 것을 볼 수 있습니다.
그럼 이번에는 위와 같이 같은 파일을 2번 열어서 읽어보는 예를 살펴보겠습니다. 같은 파일을 열었지만 각자 다른 file descriptor를 갖는 것을 확인할 수 있습니다. OFT라는 것을 볼 수 있는데 이는 Open File Table의 약자로 각각의 file descriptor의 정보를 저장하는 값입니다. 여기엔 offset도 저장하는데요, 각각의 파일에 대한 offset이 독립적으로 유지되는 것을 볼 수 있습니다.
마지막 예는 이번에 배운 lseek를 사용할 때입니다. lseek(fd, 200, SEEK_SET) 이므로 시작점으로부터 200만큼을 offset으로 설정하겠다는 의미가 되죠? 그래서 Current Offset이 시작부터 200인 것을 볼 수 있습니다. 이 상황에서 50 바이트를 읽었으니 최종적으로는 250의 offset을 갖은 뒤 close 됩니다.
Shared File Table Entries: fork()
열린 파일에 대한 정보를 기억하는 file table이라는 자료구조가 있는데 이는 보통 file descriptor와 일대일 매핑이 됩니다. 간단히 말하면 10개의 file descriptor가 있다면 10개의 file table이 존재하는 것이죠. 다른 프로세스가 같은 파일을 읽더라도 이는 유지됩니다. 그래서 아까 동일한 파일을 읽는 예에서도 각각의 offset이 유지됐었죠?
그런데 fork()를 사용하여 프로세스를 만들게 되면 file table이 공유되어 사용됩니다. 즉 프로세스를 만든 부모 프로세스의 파일 테이블을 만들어진 자식 프로세스와 공유하는 것이죠. 그러면 자식 프로세스에서 offset이 수정된다면 부모 프로세스에도 영향을 끼치게 됩니다.
위와 같이 코드로 부모, 자식 프로세스가 파일 테이블을 공유하는지에 대해 알아볼 수 있습니다. 부모 프로세스는 자식 프로세스가 끝나길 기다리기 때문에 반드시 자식 프로세스가 먼저 수행되는데요, 자식 프로세스는 lseek를 사용하여 10만큼 offset을 수정합니다. 그러면 부모 프로세스에도 영향을 주어 부모 프로세스의 offset도 10으로 수정되게 됩니다.
이렇게 파일 테이블을 공유하게 되면 위와 같은 구조를 가지게 되는데 하나의 프로세스라도 파일 테이블을 사용하고 있다면 메모리 상에서 파일 테이블을 유지해야 하기 때문에 reference count(참조 카운트)를 사용하여 이를 관리합니다. 이는 몇 개의 프로세스가 해당 파일 테이블을 공유하는지에 대한 값으로 위의 그림에서는 2개의 프로세스가 공유하기 때문에 2라는 값을 가지게 됩니다. 후에 프로세스들이 종료되거나 프로세스가 파일을 닫으면 카운트가 줄어 0이 되면 메모리에서 해제되게 됩니다. 위에서 inode라는 것이 나오게 되는데 이건 후에 알아보도록 하겠습니다.
Writing Immediately with fsync()
데이터를 디스크에 쓸 때 write 요청이 발생할 때마다 디스크에 바로 쓰는 것이 좋을까요, 아니면 어느 정도 모았다가 쓰는 것이 좋을까요? 디스크는 속도가 느리기 때문에 메모리에 어느정도 모았다가 디스크에 쓰는것이 효율적일 것 같습니다. 물론 사용자는 디스크에 써졌다고 보이지만 실제로는 메모리에만 존재하고 아직 디스크엔 존재하지 않을 수 있습니다. 이로 인해 오류가 발생할 수도 있는데 이러한 오류를 막기 위해서 UNIX에서는 fsync()라는 인터페이스를 제공합니다.
특정 file descriptor에 fsync()를 호출하면 파일 시스템은 file descriptor가 참조하는 파일에 대한 모든 수정 사항을 디스크에 강제로 적용합니다. 쓰기가 완료되면 fsync()가 반환되게 됩니다. 즉 특정 시점에 수정된 데이터를 얻고 싶을 때 아직 디스크에 적용되지 않았을 수 있기 때문에 이를 강제로 수정한 뒤 얻겠다는 의미가 됩니다.
간단하게 fsync()의 사용법을 보면 위와 같습니다. foo라는 파일을 열고 쓰기 작업을 수행합니다. 쓰기 작업을 진행한 뒤에 fsync()를 호출하여 이를 바로 디스크에 쓰도록 만듭니다. 물론 위와 같은 방법으로 모든 오류를 방지할 수 있는 것은 아닙니다. 어떤 때는 foo가 존재하는 디렉터리를 fsync() 해야 할 수도 있습니다.
Renaming Files
보통 파일을 만들면 이름을 설정해주지 않나요? 이러한 것을 mv 명령어로 할 수 있습니다.
위와 같이 사용할 수 있는데요 pingu.txt를 hello.txt로 바꾼 예입니다. 이러한 mv 명령어는 원자적으로 수행되며 이름을 바꾸는 과정에서 뭔가 문제가 발생하면 이름을 바꾸던가, 바꾸지 않던가 둘 중 하나만 하게 됩니다.
위 예는 foo.txt라는 파일에 한 줄을 추가하는 작업을 strace로 추적한 과정을 나타낸 것입니다. 첫 번째 줄을 보면 foo.txt.tmp라는 임시 파일을 만들고 여기에 쓰기 작업을 수행합니다. 그런 뒤 fsync()로 디스크에 강제로 쓰게 만든 뒤 close 합니다. 그런 뒤 foo.txt.tmp를 foo.txt로 바꿔줍니다. 이렇게 하면 파일이 수정되는데, 사용자는 원래의 파일에 새로운 데이터가 쓰였다고 보이지만 실제로는 완전히 새로운 파일을 만들고 이 파일을 원래 파일과 교체하는 작업이 진행되는 걸 알 수 있습니다.
Getting Information About Files
파일 접근 외에도 사용자는 파일 시스템이 저장하는 각 파일에 대한 많은 정보를 저장하고 싶어 하고 이러한 데이터를 Metadata라고 합니다. 특정 파일에 대한 메타 데이터를 보려면 stat(), fstat() 시스템 콜을 사용하면 됩니다. 이를 호출하면 파일에 대한 경로를 가지고 와서 메타 데이터를 보여줍니다.
실제 메타 데이터는 위와 같은 구조를 가지게 되며 파일 시스템은 이러한 정보를 inode1이라는 구조에 보관합니다. 계속해서 inode라는 개념이 언급되는데, 이는 후에 자세히 알아볼 예정입니다! 지금은 파일에 대한 정보라 고만 이해하고 넘어가도록 하겠습니다.
실제로 위와 같이 stat을 사용하여 메타 데이터를 가져올 수 있습니다.
Removing Files
이제 파일을 생성하고 접근하는 방법을 알게 되었는데요, 그럼 삭제는 어떻게 할까요? 탐색기나 finder에서 삭제는 오른쪽 버튼을 누르면 나타나는 메뉴에서 삭제를 눌러줄 수 있는데 이를 UNIX 터미널에서 삭제하려면 rm 명령어를 사용하면 됩니다.
그럼 rm 명령어를 strace를 사용하여 분석해보겠습니다.
이렇게 foo라는 파일을 삭제하기 위해 rm 명령어를 사용한 과정을 살펴보다 보면 unlink라는 호출이 있는 것을 볼 수 있습니다. unlink()는 제거할 파일의 이름을 매개변수로 받고 성공하면 0을 반환하는데요, 왜 삭제를 했더니 unlink라는 시스템 콜이 호출되었을까요? 이를 이해하기 위해서는 이제 디스크 가상화의 두 가지 중요한 요소 중 하나인 디렉터리를 이해해야 합니다.
Making Directories
그럼 이제 디렉터리에 대해 알아보도록 하겠습니다. 먼저 디렉터리를 만드는 것 부터 알아볼게요! 디렉토리 역시 관련 시스템 콜을 사용하여 만들고, 읽고, 삭제할 수 있습니다. 디렉토리의 형식은 파일 시스템에서 메타 데이터로 간주되기 때문에 파일 시스템은 이에 대한 무결성 책임이 있다고 간주합니다. 따라서 디렉토리 안에 있는 파일, 디렉토리를 생성하는 등의 방법으로 간접적으로만 업데이트가 가능합니다. 이러한 디렉토리를 만들기 위해선 mkdir() 시스템 콜을 사용하면 됩니다. 이번에도 strace를 사용하여 mkdir을 분석해보겠습니다.
위의 내용은 strace로 mkdir foo를 분석한 내용입니다. foo라는 디렉터리를 만드는건 이해가 되는데 두 번째 매개변수인 0777은 무엇을 의미할까요? 이는 디렉토리에 대한 권한을 설정하는 값으로 모든 권한을 열겠다라는 의미입니다. 하나의 숫자가 3개의 비트로 되어있는 형태로 7은 이진수로 111입니다. 이는 r,w,x가 모두 가능하다 라는 의미를 가져요. 그런 7이 3개 있다는 것은 소유자, 그룹 사용자, 기타 사용자 모두 foo라는 디렉토리를 읽고 쓰고 실행할 수 있다는 의미를 가집니다.
근데 이렇게 빈 디렉토리를 만들고 안에 뭐가 있는지 확인하는 시스템 콜인 ls -al를 사용해보면 아래와 같이 뭔가가 존재합니다.
. 과 ..이라는 것이 존재하는데, 얘네는 도대체 뭘까요? . 은 자기 자신을 나타내는 것이고 ..은 상위 디렉터리를 나타냅니다. 즉 디렉토리간에 이동을 할 때 cd .. 이렇게 하면 상위 디렉토리로 이동해보신 경험이 있으실텐데 그게 이런 의미를 갖게 됩니다.
Reading Directories
그럼 이제 디렉토리를 만들었으니 읽어보도록 하겠습니다. 아까 잠깐 언급한 ls라는 명령어로 이를 읽을 수 있었는데요, 이는 실제로는 아래와 같이 코드로 작성할 수 있습니다.
위의 코드를 보면 opendir, readdir, closedir이라는 직관적인 이름을 가진 함수들이 있습니다. 각 반복마다 inode 번호와 각 파일의 이름을 출력하는 코드인 것을 쉽게 알 수 있어요. 위에서 보면 dirent라는 구조체가 나오는데요, 얘는 아래와 같이 정의된 자료구조입니다.
디렉터리에 대한 정보는 파일 이름, inode 번호, 다음 디렉토리 자료구조 offset, 파일의 크기, 파일의 형식으로 구성됩니다.
Deleting Directories
그럼 이젠 디렉터리를 읽고, 만드는 방법도 알았으니 마지막으로 삭제를 해보겠습니다. rmdir 명령어로 디렉토리를 삭제할 수 있습니다. 디렉토리를 삭제하는 것은 디렉토리 안의 모든 데이터를 삭제하는 일이기 때문에 원하지 않는 파일도 삭제할 우려가 있어 빈 디렉토리가 아니라면 rmdir은 실패합니다. 실제 사용방법은 아래와 같습니다.
Hard Links
아까 파일을 알아보다가 디렉터리를 알아보게된 원인을 기억하시나요? 파일을 삭제할 때 unlink라는 시스템 콜이 호출되었고 이를 알아보기 위해 디렉토리를 알아본 것이었습니다. 그럼 이제 디렉토리를 알았으니 아까의 unlink에 대해 알아보도록 하겠습니다. unlink가 있으면 link도 존재한다는 것을 느낌상 알 수 있는데요, link는 파일 시스템 트리에 항목을 만드는 방법 중 하나입니다. link는 이전 경로 이름, 새로운 경로 이름을 매개변수로 갖게 되며 실제 사용 예를 보면서 이해해보겠습니다.
ln 명령어가 link를 사용하는 명령어인데요, 위의 예를 보면 hello.txt라는 파일이 존재했었는데 ln hello.txt hello2.txt를 수행하니까 hello2.txt가 생성된 것을 볼 수 있습니다.
위의 내용을 보면 두 개의 파일은 내용도 똑같고 inode 번호도 똑같은 것을 볼 수 있어요. 즉 link는 기존의 파일에 대한 내용에 대한 inode 번호만 공유한 새로운 파일을 만드는 것이죠. 파일은 하나인데 접근 방법은 2가지 방법이 되는 것입니다. 그럼 unlink는 이러한 참조를 끊는 역할을 한다는 것을 예측할 수 있습니다. 만약 hello2.txt를 unlink 하면 어떻게 될까요?
이렇게 사라지는 것을 볼 수 있습니다. 이렇게 되더라도 hello.txt는 그대로 남아있는 것을 볼 수 있죠. 이러한 것이 되는 이유는 파일 시스템이 파일 링크를 해제할 때 reference count를 확인하기 때문인데요, reference count가 의미하는 것은 해당 파일에 연결된 파일 이름의 수입니다. 즉 지금 hello.txt가 연결된 파일의 reference count는 1이 되는 것이죠. 만약 여기서 hello.txt도 unlink 한다면 reference count가 0이 되어 해당 inode와 데이터 블록도 해제하는 실제 삭제가 발생하게 되는 것입니다. 이러한 reference count를 볼 수 있는 stat() 명령어가 있는 데 사용법만 보고 넘어가도록 하겠습니다.
위와 같이 ln을 하면 reference count가 늘어나고 unlink 하면 reference count가 줄어드는 것을 확인할 수 있습니다.
Symbolic Links
방금 알아본 link와는 다른 link가 존재하는데요 이를 Symbolic link라고 부릅니다. 참고로 아까의 link는 hard link입니다. Hard link는 파일의 inode 번호를 사용하여 연결을 하기 때문에 다른 파일 시스템에 존재하는 파일에는 사용할 수 없었습니다. Inode는 파일 시스템마다 독립적이기 때문이에요. 이러한 것을 할 수 있는 link가 바로 Symbolic link 입니다. 바로 사용법을 보며 이해해보겠습니다.
아까 사용한 ln 명령어에 -s 옵션을 주면 symbolic link를 사용할 수 있는데요 위와 같이 사용해봤더니 아까와는 다르게 inode 번호가 다릅니다. 즉 두 개의 파일이 다른 inode를 가리킨다는 것을 의미하며 각자 다른 파일임을 의미합니다. stat을 사용해서 reference count도 확인해보겠습니다.
reference count도 각각 1인 것을 확인할 수 있습니다.
ls -al 명령어를 사용하여 파일과 디렉터리를 확인해보면 hello2.txt가 좀 특이한 것을 볼 수 있습니다. hello2.txt -> hello.txt라는 것이 보이나요? 또한 젤 첫 번째 필드에 lrwxr-xr-x에서 첫 글자인 l도 특이합니다. 다른 파일들은 이 부분이 -이기 때문이죠! 참고로 디렉터리는 d입니다.
즉 위와 같이 symbolic link를 사용하면 다르게 표현된다는 것을 볼 수 있습니다. 또한 크기도 다른데요, hello.txt는 12바이트인데 hello2.txt는 9바이트입니다. 동일한 파일을 나타내는데 크기가 다른 이유는, symbolic link가 형성되는 방식이 hello.txt라는 경로를 저장하는 것이기 때문이에요. 만약 경로가 더 길게 구성된다면 크기가 더 커지는 거죠. 지금은 hello.txt라는 9바이트로 구성되어 있기 때문에 9바이트가 됩니다.
경로만 가리키고 있기 때문에 만약 해당 경로의 파일이 제거된다면 더 이상 접근할 수 없게 됩니다.
위와 같이 hello.txt를 삭제하면 symbolic link인 hello2.txt가 저장한 경로에는 아무것도 없기 때문에 위와 같이 파일이 없다고 나오게 됩니다. 이러한 문제를 dangling reference이라고 합니다.
Permission Bits And Access Control Lists
이번에는 아까 mkdir을 설명할 때 잠깐 언급됐던 권한 비트에 대해 잠깐 알아보고 가겠습니다.
위와 같이 파일과 디렉터리를 정보를 보면 첫 번째 필드에 drwxr-xr-x와 같은 정보가 있는 것을 볼 수 있습니다. 이것이 바로 권한 비트이며 해석하면 아래와 같아집니다.
위와 같이 구성됩니다. 그래서 아까 나온 숫자 777은 모든 사용자에게 읽기, 쓰기, 실행 권한을 주는 것이며 위의 예에서는 755로 그룹 구성원과 다른 사람에게는 쓰기 권한은 주지 않는 상태입니다. 이러한 권한을 바꾸고 싶다면 chmod를 사용하시면 됩니다. chmod는 두 개의 매개변수를 갖게 되는데 변경할 권한 비트와 권한을 변경할 파일 이름을 써주시면 됩니다. 직접 사용해보며 이해해보겠습니다.
처음엔 pingu.txt의 권한 비트가 544였는데 chmod 777 pingu.txt를 실행하니 777로 변경된 것을 볼 수 있습니다.
Making And Mounting A File System
이제 파일과 디렉터리 링크에 대해서 알았으니 파일 시스템 자체를 만드는 방법을 알아보겠습니다. 파일 시스템을 만드는 데는 mkfs 명령어를 사용하면 됩니다.
mkfs ext4 /dev/sda1
위와 같이 사용할 수 있는데요 첫 번째 매개변수는 파일 시스템의 종류, 두 번째 매개변수는 디스크 파이션을 나타냅니다. 해석하면 /dev/sda1 파티션을 ext4 파일 시스템으로 만들겠다!라는 의미가 됩니다. 이렇게 만들게 되면 root 디렉터리를 가지는 디스크 파티션이 하나 만들어지게 됩니다. 이러한 파티션은 fdisk로 만들 수 있습니다.
이렇게 만들어진 파일 시스템을 사용자가 볼 수 있도록 해주려면 mount를 사용해줘야 합니다. 여러 개의 파일 시스템이 있을 수 있고 이들을 하나의 트리로 구성하고 싶다면 mount를 사용하면 되는데요, 그림으로 표현하면 아래와 같아요.
이렇게 mount를 하게 되면 두 개의 파일 시스템 트리가 하나의 트리로 만들 수 있습니다. Mount point를 정하여 mount를 진행하면 해당 위치에 다른 파일 시스템의 루트를 참조하게 됩니다. 이렇게 하나의 트리로 만들어서 사용자가 보기 쉽게 만들 수 있어요
Summary
이렇게 파일과 디렉터리, 그리고 파일 시스템을 다루는 방법에 대해 알아봤습니다. 많은 명령어를 알아봤으며 hard link, symbolic link에 대해서도 알아봤었죠? 그리고 파일시스템을 만드는 mkfs, 이를 구조화하는 mount까지 알아봤습니다. 다음 글에서는 Very Simple File System이라는 아주 간단한 파일 시스템을 구현해보며 파일 시스템을 자세히 알아보도록 하겠습니다.
감사합니다!
'Computer > Operating System' 카테고리의 다른 글
[OS] Fast File System의 File System 성능향상 아이디어 - OS 공부 29 (0) | 2021.02.17 |
---|---|
[OS] 간단한 FileSystem 구현 방법 - OS 공부 28 (2) | 2021.02.08 |
[OS] Redundant Arrays of Inexpensive Disks(RAID) 알아보기 - OS 공부 26 (1) | 2021.01.30 |
[OS] Hard Disk Drive 알아보기 - OS 공부 25 (2) | 2021.01.23 |
[OS] I/O Device 알아보기 - OS 공부 24 (0) | 2021.01.19 |
- Total
- Today
- Yesterday
- Swift
- System
- BFS
- Combine
- operator
- IOS
- dfs
- Xcode
- Publisher
- 테이블뷰
- 백준
- operating
- 문법
- 아이폰
- OS
- DP
- Apple
- 앱개발
- 스위프트
- 코딩테스트
- document
- 코테
- OSTEP
- pattern
- 프로그래밍
- design
- 알고리즘
- 동시성
- 자료구조
- mac
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |