나만의 백과사전 - 파일 시스템

Jiwon An·2021년 8월 27일
0

CS/운영체제

목록 보기
8/10

컴퓨터 기본 구조에서 파일을 관리하는 방법을 하드웨어적 측면과 소프트웨어적 측면에서 공부한다.
파일 시스템은 디스크에 존재하는 데이터와 프로그램의 저장과, 접근할 수 있는 기법을 제공한다.

1. 파일 개념

컴퓨터는 정보들을 자기디스크, 자기테이프, 광디스크와 같은 다양한 저장 매체에 저장할 수 있다. 운영체제는 저장장치의 물리적 특성을 추상화하여 논리적 저장 단위, 즉 파일을 정의한다. 파일은 운영체제에 의해 물리 장치들로 맵핑되고, 일반적으로 비휘발적 특성을 지니기 때문에, 전원이 끊어진 상황에서도 정보들을 영구히 보존할 수 있다.
사용자의 입장에서 파일은 논리적 보조저장장치의 가장 작은 할당 단위이다.
파일은 일반적으로 프로그램과 자료로 나누어진다.

간단 정리

  • 파일 : 정보의 집합체. 정보란 비트, 바이트, 행, 레코드 등을 모두 포함한다. 파일 작성자나 사용자가 해당 정보를 정의한다.
  • 파일은 보조기억장치에 저장되어 있고, 주로 프로그램파일 혹은 데이터파일이다.
  • 프로그램 : 원시 프로그램(소스 프로그램, C, C++), 목적(바이너리) 프로그램으로 나누어 진다.
  • 데이터 파일 : 수를 포함해 문자 또는 ASCII 코드로 된 문자 혹은 숫자로 구성되어 있다. 내용면에서는 텍스트 파일처럼 비정형화된 자유형식일 수도 있고, 데이터베이스처럼 엄격히 정형화된 형태일 수도 있다. 또한 동영상, 이미지, 소리 등 정해진 포맷을 따르고 있을 수도 있다.
  • 어떤 파일이든 하드디스크와 같은 저장장치에 저장될 때 섹터 단위로 저장된다. 즉, 하나의 파일이 디스크 내 여러개의 섹터로 구성되는 것이다. 섹터는 논리적으로는 블록에 해당되고, 일반적 PC에서 한 섹터의 크기는 512바이트이다.

2. 파일 추상화와 파일 시스템

  • 파일은 섹터단위로 저장되어 있는 정보의 집합체라고 할 수 있다.
  • 파일은 추상화라는 과정을 통해 그 용도나 기능을 확장한다.
  • 가상메모리는 추상화기법에 기반한다. 오브젝트 파일을 프로세스와 연관시키기 위해 추상화를 사용한다. EXE 파일을 구성하는 블록들을 매핑시켜 하나의 프로세스로 나타나도록 한다.
  • cf. 오브젝트 파일 : 컴파일러나 어셈블러가 소스코드 파일을 컴파일 또는 어셈블해서 생성하는 파일
  • 시스템 내부 입출력 장치를 파일이라는 개념으로 추상화해줌으로써 프로세스의 장치 접근에 일관성을 유지, 지원하낟.
  • 이러나 추상화를 실현하기 위해 파일 시스템이 존재한다.

3. 파일 시스템

  • 저장장치는 선형적 주소를 가진 바이트의 블록만을 저장한다. 이러한 블록은 섹터에 저장된다.
  • 파일 시스템은 저장장치와 응용프로그램 사이의 자료구조 차이점을 해결해준다. 데이터 파일을 예로 들어보자
  • 파일 시스템이 섹터로 조각나서 산재되어 있는 블록들을 관리해 바이트의 연속인 하나의 파일, 즉 바이트 스트림 파일로 보이도록 만들어준다. 응용프로그램은 이러한 바이트 스트림 파일을 용도에 맞추어 레코드 혹은 구조체 등의 형태로 재구성함으로써 구조화된 레코드 파일(structed-record file)로 보이도록 한다.
  • Stream-block Translation : 기억장치의 블록을 음수가 아닌 정수값을 갖는 연속된 주소의 바이트 집합(바이트 스트림)으로 변환
  • Record-stream Translation : 응용프로세스에 맞는 자료구조(레코드 혹은 구조체)로 변환
  • 저장장치에서 오브젝트 파일(실행 파일)로 저장되어 있던 것을 파일시스템이 Stream-block Translation과 Record-stream Translation로 가상메모리에 적절하도록 추상화해준다.
  • 장치제어기와 응용프로그램에 따른 추상화는 파일 시스템이 응용 프로그램에게 장치 접근을 위한 파일 API를 제공함으로써 추상화를 제공한다.

4. 바이트 스트림 파일

  • 파일 시스템은 바이트 스트림 파일을 효과적으로 다루기 위해 파일마다 file descriptor라는 구조체를 구비하고 해당 구조체에 파일에 해당하는 이름, 현재상태, 권한, 크기, 생성시간, 수정시간 등의 각종 정보를 보관한다.
  • 이러한 파일 디스크립터의 정보는 파일 내부에 저장되고, 일부 내용은 파일 검색 지원을 위해 폴더에도 수록된다. (이러한 이유로 파일이나 폴더의 포맷이 그리 단순하지는 않다.)
  • 만약 파일이 임의의 프로세스에 의해 open되면 파일 디스크립터에 해당 상태와 추가 정보(파일 입출력이 이루어지는 위치인 file position 등)를 수록한다. 그에 따라 파일 디스크립터 정보의 일부가 메모리에 로딩되기도 한다. open된 파일에 대한 접근을 신속하게 처리하기 위함이다.
  • 파일에 관한 정보의 복제본이 여러곳에 존재하는 분산 시스템의 경우, 일관성 유지를 위해 다양한 문제를 해결해야 하는데, 이는 보다 고차원의 문제이다.

5. 파일 속성

사용자의 편의를 위해 파일에 이름을 부여하고, 하나의 문자열로 나타낸다. 시스템에 따라 대소문자를 구분하기도, 안하기도 한다.
일단 파일이 만들어지면 그 파일은 프로세스, 사용자, 시스템으로부터 독립하게 된다. 한 사용자가 파일을 생성하고, 다른 사용자가 복사하거나 이메일로 첨부하여 보낼 수 있다.

일반적으로 파일의 속성은 다음과 같다.

  • 이름 : 사람이 읽을 수 있는 형태로 유지되는 유일한 정보
  • 식별자 : 파일 시스템 내에서 파일을 식별하는 고유의 번호 PK
  • 타입 : 여러 타입의 파일을 제공하는 시스템을 위해 필요
  • 위치 : 장치 내에서 파일의 위치를 가리키는 포인터
  • 크기 : 파일의 현재 크기
  • 보호 : 접근 제어 정보
  • 시간, 날짜, 사용자 식별 : 생성, 최근 변경, 최근 사용등에 대한 정보
    모든 파일에 대한 정보는 보조저장장치에 상주하는 디렉토리 구조 내에 유지된다. 파일과 디렉토리 모두 비휘발적 성질을 가져야 하므로, 저장장치 상에 저장되고, 필요할 때 조금씩 메모리로 가져와야 한다.

6. 파일 연산

운영체제가 파일을 관리하기 위해 사용하는 시스템 콜과 그것들의 조합

  • 파일 생성 : 운영체제는 파일 저장을 위한 공간을 찾고, 디렉토리에 파일 항목을 추가한다.
  • 파일 쓰기 : 파일 이름과 기록될 정보를 명시하는 시스템 콜을 호출한다. 시스템은 파일을 찾기위해 디렉토리를 탐색, 파일 내의 다음 쓰기가 일어날 위치를 가리키는 쓰기 포인터를 유지하고 있어야 한다. 쓰기 포인터는 쓰기가 일어날 때마다 갱신된다.
  • 파일 읽기 : 파일 이름과 파일이 읽혀 들어갈 블록의 위치를 명시하는 시스템 콜을 호출한다. 다음 읽기가 일어날 파일 안의 위치를 기록하는 읽기 포인터를 유지해야 한다. 다시 말해, 파일을 메모리에 쓸 위치와 읽기 포인터를 유지한다.
    프로세스는 일반적으로 파일 읽기나 파일 쓰기 중 한 가지를 하고 있기 때문에, 대부분의 시스템은 한 개의 현재 파일 위치 포인터를 가진다. 읽기, 쓰기 연산 모두 이 포인터를 이용해 공간을 절약하고, 복잡성을 감소시킨다.
  • 파일 안에서의 위치 재설정 : 디렉토리에서 적합한 항목을 탐색하고, 현재 파일 위치를 주어진 값으로 설정한다. 파일 복사와 삭제 기능으로 구현한다.
  • 파일 삭제 : 지명된 파일을 디렉토리에서 찾는다. 발견하면 파일이 차지하는 공간을 방출하고 디렉토리 항목을 삭제한다.
    정확히는 파일이 차지하고 있는 테이블을 제거하며 디렉토리도 수정한다. (디스크에 파일을 직접 삭제하지는 않는다. 덮어쓰므로 기존 정보를 지우는 것뿐, 따라서 완벽한 삭제는 물리적으로 분해하는 것이다.)
  • 파일 절단 : 파일의 내용을 지우고, 속성만을 남긴다. 즉, 파일의 길이를 제외한 모든 속성을 그대로 유지시킨다.

위에 있는 6개의 연산은 파일 조작에 필요한 최소한의 연산이다. 새로운 정보를 추가하는 첨가(appending)나 재명명(renaming)등이 더 있다.

오픈 파일 테이블

운영체제는 모든 열린 파일에 대한 정보를 갖는 오픈 파일 테이블(open file table)을 유지한다.
시스템 콜 open()은 전형적으로 열린 파일 테이블의 항목에 대한 포인터를 리턴한다. 실제 파일이 아닌 포인터를 입출력 연산에 사용함으로써 더이상의 탐색과정을 피하고 시스템 호출 인터페이스를 단순화한다.

여러 프로세스가 동시에 파일을 열 수 있는 환경에서는 open()과 close() 연산의 구현은 더 복잡한데, 보통 운영체제는 프로세스별 테이블과 범시스템 테이블을 사용한다.

  • 프로세스별 테이블 : 파일 포인터, 접근 권한
  • 범시스템 테이블 : 프로세스에 독립적인 정보들 : 디스크 상의 파일 위치, 접근 날짜, 크기
  • 오픈 파일 테이블(open file table)
    파일이 하나의 프로세스에 의해 열려 있다. 이때 다른 프로세스가 open()을 호출한 경우 오픈 파일 테이블에 범시스템 테이블에 있는 정보를 가리키는 새로운 포인터가 생긴다.
    일반적으로 오픈 파일 테이블은 파일을 연 프로세스 수를 가리키는 오픈 계수(open count)를 각 파일에 연관지어 둔다. close() 콜은 이 오픈 계수를 감소시키고 계수가 0이 되면 해당 정보를 테이블에서 제거한다.

열린 파일들을 관리하기 위해 필요한 몇 가지 정보들

  • 파일 포인터 : 가장 최근의 읽기/쓰기 위치를 가리킨다. read(), write()의 일부분으로 파일 offset을 가지고 있다. 파일을 오픈한 프로세스별로 하나가 만들어진다.
  • 파일 오픈 계수 : 열린 파일이 닫히면 파일 테이블을 정리한다. 파일의 총 열린 횟수와 닫힌 횟수를 추적하며 계수값이 0이면 테이블에서 해당 항목을 제거한다.
  • 파일의 디스크 위치 : 대부분의 파일 연산은 데이터를 변경하도록 요구, 매 연산마다 디스크에서 읽는 것을 피하기 위해 메모리에 저장한다. (한 번 메모리에 저장해 두었다가 파일을 닫을 때 다시 디스크로 옮긴다는 것 같다.)
  • 접근 권한 : 프로세스는 파일에 한가지 접근 방법으로만 접근할 수 있다. 이 정보는 프로세스별 테이블에 저장된다.

파일의 잠금

몇몇 운영체제는 열려진 파일을 잠금할 수 있는 기능을 제공한다. 한 프로세스가 파일을 잠그면 다른 프로세스는 접근이 불가하다.

  • 강제적 파일 잠금 : 어떤 프로세스가 배타적 잠금을 획득한 경우, 운영체제는 다른 프로세스가 파일에 접근하는 것을 차단한다. 잠금의 무결성이 보장된다. -> Windows
  • 권고적 파일 잠금 : 프로세스들은 잠금의 상태를 찾을 수 있고 무엇을 해야할 지 결정한다. 잠금이 적절히 획득되고 해제되는 것에 대한 보장은 소프트웨어 개발자의 몫이다. -> Unix
  • 파일 잠금의 사용은 동기화처럼 특별히 주의해야 한다. 두 개 이상의 프로세스가 파일 잠금을 얻으려고 하다가 교착 상태에 빠질 수 있으므로 특별한 대책이 필요하다.

7. 파일 타입

  • 확장자 : 파일 이름의 한 부분으로 하여금 파일의 타입을 나타내도록 하는 것이다. 대체로 마침표를 이용해 파일 이름과 확장자를 구분한다. 또한 확장자를 이용하여 연산의 유형을 표시할 수 있다. (파일에 대한 힌트)
  • 확장자 자체는 있어도 되고 없어도 된다. 다만 구분과 표시를 위해 사용할 뿐이다.
  • 시스템은 파일 확장자를 사용해(파일 타입을 인식하여) 파일이 가능한 연산, 시스템 호출 등을 표시한다.
    예를 들어, binary object 파일을 출력하려고 한다면 쓰레기값들을 만들어낸다. 그 파일은 실행파일이기 때문이다.
  • 확장자 종류
    • 실행 가능 : exe, com, bin
    • 목적 파일 : obj, o(링크되지 않은 기계어)
    • 소스 코드 : c, java, pas, asm
    • 문서 : txt, doc

8. 파일의 내부 구조

디스크 시스템의 경우 보통 섹터에 의해 결정되는 블록 크기를 가진다. 또한 어떠한 경우든 일련의 블록으로 간주된다. 여러 개의 논리 레코드를 하나의 물리 레코드(블록)에 담기도 하는데 이를 팩킹이라고 한다. 기본적인 I/O기능(입출력)은 블록 단위로 실행되며, 그렇기 때문에 내부 단편화 문제가 발생할 수 있다.

9. 파일 접근 방법

파일은 정보를 저장한다. 파일이 사용될 때 정보가 반드시 접근되어 컴퓨터 메모리로 읽혀져야 한다. 그 때, 파일에 접근하여 데이터를 읽는 방법이다.

1) 순차 접근

가장 간단한 방법으로 파일의 정보가 레코드 순서대로 차례차례 처리된다.

현재 위치를 가리키는 포인터에서 읽기/쓰기 시스템 콜이 발생한 경우 포인터를 앞으로 보내면서 읽거나 쓴다. 뒤로 돌아가기 위해서는 지정한 offset만큼 되감기를 해야 한다.
테이프 모델에 기반을 두고 있다.

2) 직접 접근

직접 접근 또는 상대 접근은 특별한 순서 없이 빠르게 레코드를 읽고 쓸 수 있다. 디스크 모델에 기반을 두며 이는 무작위 파일 블록에 대한 임의 접근(Random Access)를 허용하기 때문이다. 직접 접근의 경우 읽기나 쓰기 순서에 제약을 가하지 않는다.
대규모 정보를 즉각적으로 접근하는 데 유용하여 데이터베이스에 이용된다.

  • 현재 위치를 가리키는 변수 cp만 유지된다면 직접 접근 파일을 가지고 순차 파일 기능을 쉽게 구현할 수 있다.

3) 기타 접근 방법

직접 접근 파일에 기반을 두고 색인을 구축한다. 크기가 큰 파일을 입출력 탐색할 수 있게 도와준다.

디렉토리와 디스크 구조

통상 수천 수만 수십억 개의 파일을 하드디스크, 광학디스크, 반도체 디스크를 포함한 임의 접근장치에 저장하는 방법이다. 파일이 매우 많으므로 체계적으로 구성을 갖추어야 한다. 그래서 디렉토리의 사용을 수반한다.

  • 볼륨 : 파일 시스템은 디스크의 일부분(파티션)에 생성될 수 있다. 이러한 파일 시스템을 포함하고 있는 임의의 개체, 각 볼륨을 논리적인 가상 디스크로 취급될 수 있다. 하나 이상의 운영체제를 저장하고 부팅, 실행시킬 수 있다. 섹터들의 집합으로 연속공간이 아니어도 볼륨으로 볼 수 있다.
  • 디바이스 디렉토리(디렉토리) : 그 볼륨에 있는 모든 파일에 대한 이름, 위치, 크기, 타입과 같은 정보를 기록한다.
  • 파티션 : 연속된 저장 공간을 하나 이상의 연속되고 독립적인 영역으로 나누어서 사용할 수 있도록 정의한다.

1. 저장장치의 구조

범용 컴퓨터 시스템은 다수의 저장장치를 가지고 그 장치들은 파일 시스템을 저장할 수 있는 볼륨으로 분할된다.
파일 시스템이 없을 수도 있으며, 다양한 종류의 파일 시스템을 가질 수도 있다.

2. 디렉토리 개관

디렉토리는 파일 이름을 해당 디렉토리 항목으로 변환해주는 심벌 테이블로 볼 수 있다. 따라서 다양한 방법으로 구성될 수 있다.
파일 관리를 위해선 파일 찾기, 파일 생성, 파일 삭제, 파일의 재명명, 파일 시스템 순회를 제공해야하며, 삭제시 하위 디렉토리가 갖는 파일이 있는지 확인해야한다.

  • 파일 찾기 : 특정 파일에 해당하는 항목을 찾기 위해 탐색이 가능해야 한다. 특정 패턴과 일치하는 이름을 갖는 모든 파일을 찾을 수 있어야 한다.
  • 파일 생성 : 새로운 파일들을 생성하여 디렉토리에 추가한다.
  • 파일 삭제 : 디렉토리에서 파일을 제거한다.
  • 디렉토리 나열 : 존재하는 파일들을 나열하고 내용을 보여준다.
  • 파일의 재명명 : 이름을 변경한다.
  • 파일 시스템의 순회(Traverse) : 파일 시스템의 모든 디렉토리를 순회하면서 모든 파일들을 액세스할 필요가 있다. 전체 파일 시스템을 주기적으로 백업할 때 사용한다.

3. 디렉토리의 종류

1) 1단계 디렉토리

가장 간단한 구조의 디렉토리이다.
파일이 많아지거나 다수의 사용자가 사용할 경우 심각한 제약이 따른다.
각 파일들은 서로 유일한 이름을 가진다. 서로 다른 사용자라 하더라도 같은 이름을 사용할 수 없다.

2) 2단계 디렉토리

사용자에게 개별적인 디렉토리를 만들어 준다.

  • UFD(User File Directory) : 자신만의 사용자 파일 디렉토리, 비슷한 구조를 가지고 있지만 오직 한 사용자만의 파일을 저장한다.
  • MFD(Master File Directory) : 사용자의 이름이나 계정번호로 색인되어 있고, 각 엔트리는 사용자의 UFD를 가리킨다.

    특정한 파일을 참조할 시 사용자의 UFD에서만 탐색하므로 파일 이름이 충돌하는 문제가 사라진다.
    다른 사용자의 파일에 접근해야 하는 경우는 단점이 된다.

3) 트리 구조 디렉토리

2단계 구조 디렉토리를 확장하여 다단계 트리 구조로 만들 수 있다. 사용자들이 자신의 서브디렉토리를 만들어서 파일을 구성할 수 있게 한다. 트리 구조는 하나의 루트 디렉토리를 가지며 시스템의 모든 파일은 고유 경로를 가진다.
디렉토리의 각 항목은 한 비트를 사용하여 일반 파일인지(0) 디렉토리 파일인지(1)를 구분한다.

통상적으로 각 프로세스는 현재 디렉토리를 가지고 있다.
디렉토리의 경로명을 지정할 때에는 절대경로명과 상대경로명 두 가지가 있다.

4) 비순환 그래프

사이클이 없는 그래프는 디렉토리들이 서브디렉토리와 파일들을 공유할 수 있도록 허용한다.
트리 구조의 디렉토리를 자연스럽게 일반화한 방식이다.
절대경로명/상대경로명을 이용하여 링크라고 불리는 새로운 디렉토리 항목을 만들 수 있다.
단순한 트리 구조보다는 융통성이 있는 대신에 더 복잡하다.
파일을 삭제할 때 대상이 없는 포인터(dandling pointer)를 남긴다.
참조되는 파일에 참조 계수를 두어 계산한다. 참조 계수가 0이 되면 현재 파일을 참조하는 링크가 존재하지 않으므로 파일을 삭제할 수 있다.

5) 일반 그래프 디렉토리

디렉토리에서 순환이 허용되는 경우 무한 루프에 빠질 수도 있다. 따라서 순환이 발생하지 않도록 하위 디렉토리가 아닌 파일에 대한 링크만 허용하거나 가비지 컬렉션을 이용해 전체 파일 시스템을 순회하고, 접근 가능한 모든 것을 표시한다. 디렉토리를 순회할 때 링크가 있으면 우회하여 순환을 피할 수도 있다.

4. 파일 시스템 마운팅

  • 디렉토리 구조는 다양한 볼륨으로부터 구축될 수 있는데, 각 볼륨들이 마운트되어야 파일 시스템 지명 공간안에서 이용이 가능하다.
    • 파일이 사용되기 전에 열리는 것처럼, 프로세스들이 파일 시스템을 사용하기 전에는 먼저 마운트해야 한다.
  • 디바이스 이름과 마운트 포인트 위치(파일 시스템을 부착할 수 있는 파일 구조 내의 위치)를 전달하여 마운트한다.
  • 시스템은 기능을 명확하게 하기 위해 Semantics를 부여한다. (정책)
  • 시스템 파일 디렉토리에는 마운트가 불가하다.
  • 마운트된 이후에는 마운트된 파일 시스템만 접근하게 한다.

  • 두 개의 파일 시스템이 마운트 되기 전 삼각형은 서브디렉토리를 의미한다.

  • b 파일 시스템이 a의 /users에 마운트된 경우다. 기존 a 시스템에 있던 /users/fred/help는 마운트가 해제되기 전까지 접근할 수 없다.

5. 파일 공유

5.1 다수의 사용자

디렉토리 구조가 사용자간의 파일 공유를 허용한다면, 시스템은 파일 공유를 중재해야 한다. 대부분의 시스템은 파일/디렉토리의 소유자, 그룹이라는 개념을 사용하는 형태로 발전해왔다.
UNIX 시스템의 소유자는 파일에 대한 모든 작업을 실행할 수 있지만 그룹 멤버는 일부 작업만을 실행할 수 있다.

5.2 원격 파일 시스템(www)

네트워크를 이용하여 원거리 컴퓨터 간의 통신을 하면서 파일 시스템을 공유하는 방법이다.

  • ftp -> 분산 파일 시스템 -> www
  • 서버 <-> 클라이언트간의 통신으로 공유
    • 서버 : 파일을 제공하는 컴퓨터
    • 클라이언트 : 파일을 요청하는 컴퓨터
    • 클라이언트의 신원 확인 : ip나 네트워크 이름등의 식별자는 도용(spoofing)이나 모방(imitation)될 수도 있기에 인증 과정이 필요하다. 원격 파일 시스템이 마운트되면 로컬 파일 시스템에 적용하는 semantic(정책)과 유사한 의미를 적용하거나 다른 의미를 사용할 수도 있다.
  • 서버와 클라이언트의 관리를 쉽게 하기 위해서 분산네이밍서비스를 사용한다.(예: DNS)
  • 고장 모드를 따로 두고 파일 시스템에 오류가 발생시 대처한다.
  • 원격 파일 시스템에서는 파일의 일관성(Consistency)을 유지하는 것이 매우 중요하다.

5.3 일관성 정책(Consistency semantics)

1) UNIX 의 semantics

열린 파일에 대한 사용자의 쓰기는 동일 파일을 연 다른 사용자들에게 즉시 보인다.
공유 모드 : 사용자들이 파일 내의 현재 위치 포인터를 공유한다. 여럿이서 파일 위치 포인터를 같이 쓴다.

2) 세션 semantics

앤드류 파일 시스템
열린 파일에 대한 쓰기는 동시에 같은 파일을 연 다른이에게 보이지 않는다.
파일이 닫히면 파일에 대한 변경들이 나중에 시작되는 세션에서만 보인다.
사용자들은 지연 없이 그들의 파일 이미지에 대해 병행적으로 읽기와 쓰기 모두를 실행할 수 있다.

3) 불변 공유 파일의 semantics

파일이 공유된다고 선언되면, 더이상 변경이 불가능하게 만든다.

6. 보호

  • 시스템의 파일을 보호하기 위해 chmod와 같은 명령으로 보호한다.
  • 파일을 암호화하여 해쉬 값을 얻은 후 보호한다.

1) 접근 타입

접근을 허용하지 않거나/자유롭게 접근하거나 이 두가지의 접근법으로는 다양한 방법의 파일 접근/공유 절차를 커버할 수 없다. 그래서 우리는 통제된 접근을 구현해야 한다.
사용자가 어떤 접근 타입을 가지고 오는지에 따라 파일 연산을 통제시킬 수 있다.
파일 연산 : 읽기, 쓰기, 실행, 추가, 삭제, 리스팅

2) 접근 제어

파일과 디렉토리에 접근 제어 리스트를 둔다. (ACL, Access Control List)
특정 사용자가 어떤 파일에 접근할 경우 리스트를 보고 허용 여부를 결정한다.

  • 소유자 : 파일의 생성자
  • 그룹 : 파일을 공유하며 소유자와 유사한 접근이 필요한 사용자들의 집합
  • 모든 사람 : 시스템에 있는 모든 사용자들

유닉스의 경우 3파일에 3비트 rwx 필드를 두어 접근 권한을 관리한다.
윈도우의 경우 gui를 통해 접근이 가능하다.

파일 시스템 구현

1. 파일 시스템의 디스크 저장 공간 할당

컴퓨터 시스템 자원에서 가장 중요한 부분은 CPU이다. CPU를 어느 프로세스에 나누어 줄 것인가가 프로세스 관리를 하는 역할이다. 그 다음 중요한 자원이 메인 메모리인 주기억장치이다. 메인 메모리에 대해 페이징이나 가상 메모리와 같은 방법을 사용하는 것이 메인 메모리 관리를 하는 역할에 속했다. 다음으로 중요하다고 할 수 있는 컴퓨터 시스템 자원으로는 하드 디스크와 같은 보조기억장치라고 할 수 있다. 보조기억장치는 파일 시스템을 관리하는 역할을 수행한다.

대표적인 보조기억장치는 하드디스크이다. 하드 디스크는 트랙(track)과 트랙을 자른 섹터(sector)로 이루어져 있다. 또한 같은 거리에 존재하는 트랙들의 집합을 실린더(cylinder)라고 한다. 일반적으로 Sector size는 512bytes인데 크기가 너무 작으므로 Sector들을 여러개 모아놓은 것은 Block이라고 한다. 하드디스크는 이러한 Block들을 단위로 읽고 쓰기를 진행한다. 디스크는 처음에 free block인 비어있는 block으로 구성되게 된다. 그런데 Block 단위로 디스크가 돌아가기 때문에 파일에 Block에서 남는 공간이 발생하게 된다. 메모리 관리에서 했던 내부 단편화와 비슷한 현상이라고 할 수 있다. 이렇게 되면 공간이 낭비되므로 효율이 안 좋게 된다. 그런데 그렇다고 해서 Block의 크기를 줄이게 되면 디스크에서 읽고 쓰는 과정이 매우 오래 걸리게 될 것이다. 하나의 파일을 읽는데 더 많은 Block을 읽어야하기 때문에 속도가 떨어지게 되는 것이다. 어떻게 하면 free block을 잘 할당할 것인지, 속도를 감소시키지 않게 할 것인지를 따지면서 파일을 할당하는 것이 중요하다.

파일 할당에는 3가지 방법이 있다. 연속 할당, 연결 할당, 색인 할당이다.

연속 할당은 각 파일에 대해 디스크 상의 연속된 블록을 할당하는 방법이다. 하드 디스크에 block들이 나열되어 있는데 여기에 연속된 순서대로 파일을 저장하는 것이다. 이렇게 되면 디스크가 읽어 들어갈 때 이동 경로를 최소화할 수 있다는 장점이 있다. 빠른 I/O의 성능을 가질 수 있는 것이다. 순서적으로 읽을 수도 있고 특정 부분을 바로 읽을 수도 있게 한다. 동영상이나 음악, VOD와 같이 크기가 큰데 실시간인 자료들에 적합하다고 할 수 있다. 하지만 단점도 존재한다. 특정 파일이 삭제되면 중간에 빈 공간인 hole이 생성되게 된다. 계속해서 파일의 생성과 삭제를 반복하면 곳곳에 흩어지는 hole들이 생성되게 된다. 이는 외부 단편화가 생긴 것으로 생각할 수 있다. 그러면 디스크의 공간 낭비가 매우 심하게 될 것이다. 또한 연속되게 파일을 할당하면 중간에 파일의 크기를 계속 증가시킬 수 없다. 뒤의 block에는 다른 파일이 공간을 차지하고 있으니 크기 조절이 불가능하게 된다.

연결 할당은 파일을 linked list의 형태로 저장하는 것을 말한다. 파일은 각자 디렉토리를 가지고 있는데, 여기에는 어떤 block에 할당되어 있는지를 기억한다. 디렉토리에 제일 처음 저장되는 block을 가리키게 되고 각 block은 포인터를 저장을 위한 4바이트 이상을 가지고 있어서 다음 block을 지칭하게 된다. 새로운 파일이 만들어진다고 생각을 하면 비어있는 임의의 block을 첫 block으로 지정하고 파일이 커지면 다른 block을 할당 받고 포인터를 이용해 연결을 하면 된다. 이런 방법을 사용하면 외부 단편화를 없앨 수 있다. 임의의 자리에 넣고 포인터로 연결만 하면 되기 때문에 딱 block에 맞는 사이즈만 맞추어 넣으면 되기 때문이다. 하지만 단점도 존재한다. 연결 할당을 하게 되면 각각 순서대로 포인터로 연결되어 있기 때문에 순서대로 읽는 것 밖에 할 수 없다. 중간에 있는 자료만 읽고 싶어도 포인터를 따라 가지 않으면 읽을 수 없기 때문이다. 또한 포인터 저장을 위해 4바이트 이상을 손실시켜야 되고 만약 포인터가 끊어지면 이하 접근이 불가하기 때문에 낮은 신뢰성을 가진다. 그리고 포인터를 따라가는 과정을 거쳐야 하므로 속도 면에서 느릴 수 있다.

색인 할당은 파일당 인덱스 block을 사용하여 파일을 할당하는 방법이다. 인덱스 block은 각 파일에 할당된 포인터를 저장하는 모음이다. 연결 할당과 같은 방식으로 할당하지만 인덱스 block을 둔다는 점에서 다르게 된다. 인덱스 block에 각 포인터에 대한 정보를 저장하게 되면 연속 할당의 장점인 순서적으로 읽을 수도 있고 특정 부분을 바로 읽을 수도 있게 한다. 또한 연결 할당의 장점인 외부 단편화도 없어지는 효과를 가지게 된다. 하지만 인덱스 블록에 할당에 따른 저장 공간의 손실이 발생할 수 있다.

참고

https://velog.io/@codemcd/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-4.-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EC%84%9C%EB%B9%84%EC%8A%A4
https://copycode.tistory.com/129
https://noep.github.io/2016/02/23/10th-filesystem/
https://drawdeveloper.tistory.com/27?category=670816

profile
아무것도 모르는 백엔드 3년차 개발자입니다 :)

0개의 댓글