File and File System
Open()
메모리에 파일의 메타데이터가 올라가는것이다.
메타데이터에는 저장위치가 있으니까 포인터로 file content를 가르키고 있는 상태이다.
예시로, open("/a/b") 를 해보자.
그러면 우리는 b라는 메타데이터를 메모리로 가져와야한다.
사용자 메모리 영역에서 ProcessA가 open으로 system call을 하면, 운영체제로 cpu 가 넘어가서 커널로 들어가면 ProcessA의 PCB와 OpenFileTable이 존재하게 된다.
root의 metadata는 이미 알려져 있으므로, root의 metadata를 메모리에 올린다. 그러면 메타데이터에는 실제 content의 위치를 알 수 있으므로, content를 찾으러 간다.
그러면 이 root의 content에는 a의 메타데이터가 있다.
이걸 다시 메모리에 가져오고, b도 이런방식으로 수행하면, b라는 메타데이터가 processA의 PCB에서 b의 file descriptor로 저장이 되게 된다.
그래서 앞으로 fd의 index 숫자만 가지고 read write를 할 수 있게 되는것이다.
그래서 이 read system call의 파라미터로 이 fd라는 index 숫자를 넣어주는것이다.
그리고, b의 content를 read할때는 커널의 메모리 영역 내에서 buffer cache부분에 카피를 해놓고, processA에게 전달을 하는데 다른 프로세스나 해당 프로세스가 다시 read요청을 하면, 어쨋든 systemcall이니까 CPU제어권이 운영체제로 넘어가서 커널 영역으로 들어가게 되고, 거기서 cache에서 요청 file을 확인하고 있으면 buffer cache에서 주고 없으면 disk에서 꺼내서 가져오는 과정을 거친다.
핵심은 버츄얼 메모리와는 다르게, 여기서는 무조건 read,wirte던 뭐던 어차피 systemcall을 하는 방식이기 때문에, 어떤 요청을 하던 운영체제가 처리를 하게 된다.
그러면, 모든 정보를 운영체제가 전부 다 안다는 뜻이고, 이전 쳅터의 버츄얼 메모리는 모든 정보를 운영체제가 알지 못하고 반쪽짜리 정보만 알고 있으므로, LRU같은 알고리즘을 못썻지만, 여기서는 운영체제가 전부 관리 하므로 해당 알고리즘을 사용할 수 있다.
File Protection
각 파일에게 어떤 유형의 접근 read write execution을 허락할 것이냐?
Access Control
matrix를 사용하여서 열에는 사용자, 행에는 file을 둬서 권한을 표시한다.
문제가 user는 적고, file은 압도적으로 많기 때문에 빈공간이 생긴다.
Access Control List
파일을 주체로, file에 해당하는 read,write권한등을 가지고 있는 user들을 linked list로 연결한다. 그러면 matrix를 사용하는것보다 빈공간이 줄어든다.
Capability
사용자를 중심으로 해당 사용자에 접근 권한이 있는 file들을 linked list로 엮어논다.
Grouping
전체 user를 owner,group,public의 세 그룹으로 구분하고, 세그룹의 접근 권한을 3비트씩 표시한다.
rxxr r-- r--
현대 운영체제가 사용하는 방식
Password
파일마다 password를 두는 방법
접근 권한 별 passowrd 암기 문제, 관리 문제
File System의 Mounting
그림의 왼쪽 부분처럼 하나의 물리적 디스크를 파티셔닝을 통해 각 논리적 디스크1,2,3으로 나눌수 있다.
그리고 각 disk마다 file system을 설치할 수 있는데
하나의 파티션에서 다른 파티션으로 접근하기위해서 mount를 사용하여서 연결해서 사용한다.
AccesMethod
파일 정보의 접근 방식
순차접근
카세트 테이프처럼 읽거나 쓰면 offset이 자동적으로 증가
abc순서라면 a를 보고 c를 보고 싶다면, 반드시 b를 봐야하는 방식
직접 접근
LP 레코드처럼 파일을 구성하는 레코드를 임의의 순서로 접근가능
abc순서라면 a를 보고 c도 바로 볼 수 있음
Allocation of File Data in Disk
디스크에다 파일을 저장하는 방법
Contiguous Allocation
오른쪽이 디렉토리이면, tr이 14에서 start이면 3의 길이라면 contiguous는 14,15,16으로 저장을 한다.
그러나 모든 파일마다 크기가 균일하지 않으므로, blank가 생긴다.
file을 수정을 하면서 grouw가 생기는데 제한이 있다. -> blank만큼만 grow가능하기 때문이다.
Fast I/O 가능 한번의 seek/rotation을 통해 많은 바이트를 transfer한다.
Direct Access 가능 mail이라는 file의 5번째 block을 보고싶다면, 나머지 앞에 4개를 안봐도 그냥 start에서 5를 더해서 access 가능
Linked Allocation
start가 9번이면 다음 block의 위치를 16번 저장해 놓는것이다. 그런식으로 타고 타고 가다가 끝나면 -1로 설정해 놓는다.
직접 접근이 불가능 하다는 단점이 있다.
중간에 하나가 bad sector라서 고장나면 뒤에 껄 전부 다 놓친다.
변형-> file - allocation talbe FAT 파일 시스템
포인터를 별도의 위치에 보관해서 realiability와 공간 효율성 문제 해결 -> 뒤에서 설명
Indexed Allocation
직접 접근을 가능하게 하기 위해서 디렉토리에서는 index block을 가르키게 한다.
jeep라는 파일은 5개의 block으로 구성되어있고 나머지 안쓰는걸 -1로 설정해 놓는다.
장점으로 외부조각이 생기지 않으면서, 직접 접근이 가능하다.
단점으로는 small file일 경우 공간낭비가 생긴다 왜냐하면, index block이 필요하니까 실제로 많은 file이 small file이다.
또한 너무 큰 file일 경우에는 하나의 index block으로는 충분하지 못하는 경우가 있다.
Unix 파일 시스템의 구조
boot block - 부팅에 필요한 정보
super block - 파일 시스템에 관한 총체적인 정보를 담고 있음 -> 어디가 빈블록이고, 어디가 file이 저장되어 있는 블록인지 등등
Inode list - 파일의 메타데이터를 저장한다. (파일 block의 위치 정보)
파일의 크기가 작다면 direct blocks로 한번에 가르키고(index블록 없음)
파일의 크기가 크다면 indirect blocks들을 사용하여 index블록을 사용하여 single double triple로 가르킨다.
왜냐하면 대부분의 파일들은 크기가 작기 때문에 directBlocks를 사용하고, 가끔 만약 큰게 들어오면 indirect를 사용하면 된다.
FAT File System
FAT - 메타데이터의 일부를 FAT에다가 저장한다. 원래 메타데이터는 data block에 있는 directory file이 가지고 있다.
그러나 여기서는 file 이름, 접근 권한, 데이터, 파일의 첫번째 위치 등등을 directory에서 가지고 있지미나, 그 다음에 블락이 오는 위치를 FAT에다가 저장해 놓는다.
이렇게 하면, data에 block의 갯수가 n개가 있다면, FAT의 크키도 또한 n개 인데, 같은 file인지 아닌지를 구분하지 않고, 그냥 다음 block의 위치를 저장해둔다.
그래서 만약 217번에서 출발하면, 217번 block의 data를 전부 확인 했다면, FAT으로 가서 217번 다음의 파일 위치를 찾고 그게 616이니까 다시 data의 block번호 616으로 와서 data를 확인하고, 이런식으로 진행된다.
이렇게 하면, direct 접근이 가능한데, 왜냐하면 FAT은 아주작은 table이므로 Disk가 전부 Seek해야하는게 아니니까 그냥 3번째 블락을 보고싶은 FAT table을 3번째까지 타고타고 가서 block위치를 확인한 다음에 디스크 헤드를 이동시켜 seek하면 된다.
Free-Space Management
빈공간 관리 방법
Bit-Map
만약 block의 갯수가 n개라면, bitmap은 0번지부터 n-1번지 까지 있어서 그 block의 번째가 free인지 이미 쓰고있는지를 확인하는것이다.
연속적인 n개의 free block을 찾는데 효과적이다.
Linked List
비어있는 block들을 연결한다.
연속적인 가용공간을 찾는것이 쉽지 않다.
Grouping
Linked list방식 변형
첫번째 free block이 n개의 pointer를 가진다. 이게 index block의 역할을 하는것이다.
Counting
첫번째 블록과, 몇개가 연속적으로 비어있는지 갯수를 쌍으로 저장한다.
Directory Implementation(디렉토리 구현)
Linear list
파일 이름과 메타데이터를 순차적으로 저장하는것이다.
디렉토리 내에 파일이 있는지 찾기 위해서 linear search가 필요하다. 시간이 오래걸린다.
Hash Table
linear list + hashing
해시함수를 적용해서 파일명을 cccc->1로 바꿔서 저장하는것이다. search time을 없앴다.
File의 metadata의 보관위치는 앞에서 설명한것처럼 디렉토리 내에 직접 보관해도 되고 디렉토리에는 포인터를 두고 다른곳에 보관하는 방법도 있다. ex) inode,FAT
Long File name의 지원
포인터를 둬서 aaabb인데 aaa까지만 저장되면 나머지 bb는 포인터를 사용하여서 뒤에서부터 이름을 채운다.
Page Cache and Buffer Cache
Page Cache
우리가 메모리를 관리할때 page frame을 두고 당장 필요한 부분은 frame에다가 두고 사용하고 필요할때 마다 올려다가 쓰고 이런걸 cache의 관점에서 Page Cache라고 한다.
Buffer Cache
프로그램이 실행되는 과정에서 file 입출력을 해야할때 Disk에 있는 file에서 OS가 가져와서 커널 메모리 영역에 카피를 해두고 사용자 프로그램한테 전달해 주는것,
다음에 동일한 file data에 대한 read/write call이 오면 disk까지 안가고 처리한다.
고로 Page cache는 프로세스 주소공간을 구성하는 page가 당장 swap area에 내려가 있느냐 아님 올라와있느냐 이말을 하는거고, Buffer Cache에서는 file system내에서 file이 disk에 올라와 있냐 없냐 이걸 말한다.
최근에는 Unified Buffer Cache라고 해서 buffer cache가 page cache에 통합되서 사용된다. 위의 그림처럼 따로 buffer cache와 page cache가 구분되어서 사용되는것이 아니라, 그냥 구분없이 통채로 사용하다가 그때그때 필요할때마다 할당해서 사용한다.
Memory-Mapped I/O
프로세스의 주소공간 일부에다가 file을 mapping해두는 것이다. 그래서 나중에 file을 접근할때 기존처럼 Disk에서 read/write를 하는게 아니라 그냥 메모리 접근 연산을 통해서 파일 입출력을 수행한다.
왼쪽 그림에서 file을 I/O를 해야한다고 치자, 오른쪽 브랜치 경우에는 동일하게 OS한테 CPU가 넘어가서 그다음에 file read/write하고 buffer cache에다가 올린다음에 프로세스한테 파일을 넘겨준다면, memory-mmaped I/O에서는 page cache에 해당 파일이 올라와 있으므로 이건 자신의 주소공간에 있는 내용이니까 OS도움없이 그냥 메모리 접근법으로 file을 I/O한다.
오른쪽 그림에서는 unified buffer-cache에서는 경로가 더 단순한다. read/write syscall을할때는 운영체제가 buffer cache에 올라와있으면 그냥 카피해서 전해주고, 없다면 file system에서 불러와서 카피를 다시 해주고 프로세스한테 줘야한다. memory mapped io에서는 처음에 운영체제한테 자신의 주소 영역 중에 일부를 file에다가 mapping을 하고 나면, 사용자 프로그램의 주소영역에 page cache가 mapping되어 그냥 쓰면 된다.
이렇게 말하면 어려우니까 그림을 통해서 다시 알아보자
Memory mapped IO 과정
만약에 file system에 있는 검은색 데이터 파일을 가져다 쓰고싶은데 memory mapped Io과정으로 사용한다고 쳐보자. 그러면 우선, mmap()을 통해서 운영체제한테 프로세스가 해당 데이터파일 일부를 내 주소공간에 mapping해달라한다. 그러면 그림처럼 virtual memory의 주소공간에다가 일부를 매핑해둔다.
그러면 프로그램이 실행되면서 file 접근을 하게 될때, file 접근에 필요한 메모리 위치를 접근했을 때 없다면, page fault가 날것이다. 현재 검은색 data를 가져오지 않았으니까, 그러면 OS로 cpu가 넘어가서 그 page fault난 페이지를 물리적 페이지로 올려놓는다. 여기까지가 그림에서 physical memory에 검은색 data page 가 올라온것까지이다.
그후에 이 물리적 메모리에 올라간 페이지가 virtual memory에 올라간 검은색 data에 해당하는 page가 매핑되는것이다.
그러면 이제부터는 프로세스 B가 검은색 data에 접근을할때는 기존의 file을 read/write하기위해서 syscall을 하는게 아니라 OS의 도움을 받지 않고 그냥 자신의 주소공간에 있기 때문에 물리적 메모리에 있는 file에다가 직접 접근해서 read write할 수 있다.
고로, file에 대한 IO는 무조건 항상 OS의 도움을 받아야하는데, 이제는 그냥 physical memory에 올라와있는 file이 내 주소공간에 mapping되어있으니까 굳이 OS의 도움을 받지 않고 read/write할 수 있다는 말이다.