CS/운영체제

[OSTEP 영속성(persistence)]파일과 디렉터리

빙응이 2025. 6. 4. 00:53

📝서론 

이번 장에서는 영속 저장 장치라고 하는 또 하나의 핵심적인 가상화 퍼즐을 알아보자.

 

하드 디스크 드라이브 또는 좀 더 최근의 솔리드 스테이트 드라이브(SSD)와 같은 저장 장치는 영구적으로 정보를 저장한다.
전원 공급이 차단 되어도 그대로 데이터를 보존하며 운영체제는 이러한 장치를 더 신중히 다뤄야한다.

 

핵심 질문 : 어떻게 영속 장치를 관리하는가?
운영체제는 어떻게 영속 장치를 관리할까?
구현에서의 중요한 측면은 무엇일까

 

 

들어가기 앞서 우리는 Unix의 파일 시스템을 볼 것이다. 

 

 

📝파일과 디렉터리

저장 장치의 가상화에 대한 두 가지 주요 개념이 개발되었다.

  • 파일
    • 단순히 읽고 쓸 수 잇는 순차적인 바이트의 배열
    • 각 파일은 저수준의 이름을 갖고 있으며 보통 숫자로 표현되며 사용자는 알지 못한다.(아이노드 번호)
    • 대부분 시스템에서 운영체제는 파일의 구조를 모른다.
    • 파일 시스템의 역할은 그러한 데이터를 디스크에 안전히 저장하고 조회하는 것이다. 
  • 디렉터리 
    • 저수준의 이름을 갖는다.(아이노드 번호)
    • 파일과 달리 디렉터리의 내용은 구체적으로 정해져 있다.
    • 디렉터리는 사용자가 읽을 수 있는 이름, 저수준의 이름으로 이루어져있다.
      • 디렉터리의 읽을 수 있는 이름은 아이노드 번호와 연결된 테이블을 통해서 식별된다.
    • 디렉터리 내에 다른 디렉터리를 포함함으로써 계층을 형성할 수 있다.
      • 예를 들어보자면 루트 디렉터리(/)로 시작하여 /C#/사용자/hello.txt 같은 것이다.
    • 디렉터리도 사실 하나의 파일이지만 더 확장된 버전인 것
중간으로 생각해보면 저장 장치의 가상화는 무엇일까요?
디스크는 블록 단위로 저장되며 단순히 블록 번호로 구분합니다.
파일 시스템이 이 디스크에 질서를 부여하여 가상화를 이루어내는 것입니다.
그 개념의 핵심이 바로 아이노드 번호와 파일, 디렉터리가 되는 것입니다.

 

📝파일의 생성

int fd = open("foo", O_CREAT | O_WRONLY | O_TRUNC);

파일은 open 시스템 콜을 사용하여 생성할 수 있다. open()을 호출하면 O_CREAT 플래그를 전달하여 프로그램이 새로운 파일을 만든다. 

  • O_CREAT : 파일 생성 플래그
  • O_WRONLY : 파일이 열렸을 때 쓰기만 가능한 플래그
  • O_TRUNC : 파일이 이미 존재한다면 기존 내용을 모두 삭제하고 여는 플래그

 

해당 명령어는 파일 디스크립터가 관리한다. 물론 사용하려면 해당 파일에 대한 권한이 있어야한다. 

 

📝파일의 읽기, 쓰기 

파일이 있다면 그 파일을 당연히 읽거나 쓸 수 있다. 

 prompt>stracecatfoo
 ...
 open(“foo”, O_RDONLY|O_LARGEFILE)= 3
 read(3,“hello\n”, 4096)=6
 write(1,“hello\n”, 6)=6
 hello
 read(3,“”, 4096)=0
 close(3)= 0
 ...
 prompt>

 

 

1 `open("foo", O_RDONLY | O_LARGEFILE) = 3` 파일을 열며 파일 디스크립터의 번호를 리턴
2 read(3, "hello\n", 4096) = 6 파일 디스크립터 3으로부터 최대 4096바이트를 읽습니다. 실제로는 "hello\n" (6바이트)를 읽었습니다.
3 write(1, "hello\n", 6) = 6 읽은 내용을 표준 출력(파일 디스크립터 1)에 씁니다. "hello\n"이 출력됩니다.
4 read(3, "", 4096) = 0 파일의 끝(EOF)에 도달했기 때문에 더 이상 읽을 내용이 없고, 0을 반환합니다.
5 close(3) = 0 파일 디스크립터 3을 닫아 파일을 종료합니다.

 

해당 로그에 나온 명령어는 모두 시스템 콜이다.

 

 

📝 fsync()를 이용한 즉시 기록

write() 호출의 목적은 대부분 해당 데이터를 가까운 미래에 영속 저장 장치에 기록해달라는 요청이다.

성능상의 이유로 파일 시스템은 쓰기를 지연하여 메모리에 모은다 

그러나 드물게 데이터가 메모리의 오류로 데이터가 유실되는 경우가 발생한다. 

즉, fsync()를 호출해서 파일 시스템은 지정된 파일의 모든 더티(변경된) 데이터를 디스크에 강제로 저장한다.
영속성을 보장하는 것이다. 

 

📝 파일 정보 추출

파일 시스템은 각 파일에 대한 정보를 보관한다. 파일에 대한 정보를 메타 데이터라고 부른다.

시스템 콜을 이용해 볼 수 잇으며 많은 정보를 확인할 수 있다. 

 

 struct stat {
 	dev_t st_dev;
 	ino_t st_ino;
 	mode_t st_mode;
 	nlink_t st_nlink;
 	uid_t st_uid;
 	gid_t st_gid;
	dev_t st_rdev;
	off_t st_size;
 	blksize_t st_blksize;
 	blkcnt_t st_blocks;
 	time_t st_atime;
 	time_t st_mtime;
 	time_t st_ctime;
 };

 

 

 


 

유닉스의 파일 생성, 삭제, 이름 변경, 디렉터리의 생성 등은 직접 실습해보시기 바랍니다.

 

 

📝 하드링크

 

파일 삭제 시에 unlink() 시스템 콜을 사용하게 된다.

  • unlink()는 파일 이름과 디렉터리 엔트리 연결을 끊는 역할을 한다.
  • 파일 데이터가 저장된 실제 데이터는 여러 파일 이름을 가리킬 수 있다. 
  • 파일 이름을 모두 unlink() 해서 연결을 끊으면 더 이상 참조되는 이름이 없으므로 커널이 데이터를 삭제한다.

link(oldpath, newpath)는

  • 기존 파일(경로명 oldpath)에 대해
  • 새로운 경로명 newpath로 하드링크를 추가하는 것입니다.

결과적으로...

  • 동일한 파일 데이터(아이노드)를 가리키는 여러 이름이 만들어진다.
  • 모든 이름이 같은 파일에 대한 포인터 역할인 셈이다.
더보기

이걸 배우면서 떠오른 생각은 이름을 변경시에는 link() unlink() 모두 쓴다는 사실이다.

새로운 이름으로 하드 링크를 만들고 기존 이름을 unlink 해서 끊는 것이다.

 

📝 심볼릭 링크

또 다른 아주 유용한 링크가 있다.

심볼릭 링크라 하고 때로는 소프트 링크라고 부른다.

 

하드링크는 사실 제한이 많은 편이다.

  • 디렉터리에 대해서는 하드 링크를 만들 수 없다(디렉터리 트리에 순환 구조를 만들까 우려)
  • 다른 디스크 파티션의 파일에 대해서도 하드 링크를 걸 수 없다.

그렇기에 심볼릭 링크가 탄생했다.

심볼릭 링크는 별도의 파일로 존재하며, 그 안에 원본 파일의 경로명을 저장한다.

그래서 심볼릭 링크는 원본 파일이 어디 있는지 경로만 알고있어 파일 내용과 독립적이다. 

 

 

📝 파일 시스템 생성과 마운트

파일과 디렉터리 그리고 몇 가지 종류의 링크를 살펴보았다.

아직 논의해야 하는 의제가 있다.

 

다수의 파일 시스템들이 존재할 때 이들을 어떻게 묶어서 큰 디렉터리 트리로 구성하는가?

 

 

유닉스는 여러 개의 파일 시스템 파티션들이 모여 하나의 큰 디렉터리를 구성한다.

각각의 파일 시스템을 생성하고, 이들을 마운트 함으로써 단일 디렉터리 트리를 구성한다. 

 

파일 생성 도구 mkfs
  • mkfs는 특정 파티션에 새로운 파일 시스템을 생성할 수 있다.
    • 예) mkfs -t ext3 /dev/sda1 : /dev/sda1 파티션에 EXT3 형식의 빈 파일 시스템을 만듭니다.
  • 생성된 파일 시스템은 자신만의 독립된 디렉터리 구조(루트 디렉터리 / 포함)를 가집니다.
파일 시스템 마운트
  • 새로 생성된 혹은 기존 파일 시스템을 운영체제가 기존 디렉터리 트리에 연결하는 작업을 마운트라고 합니다.
  • 마운트할 때는 기존 디렉터리 중 하나를 마운트 기점으로 지정합니다.
    • 예) mount -t ext3 /dev/sda1 /home/users → /dev/sda1 파일 시스템을 /home/users 디렉터리에 연결합니다.
  • 이렇게 하면 /home/users 경로 아래에서 /dev/sda1 파티션의 내용을 접근할 수 있게 됩니다.
  • 여러 개의 개별 적인 파일 시스템을 갖는 대신에 마운트는 모든 파일 시스템들을 하나의 트리 아래에 통합시키는 것입니다.

 

 

📝요약

1. 영속 저장 장치란?

  • 하드디스크(HDD), 솔리드 스테이트 드라이브(SSD) 등 전원이 꺼져도 데이터를 유지하는 저장 장치.
  • 운영체제는 이러한 장치를 신중히 관리해야 한다.

2. 저장 장치 가상화의 핵심 개념: 파일과 디렉터리

  • 파일: 순차적인 바이트 배열, 내부 식별 번호(아이노드 번호)를 가짐. 운영체제는 파일 내용 구조를 모름.
  • 디렉터리: 이름과 아이노드 번호를 가진 특별한 파일. 이름과 아이노드 번호 매핑 테이블로 구성되어 있고, 계층 구조 형성 가능.
  • 디스크는 블록 단위로 저장되며, 파일 시스템이 이를 정리해 가상화 구현.

3. 파일 생성과 조작

  • open() 시스템 콜로 파일 생성 가능. 예) open("foo", O_CREAT | O_WRONLY | O_TRUNC)
  • 플래그 설명
    • O_CREAT: 파일 생성
    • O_WRONLY: 쓰기 전용
    • O_TRUNC: 기존 파일 내용 삭제 후 열기
  • 파일 읽기/쓰기: read(), write() 시스템 콜 사용
  • 파일 작업은 시스템 콜을 통해 이루어짐 (예: open, read, write, close)

4. 데이터 영속성 보장: fsync()

  • 일반적으로 쓰기 작업은 메모리에 잠시 보관 후 디스크에 기록 (성능 최적화).
  • fsync() 호출 시 변경된 데이터를 즉시 디스크에 기록해 데이터 유실 방지.

5. 파일 메타데이터

  • 파일 관련 정보(메타데이터)는 struct stat 구조체로 확인 가능.
  • 주요 정보: 아이노드 번호, 크기, 권한, 생성 및 수정 시간 등.

6. 파일 링크

  • 하드 링크 (link()): 동일 아이노드를 가리키는 여러 파일 이름 생성. 모든 이름이 unlink() 되어야 실제 데이터 삭제됨.
  • 심볼릭 링크: 별도의 파일에 원본 경로명 저장. 디렉터리에도 만들 수 있고, 다른 파티션 파일도 링크 가능.

7. 파일 시스템 생성과 마운트

  • 여러 파일 시스템(파티션)(예. C드라이브, D드라이브)을 하나의 디렉터리 트리로 통합하는 과정 필요.
  • mkfs 명령어로 파일 시스템 생성 (예: mkfs -t ext3 /dev/sda1).
  • mount 명령어로 파일 시스템을 특정 디렉터리에 연결하여 단일 트리로 구성 (예: mount -t ext3 /dev/sda1 /home/users).