[OS] Chap13-01 : 파일 시스템 인터페이스_파일 개념
운영체제(Operating System Concepts) 를 읽고 정리한 정리본입니다.
📌 Chap13-01 : 파일 시스템 인터페이스_파일 개념
파일 시스템은 가장 많이 노출되는 범용 운영체제의 한 부분이다. 운영체제와 컴퓨터 시스템의 모든 사용자의 데이터와 프로그램을 온라인으로 저장하고 접근하는 기법을 제공한다.
파일 시스템은 크게 다음과 같은 두 가지로 구성된다.
- 파일의 집합체
- 디렉터리 구조
즉, 파일 시스템은 관련된 정보 자료를 저장하는 파일의 집합체이자 시스템 내 모든 파일에 관한 정보를 제공하는 디렉터리 구조로 볼 수 있다.
이러한 파일 시스템에서 파일은 어떤 식으로 정의를 내릴 수 있을까?
🫧 파일이란?
: 운영체제가 정보 저장을 쉽게 관리할 수 있도록 도와주는 저장 정보 단위.
컴퓨터는 NCM 장치, HDD, 자기 디스크, 자기 테이프, 광디스크 등 정보 저장이 가능하다. 운영체제는 이러한 저장된 정보를 논리적 저장 정보 단위를 통해 관리한다.
여기서의 논리적 저장 정보 단위
를 파일이라 일컫는다. 따라, 보조 저장 장치에 기록된 정보의 집합이며, 쉽게 말해 운영체제가 정보 저장 시 쓰는 논리적 단위라고 할 수 있다.
이는 자료가 파일 안에 존재해야만 보조 저장 장치에 기록 가능하고, 비휘발성이기 때문에 시스템이 재부팅되어도 저장된 내용은 영구히 존속된다는 개념을 도출해낼 수 있음을 시사한다.
🫧 파일 속성
운영체제마다 다른 파일 속성이 존재하지만, 전형적으로 다음과 같은 속성들을 가진다.
- 이름
- 식별자 : 하나의 숫자로, 파일 시스템 내에서 파일을 확인할 수 있도록 해 준다. 사람이 읽을 수 없다.
- 유형
- 위치 : 파일이 존재하는 장치와 그 장치 내 위치에 대한 포인터
- 크기 : 파일의 현재 크기와 최대 허용 가능한 크기. (바이트, 워드, 블록들로 나타냄)
- 보호 : 읽기, 쓰기, 실행에 관한 접근 제어 정보
- 타임스탬프와 사용자 식별 : 생성, 최근 변경, 최근 사용 등을 유지하고 보호, 보안 및 사용자 감시를 위해 사용
몇몇 새로운 파일 시스템은 파일의 문자 인코딩 정보와 파일 체크섬과 같은 보안 정보들을 포함하여 확장된 파일 속성 을 지원하기도 한다.
🫧 디렉터리
: 서로 관련 있는 파일을 하나로 모아놓은 것
cf) UNIX 계열에서는 디렉터리를 하나의 특수 용도를 가진 파일로 취급한다. 반면 Window 계열에서는 디렉터리와 일반 파일을 구분한다. 이는 시스템마다 조금씩 다르다.
모든 파일에 대한 정보는 파일 자신과 같은 장치에 상주하는 디렉터리 구조에 의해 유지된다.
디렉터리는 크게 두 가지로 구성되어 있다.
- 파일 이름
- 고유의 식별자 (다른 파일 속성을 찾는데 사용)
파일의 휘발성과 일치해야 하므로 파일과 같은 장치에 저장되어 있어야 한다.
🫧 파일 연산
- 파일 생성
- 파일 열기
- 파일 쓰기
- 파일 읽기
- 파일 안에서의 위치 재설정 = 파일 탐색
- 파일 삭제
- 파일 절단 = 파일 내용만 지우기
✨ 파일 생성
1) 파일 시스템 내 공간 할당
2) 디렉터리 내 새로 생성된 파일에 대한 항목 생성
✨ 파일 열기
- 생성과 삭제를 제외한 모든 연산 전 반드시 파일을 open() 해야 한다.
☁️ open()
모든 파일 연산에서 운영체제는 이름을 검사하고, 접근 권한을 확인해야 한다. 만일 포인터가 아닌 파일 이름으로 파일 연산을 수행한다고 하면 운영체제는 매번 이름을 검사하고 접근 권한을 확인하는 등의 작업을 수행해야 할 것이다.
open() 연산은 파일의 이름을 취하여 그 이름으로 디렉터리를 찾고 디렉터리 항목을 열린 파일 테이블로 복사한다. (열린 파일 테이블은 아래에서 추가 설명 예정이다.)
open() 함수는 리턴 값으로 열린 파일 테이블의 항목에 대한 포인터를 반환한다.
파일명이 아닌 포인터를 입출력 연산에 사용함으로써 더 이상의 탐색 과정을 피하고 시스템 콜 인터페이스를 단순화할 수 있다.
✨ 파일 쓰기 및 읽기
하나의 “현재 파일 위치 포인터”를 가진다. 이 현재 파일 위치 포인터는 어떤 연산인지에 따라 부르는 말이 다르다.
파일 쓰기인 경우 쓰기 포인터라고 지칭하며, 파일 읽기인 경우 읽기 포인터라고 지칭한다.
쓰기 포인터는 파일 내 다음 순차적 쓰기가 일어날 위치를 가리키는 포인터이며, 쓰기가 일어날 때마다 갱신이 필요하다. 읽기 포인터는 파일 내 다음 순차적 읽기가 일어날 위치를 가리키는 포인터이며, 읽기가 일어날 때마다 갱신이 필요하다.
분리하지 않고 상황에 따라 이름을 달리해 쓰는 이유는 프로세스의 특성에 있다.
프로세스는 일반적으로 파일을 읽거나 파일을 쓴다. 둘이 동시에 일어날 일은 거의 없다고 보면 된다.
이렇게 읽기와 쓰기 연산 모두 “현재 파일 위치 포인터”를 사용함으로써 공간 절약 + 시스템 복잡성 감소의 효과가 뒤따른다.
✨ 파일 안에서의 위치 재설정 = 파일 탐색
열린 파일의 현재 파일 위치를 주어진 값으로 설정한다.
이 과정에서 실제 입출력은 일어나지 않는다.
✨ 파일 삭제
파일 삭제 과정은 다음과 같다.
- 지정된 파일을 디렉터리에서 찾음
- 모든 파일 공간 해제, 디렉터리 항목 지우기, 사용 가능으로 표시
참고로, 하드 링크의 경우 실제 파일 내용은 마지막 링크가 삭제될 때까지 삭제하지 않는다.
✨ 파일 절단 = 파일 내용만 지우기
: 파일의 길이를 제외한 모든 속성 유지.
파일의 길이가 0으로 재설정되고, 파일이 가지고 있던 공간이 해제된다.
🫧 열린 파일 테이블
- 운영체제는 모든 열린 파일에 대한 정보를 갖는 열린 파일 테이블을 유지한다.
- 임의의 파일 연산이 요구되면, 이 테이블에 대한 인덱스로 그 파일을 지정하므로 어떠한 탐색도 필요하지 않다.
- 파일이 더는 사용되지 않으면 프로세스에 의해 닫히고 운영체제는 열린 파일 테이블에 있는 항목을 제거하여, 락을 해제할 수 있다.
cf) create()와 delete()는 열린 파일보다는 닫힌 파일을 대상으로 동작하는 시스템 콜이다.
🫧 파일의 동시 접근
보통 운영체제는 두 단계의 내부 테이블을 사용한다.
- 프로세스별 테이블
- 범 시스템 테이블
✨ 프로세스별 테이블
- 각 프로세스가 연 모든 파일 기록
- 프로세스가 파일을 어떻게 사용하는지에 대한 정보
ex) 각 파일에 대한 파일 포인터 위치, 접근 권리 등
✨ 범 시스템 테이블
- 프로세스별 테이블의 각 항목은 다시 범 시스템에 열린 파일 테이블들을 가리킨다.
- 프로세스의 독립적인 정보를 갖고 있다.
ex) 디스크 상의 파일 위치, 접근 날짜, 파일 크기 등
열린 파일 테이블은 파일을 연 프로세스 수를 가리키는 열린 계수를 각 파일에 연관시킨다.
close()는 계수 감소를 뜻하며, 계수가 0인 경우 파일이 더는 사용되지 않음을 나타내고 열린 파일 테이블로부터 제거한다.
🫧 테이블 간 관계
열린 파일 테이블, 프로세스 별 테이블, 범 시스템 테이블 간 관계는 다음과 같다.
- open() 함수를 통해 파일의 정보를 가져온다. open() 함수의 리턴값은
파일 디스크립터
라고도 부르는 포인터이다. - 프로세스별 테이블이 열린 파일 테이블의 엔트리를 참조한다.
- 열린 파일 테이블의 각 엔트리는 범 시스템 테이블의 inode나 디스크 블록 정보를 참조한다.
즉, 파일 디스크립터 -> 프로세스별 테이블 -> 열린 파일 테이블의 인덱스를 통해 범 시스템 테이블의 정보를 간접적으로 접근할 수 있다.
또한, 여러 프로세스가 동일한 파일을 열 때, 파일 시스템은 동일한 파일에 하나의 열린 파일 테이블 항목을 생성한다. 열린 파일 테이블은 시스템 전역 테이블로, 여러 프로세스가 같은 파일을 열어도 그 파일의 상태(읽기/쓰기 모드 등) 는 동일한 항목을 참조한다.
범 시스템 테이블도 마찬가지로, 여러 프로세스가 동일한 파일을 열더라도 범 시스템 테이블에서 해당 파일을 위한 항목이 하나만 생긴다.
범 시스템 테이블은 파일의 실제 물리적 데이터를 추적하는 가장 하위 레벨의 테이블이다. 디스크 블록, inode 정보, 파일 속성 등 파일은 디스크 상에 물리적으로 하나만 존재하기 때문이다.
🫧 파일 락
: 하나의 프로세스가 파일을 잠그고 다른 프로세스들이 접근을 막는데 사용될 수 있다.
- shared lock (공유락)
: 여러 프로세스가 동시에 락 획득 가능 (≓ 읽기 락)
- exclusive lock (배타락)
: 한 번에 한 프로세스만 락 획득 가능 (≓ 쓰기 락)
어떤 시스템은 배타적 락만 지원하기도 한다.
또한, 공유락과 배타락 외에도 강제적 파일 락과 권고적 파일 락이 존재한다.
어떤 프로세스가 배타적 락을 획득하면 운영체제가 다른 프로세스가 잠겨진 파일에 접근하는 것을 막는 것이 강제적 파일 락이며, 권고적 락의 경우 강제하지 않기에 더 유연하다는 특징이 있다.
강제적 파일 락은 락 무결성을 보장한다는 장점과 동시에 교착상태에 빠질 수 있다는 단점을 가지고 있다.
🫧 파일 유형
시스템이 파일 유형을 지원한다면 파일에 대한 합리적 연산 수행이 가능해진다.
대부분의 시스템은 확장자를 통해 파일 유형을 구분하며, 생략 시 운영체제가 알아서 판단해 해당 파일 유형을 구분해 준다.
🫧 파일 구조
파일 유형으로 내부 구조를 짐작할 수 있다.
각각의 파일들은 그 파일을 다루는 프로그램
에 의해 인식 가능한 내부 구조를 일정한 형태로 가지게 된다.
프로그램 뿐 아니라, 실행파일과 같은 특수 파일의 경우 운영체제가 인식할 수 있도록 미리 정해진 구조를 따라야 할 때도 있다.
그러나 이런 틀에 잡힌 파일 구조가 마냥 좋은 것만은 아니다.
운영체제가 여러 파일 구조를 지원할 시, 크게 두 가지의 문제가 생기게 된다.
-
운영체제의 크기가 커지고 관리가 힘들어짐
-> 파일 구조 지원을 위한 코드가 부가적으로 필요
-
파일 유형의 한계
-> 모든 파일은 운영체제에서 지원하는 파일 유형 중 하나로만 정의되어야 함.
이러한 단점 때문에, UNIX, 윈도우에서는 실제로 파일 형태, 구조에 대해 제한을 두고 있지 않는다.
참고로, 모든 운영체제는 반드시 프로그램을 로딩하고 실행할 수 있는 실행 파일의 구조를 지원해야 한다.
🫧 파일의 내부 구조
디스크 시스템은 보통 섹터의 크기에 의해 결정되는 블록 크기를 가진다.
모든 디스크 I/O는 한 블록 단위로 수행되며, 모든 디스크 블록들은 동일한 크기를 가진다.
그렇기 때문에 내부 단편화 문제도 발생하곤 한다.
디스크 공간이 항상 블록 단위로 할당되기 때문이다.