3 분 소요

File System Implementation

File system Interface 들이 실제로 내부구조와 어떻게 작동하여 구현되는지에 대해 포스팅 하겠습니다.

  • File system 은 순수한 소프트웨어 입니다.
  • 즉, CPU 나 Memory 가상화와는 달리 추가적인 하드웨어들의 도움이 없습니다.

Overall Organization

  • Blocks
    • divide the disk into blocks
  • Data region
    • fixed portion of the disk for these blocks
    • 8 blocks (metaData) + 56 blocks (Data)
  • Metadata
    • 각각의 파일의 Track 정보 입니다.
    • inode (index node)
      • metadata 를 저장합니다.
      • disk 의 일정 부분(5 blocks of 8 blocks) 을 inode table 로 구성합니다.
  • Allocation structures
    • inodes 혹은 Data blocks 가 free 한지 혹은 할당되었는지 알기 위해 사용됩니다. (2 blocks)
    • Free list of bitmap
  • Superblock
    • 전체 file system 의 정보를 포함합니다. (1 block)
    • inode 와 data blocks 들의 갯수 혹은 시작점 그리고 끝점 등을 저장합니다.
    • File system 을 mounting 할때, 운영체제는 superblock 을 우선적으로 읽습니다.

inode

예를들어, Block size 를 4KB 라고 하겠습니다. 64 blocks 가 있으므로 총 256 KB partition 을 갖습니다. inode 의 사이즈가 256B 라고 한다면 한개의 block 안에는 16 개의 inodes 가 들어갈 수 있고 total 80개의 inode 를 갖습니다.

i-number

각각의 inode 들은 내부적으로 number 로 참조되어 있습니다. i-number 를 제공받으면 inode 가 위치한 disk 의 위치를 직접적으로 계산할 수 있습니다.

  • inode number 32
    • offset into the inode : 32 * sizeof(inode) = 8KB
    • start address of the inode table on disk : 12KB
    • 8 + 12 = 20KB
  • Disk 는 byte 단위로 읽지 않고 Sector 단위로 읽습니다. 즉, 해당 inode 를 읽기 위해서는 sector 번호를 알아야 합니다.
    • 하나의 sector 는 보통 512B 입니다.
    • sector address : (20*1024) / 512 = 40

Multi-level index

inode 는 고정된 수의 direct pointers 와 한개의 indirect pointer 를 가지고 있습니다.

  • indirect pointer
    • Data block 을 가리키지만, 해당 Data block 안에는 다시 Data block 을 가리키는 pointer 포함합니다.
    • 만약 file 이 충분히 커지면 indirect block 이 할당됩니다.
    • Double indirect pointer 는 충분이 큰 files 에 대하여 지원합니다.

Directory Organization

Directory 도 일종의 file 처럼 관리됩니다. inode 에 regular file 대신 “directory” 로 marking 됩니다. Direct pointer 를 타고 Data block 을 들어가면 entry name, i-number 쌍을 저장하고 있습니다. 추가로 record length 정보와 file name 의 length 정보를 가지고 있습니다. 만약 file 지울 때 Data 를 모두 초기화 하는 작업은 overhead 를 발생시킬 수 있습니다. 그리하여 i-number 를 0으로 바꾸는 작업만 수행합니다. 만약 새로운 entry 가 이전에 사용했던 entry 의 length 를 넘지 않는다면, 해당 entry 를 재사용하게 됩니다.

Rading a File from Disk

  • open(“/foo/bar”, O RDONLY)
    • 우선 file /foo/bar 의 inode 를 찾습니다.
      • Root directory 의 inode 를 읽습니다
      • foo 의 entry 를 찾고 foo 의 i-number 를 찾습니다
      • foo 의 inode 를 포함하고 있는 block 을 읽고 bar 의 inode 를 찾습니다
  • bar 의 inode 를 memory 로 읽습니다.
  • permission check
  • file descriptor 를 할당합니다.
  • read()
    • file 의 첫번째 block 을 읽어와 inode 정보를 얻습니다.
    • indoe 의 access time 을 update 합니다.
    • file offset update
    • read pointer 를 4KB 증가시킵니다.
  • close()
    • file descriptor 를 반납합니다
  • write()
    • Data block 에 write 합니다.
    • 만약, 새롭게 file 을 open 한다면 data block 을 새로 할당해주고 inode 를 update 해야합니다.
      • data bitmap 을 읽습니다
      • bitmap 을 update 합니다
      • inode 를 읽어오고 update 합니다
      • 실제 data block 에 write 작업을 합니다.

Caching and Buffering

reading 과 writing 작업은 매우 비싸고 disk 에 많은 I/O 를 발생시킵니다. 운영체제는 이러한 문제를 해결하기 위해 page cache 를 관리하고 있습니다.

  • Page cache
    • 자주 읽는 data block 에 대해 cache 에 그 정보 (ex. inode and data)를 저장합니다.
  • Write buffering
    • write 정보를 buffering 하여 delay 시키고 한번에 update 합니다.
    • disk scheduling 이 효과적 입니다.
    • 같은 영역에 대해 여러번 write 이 발생할 시 최신 과정만 update 하면 됩니다.

문제점

cache 와 buffer 은 memory 에 지니고 있습니다. 즉, momory 에 한시적으로 가지고 있을 때 전원이 꺼지면 disk 의 정보와 memory 정보 간에 불일치가 발생합니다. 즉 update 가 되지 않습니다.

업데이트: