그럼 이제 fat 관련 함수들을 먼저 구현해보자.
우리가 구현해야할 함수들은 아래와 같다.
cluster_t fat_fs_init(void);
cluster_t fat_create_chain(cluster_t clst);
void fat_remove_chain(cluster_t clst, cluster_t pclst);
void fat_put(cluster_t clst, cluster_t val);
cluster_t fat_get(cluster_t clst);
disk_sector_t cluster_to_sector(cluster_t clst);
클러스터와 클러스터 체인이 무엇인지는 이전 포스트에서 정리해두었으니 아직 모른다면 보고 오자. https://gooch123.tistory.com/33#0
[pintOS] 파일 시스템 찍먹하기
vm이 2주일치 과제였지만 1주일만에 끝낸 관계로 파일 시스템을 찍먹해보기로 결정했다. 사실 학부 때 파일 시스템을 제대로 공부하지 않았기도 했고, 동기들이 pintOS를 할 때 나만무 준비를 위해
gooch123.tistory.com
fat_fs_init

void fat_fs_init(void)
{
/* TODO: Your code goes here. */
fat_fs->fat_length = fat_fs->bs.fat_sectors * DISK_SECTOR_SIZE / (sizeof(cluster_t) * SECTORS_PER_CLUSTER);
fat_fs->data_start = fat_fs->bs.fat_start + fat_fs->bs.fat_sectors;
fat_fs->last_clst = ROOT_DIR_CLUSTER + 1;
lock_init(&fat_fs->write_lock);
}
fat 파일 시스템을 초기화하는 함수이다. 총 클러스터 수와 데이터 영역 시작 섹터 번호를 초기화해야 한다.
fat_fs->bs는 boot sector 즉, 파일 시스템 부팅을 위한 정보가 들어있다.
우리는 이를 이용해서 fat의 길이와 데이터 시작 영역을 찾아주면 된다.
fat_create_chain

clst가 포함된 클러스터의 체인 마지막에 새로운 클러스터를 붙여서 확장해야 한다. 만약 clst가 0이라면, 디렉토리나 파일을 새로 만든 것이므로 0을 넘겨준다. 이후에 새로 할당된 클러스터 번호를 반환해준다.
클러스터를 확장하려면 먼저 빈 클러스터를 찾아야 한다. fat_create_chain 내에 로직을 작성해두는 것 보다야 다른 함수로 작성해서 사용하는 것이 더 깔끔하니까 find_free_cluster라는 함수를 하나 만들어주자.
cluster_t find_free_cluster(void)
{
cluster_t find_end = fat_fs->last_clst;
// last_clst는 할당되어 있으므로, last_clst + 1 위치부터 탐색 시작
cluster_t finding_clst = find_end + 1;
// 최대지점(fat_length) 도달 시 처음(2)로 돌아가 last_clst 까지 탐색
while (finding_clst != find_end)
{
if (fat_get(finding_clst) == 0)
return finding_clst;
finding_clst++;
if (finding_clst == fat_fs->fat_length)
finding_clst = 2;
}
// 없을 시 0 반환
return 0;
}
fat_fs 구조체에 있는 last_clst 부터 탐색을 시작하자. 이 필드는 마지막으로 저장을 실행했던 클러스터 번호를 담아둔 필드다. 이 번호 이전의 클러스터들은 할당이 해제되지 않았으면 무조건 이미 할당이 되어있기 때문에 이 번호 +1 부터 탐색을 시작하면 된다.
하지만, last_clst 이후의 클러스들이 모두 할당되어있을수도 있다. 이때는 원형 큐처럼 처음으로 돌아와서 다시 탐색을 시작하도록 해주자. fat_fs의 fat_length는 fat의 길이이므로, 마지막 클러스터 번호가 된다.
그럼 비어있는 클러스터는 어떻게 알 수 있을까? 이전 포스팅에서도 나와있다시피 해당 배열에 0이 들어가있으면 빈 클러스터이고, EOChain이 들어가있으면 클러스터의 마지막이다. 우리는 해당 클러스터에 담겨있는게 0인지만 확인하면 된다.
마지막으로 모든 클러스터가 차 있다면 0을 반환해주도록 하자
이렇게 빈 클러스터를 찾는 함수를 완성했다면, 이를 이용해 클러스터를 확장해주자.
cluster_t
fat_create_chain(cluster_t clst)
{
/* TODO: Your code goes here. */
ASSERT(clst < fat_fs->fat_length);
// 빈 클러스터 탐색
cluster_t new_clst = find_free_cluster();
if (new_clst == 0)
return 0;
fat_put(new_clst, EOChain);
// 탐색 성공한 클러스터 번호를 저장(이후 탐색은 last_clst부터(=next_fit))
fat_fs->last_clst = new_clst;
if (clst == 0)
return new_clst;
// 만약에라도 무한루프가 생기면 이쪽 확인할 것
// 이 코드가 문제가 아니라 get으로 나온게 EOChain인게 문제
while (clst != ROOT_DIR_CLUSTER && fat_get(clst) != EOChain)
{
clst = fat_get(clst);
}
fat_put(clst, new_clst);
return new_clst;
}
find_free_cluster로 찾은 빈 클러스터 번호를 new_clst에 담아주자. 만약 이 번호가 0이라면 모든 클러스터가 사용 중이라는 뜻이니까, 0을 반환해주자.
찾은 new_clst는 체인의 마지막으로 사용될 클러스터니까 fat_put 함수를 통해 클러스터 체인의 끝임을 나타내는 EOChain을 넣어주자.
이후에 last_clst를 new_clst로 업데이트해준다.
그리고 기존의 클러스터 체인을 while문으로 순회하면서 체인의 끝을 찾는다. ROOT_DIR_CLUSTER일 경우에는 while루프를 탈출하도록 해놓았는데, 루트 클러스터를 fat_get으로 찾으면 0이 나오고 fat_get으로 0을 찾으면 1이 나오는 무한 루프가 반복되어서 임시로 작성해둔 코드다. 사실 루트 디렉토리도 확장이 가능해야 하므로 정말 정답인 코드는 아니다. 추후에 수정이 필요하다.
이후에 체인의 끝이 되는 clst에 new_clst 번호를 넣어주고, new_clst를 반환해주자.
fat_remove_chain

이 함수는 클러스터 체인에서 clst부터 시작된 모든 클러스터를 해제한다. pclst는 clst의 이전 클러스터야 한다. 만약 clst가 클러스터 체인의 첫번째라면 pclst는 0으로 주어져야 한다.
void fat_remove_chain(cluster_t clst, cluster_t pclst)
{
ASSERT(clst < fat_fs->fat_length);
if (pclst != 0)
fat_put(pclst, EOChain);
while (clst != EOChain)
{
cluster_t next = fat_get(clst);
fat_put(clst, 0);
if (fat_fs->last_clst == clst)
fat_fs->last_clst = 2;
clst = next;
}
return;
}
pclst가 0이 아니라면, 그러니까 클러스터 체인의 마지막이 될 클러스터라면 EOC를 넣어주자. 그 다음 루프를 돌면서 체인의 기존 끝 클러스터를 만나기 전까지 클러스터들을 모두 해제해주자. fat_create_chain에서 봤다시피 원형 큐처럼 한바퀴를 돌면서 체인이 이어질수도 있다.
fat_put / fat_get
void fat_put(cluster_t clst, cluster_t val)
{
fat_fs->fat[clst] = val;
}
cluster_t
fat_get(cluster_t clst)
{
return fat_fs->fat[clst];
}
이 두 함수는 크게 볼 것은 없다. fat 자체가 배열이기 때문에 fat_put은 해당 인덱스에 다음 클러스터 번호를 넣어주고, fat_get은 해당 배열의 정보를 리턴해주면 끝이다.
cluster_to_sector
disk_sector_t
cluster_to_sector(cluster_t clst)
{
return fat_fs->data_start + (clst - 1);
}
클러스터와 매핑된 섹터 번호를 반환하는 함수. fat_fs의 data_start는 실제 데이터들이 저장된 영역의 섹터 번호이다. fat 자체도 섹터에 저장되어있어야 하기 때문에, data_start 이전까지는 fat의 데이터가 저장되어있는 영역이라고 보면 된다.
여기까지 해주면 project1의 테스트들은 모두 통과한다.
계속 구현해보자 !
'크래프톤 정글' 카테고리의 다른 글
| [pintOS] 파일 확장 기능 구현 -2 (0) | 2025.06.13 |
|---|---|
| [pintOS] 파일 확장 기능 구현 - 1 (0) | 2025.06.11 |
| [pintOS] 파일 시스템 찍먹하기 (4) | 2025.06.08 |
| [pintOS] Copy-on-write 구현기 (4) | 2025.06.07 |
| [pintOS] swap-in/out 구현기 (5) | 2025.06.05 |