[PintOS, Project 4] Indexed and Extensible Files (tistory.com)
할 일을 정리해보자.
원래는 inode_create()에서 인자로 length (파일의 크기) 를 받았다. 그러나 이제 length는 0으로 들어올 것이다.
즉, inode_create()때는 inode만 가지고 있는 file하나만 생성되는 것이다.
그리고 inode_write_at()에서 데이터를 받는대로 EOF를 늘려야되는 것 같다.
그렇다면 write_at()에서 인자가 어떻게 들어올 지 생각해보자. 신생 파일의 경우에는 offset은 0으로 들어오고, size는 실제 file length만큼 들어올 것이다.
상상해보자. 맨 처음에는 inode_disk밖에 없을 것이다.
그럼 이제 byte_to_sector로 가겠지.
여기서 잘 생각을 해야한다. 이 참에 file이 생성되는 과정을 정리해볼까?
bool
filesys_create (const char *name, off_t initial_size) {
#ifdef EFILESYS
disk_sector_t inode_sector = fat_create_chain(0);
struct dir *dir = dir_open_root ();
bool success = (dir != NULL
&& inode_create (inode_sector, initial_size)
&& dir_add (dir, name, inode_sector));
if (!success && inode_sector != 0)
fat_remove_chain(inode_sector, 0);
dir_close (dir);
return success;
filesys_crate()에서는 inode_create()를 하고, directory에 추가해준다. (현재는 root_dir에만 들어가게 되어있다.)
initial_size는 0으로 바뀔 것인데, 그러면
bool inode_create(disk_sector_t sector, off_t length)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
struct inode_disk *disk_inode = NULL;
bool success = false;
ASSERT(length >= 0);
/* If this assertion fails, the inode structure is not exactly
* one sector in size, and you should fix that. */
ASSERT(sizeof *disk_inode == DISK_SECTOR_SIZE);
disk_inode = calloc(1, sizeof *disk_inode);
if (disk_inode != NULL)
{
size_t sectors = bytes_to_sectors(length);
disk_inode->length = length;
disk_inode->magic = INODE_MAGIC;
// 남은 자유 블륵이 sectors보다 많은가
if (ctrl_free_blocks_EA(0) >= sectors)
{
disk_write(filesys_disk, sector, disk_inode);
if (sectors > 0)
{
static char zeros[DISK_SECTOR_SIZE];
size_t i;
// chain을 만든다.
disk_inode->start = fat_create_chain(0);
disk_write(filesys_disk, sector, disk_inode);
disk_sector_t prev = disk_inode->start;
for (i = 1; i < sectors; i++)
{
// 섹터가 2개 이상이면 chain으로 이어준다.
disk_sector_t sector_idx = fat_create_chain(prev);
disk_sector_t tmp = fat_get(prev);
disk_write(filesys_disk, sector_idx, zeros);
prev = sector_idx;
}
}
success = true;
}
free(disk_inode);
}
return success;
그리고 여기는 받은 size을 sector의 수로 환산해서 그만큼 빈 공간을 만든다.
그런데 이제부터는 length가 0으로 들어올 것이다. 그렇기 때문에 "if (ctrl_free_blocks_EA(0) >= sectors)" 밑으로는 들어가지 않을 것이다.
disk_inode->start = fat_create_chain(0);
disk_write(filesys_disk, sector, disk_inode);
이 두 문구가 문제인데, 어떻게 할 지 고민중이다. disk_inode->start = EOC로 만들고, byte_to_sector()에서 EOC를 만나면 fat_create_chain()을 호출하도록 하는 것이 나아보이긴 한다. 인자pos자체는 그대로일 것이니깐.
이렇게하면 inode_create()는 문제없을 것 같다. 다시 inode_write_at()으로 가보자.
ilfe_growth의 기준이라면, offset이 inode에 적혀있는 length보다 크게 들어올 수 있는데 예외처리 등에 걸리는지 보자.
여기서 걸리는 것은
off_t inode_left = inode_length(inode) - offset;
이 부분이다. inode_length는 inode에 적혀있는 length를 가져오는건데, file growth에서는 length가 0으로 되어있을 거다. 그래서 inode_left가 0으로 나온다. 그렇다면 왜 inode_left를 계산하는지 보자.
int min_left = inode_left < sector_left ? inode_left : sector_left;
바로 찐 남은 byte를 계산하기 위해서인데, 이걸로 실제로 sector에 얼마만큼 쓰는가를 알기 위해서이다. 이 둘을 정리해보자.
sector_ofs : offset % disk_sector_size 로 offset 기준으로 sector에서 이 offset이 어디서부터 시작하는지 계싼
sector_left = sector내에서 남은 byte
inode_left : length - offset으로 남은 byte
그런데 뭐가 다른거지? 일단 offst이 0부터 시작하면 다를게 없어 보인다. 그렇다면 중간에서 들어왔을 때 달라지나?
일단 min_left는 '현재 sector내에서' 얼마만큼 더 써야하는 가를 나타내는 것이다. 섹터 중간에서 시작해서 진행하는 경우면 sector_left를 쓸 것이고, 마지막 sector에서 쓰는 경우면 inode_left를 쓰는 것 같다.
그렇다면 inode_length가 0으로 들어오면 어떻게 되는걸까. inode_left 는 음수가 되겠지.
그런데 생각해보면 inode_length는 고정 파일 크기인데, 이제 할 것은 유동파일 크기 시스템이다. 아예 얘를 없애버려야하나? 그래도되나?
만약 file을 새로 쓰는 경우면은 inode_length가 아니라 size로 들어와야할 것 같은데. (기존 시스템에서 size == length라고 생각되었으니깐)
아니면은 시작할 때, inode_length와 size 중 큰 것을 기준으로 하면되지 않을까?
근데 중간부터 시작한다면? 그러면 inode_length랑 ofs+size를 비교?
괜찮아보이는데 문제될 것은 없나? 의도에는 맞나?
일단 file 크기가 줄어드는 것이 아니면, 상관없을 거 같다. 수정해보자.
만약 추잡하게 한다면, inode_length를 바로 inode->length 에 박아도 되겠지만, 최소한의 양심은 있기에 (중간에 bounce의 malloc에 실패할 가능성이 있기에) write가 끝나면 갱신하도록 하자.
그런데 생각해보니, write_at을 시작할 때, offset을 inode->length로 잡고, write할 때마다, bytes_written을 잘 되지 않을까?
근데 이러면 중간만 수정하는 경우는 이상하게 되겠네. (시무룩)
write가 끝나고 inode_length를 집어넣는 식으로 하면, 크기가 안 바뀔 때, 크기가 커질 때, 중간에 write가 멈출 때 대응이 되지 않을까. 그런데 생각해보니, 중간에 수정하다가 터졌다고 해도 수정만 실패하는거지, file 크기는 변하지 않지 않나.
/* Writes SIZE bytes from BUFFER into INODE, starting at OFFSET.
* Returns the number of bytes actually written, which may be
* less than SIZE if end of file is reached or an error occurs.
* (Normally a write at end of file would extend the inode, but
* growth is not yet implemented.) */
off_t inode_write_at(struct inode *inode, const void *buffer_, off_t size,
off_t offset)
{
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
#ifdef EFILESYS
const uint8_t *buffer = buffer_;
off_t bytes_written = 0;
uint8_t *bounce = NULL;
if (inode->deny_write_cnt){
return 0;
}
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
int inode_length = inode_length(inode) > offset + size ? inode_length(inode) : offset + size;
tmp_length = offset;
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
while (size > 0)
{
/* Sector to write, starting byte offset within sector. */
disk_sector_t sector_idx = byte_to_sector(inode, offset);
int sector_ofs = offset % DISK_SECTOR_SIZE;
/* Bytes left in inode, bytes left in sector, lesser of the two. */
off_t inode_left = inode_length - offset;
int sector_left = DISK_SECTOR_SIZE - sector_ofs;
int min_left = inode_left < sector_left ? inode_left : sector_left;
/* Number of bytes to actually write into this sector. */
int chunk_size = size < min_left ? size : min_left;
if (chunk_size <= 0)
break;
if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE)
{
/* Write full sector directly to disk. */
disk_write(filesys_disk, sector_idx, buffer + bytes_written);
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
tmp_length += bytes_written;
inode->length = inode->length > tmp_length ? inode->length : tmp_length;
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
}
else
{
/* We need a bounce buffer. */
if (bounce == NULL)
{
bounce = malloc(DISK_SECTOR_SIZE);
if (bounce == NULL)
break;
}
/* If the sector contains data before or after the chunk
we're writing, then we need to read in the sector
first. Otherwise we start with a sector of all zeros. */
if (sector_ofs > 0 || chunk_size < sector_left)
disk_read(filesys_disk, sector_idx, bounce);
else
memset(bounce, 0, DISK_SECTOR_SIZE);
memcpy(bounce + sector_ofs, buffer + bytes_written, chunk_size);
disk_write(filesys_disk, sector_idx, bounce);
}
/* Advance. */
size -= chunk_size;
offset += chunk_size;
bytes_written += chunk_size;
}
free(bounce);
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
inode->length = inode_length;
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
return bytes_written;
/* ---------------------------- << Project.4 FAT << ---------------------------- */
여기서 드는 의문은 size가 과연 실 data크기인지, 아니면 page단위라던가 무튼 실 data 보다 클수도 있는지가 걱정되는데, 일단 실 data라는 전제하에 적고, 아니라면 나중에 수정한다.
주석을 읽어보면, written bytes가 size보다 작아질 수 있는데, 이 경우는 EOF를 만난 경우이다. 아마 EOC를 말하는 거겠지. 그런데 file_growth를 구현한다면, EOC를 만나면 끝나는 것이 아니라 chain을 연장시켜야한다고 한다.
이를 구현하기 위해 byte_to_sector로 가자.
/* Returns the disk sector that contains byte offset POS within
* INODE.
* Returns -1 if INODE does not contain data for a byte at offset
* POS. */
static disk_sector_t
byte_to_sector(const struct inode *inode, off_t pos)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
ASSERT(inode != NULL);
if (pos < inode->data.length)
{
disk_sector_t cur = inode->data.start;
uint32_t cnt = pos / DISK_SECTOR_SIZE;
int i = 0;
for (i ; i < cnt ; i++)
{
cur = fat_get(cur);
}
return cur;
}
else
return -1;
/* ---------------------------- << Project.4 FAT << ---------------------------- */
음...
if문만 지우면되나? 괜찮나? 이런 안일한 mind
응 안돼
이것은 이미 inode_create()에서 free_block을 할당받았다는 기준으로 생각한 것이다.
그러면 fat_get()이 아니라 fat_create_chain()으로 바꿔야하지 않을까.
그런데 생각해보니, 기존에 있는 것을 찾을 수도 있잖아.
그러면 if문으로 분기를 해야겠는걸
다행히 if문을 그대로 쓰면 될 것 같다. 기존에 있는 sector를 찾을 때는 if문 안을 쓰고
아닐 경우에는 else로 가서 할당받으면 될 거 같다.
그러고보니 여기서 inode->data.length 를 사용한다. 그러면 어떻게 해야할까. 걱정되는 부분은 inode_read_at에서 잘못된 offset으로 이 함수를 호출하는 경우이다. 이 경우는 inode_read_at에서 offset이 이상하면 못 들어오도록 해야겠다.
이제 생각해야할 것은 wriet_at()에서 while문을 돌 때마다 이 함수를 호출할 것인데, 맨 처음에 필요한 block을 모두 할당하고, 다음 while문에서는 if문으로 들어오도록 할 것인지, 아니면 while문에서 여기를 들어올 때마다 할당을 한번씩 해줄 것인지.
아무래도 while문 들어올 때마다 받는 것이 낫겠지? 그리고 블록을 할당받았다는 것은, file의 실제 크기가 늘었다는 것이니깐 length도 늘려주자.
/* Returns the disk sector that contains byte offset POS within
* INODE.
* Returns -1 if INODE does not contain data for a byte at offset
* POS. */
static disk_sector_t
byte_to_sector(const struct inode *inode, off_t pos)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
ASSERT(inode != NULL);
if (pos < inode->data.length)
{
disk_sector_t cur = inode->data.start;
uint32_t cnt = pos / DISK_SECTOR_SIZE;
int i = 0;
for (i ; i < cnt ; i++)
{
cur = fat_get(cur);
}
return cur;
}
else
// return -1;
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
disk_sector_t cur = inode->data.start;
disk_sector_t new = fat_create_chain(cur);
inode->data.length += DISK_SECTOR_SIZE;
return new;
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
/* ---------------------------- << Project.4 FAT << ---------------------------- */
그리고 read_at()에서 예외처리를 해주자.
/* Reads SIZE bytes from INODE into BUFFER, starting at position OFFSET.
* Returns the number of bytes actually read, which may be less
* than SIZE if an error occurs or end of file is reached. */
off_t inode_read_at(struct inode *inode, void *buffer_, off_t size, off_t offset)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
uint8_t *buffer = buffer_;
off_t bytes_read = 0;
uint8_t *bounce = NULL;
// printf("---DEBUG // i_read // inode->sector : %d\n", inode->sector);
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
disk_sector_t cur = inode->data.start;
if (offset > inode->data.length) {
printf("---ERROR // i_read // offset > length : %d\n");
return 0;
}
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
그리고 나중에 혹시 이쪽이 문제가 될 수 있으니 ERROR print를 걸어놓자.
이제 생각해야할 것은 offset이 EOF를 넘어서 들어오는 경우이다.
생각해보니 offset이 EOF보다 훨씬 뒤에 있는 경우에도 블록은 byte_to_sector()에서 한번만 받을건데, 문제가 있어보이네.
그냥 offset까지 while문을 돌려서 할당하자. 생각해보니 offset (=pos) 는 현재 위치이니 여기까지 할당받는 것이 맞다.
그리고 아예 코드가 개판이네. data.start부터 시작하는 것이 아니라 끝부터 시작해야한다. 멍충이
그럼 우선 while문으로 현 file의 끝 블록을 찾아오고, length가 offset보다 길어질 때까지 블록을 할당한다.
그런다음 할당받은 sector에 0으로 채워주자.
/* Returns the disk sector that contains byte offset POS within
* INODE.
* Returns -1 if INODE does not contain data for a byte at offset
* POS. */
static disk_sector_t
byte_to_sector(const struct inode *inode, off_t pos)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
ASSERT(inode != NULL);
if (pos < inode->data.length)
{
disk_sector_t cur = inode->data.start;
uint32_t cnt = pos / DISK_SECTOR_SIZE;
int i = 0;
for (i ; i < cnt ; i++)
{
cur = fat_get(cur);
}
return cur;
}
else
// return -1;
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
disk_sector_t cur = inode->data.start;
while (fat_get(cur) != EOChain)
{
cur = fat_get(cur);
}
disk_sector_t new;
uint8_t bounce;
memset(bounce, 0, DISK_SECTOR_SIZE);
while (pos < inode->data.length)
{
new = fat_create_chain(cur);
uint8_t bounce = malloc(DISK_SECTOR_SIZE);
disk_write(filesys_disk, new, bounce);
cur = new;
inode->data.length += DISK_SECTOR_SIZE;
}
free(bounce);
return new;
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
/* ---------------------------- << Project.4 FAT << ---------------------------- */
이렇게 하면, file을 생성하고 첫 블록받을 때 문제가 없나?
일단 inode_create()를 바꿔야할 것 같다.
bool inode_create(disk_sector_t sector, off_t length)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
struct inode_disk *disk_inode = NULL;
bool success = false;
ASSERT(length >= 0);
\
/* If this assertion fails, the inode structure is not exactly
* one sector in size, and you should fix that. */
ASSERT(sizeof *disk_inode == DISK_SECTOR_SIZE);
\ disk_inode = calloc(1, sizeof *disk_inode);
if (disk_inode != NULL)
{
size_t sectors = bytes_to_sectors(length);
disk_inode->length = length;
disk_inode->magic = INODE_MAGIC;
만약 disk_inode->length = 0;
disk_inode->start = 0;으로 한다면 어떤 일이 일어날까.
우선 write_at()에서는 byte_to_sector()로 들어올 것이고...
pos = 0, length = 0이니깐 할당을 받으러 else문으로 들어올 것이다.
그러면 fat_get(0) = EOC이므로, cur = 0이 되고, fat_create_chain(0)이니 new부터 새 chain을 만들 것이다.
아 그런데, 이 경우에는 inode_disk->start 에 기록이 안되어있을 테니 구현이 복잡하겠네.
inode_create()에서 그냥 블록 하나 받고 시작하도록 하고, length는 512byte부터 하도록하자. 이게 맘 편할 것 같다.
bool inode_create(disk_sector_t sector, off_t length)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
struct inode_disk *disk_inode = NULL;
bool success = false;
ASSERT(length >= 0);
// printf("---DEBUG // i_create // sector : %d\n", sector);
// printf("---DEBUG // i_create // length : %d\n", length);
/* If this assertion fails, the inode structure is not exactly
* one sector in size, and you should fix that. */
ASSERT(sizeof *disk_inode == DISK_SECTOR_SIZE);
// printf("---DEBUG // i_create // START\n");
disk_inode = calloc(1, sizeof *disk_inode);
if (disk_inode != NULL)
{
size_t sectors = bytes_to_sectors(length);
// disk_inode->length = length;
disk_inode->magic = INODE_MAGIC;
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
disk_inode->length = DISK_SECTOR_SIZE;
disk_inode->start = fat_create_chain(0);
disk_write(filesys_disk, sector, disk_inode);
static char zeros[DISK_SECTOR_SIZE];
disk_write(filesys_disk, disk_inode->start, zeros);
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
// // 남은 자유 블륵이 sectors보다 많은가
// if (ctrl_free_blocks_EA(0) >= sectors)
// {
// disk_write(filesys_disk, sector, disk_inode);
// if (sectors > 0)
// {
// static char zeros[DISK_SECTOR_SIZE];
// size_t i;
// // chain을 만든다.
// disk_inode->start = fat_create_chain(0);
// disk_write(filesys_disk, sector, disk_inode);
// disk_sector_t prev = disk_inode->start;
// for (i = 1; i < sectors; i++)
// {
// // 섹터가 2개 이상이면 chain으로 이어준다.
// disk_sector_t sector_idx = fat_create_chain(prev);
// disk_sector_t tmp = fat_get(prev);
// disk_write(filesys_disk, sector_idx, zeros);
// prev = sector_idx;
// }
// }
// success = true;
// }
// free(disk_inode);
// }
// printf("---DEBUG // i_create // suc : %d\n", success);
return success;
/* ---------------------------- << Project.4 FAT << ---------------------------- */
이런식으로 기존에 할당받던 코드를 날리고, 블록 하나를 받아서 start에 새기고, length는 512byte를 넣어줬다.
문제 없겠지?
응 문제있어
/* Returns the disk sector that contains byte offset POS within
* INODE.
* Returns -1 if INODE does not contain data for a byte at offset
* POS. */
static disk_sector_t
byte_to_sector(const struct inode *inode, off_t pos)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
ASSERT(inode != NULL);
disk_sector_t cur = inode->data.start;
if (pos < inode->data.length)
{
uint32_t cnt = pos / DISK_SECTOR_SIZE;
int i = 0;
for (i ; i < cnt ; i++)
{
cur = fat_get(cur);
}
return cur;
}
else
// return -1;
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
while (fat_get(cur) != EOChain)
{
cur = fat_get(cur);
}
disk_sector_t new;
uint8_t bounce = malloc(DISK_SECTOR_SIZE);
memset(bounce, 0, DISK_SECTOR_SIZE);
off_t tmp_length = inode->data.length;
while (pos < tmp_length)
{
new = fat_create_chain(cur);
disk_write(filesys_disk, new, bounce);
cur = new;
tmp_length += DISK_SECTOR_SIZE;
}
inode->data.length = tmp_length;
free(bounce);
return new;
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
/* ---------------------------- << Project.4 FAT << ---------------------------- */
중간중간에 컴파일을 하지 않아 곳곳에 틀린 곳이 많습니다. malloc()위치가 멍청해다. 그리고 data.length는 read_only란다. ㅟㅏ const였네.
고심 끝에 const를 해체하겠습니다.
문제없겟지?
아몰랑
결과 :
시작부터 망ㅇ했다...
To be Continue....
++++ 1차 crystal ++++
byte_to_sector()에서 모든것을 하려고 했던것이 북경원인이었다.
만약 지금 할당받은 byte가 딱 경계선이라면 (즉, 1sector만 가지고 있는데 512byte를 읽으려고 한다면), inode_read_at()에서 새로운 블록을 할당해버리기때문에 문제가되었다.
sector가 부족할 때, sector를 늘리는 것을 함수로 분리해주자.
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
static disk_sector_t
extend_sector(struct inode *inode, off_t pos)
{
disk_sector_t cur = inode->data.start;
while (fat_get(cur) != EOChain)
{
cur = fat_get(cur);
}
disk_sector_t new;
uint8_t bounce = malloc(DISK_SECTOR_SIZE);
memset(bounce, 0, DISK_SECTOR_SIZE);
off_t tmp_length = inode->data.length;
while (pos < tmp_length)
{
new = fat_create_chain(cur);
disk_write(filesys_disk, new, bounce);
cur = new;
tmp_length += DISK_SECTOR_SIZE;
}
inode->data.length = pos;
free(bounce);
return new;
}
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
문제는 length를 어떻게 하느냐인데... 일단 pos으로 해주고, 나중에 쓰고나서 쓴만큼 한번더 갱신해주는 걸로 충분하지 않을까 싶다.
inode_write_at() 을 수정하자.
off_t inode_write_at(struct inode *inode, const void *buffer_, off_t size,
off_t offset)
{
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
#ifdef EFILESYS
printf("\n---DEBUG // i_write_at // START \n");
const uint8_t *buffer = buffer_;
off_t bytes_written = 0;
uint8_t *bounce = NULL;
printf("---DEBUG // i_write_at // size : %llu\n", size);
if (inode->deny_write_cnt){
return 0;
}
printf("---DEBUG // i_write_at // ofs : %llu\n", offset);
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
int length = inode_length(inode) > offset + size ? inode_length(inode) : offset + size;
int tmp_length = offset;
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
printf("---DEBUG // i_write_at // inode_sector : %llu\n", inode->sector);
while (size > 0)
{
/* Sector to write, starting byte offset within sector. */
disk_sector_t sector_idx = byte_to_sector(inode, offset);
if (sector_idx = -1)
{
sector_idx = extend_sector(inode, offset);
}
그리고 byte-to_sector는 원래대로 돌려놨다.
static disk_sector_t
// byte_to_sector(struct inode *inode, off_t pos)
byte_to_sector(const struct inode *inode, off_t pos)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
ASSERT(inode != NULL);
disk_sector_t cur = inode->data.start;
if (pos < inode->data.length)
{
uint32_t cnt = pos / DISK_SECTOR_SIZE;
int i = 0;
for (i ; i < cnt ; i++)
{
cur = fat_get(cur);
}
return cur;
}
else
return -1;
/* ---------------------------- << Project.4 FAT << ---------------------------- */
그래도 안된다.
생각해보니 root_dir 만들때 할당이 안될거같은 느낌이다. 살펴보자
(2hours later)
나는 천하의 멍텅구리임을 엄숙하게 선언합니다.
+++++++++ 수정사항 +++++++++
조금 이거저거 많이 고쳤다.
많이 고쳣나?
무튼
문제가 있었던 곳은 inode_read_at (정확히는 byte_to_sector) 랑 inode_write_at이었다.
우선
static disk_sector_t
byte_to_sector(const struct inode *inode, off_t pos)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
ASSERT(inode != NULL);
disk_sector_t cur = inode->data.start;
if (pos < inode->data.length)
{
uint32_t cnt = pos / DISK_SECTOR_SIZE;
int i = 0;
for (i ; i < cnt ; i++)
{
cur = fat_get(cur);
}
return cur;
}
else
return -1;
/* ---------------------------- << Project.4 FAT << ---------------------------- */
byte_to_sector 를 원래대로 돌려놨다.
/* Reads SIZE bytes from INODE into BUFFER, starting at position OFFSET.
* Returns the number of bytes actually read, which may be less
* than SIZE if an error occurs or end of file is reached. */
off_t inode_read_at(struct inode *inode, void *buffer_, off_t size, off_t offset)
{
#ifdef EFILESYS
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
uint8_t *buffer = buffer_;
off_t bytes_read = 0;
uint8_t *bounce = NULL;
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
if (offset > inode->data.length) {
return 0;
}
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
while (size > 0)
{
/* Disk sector to read, starting byte offset within sector. */
disk_sector_t sector_idx = byte_to_sector(inode, offset);
if (sector_idx == -1)
{
printf("\n---ERROR // i_read // sector_idx : -1\n\n");
break;
}
int sector_ofs = offset % DISK_SECTOR_SIZE;
/* Bytes left in inode, bytes left in sector, lesser of the two. */
off_t inode_left = inode_length(inode) - offset;
int sector_left = DISK_SECTOR_SIZE - sector_ofs;
int min_left = inode_left < sector_left ? inode_left : sector_left;
/* Number of bytes to actually copy out of this sector. */
int chunk_size = size < min_left ? size : min_left;
if (chunk_size <= 0)
break;
if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE)
{
/* Read full sector directly into caller's buffer. */
disk_read(filesys_disk, sector_idx, buffer + bytes_read);
}
else
{
/* Read sector into bounce buffer, then partially copy
* into caller's buffer. */
if (bounce == NULL)
{
bounce = malloc(DISK_SECTOR_SIZE);
if (bounce == NULL)
break;
}
disk_read(filesys_disk, sector_idx, bounce);
memcpy(buffer + bytes_read, bounce + sector_ofs, chunk_size);
}
/* Advance. */
size -= chunk_size;
offset += chunk_size;
bytes_read += chunk_size;
}
free(bounce);
return bytes_read;
그리고 inode_read_at은 offset이 EOF 보다 멀리 있으면 return 0을 하게 했다.
/* Writes SIZE bytes from BUFFER into INODE, starting at OFFSET.
* Returns the number of bytes actually written, which may be
* less than SIZE if end of file is reached or an error occurs.
* (Normally a write at end of file would extend the inode, but
* growth is not yet implemented.) */
off_t inode_write_at(struct inode *inode, const void *buffer_, off_t size,
off_t offset)
{
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
#ifdef EFILESYS
// printf("\n---DEBUG // i_write_at // START \n");
const uint8_t *buffer = buffer_;
off_t bytes_written = 0;
uint8_t *bounce = NULL;
if (inode->deny_write_cnt){
return 0;
}
/* ---------------------------- >> Project.4 File Growth >> ---------------------------- */
int cnt = 1;
disk_sector_t cur = inode->data.start;
while (fat_get(cur) != EOChain)
{
cur = fat_get(cur);
cnt ++;
}
if (inode->data.length < offset + size)
{
int sectors_to_make = bytes_to_sectors(offset + size) - cnt;
for (int i = 0 ; i < sectors_to_make ; i++)
{
cur = fat_create_chain(cur);
}
inode->data.length = offset + size;
disk_write(filesys_disk, inode->sector, &inode->data);
}
/* ---------------------------- << Project.4 File Growth << ---------------------------- */
while (size > 0)
{
/* Sector to write, starting byte offset within sector. */
disk_sector_t sector_idx = byte_to_sector(inode, offset);
int sector_ofs = offset % DISK_SECTOR_SIZE;
/* Bytes left in inode, bytes left in sector, lesser of the two. */
off_t inode_left = inode_length(inode) - offset;
int sector_left = DISK_SECTOR_SIZE - sector_ofs;
int min_left = inode_left < sector_left ? inode_left : sector_left;
/* Number of bytes to actually write into this sector. */
int chunk_size = size < min_left ? size : min_left;
if (chunk_size <= 0)
break;
if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE)
{
/* Write full sector directly to disk. */
disk_write(filesys_disk, sector_idx, buffer + bytes_written);
}
else
{
/* We need a bounce buffer. */
if (bounce == NULL)
{
bounce = malloc(DISK_SECTOR_SIZE);
if (bounce == NULL)
break;
}
/* If the sector contains data before or after the chunk
we're writing, then we need to read in the sector
first. Otherwise we start with a sector of all zeros. */
if (sector_ofs > 0 || chunk_size < sector_left)
disk_read(filesys_disk, sector_idx, bounce);
else
memset(bounce, 0, DISK_SECTOR_SIZE);
memcpy(bounce + sector_ofs, buffer + bytes_written, chunk_size);
disk_write(filesys_disk, sector_idx, bounce);
}
// printf("---DEBUG // i_write_at // chunk_size : %d\n", chunk_size);
/* Advance. */
size -= chunk_size;
offset += chunk_size;
bytes_written += chunk_size;
}
free(bounce);
return bytes_written;
inode_write_at()에는 깝죽거리지않고, 처음에 file이 가져야할 sector 수 - file이 가지고 있는 sector 수로 현재 할당해야할 sector수를 구하고 그만큼 할당받는다.
그리고 length랑 offset+size 중에 큰 수를 length로 정한다.
이러니 깔끔하게 통과했다.
이제 깝치지않고 내 방식대로 추잡하게 나아가야겠다. 괜히 원칙지켰다가 피봤따
흑흑
+++++++++++++++++++++++ 다음화 예고 ++++++++++++++++++++++++++++++
// 중간중간에 컴파일을 하지 않아 곳곳에 틀린 곳이 많습니다.
// 알아서 수정하세요 ^오^
'Pintos Project > Project 4' 카테고리의 다른 글
[PintOS, Project 4] Buffer Cache 구현 (0) | 2021.03.08 |
---|---|
[PintOS, Project 4] Buffer Cache (0) | 2021.03.06 |
[PintOS, Project 4] Directory.c 공부 (0) | 2021.03.05 |
[PintOS, Project 4] Filesys.c 구현 (0) | 2021.03.04 |
[PintOS, Project 4] inode.c 구현 (0) | 2021.03.04 |
댓글