이 영역을 누르면 첫 페이지로 이동
천천히 꾸준히 조용히 블로그의 첫 페이지로 이동

천천히 꾸준히 조용히

페이지 맨 위로 올라가기

천천히 꾸준히 조용히

천천히 꾸준히 조용히.. i3months 블로그

[Operating System] File System

  • 2025.05.10 18:47
  • Computer Science/Operating System
반응형

 

 

 

파일은 보조 기억 장치에 저장되고 전원이 끊기더라도 지워지지 않는 정보의 저장 단위를 의미한다.

사용자가 파일을 만들면 운영체제는 그 정보를 저장하는 자료구조를 운영체제 내부에 만들어 파일과 함께 저장한다.

 

이 자료구조는 파일을 사용하지 않을 때는 보조 기억 장치에 있다가 파일을 사용할 때는 메모리에 올라온다.

 

 

 

 

이 자료구조를 File Control Block이라고 부른다.

이 자료구조는 파일명, 만들어진 시기, 권한을 가진 사람 등 여러 정보를 포함한다.

 

프로세스가 만들어질 때 함께 생성되는 PCB와 유사하지만.. PCB는 메인 메모리에서 관리되고 FCB는 보조 기억 장치에 저장된다.

 

사용자가 파일에 접근하려 할 때, 운영체제는 해당 파일이 존재하는지 확인하고 디스크의 어느 위치에 있는지 확인해야 한다.

위치를 알아낸 후 사용자가 해당 파일에 대한 적합한 권한이 있는지 확인하고, 동시성을 관리해준다.

파일을 수정해서 파일의 크기가 늘어났을 때, 디스크의 어느 공간에 파일을 다시 저장할지를 관리한다.

 

사용자가 파일을 다룰 때, 모든 작업은 운영체제의 System Call을 경유해서 수행된다.

 

 

 

리눅스에서 ls -l 명령어를 수행하면 위와 같은 메세지가 출력된다. 

 

첫 번째 파일은 hda라는 장치에 1993년 10월 3일에 만들어졌고, 소유주는 root이며 disk그룹에 포함된다.

해당 파일의 hda의 식별자로 major number는 3이고 minor number는 0이다.

 

b는 블럭형 장치를 의미하고 c는 문자 장치 파일을 의미한다.

그 뒷부분은 접근 권한을 나타내고, -를 기점으로 그룹 권한을 나타낸다.

 

 

 

 

컴퓨터 본체에 여러 터미널과 디스크들이 연결되어있다.

터미널은 모니터와 키보드로 구성되는데.. 한 컴퓨터에 접속하는 여러 사람이 있다고 생각하면 된다. 

 

유닉스 계열의 운영체제는 "모든 것은 파일"이라는 철학으로 설계되었다.

ls -l로 출력되는 결과에서 tty장치가 있는데, 운영체제는 일반 파일 / 디렉토리 / 장치 / 파이프 / 소켓 모든 요소를 파일으로 취급해 사용자나 프로그램이 하드웨어를 직접 다루지 않고 파일처럼 다룰 수 있도록 추상화한다. 

 

 

 

 

major number를 설정할 때는 운영체제가 미리 정의해두고 사용하는 번호를 피해서 설정하자.

 

디렉토리는 파일에 대한 정보를 가지고 있는 특수 파일이다.

파일도 파일이고.. 파일에 대한 정보를 가지고 있는 주체도 파일이다. 

FCB도 파일에 대한 정보를 가지고, 디렉토리도 파일에 대한 정보를 가지니 파일 속성이 변경될 때 두 군데를 모두 수정해야 해 비효율적이다.

 

논리적으로는 디렉토리가 파일 속성을 가지고 있는 것 처럼 보이지만, 물리적으로는 그렇지 않다.

보통 디렉토리에는 파일명과 FCB의 식별자만 저장한다.

 

 

 

계층 구조로 구성된 디렉토리에서 최상위는 Root Directory이고, 현재 작업 중인 디렉토리는 Current Directory이다.

 

FCB는 리눅스와 유닉스에서 inode라고 불리고, inode number는 FCB의 고유 식별자로 사용된다.
특정 파일을 읽으려면 그 파일이 어디에 저장되어있는지 알아야 하고, 그 정보는 FCB에 저장되어있다. 

 

 

 

FCB를 읽으려면 inode number를 알아야 한다. 

유닉스 운영체제에서 루트 노드의 inode는 2번으로 정해져 있고, 예시에서 140번 블록에는 루트 디렉토리의 내용이 들어있다.

 

/usr/member/list.txt 파일을 읽는다고 해보자. 

루트 노드의 inode부터 시작해서 계속해서 타고 가다 보면 해당 파일이 있는지 쉽게 확인할 수 있다. 

 

 

 

 

 

계층형 구조 대신 그래프 형태로 확장하면 링크를 통해 파일에 빠르게 접근할 수 있다. 


저 예시에서 a 파일을 지운 경우 b가 가리키는 파일도 없어지게 돼 dangling pointer문제가 발생한다.

윈도우에서는 dangling pointer가 발생했을 때 사용자가 알아서 처리하도록 유도하고, 리눅스에서는 Entry-count solution을 사용한다.

디렉토리에 파일이나 링크가 만들어 질 때 마다 Entry-Count 값을 증가시키고 제거 될 때 값을 감소시켜 0일 때만 파일을 지우는 방식이다.

 

커널은 동시성을 민감하게 다루는데, 파일에 대한 동시성은 사용자들이 알아서 관리하도록 유도한다. 

 

파일을 공유할 때, 파일마다 접근 권한을 설정해 줘야 한다.

운영체제는 파일에 대한 권한을 read / write / execute 세 가지로 나눠서 관리한다.

 

사용자는 세 가지로 구분된다.

owner, group, public 인데.. 여기서 owner는 파일의 소유자를 의미하고 public은 일반 사람들을 의미한다. 

 

 

 

 

파일 시스템은 파일을 저장하는 자료구조로, 보조 기억 장치에 저장되며 파일에 접근하는 알고리즘까지 포함한다. 

 

하나의 물리적인 디스크 위에서 하나의 파일 시스템만 사용하는 경우도 있고, 그림처럼 여러 영역으로 나눠 각 파티션마다 파일 시스템을 만들어서 사용하는 경우도 있고, 여러 디스크 위에서 하나의 파일 시스템만 사용하는 경우도 있다.

 

 

 

 

부트미디어로 정의된 부분에 Boot Block이 들어간다.

컴퓨터가 부팅되면 BIOS는 어떤 하드웨어가 컴퓨터에 연결되었는지 확인하고, 부트미디어에서 부트로더를 메모리로 읽는다.

CPU는 부트코드를 가져가서 실행하는데, 부트코드는 실제 운영체제가 저장된 영역으로 접근해 OS를 메모리로 읽는다.

 

 

Super Block은 파일 시스템에 대한 제어 정보를 가진 헤더 역할을 수행한다.

Partician(File System) Control Block이라고도 불리고 이 블럭이 손상되면 모든 파일에 접근할 수 없게 된다.

전체 파일시스템의 크기, 파일시스템 내 비어있는 데이터의 수, FCB의 개수, 어떤 inode가 비어있는지를 저장한다.

 

파일 하나당 inode가 하나씩 배정되니..

inode table에 만들어진 inode의 개수가 해당 파일 시스템이 담을 수 있는 파일의 최대 개수라고 할 수 있다.

 

FCB List

파일이 만들어지면 운영체제는 해당 파일에 대한 정보를 저장하는 FCB를 만드는데, 이 FCB는 파일 내부가 아니라 FCB List라는 공간에 따로 저장해둔다.

파일 시스템을 처음 만들 때 FCB List의 최대 길이가 정해진다.

 

Data block 에서는 실제 파일의 내용을 저장한다.

 

 

파일은 블럭 단위로 저장되고, 블럭의 단위는 4096바이트이다.
파일 하나가 만들어질 때, 파일 내용을 담을 데이터 블럭을 어떻게 연결할 지를 결정하는 방법을 File Allocation이라고 부른다.

 

Contiguous Allocation

디스크에서 연속된 블럭을 할당해서 파일을 저장하는 방법으로, 지금은 사용하지 않는 방법이다.

 

 

파일을 읽고 쓸 때 시간이 적게 걸리지만, External Fragmentation이 발생한다.

Framentation은 저장 장치에 작은 크기의 빈 공간이 생기는 현상을 의미하고, 이 Fragment들은 공간 활용에 방해된다.

 

External Fragmentation은 Fragment가 특정 파일의 외부에 있는 현상이고, Internal Fragmentation은 파일 내부에서 100% 사용하지 않는 블럭이 있는 현상이다. 

 

파일 크기가 커질 때, 이어지는 블럭이 없는 경우 새로운 공간을 찾아야 해 매우 비효율적이다. 

 

 

Chained Allocation

블럭의 구조를 바꿔보자. 모든 블럭은 다음 블럭을 가리키는 포인터를 포함한다.

LinkedList 자료구조를 생각하면 이해하기 쉽다.

 

 

 

 

FileB는 1번 블럭부터 시작해서, 따라오는 5개의 블럭으로 구성된다. (자신 포함) 

 

External Fragmentation을 걱정하지 않아도 되지만, 연결된 블럭 중 하나에서 Bad Sector 오류가 발생한 경우 연결되는 모든 블럭에 접근할 수 없고, 파일의 뒷부분을 읽으려면 앞에서부터 순차적으로 접근해야 해 Direct Access가 불가능하다. 

 

 

Indexed Allocation

파일의 데이터 블럭을 Index Block이라는 별도의 테이블에 저장한다. 

 

 

 

Index Block에는 파일의 순서대로 주소가 저장된다. 

이제 파일은 Index Block만 알려주면 해당 내용을 통해 전체 파일에 접근할 수 있다. 

 

인덱스 블럭을 하나 더 쓰는 셈이니.. 원래 파일을 저장 할 때 보다 블럭을 하나 더 사용한다.

인덱스 블럭에서 Bad Sector가 발생하면 전체 파일에 접근할 수 없지만.. 파일 블럭에서 Bad Sector가 발생하면 그 부분을 제외한 나머지 부분은 인덱스 블럭을 통해 접근할 수 있다. 

 

파일의 확장도 쉽고, Direct Access도 가능해 가장 많이 사용되는 방식이다. 

 

 

 


 

 

 

 

디스크에 구성되는 전체 파일을 어떻게 관리할 지 생각해보자.

디스크의 블럭이 특정 파일로부터 할당됐는지 할당되지 않았는지는 Super Block이 관리한다.

 

 

Counting 

디스크 내 할당되지 않은 블럭을 계산할 때 Contiguous Allocation과 유사한 방법을 사용한다.

 

 

"n번 블럭에서 시작해 k개의 블럭이 비어 있다"형식으로 Counting한다.

 

 

 

LinkedList

Chained Allocation 방식으로 비어 있는 블럭을 Counting한다.

블럭에서 다음으로 비어 있는 블럭의 번호를 따로 저장해 빈 블럭을 연쇄적으로 찾아갈 수 있다.

 

 

 

어차피 빈 데이터 블럭을 할당해 주니까.. 굳이 뒤에서부터 할당할 필요가 없어 새로운 블럭을 할당할 때 head를 조작하면 된다.

Bad Sector 문제는 여전히 해결되지 않는다. 

 

 

Grouping

유닉스 초기 파일 시스템에서 사용된 방법으로, Indexed Allocation 방식을 사용한다.

비어 있는 블럭의 정보를 Index Block에 저장한다. 

 

 

 

 

파일 시스템의 Super Block 중 하나를 인덱스 번호를 저장하는 용도로 사용한다.

109가 저장되어있는데, 109번 블럭이 비어있으니 파일을 저장할 수 있음을 의미한다. 

 

블럭은 4096바이트이고 정수는 4바이트니까 1024개의 정수를 저장할 수 있고, 1024개의 블럭 정보를 저장할 수 있다. 

1024개를 모두 저장했는데 비어 있는 블럭이 남아있다면 제일 처음 빈 블럭인 109번 블럭을 임시로 인덱스 블럭으로 사용한다. 

그래도 부족하다면 109번 블럭에서 제일 첫 번째로 저장된 비어 있는 블럭을 인덱스 블럭으로 사용하고... 

이런식으로 연쇄적으로 계속해서 빈 블럭을 저장한다.

 

빈 블럭을 사용해야 하는 경우 뒤에서부터 사용하도록 해 임시로 지정한 인덱스 블럭이 최대한 사용되지 않도록 한다.

임시 데이터 블럭으로 사용되는 109번 블럭에 일반 데이터를 할당할 때는, Super Block에 인덱스 관련 정보를 모두 복사한다. 

 

 

Bit Vector (Bit Map)

리눅스에서 사용하는 방식으로, 파일 시스템 내 데이터 블럭의 수 만큼 비트블럭을 할당한다. 

 

 

여기서 n은 파일 시스템 내 존재하는 모든 블럭의 수를 의미한다.

0이 사용중이고 1이 비어있음을 의미하는데, 이렇게 설정해야 비어 있는 블럭을 빠르게 찾을 수 있다. 

 

편리하고 좋은 방법이지만.. 공간을 너무 많이 차지한다. 

1TB는 2^40바이트인데.. 이러면 블럭의 수는 2^28개가 나오고.. 비트맵은 32MBytes 크기를 가진다. 

 

 


 

 

유닉스의 파일 시스템과 리눅스 파일 시스템을 살펴보자.

 

 

 

inode lists는 유닉스에서 FCB를 부르는 명칭이다.

유닉스는 Indexed Allocation을 살짝 변형한 방식을 사용해 파일을 관리한다. 

 

 

 

 

한 인덱스 블럭에서는 1024개의 인덱스 넘버를 저장할 수 있고, 인덱스 블럭의 위치를 각 파일의 FCB에다가 저장한다.

인덱스 넘버를 모두 인덱스 블럭에다가만 저장하지 않고, 일부는 inode에 저장하는데 전부 저장하기에는 번호가 너무 많으니 첫 10개만 inode에 직접 저장한다. (추후 12개로 확장 - direct block)

 

하나당 4KBytes이니 Direct Block으로는 40KB를 접근할 수 있다. 

 

그 다음부터는 인덱스 블럭을 사용하는데, indirect block은 single / double / triple indirect로 구분된다.

 

single indirect는 인덱스 블럭을 한 번 거쳐서 가면 파일 내용에 접근할 수 있고, 

double indirect는 인덱스 블럭을 두 번 거쳐서 가면 파일 내용에 접근할 수 있다.

 

블럭은 하나당 4KB이고, 하나의 인덱스 블럭은 1024개의 블럭을 포인팅 할 수 있으니 Single Indirect로는 4MB를 접근할 수 있다.

같은 원리로 Double Indirect로는 4GB를, Triple Indirect로는 4TB를 접근할 수 있다.

 

따라서 예전 유닉스 운영체제의 최대 크기는 4TB + 4GB + 4MB + 40KB 로 계산된다.

현대 유닉스 운영체제도 숫자만 다르고 같은 방식으로 파일을 관리한다. 

 

블럭 사이즈를 더 크게 만들거나.. quad indirect를 지원하거나.. 더 큰 파일을 다루는 건 가능하지만, 파일 하나를 너무 크게 다루는건 효율적이지 않고, 여러 개의 파일에 나눠서 저장할 때 읽기 / 쓰기 성능이 더 좋다.

 

inode 자체는 디스크에 저장되어 있지만 file open을 통해 메인 메모리로 읽어들인다.

그러니 direct block, indirect block 자체는 빠르게 읽을 수 있지만, indirect 방식을 사용하면 Disk Access를 그만큼 더 많이 해야 한다. 

 

 

리눅스에서는 Virtual File System을 사용한다. (논리적인 파일 시스템)

 

 

 

 

 

파일 시스템마다 설계자가 달라 그 구조나 접근하는 방식이 다르다. 

파일에 접근하는 응용 프로그램을 구현할 때, 해당 파일이 어떤 파일 시스템에 속한 파일인지에 따라서 로직을 다르게 작성해야 하는데.. Virtual File System은 이 부분을 추상화해서 파일 시스템의 종류에 상관 없이 리눅스에서 접근할 수 있도록 도와준다.

 

자바의 interface와 동일한 개념이다. 사용자들은 Virtual File System Call 만 알고 응용 프로그램을 작성할 수 있다. 

 

Virtual File System이 없다면 운영체제가 모든 파일 시스템의 코드를 가지고 있어야 하는데.. 이러면 운영체제의 크기가 커져 메인메모리의 공간이 부족해진다. 

물론 모듈 기능을 사용해 디스크에 파일 시스템 코드를 준비해 두고  필요할 때 동적으로 추가하고 제거하는 방식을 사용하긴 하지만, VFS는 항상 함께 사용된다. 

 

Page Cache는 입출력 관리에서 사용되는 Disk Cache 및 Buffer Cache와 같은 의미로 사용된다.

Disk Controller를 통해 디스크에서 블럭을 읽어오면 임시로 그 값을 저장하는 캐시라고 생각하면 된다. 

 

 

 

 

전반적인 구조는 비슷하다. 

초기 유닉스 파일 시스템과는 다르게 리눅스에서는 direct block이 12개이고, 요즘 사용되는 ex4 inode의 크기는 256바이트로 이전과 비교했을 때 2배 커졌다. 

 

 

파일 관련 연산을 수행할 때는 System Call을 사용해 운영체제에게 요청하는데, 운영체제는 사용자가 다루는 파일이 어떤 파일인지 파악하고 적절한 연산을 수행한다. 

 

 

 

 

 

운영체제는 파일 타입별로 그 타입에 해당되는 연산들을 함수로 구현해두고, 그 함수의 주소를 테이블에 기록한다. 

FCB의 file_operation 필드에 저 주소 테이블이 저장되고, 파일을 다룰 때 사용된다. 

 

 

 

 

 

새로운 프로세스가 만들어지면 task_struct(PCB)가 만들어지고, PCB의 files 필드에 files_struct 주소를 저장한다.

files_struct는 file descriptor를 저장하고, file을 가리킨다. (경유지 역할)

 

file에는 현재 파일을 어떤 권한으로 열었는지, 파일을 열고 있는 프로세스는 몇 개인지, 파일 명령어의 주소는 어디인지 등 파일 관련 정보를 저장한다.

task_struct, file_struct는 프로세스마다 하나씩 만들어지고, file table은 운영체제에 하나만 존재한다.

 

 

 

 

 

프로그램이 System Call을 호출하면 컴파일러는 sys_open 등 적당한 이름으로 바꿔서 호출한다.

커널은 내부적으로 filp_open 함수를 호출하고, filp_open 함수는 open_namei 함수를 호출한다. 

이 함수는 해당 파일이 실제로 존재하는 파일인지를 검사하고 inode 번호를 반환한다.

filp_open 함수는 inode를 가지고 struct_file 공간을 할당하고 f_op 함수를 호출한다. 

 

read 함수도 open 함수와 비슷한 흐름으로 처리된다. 

 

 

 

 

 

 

 

 

 

 

반응형
저작자표시 (새창열림)

'Computer Science > Operating System' 카테고리의 다른 글

[Operating System] Disk Scheduling  (0) 2025.05.13
[Operating System] I/O Management  (0) 2025.05.11
[Operating System] Deadlock and Starvation  (0) 2025.04.13
[Operating System] Semaphore  (0) 2025.04.08
[Operating System] 프로세스와 동시성 제어  (0) 2025.03.28

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [Operating System] Disk Scheduling

    [Operating System] Disk Scheduling

    2025.05.13
  • [Operating System] I/O Management

    [Operating System] I/O Management

    2025.05.11
  • [Operating System] Deadlock and Starvation

    [Operating System] Deadlock and Starvation

    2025.04.13
  • [Operating System] Semaphore

    [Operating System] Semaphore

    2025.04.08
다른 글 더 둘러보기

정보

천천히 꾸준히 조용히 블로그의 첫 페이지로 이동

천천히 꾸준히 조용히

  • 천천히 꾸준히 조용히의 첫 페이지로 이동

검색

방문자

  • 전체 방문자
  • 오늘
  • 어제

카테고리

  • 분류 전체보기 (679) N
    • Algorithm (205)
      • Data Structure (5)
      • Theory && Tip (33)
      • Baekjoon (166)
      • ALGOSPOT (1)
    • Spring (123)
      • Spring (28)
      • Spring Web MVC (20)
      • Spring Database (14)
      • Spring Boot (6)
      • Spring 3.1 (11)
      • Spring Batch (6)
      • Spring Security (16)
      • JPA (12)
      • Spring Data JPA (5)
      • QueryDSL (4)
      • eGovFramework (1)
    • Programming Language (74)
      • C (25)
      • C++ (12)
      • Java (19)
      • JavaScript (15)
      • Python (1)
      • PHP (2)
    • Computer Science (142)
      • Machine Learning (38)
      • Operating System (18)
      • Computer Network (28)
      • System Programming (22)
      • Universial Programming Lang.. (8)
      • Computer Architecture (4)
      • Compiler Design (11)
      • Computer Security (13)
    • Database (21)
      • Database (7)
      • MySQL (3)
      • Oracle (3)
      • Redis (5)
      • Elasticsearch (3)
    • DevOps (20)
      • Docker && Kubernetes (8)
      • Jenkins (4)
      • Amazon Web Service (8)
    • Mobile (28)
      • Android (21)
      • Flutter (7)
    • 💡 솔루션 (17)
    • 👥 모각코 (10)
    • 💬 기록 (8) N
    • 📚 공부 (6)
    • -------------- (25)

최근 글

나의 외부 링크

메뉴

  • 홈
반응형

정보

i3months의 천천히 꾸준히 조용히

천천히 꾸준히 조용히

i3months

블로그 구독하기

  • 구독하기
  • RSS 피드

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © i3months.

티스토리툴바