※ 이 글은 Project 4를 구현중인 불확실과 추론의 영역입니다.
특히 이부분은 다른 곳을 구현하면서 수정할 여지가 높은 곳입니다.
착한 어린이들은 따라하지 마세요.
※ fat.c 공부때랑 좀 달라진 곳이 많다. 혹시나 참고하셨던분들은 죄송합니다. ㅎㅎ;;
void fat_fs_init (void) { /* TODO: Your code goes here. */ /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ fat_fs->fat = NULL; fat_fs->fat_length = fat_fs->bs.fat_sectors; fat_fs->data_start = fat_fs->bs.fat_start+fat_fs->bs.fat_sectors; fat_fs->last_clst = fat_fs->bs.total_sectors-1; lock_init(&fat_fs->write_lock); /* ---------------------------- << Project.4 FAT << ---------------------------- */ }
fat_fs를 초기화하는 곳이다.
fat은 fat_create에서 따로 받을 것이기 때문에 NULL을 지정하겠다.
fat_length는 filesystem disk안에 들어가는 disk sector들의 총 갯수이다. 이를 fs_boot에서 받아오자.
data_start는 실제 데이터가 들어가는 곳인데, 여기에 FAT을 포함시켜야되는지 고민이 많았다.
현재 내가 생각하고 있는 sector배치는
0 : fs_boot 구조체
1 : root_directory
2 ~ x : FAT
x+1 ~ : 실제 data
로 생각하고 있기 때문에, 2에 fat_stasrt, x+1에 data_start가 들어갈 예정이다. 다행히, FAT의 (섹터 단위) 크기는 fa_sectors에 저장되어있기 때문에 fat_start + fat_sectors로 하면 실제 data의 시작 sector index가 들어갈 것 같다.
last_clst 는 아직 미정인데, 현재는 disk가 보유하고 있는 sector 중 마지막 sector를 가리키는 걸로 할까 싶다. 나중에 바뀔수도 있겠지만, 일단은 이렇게 하자. (-1을 한 이유는 array의 인덱스를 가리키고 있기 때문이다.)
lock_init 으로 wrtie_lock을 설정하자.
그리고 나는 빈 섹터들을 하나의 linked list로 묶을 생각이다. fat_create()에 구현해놓자.
void fat_create (void) { // Create FAT boot fat_boot_create (); fat_fs_init (); // Create FAT table fat_fs->fat = calloc (fat_fs->fat_length, sizeof (cluster_t)); if (fat_fs->fat == NULL) PANIC ("FAT creation failed"); // Set up ROOT_DIR_CLST fat_put (ROOT_DIR_CLUSTER, EOChain); // Fill up ROOT_DIR_CLUSTER region with 0 uint8_t *buf = calloc (1, DISK_SECTOR_SIZE); if (buf == NULL) PANIC ("FAT create failed due to OOM"); disk_write (filesys_disk, cluster_to_sector (ROOT_DIR_CLUSTER), buf); free (buf); /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ uint32_t i = 0; for (i ; i < fat_fs->last_clst ; i++) { fat_fs->fat[i] = i+1; } fat_put(0, EOChain); fat_put(1, EOChain); fat_put(fat_fs->bs.fat_start+fat_fs->bs.fat_sectors-1, EOChain); fat_put(fat_fs->last_clst, EOChain); /* ---------------------------- << Project.4 FAT << ---------------------------- */ }
이렇게 하면, data_start부터 끝까지 하나의 linked list가 구현되고, 마지막은 EOC이 새겨진다.
일단, 처음부터 끝까지 하나의 연결리스트를 구현하고, EOC를 박는걸로 chain을 끊어주자.
이러면, fat은 하나의 chain이 되고, 빈 블록들도 하나의 chain이 된다.
생각해보니 free_blocks들의 갯수로 저장해놔야할 것 같다. 이도 구현놓자.
/* Should be less than DISK_SECTOR_SIZE */ struct fat_boot { unsigned int magic; unsigned int sectors_per_cluster; /* Fixed to 1 */ unsigned int total_sectors; unsigned int fat_start; unsigned int fat_sectors; /* Size of FAT in sectors. */ unsigned int root_dir_cluster; /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ unsigned int init_free_blocks; /* ---------------------------- << Project.4 FAT << ---------------------------- */ };
void fat_boot_create (void) { unsigned int fat_sectors = (disk_size (filesys_disk) - 1) / (DISK_SECTOR_SIZE / sizeof (cluster_t) * SECTORS_PER_CLUSTER + 1) + 1; fat_fs->bs = (struct fat_boot){ .magic = FAT_MAGIC, .sectors_per_cluster = SECTORS_PER_CLUSTER, .total_sectors = disk_size (filesys_disk), .fat_start = ROOT_DIR_CLUSTER + 1, .fat_sectors = fat_sectors, .root_dir_cluster = ROOT_DIR_CLUSTER, /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ // free_blocks = total_sectors - fat_sectors - boot_sector - root_dir - head and taile .init_free_blocks = disk_size (filesys_disk) - fat_sectors - 4 /* ---------------------------- << Project.4 FAT << ---------------------------- */ }; }
fat_boot에 init_free_blocks를 추가해놓고 초기 값을 넣어준다.
이는 전체 섹터 - FAT의 섹터 - ROOT_DIR 섹터 - BOOT 정보 섹터 - free_list의 HEAD 블록 (data_start) - TAIL 블록 (last_clst) 로 계산했다.
그러면 fat_fs_init()도 수정해야한다.
/* FAT FS */ struct fat_fs { struct fat_boot bs; cluster_t *fat; unsigned int fat_length; disk_sector_t data_start; cluster_t last_clst; struct lock write_lock; /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ unsigned int free_blocks; /* ---------------------------- << Project.4 FAT << ---------------------------- */ };
void fat_fs_init (void) { /* TODO: Your code goes here. */ /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ fat_fs->fat = NULL; fat_fs->fat_length = fat_fs->bs.total_sectors; fat_fs->data_start = fat_fs->bs.fat_start+fat_fs->bs.fat_sectors; fat_fs->last_clst = fat_fs->bs.total_sectors-1; lock_init(&fat_fs->write_lock); fat_fs->free_blocks = fat_fs->bs.init_free_blocks; /* ---------------------------- << Project.4 FAT << ---------------------------- */ }
fat_fs_init()에서 초기값을 넣어준다.
그러고보니 빈 블록 리스트에서 빈 블록을 하나 가져오는 함수를 만들어야할 것 같다.
함수를 만들어보자.
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */ cluster_t get_free_cluster(void) { cluster_t start = fat_fs->data_start; cluster_t free_clst = fat_get(start); if (free_clst == fat_fs->last_clst) { return -1; } cluster_t start_next = fat_get(free_clst); fat_put(start, start_next); fat_put(free_clst, EOChain); fat_fs->free_blocks -= 1 return free_clst; } /* ---------------------------- << Project.4 FAT << ---------------------------- */
data_start는 항상 고정이다. 그리고 이 다음 블록부터 할당하도록 할 것이다. 그리고 할당한 뒤에는 끊어버린다.
만약 free_clst에 last_clst가 들어왔다면, 더 이상 할당할 수 없다는 말이니 -1을 반환하자.
만약 이 상위 함수에서 free_clst가 필요없어지면 다시 free_block_list에 붙이는 것을 잊지 말자. 그리고 새로운 free_block을 넣을 때는 data_start 바로 뒤에 붙이자. (last_clst가 항상 마지막에 있어야하기 때문에)
/* Add a cluster to the chain. * If CLST is 0, start a new chain. * Returns 0 if fails to allocate a new cluster. */ cluster_t fat_create_chain (cluster_t clst) { /* TODO: Your code goes here. */ /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ cluster_t new = get_free_cluster(); if (new == -1) { return 0; } if(clst != 0){ fat_put(clst, new); } return new; /* ---------------------------- << Project.4 FAT << ---------------------------- */ }
우선 chain을 새로 만들거나 늘리는 과정이다. clst에 어떤 clst가 들어오는지 헷갈리는데, file의 시작 clst가 들어오는지, 마지막 clst가 들어오는지 아니면 임의의 clst가 들어오는 지 애매하다.
범용성을 위해서 임의의 clst가 들어오고, 만약 이 clst가 chain의 중간 clst라 하더라도, 상위함수에서 이미 chain을 끊어놓은 상태라고 가정한다. 즉, clst는 '현재' chain의 마지막 clst라고 가정한다.
만약 free_clst를 할당하는데 실패한다면 0을 반환한다.
할당에 성공하고, clst가 0이라면 새로운 chain을 만들고, 아니라면 clst에 free_clst를 이어준다.
/* Remove the chain of clusters starting from CLST. * If PCLST is 0, assume CLST as the start of the chain. */ void fat_remove_chain (cluster_t clst, cluster_t pclst) { /* TODO: Your code goes here. */ /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ if (pclst != 0) { fat_put(pclst, EOChain); } cluster_t start = fat_fs->data_start; cluster_t start_next = fat_get(start); cluster_t cur = clst; cluster_t next = fat_get(cur); fat_put(cur,start_next); fat_put(start, cur); fat_fs->free_blocks += 1; while (next != EOChain) { cur = fat_get(next); start_next = fat_get(start); fat_put(next, start_next); fat_put(start, next); fat_fs->free_blocks += 1; } /* ---------------------------- << Project.4 FAT << ---------------------------- */ }
fat_remove_chain은 이렇게 이해했다.
plcst와 clst를 끊어서, plcst로 끝나는 한 체인과, clst로부터 시작하는 한 체인을 만드는 것이라고 생각했다.
생각해보니 chain을 끊어서 두개로 만드는 것이면, 그냥 pclst에 EOC를 넣으면 끝이다.
아마 file삭제나 수정을 위해서 clst부터 cluster를 삭제하는 함수인 것 같다.
그리고 삭제한 cluster는 free_block_list에 넣는다.
/* Update a value in the FAT table. */ void fat_put (cluster_t clst, cluster_t val) { /* TODO: Your code goes here. */ /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ fat_fs[clst] = val; /* ---------------------------- << Project.4 FAT << ---------------------------- */ } /* Fetch a value in the FAT table. */ cluster_t fat_get (cluster_t clst) { /* TODO: Your code goes here. */ /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ return fat_fs[clst]; /* ---------------------------- << Project.4 FAT << ---------------------------- */ } /* Covert a cluster # to a sector number. */ disk_sector_t cluster_to_sector (cluster_t clst) { /* TODO: Your code goes here. */ /* ---------------------------- >> Project.4 FAT >> ---------------------------- */ return clst; /* ---------------------------- << Project.4 FAT << ---------------------------- */ }
나머지는 간단하니 함수로 표현하겠다. 나중에 생각나면 예외처리도 덧붙여야겠다.
+추가사항+
fat_fs는 static이라 다른 파일에서 호출할 수 없다.
free_blocks를 관리하기 위해 함수를 하나 만든다.
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */ size_t ctrl_free_blocks_EA(uint32_t a) { fat_fs->free_blocks += a; return fat_fs->free_blocks; } /* ---------------------------- << Project.4 FAT << ---------------------------- */
a를 넣으면, free_blocks에 a를 더하고 free_blocks를 반환한다.
만약 a에 0을 넣으면 free_blocks를 그대로 반환할 것이다.
'Pintos Project > Project 4' 카테고리의 다른 글
[PintOS, Project 4] Filesys.c 구현 (0) | 2021.03.04 |
---|---|
[PintOS, Project 4] inode.c 구현 (0) | 2021.03.04 |
[PintOS, Project 4] inode.c 공부 (2) | 2021.03.04 |
[PintOS, Project 4] fat.c 공부 (2) | 2021.03.03 |
[PintOS, Project 4] Indexed and Extensible Files (0) | 2021.03.02 |
댓글