개발/공부 기록

Pintos 완주 후 다시 읽기 4: 파일 시스템은 이름을 디스크 조각으로 번역하는 길이었다

cedis 2026. 5. 22. 21:55

 

Pintos 완주 후 다시 읽기

Project 4의 path, directory, symlink, inode, FAT를 하나의 번역 흐름으로 다시 읽는다.

이 글에서 다루는 것

Project 4는 파일 시스템 기능을 많이 추가한다. 하지만 완성 후 다시 보면 핵심 질문은 하나다. user가 준 문자열 경로를 어떻게 실제 디스크 조각까지 연결할 것인가.

  • 상대/절대 경로와 현재 디렉터리
  • directory entry와 inode
  • symlink 재해석
  • 파일 grow와 FAT chain

1. 경로는 문자열이 아니라 탐색 계획이다

/a/link/file 같은 문자열은 파일 자체가 아니다. 루트에서 시작할지 현재 디렉터리에서 시작할지 정하고, 토큰을 하나씩 lookup하면서 inode를 찾아가야 한다.

경로 해석 흐름

1
path가 /로 시작하면 root에서 시작하고, 아니면 current working directory에서 시작한다.
2
문자열을 / 기준으로 token으로 나눈다.
3
현재 directory에서 token 이름을 가진 entry를 찾는다.
4
symlink면 target 경로와 남은 경로를 이어붙여 다시 해석한다.
5
마지막 inode를 file 또는 directory 객체로 감싸 syscall에 돌려준다.
while (token != NULL) {
    char *next = strtok_r (NULL, "/", &save);
    struct inode *inode = NULL;

    if (!dir_lookup (dir, token, &inode)) {
        free (copy);
        dir_close (dir);
        return NULL;
    }

    if (inode_is_symlink (inode) && (follow_final || next != NULL)) {
        char *joined = join_symlink_path (inode_symlink_target (inode),
                next, save);
        struct inode *resolved = NULL;

        resolved = resolve_path_from (dir, joined, follow_final, depth + 1);
        inode_close (inode);
        free (copy);
        dir_close (dir);
        return resolved;
    }
}

2. directory는 특별한 파일처럼 읽을 수 있다

Project 4에서 directory fd가 중요해진다. open이 파일만 여는 것이 아니라 directory도 열 수 있고, readdir, isdir, inumber는 열린 fd가 가리키는 inode 성격을 물어본다.

기능 커널이 실제로 해야 하는 일
chdir 현재 thread의 cwd를 다른 directory inode로 바꾼다.
mkdir 새 directory inode를 만들고 . 과 .. entry를 구성한다.
readdir directory entry를 하나씩 읽되 . 과 .. 은 사용자에게 보통 넘기지 않는다.
isdir fd가 directory inode를 가리키는지 확인한다.
inumber inode 번호를 반환해 같은 객체인지 비교할 수 있게 한다.

3. symlink는 파일 복사가 아니라 경로 재해석이다

symlink를 처음 보면 target 파일을 복사하는 기능처럼 오해하기 쉽다. 실제로는 link inode 안에 target 문자열을 저장해두고, 그 link를 따라가야 하는 상황에서 target 경로로 다시 해석한다.

복사라고 생각하면

link를 만들 때 파일 내용까지 복제해야 한다고 착각한다. 그러면 target이 directory일 때나 link chain일 때 설명이 깨진다.

경로 재해석으로 보면

link inode는 target 문자열을 품고 있고, open/create/write 흐름에서 필요한 순간 resolve가 다시 돈다.

4. grow는 inode 길이와 FAT chain이 같이 움직여야 한다

파일에 더 큰 offset으로 write가 들어오면 inode 길이만 늘린다고 끝나지 않는다. 새 데이터를 담을 cluster를 FAT에서 확보하고 기존 chain 뒤에 연결해야 한다.

for (candidate = start; candidate < fat_fs->fat_length; candidate++) {
    if (candidate > 0 && fat_fs->fat[candidate] == 0)
        goto found;
}

found:
fat_fs->fat[candidate] = EOChain;
if (clst != 0)
    fat_fs->fat[clst] = candidate;
fat_fs->last_clst = candidate + 1;

이 흐름은 inode_write_at()에서 실제 write 범위에 맞춰 필요한 cluster를 늘리는 동작과 연결된다. inode는 파일의 논리적 길이를 알고, FAT는 그 파일이 디스크의 어떤 cluster들을 따라가야 하는지 기억한다.

검증 감각

이 기준의 Project 4 파일 시스템 구현은 basic/extended 파일 시스템 테스트 146개 PASS 결과를 가진 코드에서 읽었다. buffer cache bonus는 별도 최적화 영역으로 두고, 여기서는 기본/extended 요구 흐름을 기준으로 설명한다.

테스트 감각 묻는 흐름
grow-* 파일 길이가 늘어날 때 inode와 FAT chain이 함께 확장되는가
dir-* 상대/절대 경로, . / .., cwd가 일관되게 동작하는가
readdir/isdir/inumber directory fd가 일반 file fd와 구분되어 처리되는가
symlink-* link inode가 target 경로를 재해석하고 persistence까지 유지되는가

이번 글에서 기억할 것

  • 파일 시스템은 이름을 곧바로 데이터로 바꾸지 않는다. 이름은 directory entry와 inode를 거쳐야 한다.
  • symlink는 파일 복사가 아니라 경로 문자열의 재해석이다.
  • 파일 grow는 inode length와 FAT chain 확장이 함께 맞아야 통과된다.

스스로 점검

  • 상대 경로는 어떤 directory에서 출발하는가?
  • symlink의 final component를 따라갈지 말지는 왜 상황마다 달라질 수 있는가?
  • 파일 길이가 늘 때 inode와 FAT 중 하나만 수정하면 어떤 문제가 생기는가?

다음 글 예고

마지막 글에서는 user program의 write 요청 하나가 syscall, user pointer 검증, VM, fd table, file, inode, FAT, disk까지 내려가는 전체 경로를 한 번에 따라간다.

한 줄 정리

Project 4의 파일 시스템은 경로 문자열을 inode와 FAT chain으로 번역하는 긴 파이프라인이었다.