여행다니는 펭귄

I/O , File 과 Directory 측면에서 본문

컴퓨터/운영체제

I/O , File 과 Directory 측면에서

핑구힝구 2021. 12. 10. 23:09

전 글에서 Process Virtualization, Memory Virtualization에 대해 모두 다루었죠?

이제는 마지막 Virtualization인 Storage Virtualization에 대해서 다뤄보도록 하겠습니다.

 

우리가 어떤 저장장치를 쓰던 관계없이, 저희는 일관적인 방식으로 Storage에 접근할 수 있어야 해요.

여기엔 두 가지 Concept가 필요합니다.

 

  • File
    • File은 연속된 array의 bit으로, 저희가 읽고 쓸 수 있습니다.
      • 이것의 내용은 제작자에 의해 정의됩니다 ( text 파일인지 binary 파일인지)
      • 그리고 inode number로 식별되죠 ( pid 와 비슷한 개념 )
  • Directory
    • Directory는 특별한 종류의 파일로 다른 파일과 다른 디렉토리를 Collection 한 것입니다
      • 이것의 내용은 앞에 나온것과는 다르게 (filename(user readable name), inode) 의 집합이 됩니다.
      • Hierarchical한 구조를 가집니다.
      • 이것 역시 inode number로 식별됩니다.

이 두가지 개념을 통해서 OS가 Storage를 관리하는 것입니다.

 

 

 

UNIX File System은 어떻게 돌아갈까요?

UNIX는 file의 컨셉트를 아주 폭 넓게 보아서 normal file 뿐 아니라 프로세스간 통신 경로, 각종 I/O 장치들을 전부 포함시켰습니다. Kernel 역시 파일로 관리되지요.

그리고 이 파일 역시도 inode number로 식별됩니다.

Directory 역시 파일이며 inode number을 가집니다. (user-readable name, inode number)을 포함하는 리스트죠.

 

그렇다면 어떤 파일이던 열어볼 수 있을까요?

이런 열기, 읽기 권한같은 경우는 다음과 같은 개념으로 관리됩니다.

 

  • Ownership
    • 각 파일에는 그 파일을 소유한 User가 있습니다.
    • Owner는 어떤 Permission을 줄지 결정할 수 있습니다.
  • Permissions
    • 누가 파일에 접근할 수 있는지, 어떤 방식으로 접근이 가능한지 입니다.
    • Ownership에 의해 부여됩니다.

Permission은 어떻게 표현될까요?

 

UNIX에서 File I/O는 어떻게 할까요?

 

  • Opening Files
    • File을 오픈하기 위해서는 Kernel에 File에 Access하고 싶다고 알립니다. 
    • int fd; // file descriptor if ((fd = open("/etc/hosts", O_RDONLY) <0 ){ perror("open"); exit(1); }​
    • 그러면 file descripter를 file을 식별하기 위해서 반환해 줍니다.
      • file descriptor 0,1,2는 각각 standard input/output/error 입니다.
    • 만약 -1 이면 정상적으로 열리지 않았다는 의미입니다.
  • Closing Files
    • File Descriptor를 사용해서 File을 닫습니다. 이때도 Kernel에게 File을 닫는다는 사실을 알려야 합니다.
      int fd;
      int retval;
      if ((retval = close(fd)) < 0){
          perror("close");
          exit(1);
      }​
    • 이 경우에 Return Value 역시 Error Check에 사용됩니다.
  • Reading and writing
    • 일단 open() 으로 file을 열고 난 뒤에 read(), write()를 시스템 콜로 호출하고, close()를 해 줍니다.
    • 만약 파일이 클 경우 반복해서 호출해 줘야 합니다.
      • open( file name with path , flags)
        • file descriptor를 return 합니다.
      • read(file descriptor, buffer pointer, the size of buffer)
        • 이것이 읽은 byte의 수를 return 합니다
      • write(file descriptor, buffer pointer, the size of buffer)
        • 이것이 쓴 byte의 수를 return 합니다.
        • Read and Write는 Current offset 이 있어서 내가 어느 위치에 있는지를 확인해야 합니다.
          • Implicitly : N byte를 읽었다면, Offset이 N만큼 늘어납니다
          • Explicitly : lseek() 함수를 통해 조정할 수 있습니다.
      • lssek(int fildes, off_t offset, int whence)
        • 위 함수는 whence ( 0 = seek_set, 1 = seek_cur, 2 seek_end ) 로 부터 offset만큼 떨어진 곳으로 current offset을 조정합니다.
  • Renaming Files
    • atomic cell로 일어나는 작업입니다.
    • 바꿀 이름의 파일을 만들고 copy한 다음 fsnyc()를 호출해서 모든 파일의 변경점을 디스크에 기록해야 합니다.
    • 그 후에 기존 파일을 지웁니다.
  • Getting Informatiion About Files
    • fstat(), stat() 함수를 통해 파일의 메타데이터를 볼 수 있습니다.
    • 이 메타데이터는 disk의 innode structure에 저장됩니다.
  • Removing Files
    • unlink()라는 함수를 통해서 파일을 지우는데, 이게 delete나 remove가 아닌 이유는 linking에 대해서 알아보면서 살펴봐야 합니다.
    • 여기서 간단하게 설명하자면, 파일을 0으로 덮어씌우는 그런것이 아니라 접근할 수 있는 주소를 없앤다는것이 맞는 표현입니다.
  • Making Directories
    • mkdir()을 통해 디렉토리를 만듭니다.
    • Directory가 맨 처음 생성되었을때 그것은 비어있습니다.
    • 그 다음 자기 자신과 Parent로 가는 엔트리만 추가됩니다.
  • Reading Directories
    • ls 함수를 통해서 directory를 읽을 수 있습니다.
    • Directory가 (inode, user readable) name으로 되어있다고 했는데, 이를 읽는 것이 directory를 읽는 것입니다.
    • 이는 struct dirent 안에 포함되어 관리됩니다.
  • Deleting a directory
    • rmdir()로 Directory를 지웁니다.
    • empty한 경우에만 실행할 수 있습니다.

 

Link는 무엇일까요?

 

아까 Link에 대해 언급을 간단하게 했었죠? Link의 종류에는 Hard link가 있고 Soft Link가 있습니다.

 

Hard Link는 link(or ln)(old pathname, new one)이라는 함수를 통해서 하게되는데 이 llink 함수는 어떻게 동작할까요?

  • 새로운 이름을 가진 file 하나를 directory에 생성합니다.
  • Original file의 inode number를 file에 줍니다.
  • 그렇게 되면 복제하여 저장할 필요 없이 하나의 파일을 두개 이상의 이름으로 참조할 수 있게 되는 것입니다.

이는 파일 이름이 기본 메타데이터에 대한 링크임을 보여줍니다.

그러니 기본 파일은 그대로 있고, 저희는 link를 통해서 이 file을 찾을 경로를 생성하는 셈입니다.

 

그래서 remove를 할때 unlink를 통해 이 파일을 찾을 수 있는 경로만 끊어내는 것이죠.

reference count는 특정 inode를 가진 파일이 얼마나 많이 링크되어있는지의 수를 보여주는데, unlik가 호출되면 reference count는 감소합니다.

만약 reference count가 0이라면 파일 시스템이 이 파일을 절대 접근할 수 없기 때문에 Delete된 것과 마찬가지인 것이죠.

 

Hard Link에 대해 알아보았으니 Symbolic Link에 대해서도 알아봅시다.

 

Symbolic link는 hard link보다 훨씬 유용합니다.

Hard link는 다른 파티션에 있는 파일에 대해서 Link할 수 없기 때문이죠. 이는 inode number가 file system마다 unique한 것이기 때문입니다.

 

Symbolic link는 ln - s방식으로 이루어집니다.

그리고 Symbolic link는 Hard link와는 다르게 pathname을 저장하는 방식으로 이루어집니다. 

만약 pathname이 길면 Sybmolic link의 size도 커지게 됩니다.

 

다만 이는 Original File이 삭제되면 Symbolic link가 빈 곳의 주소를 참조하게 되는 Dangling reference문제를 발생시킵니다.

 

 

다른 file system은 어떻게 열 수 있을까요?

 

  • mkfs tool
    • file system을 만들 수 있습니다.
    • Input으로 partition된 disk와, file system type을 넣으면 됩니다.
    • Output으로는 루트 디렉토리를 가진 empty file system이 나옵니다.
  • mount()
    • 이것이 바로 다른 file system을 여는 방법이죠.
    • 이미 존재하는 디렉토리 하나를 mount point로 만들고, 새로운 파일 시스템을 그 mount point에 붙여넣습니다.
    • 그럼 무엇이 mount 될까요?
      • ext 3 : A standard disk-based file system
      • proc : A file system for accessing information about current process
      • tmpfs : A file system just for temporaray files
      • AFS : A distributed file system

 

 

'컴퓨터 > 운영체제' 카테고리의 다른 글

Paging  (0) 2021.12.12
File System Implementation  (0) 2021.12.12
Flash-based SSD  (0) 2021.12.10
HDD란?  (0) 2021.12.09
I/O Devices  (0) 2021.12.09