Layered Structure
- 드라이버 : 물리디스크 => 논리디스크로 추상화
- FS : 논리 디스크 블럭들을 파일이라는 객체로 추상화
- 시스템콜 : 인터페이스로 추상화
- VFS : specific한 파일 시스템을 통일된 인터페이스로 추상화
- 라이브러리 : 시스템콜 추상화
- 커널로 진입해서 brk()로 반복해서 할당받으면 비효율적이므로 4096B를 미리 할당받음
- 다른 mlloc이 오면 제공
- ext2,3,4 FAT를 통합한 인터페이스로 사용자에게 제공해야한다.
- block driver : I/O 스케줄링 , Request 통합
- 라이브러리 => 시스템콜 , 모드스위치 필요 / 인텔에서는 trap
- 파일시스템에서는 커널스레드 사용, 락, 세마포어
- 파일시스템에서 데이터를 읽어올 때 페이지 캐시, 버퍼를 통해 읽어옴
- 페이지 : 4KB
- 버퍼캐시 : 필요한 아이노드 사이즈만큼 // ex)bread
- 블럭레이어 : I/O
VFS
- 소프트웨어 계층
- 사용자 프로세스와 특정한 파일시스템의 중간 역할을 하는 레이어
- 직접 호출하는 것이 아니라 함수 포인터를 활용한다.
VFS가 필요한 이유
- 3개의 파일 시스템이 있다. 각각 파일시스템마다 open 함수가 다르고 inode 구조가 다르다.
- 각각 호출하려면 너무 힘들다.
- 층을 도입. ==> VFS (open으로 통일)
- 사용자가 입력한 open을 inode를 통해 어느 파일시스템에 존재하는 open인지 조사를 함.
- type를 판단해서 매핑을 함
- 다양한 오퍼레이션을 정의
VFS에서 사용하고 있는 핵심적인 자료구조
- struct_file : 사용자관점)open된 파일 관리
- file operations: open, read, write, lseek, ioctl
- struct_inode : FS관점) mode , inode number
- create , link , unlink , mkdir , lookup
- address_number : 파일을 read ,write시 페이지로 매핑됨 ==> 읽어온 페이지들을 페이지 캐시로 관리.
- address_space operations: readpage, writepage, set_page_dirty
- struct_dentry : 파일 이름에서 아이노드까지 연결 관리
- dentry operations: d_hash, d_compare (for lookup), revalidate, ..
- struct_super_block : 파일시스템 자체를 관리.
- superblock operations: statfs, sync_fs, alloc_inode, write_inode, …
- 태스크 스트럭트 => 파일 디스크립터 => 터미널 가리킴 => 파일 스트럭쳐 => 5가지 자료구조
- open된 파일들의 offset이 파일 스트럭쳐에 존재
- dentry를 따라가면 inode를 가리키는 포인터가 존재.
- inode가 어느 파일에 있는지 슈퍼블럭을 가리키는 필드가 있음.
- 매핑 : 어느 어드레스 스페이스인지를 가리킬 수 있음
- address는 페이지들의 집합. 위의 네모들이 해당 오프셋에 대응되는 데이터를 특정 페이지에 담아온다.
정리) 각각 자료구조는 오퍼레이션을 가지고 있다. 파일스트럭쳐는 파일 오퍼레이션 , 아이노드를 따라가면 아이노드 오퍼레이션: 아이노드를 생성하는 오퍼레이션 ....
파일시스템 입장에서 필요한 오퍼레이션
- open/create: open, mkdir, link, lookup, alloc_inode, alloc_block, …
- read/write: read, write, readdir, get_block, bio_submit, bread, …
- page cache: readpage, writepage, set_dirty, …
- mount: mount, fs_type, fill_super, …
- hello.c의 아이노드를 알아낼 수 있는 인터페이스가 필요하다.
- lookup사용 , 아이노드 할당 , 블럭 할당 등의 오퍼레이션이 필요
- getblock : offset을 적용한 디스크 블럭의 위치 파악
- biosubmit : 블럭i/o를 블록 드라이버에 보냄
파일시스템이 커널의 어떤 요소들과 상호작용?
1. System call: open, read, readdir, …
2. Page cache (buffer cache): readpage, …
3. Block driver: submit_bio, …
4. FS Initialization: mount, fs_type, …
정리
- read()가 vfs read를 호출 => 파일오퍼레이션 자료구조를 통해 normal한 read로 체크
- normal한 read면 new_sync_read()로 이동
- 여기서 specific한 fs로 이동. ext2일 경우 ext2_files_read_iter()로 이동
- 여기서 direct i/o or page cache를 검색하는 부분으로 올라옴
- 이후 버퍼를 뒤지고 발견이 되면 get_pages , 없으면 no_cache_page
- 이후 버퍼드 리드 페이지 라는 함수를 부르게되고, 페이지를 할당받아서 lru에 집어넣고
- 그 페이지를 인자로하여 readpage()를 호출함. // address_space operations
- 여기서 vfs 인터페이스가 specific한 인터페이스로 매핑을 한다.
==> ext2_readpage
- mpage_readpage 호출
- ext2 get_block을 인자로 넘겨서 어느위치에 몇번 디스크 블록을 접근하면 되는지 완성해 준다. 그리고 submit_bio를 불러서 블럭레이어를 통해서 디바이스 드라이버로 들어간다.