# File System

	 ----- fd -----              ---- inode ----              ---- device ----
	| 1:i1:a.file  | <--------- | i1:a.file     | <--------- | a.file         |
	|--------------|      /     |---------------|            |----------------|
	| 2:i1:a.file  | <----      |               |            |                |
	|--------------|    /       |---------------|            |----------------|
	| 3:i1:a.file  | <--      - | i3:b.file     | <--------- | b.file         |
	|--------------|         /  |---------------|            |----------------|
	| 4:i3:b.file  | <-------   |               |            | c.file         |
	|--------------|            |---------------|            |----------------|
	| 5:i5:d.file  | <--------- | i5:d.file     | <--------- | d.file         |
	 --------------              ---------------              ----------------

시스템은 하나의 file descriptor table 과 하나의 inode table 을 관리한다. inode
오브젝트는 파일당 단 하나의 오브젝트만 생성하는 반면, file descriptor 는
사용자가 open 할 때마다 새로운 instance 를 생성한다.

## embedfs

내장 플래시 파일 시스템(`/dev/efm`).

커널이 위치한 내장 플래시 메모리 공간은 /dev/efm. embedfs 사용할 공간은
/dev/efm1.

프로토타입인데다 공간낭비를 막기 위해 블럭 쓰기/읽기를 바이트 단위로
처리하다보니 최적화 여지가 많다. 아직 전체그림을 그리지 못해서 구조적으로도
허술한데 FAT이나 ext2 드라이버 구현하면서 대폭 개선될 듯.

직접블럭 7개 1/2/3차 간접 블럭 각 하나씩 총 10개의 데이터 블럭. 블럭 사이즈에
따라 파일의 최대 크기는 달라질 수 있지만, `WORD_SIZE`의 주소범위를 넘어서지는
못한다. inode의 사이즈 변수가 `int`형이기 때문이다. 즉, 32비트 시스템에서
파일의 사이즈는 4GB가 최대이다.

	블럭 사이즈(bytes) || 64      | 128       | 256        | 512
	-------------------||---------|-----------|------------|--------------
	파일 최대 크기     || 280,000 | 4,330,368 | 68,175,616 | 1,082,199,552

데이터 블럭 갯수를 늘리고 블럭 사이즈를 작게 유지하는 게 메모리 절약에
유리해보인다. 하지만 데이터 블럭의 갯수를 늘리거나 4차 5차까지 확장하는 건
코딩에 부담이 될 뿐더러 오버헤드가 커진다. 1k 미만 파일의 비중이 압도적인 것과
멀티미디어 파일까지 수용할 것을 고려한다면 직접블럭으로 1k까지 커버, 간접블럭
포함하여 수MB 단위를 지원하는 게 적당해보인다. 루트 파일시스템의 경우 `/dev`
용도정도 뿐, 멀티미디어 파일 같은 경우 ext나 fat등의 여타 파일시스템을 마운트
해서 사용하게 될 것이므로 디폴트는 페이지 사이즈로.

`FT_DEV` 타입일 경우 디바이스의 주번호와 부번호는 `data[0]`에 저장됨.

할당받은 고유한 물리 메모리 주소를 그대로 inode로 사용하는 것은 보안상 문제가
발생할 수 있음.

파일 시스템 구현을 앞두고 보름 넘게 손을 놓았다. 잘 몰라서 그런지 한없이
게을러지는. 이번주에는 마무리 합시다!!

----

램 상에 인터페이스만 구현해두고 디바이스 노드만 생성해서 사용한다는 대충의
생각으로 코딩을 시작했는데, 결과가 썩 만족스럽지 않다. 그래서 어설픈 위의 초기
구현을 대체할 파일 시스템을 구축하기로. 버퍼와 같은 최적화는 차후에 고려하도록
하고, 커널외의 플래시 공간 또는 EEPROM을 적절한 블럭크기의 파일 시스템을
구축한다.

플래시 메모리의 비영구적 쓰기 특성을 고려하지 않은 소형 시스템을 운영하기 위한
기본 파일 시스템으로 설계되었기 때문에 쓰기는 가급적 제한하도록 한다. 소형
시스템의 내부 플래시 메모리는 파일 시스템을 운용할만큼 용량이 크지도 않다.
그리고 내장 플래시 메모리에 쓰는 동안 플래시 메모리로 접근이 stall된다. 즉
그동안 플래시 메모리에 저장된 코드를 실행할 수 없으므로(중지되므로) 시스템
성능이 저하된다.

파일 시스템을 구축하기로 한 이상, 모든 디바이스 노드는 파일을 통해, 즉 inode
형으로 일반화한다.

	내부 플래시 메모리 맵:

	                         [0]      [1]      [2]                ......               [N-1]
	 --------------------------------------------------- ~ --------- ~ ------------ ~ ----------
	| .text | .data | .bss   | super  | inode  | data       | inode     | data   |  ~  | data   |
	|                        | block  | bitmap | bitmap     | table     | block  |  ~  | block  |
	|------------------------|-------------------------- ~ --------- ~ ------------ ~ ----------|
	|<---- kernel space ---->|<------------------------- file system -------------------------->|
	v
	0x00000000

	kernel space 와 super block 사이에는 블럭크기로 정렬하기 위한 padding이
	삽입된다.

	block[0] = superblock
	block[1] = inode bitmap
	block[2] = data bitmap

inode는 디스크 전체 사이즈의 1% 를 취하도록 한다.

	The total number of inodes = disk_size * 1/100 / inode_size

inode 크기를 최소 64바이트라 가정할 때 최소 10개의 inode를 확보하기 위해서는
적어도 64KiB 이상의 디스크 용량이 필요하다. 최소한의 정보만 유지하더라도 inode
사이즈는 60바이트 전후가 최소다. 커널 자체 공간도 고려한다면 64KiB 이하는
무리다(하지만, SD 카드등 외부 디스크를 활용할 수 있을 것이다). 최소한의
디바이스 노드만 생성할 요량이라면 inode 비율을 늘려 32KiB 까지 어찌저찌 커버할
수 있을지도 모르겠다. 커널 크기가 있으므로 그 이하는 욕심내지 않기로.

메타 데이터 백업본을 유지하는 게 좋겠지만 차후 추가하는 걸로.

디렉토리 항목에서 레코드 길이를 유지함으로써 파일 삭제시 해당 공간을 재할당
가능하도록 한다(램 상에 그냥 인터페이스만 구현할 때는 왜 레코드 길이를 유지해야
하나 싶었는데).

구현에 앞서 포팅을 염두해 둔 시스템들의 롬 블럭 사이즈와 in application
programming 의 가능여부를 확인해 둘 것.

super block 과 inode bitmap 크기는 항상 1블럭. 할당 가능한 inode와 block 갯수만
유지하고, 할당시 순차검색.

할당 가능한 최대 inode 갯수는 65536(2 bytes).

블럭 사이즈가 커질 경우, 버퍼로 사용되는 로컬 변수들 때문에 스택 오버플로우
발생 여지

### super block

	inode_size
	block_size
	free_inodes_count
	free_blocks_count
	inode_table
	data_block
	root_inode
	magic

### inode bitmap

항상 1블럭만 차지하므로 할당할 수 있는 최대 inode 갯수는 `block_size * 8`.
inodes 전체 갯수 이상의 비트맵 영역은 사용중(1)으로 체크.

### data bitmap

	disk_size / block_size / 8

`block_size` 단위로 정렬. 남은 비트맵 영역은 사용중(1)으로 체크.

## VFS

### `fs_init()`

디바이스 노드를 등록하기 위해서 devfs가 마운트 되어 있어야 한다. devfs는
ramfs으로 구현된다. `device_init()`에서 디바이스 노드를 등록할 수 있도록
`fs_init()`에서 devfs를 마운트한다.

### mount

파일 시스템 드라이버는 해당 파일 시스템 타입을 등록한다(`add_file_system()`).
등록된 파일 시스템 타입은 링크드 리스트로 모두 연결되어 있으며 name으로
구분된다.

마운트 시 해당 파일 시스템 타입을 찾아 수퍼블럭을 읽어들인다. `read_super()`
함수는 특정 파일시스템의 고유 수퍼블럭을 VFS에서 사용할 수 있도록 공통
수퍼블럭(struct superblock)형으로 변환해 제공한다.

마운트 포인트가 해당 파일 시스템의 진입점이 된다. 마운트된 모든 수퍼블럭은
링크드 리스트로 연결된다.

file system 자료구조 필요.

	mount(pathname, fs_type);

	1. 블럭 디바이스
	2. 해당 블럭 디바이스 특정 파일시스템으로 마운트
	3. 수퍼블럭의 fop는 파일시스템의 op로 등록
	4. 파일 시스템의 디바이스 접근은 수퍼블럭의 dev 변수로
	open/read/write 류 함수는 file 타입을 매개변수로 받기 때문에
	특정디바이스 연산은 file->dev->op로 접근가능

	fs_list_head

	1. 해당 수퍼블럭 찾음
	2. 수퍼블럭 fop ---> file->op

	e.g.
	1. ls dev
	2. find superblock
	3. sb->fop->read(pathname)
	4. find inode of pathname starting from sb->root_inode
	5. return data of inode

	1. open(pathname)
	2. find superblock
	3. sb->fop->read(pathname)
	4. find inode of pathname starting from sb->root_inode
	5. return data of inode

	1. read(fd)
	2. retrieve file object of fd from filetab

struct file

`filelist`에 열린 전체 파일을 관리. open 시 새로운 항목을 할당, index 리턴.
close 시 삭제(참조하는 객체가 없는 경우).

`file_link()` 새로운 파일을 등록

`file_get()` 등록된 파일 얻기

`file_unlink()`

### super block

	dev
	pathname
	pathname_len
	count
	fop
	iop
	list
	magic
	lock

root inode 는 항상 0으로 가정.

파일 접근시 연결리스트에 등록된 수퍼블럭의 마운트 포인트(pathname)와 비교해
올바른 파일 시스템을 찾는다. 매칭 문자열 길이가 가장 긴 쪽이 해당 파일 시스템.
다음 단계부터는 파일 시스템 특정 루틴(iop) 사용.

### inode

	mode
	size
	count
	data
	parent
	sb
	lock

parent는 꼭 필요한 요소는 아니지만 연산 오버헤드를 줄일 수 있지 않을까 싶은
생각에..

	|<---- block 1 ---->|<---- block 2 ---->|
	 -------------------|-------------------
	|            | fore | rest |            |
	 -------------------|-------------------
	             |<-- entry -->|
	             v
	           offset

	fore_size = entry_size
	if offset + entry_size > block_size
	  fore_size = block_size - offset
	  rest_size = entry_size - fore_size

dir

	(bytes) |    2    |    2    |  1  |  1  |        4        |
	         -------------------------------------------------
	        |  inode  | rec_len | ty- | name| name string     |
		|         |         | pe  | len |                 |
	         -------------------------------------------------

	neme_len이 1바이트이므로 파일명은 255자가 최대.

### fs superblock list

동일 파일 시스템은 하나의 드라이버를 공유하지만 개별적인 자료구조를 유지해야
한다. 활성화된 파일시스템의 각 수퍼블럭은 `fs_superblocks_list` 라는 커널
자료구조로 관리된다. 파일시스템마다 수퍼블럭이 다르므로 void 형 포인터를 사용.

`int register_superblock(void *sb, dev_t id)` - 새로운 수퍼블럭을 등록.
리턴값이 0이 아니면 오류

`void *get_superblock(dev_t id)` - 해당 디바이스로 등록된 파일시스템의
수퍼블럭을 구함. 리턴값이 NULL 이면 오류
