앞선 게시물과 중복되는 코드가 있을 수 있다. 왜냐하면 All Pass 를 받고나서 정리를 했기 때문이다.
그래도 혹시 같은 문제로 고생하는 사람들을 위해 내가 어떻게 문제를 해결했는지 정리해 놓은 것을 공유한다.
확실히 fail을 pass로 만드는 과정에서 더 알아보게 되고, 더 남는게 많은 것 같다.
현재 8개 fail
FAIL tests/userprog/open-twice
FAIL tests/userprog/read-stdout
FAIL tests/userprog/write-stdin
FAIL tests/userprog/exec-read
FAIL tests/userprog/rox-simple
FAIL tests/userprog/rox-child
FAIL tests/userprog/rox-multichild
FAIL tests/userprog/no-vm/multi-oom
// 8 of 95 tests failed.
tests/userprog/read-stdout ✔
read에서 stdout=1이 들어올 때 처리를 해주니까 pass로 바뀌었다.
int read(int fd, void *buffer, unsigned size)
{
check_address(buffer);
off_t read_byte;
uint8_t *read_buffer = buffer;
if (fd == 0) // stdin
{
char key;
for (read_byte = 0; read_byte < size; read_byte++)
{
key = input_getc();
*read_buffer++ = key;
if (key == '\0')
{
break;
}
}
}
else if (fd == 1) // stdout
{
return -1;
}
else
{
struct file *read_file = find_file_by_fd(fd);
if (read_file == NULL)
{
return -1;
}
lock_acquire(&filesys_lock);
read_byte = file_read(read_file, buffer, size);
lock_release(&filesys_lock);
}
return read_byte;
tests/userprog/write-stdin ✔
write에서 fd로 stdin이 들어올 때 처리를 해주면 pass로 바뀐다.
int write(int fd, const void *buffer, unsigned size)
{
check_address(buffer);
int write_result;
if (fd == 0) // stdin
{
return 0;
}
else if (fd == 1) // stdout
{
putbuf(buffer, size);
return size;
}
else
{
struct file *write_file = find_file_by_fd(fd);
if (write_file == NULL)
{
return 0;
}
lock_acquire(&filesys_lock);
off_t write_result = file_write(write_file, buffer, size);
lock_release(&filesys_lock);
return write_result;
}
}
tests/userprog/open-twice ✔
open-twice.output을 살펴보면
Executing 'open-twice':
(open-twice) begin
(open-twice) open "sample.txt" once
(open-twice) open "sample.txt" again
(open-twice) open() returned 2 both times: FAILED
같은 파일을 두 번 열었는데 둘다 2를 return해서 실패한 것 같다.
같은 파일을 열더라도 다른 fd를 return해야 한다(GITBOOK에 써있음).
int add_file_to_fdt(struct file *file)
{
struct thread *cur = thread_current();
struct file **fdt = cur->fd_table;
// Find open spot from the front
// fd 위치가 제한 범위 넘지않고, fd table의 인덱스 위치와 일치한다면
while (cur->fd_idx < FDCOUNT_LIMIT && fdt[cur->fd_idx])
{
cur->fd_idx++; //현재의 fd_idx를 +1
}
...
}
이 코드를 추가해주었다.
?!
이 코드를 추가해주니까 open-twice 문제가 해결되었는데
pass tests/userprog/open-twice // -> clear
갑자기 exec-read와 multi-oom도 pass가 떠버렸다!!
pass tests/userprog/exec-read // -> clear
pass tests/userprog/no-vm/multi-oom // -> clear
그 이유를 한 번 생각해보면
exec-read에서 부모 thread가 sample.txt를 open한 후에 child가 다시 한번 sample.txt를 open하는데 이 때, fd가 다르게 부여받지 못해서 fail이 떴던 것으로 유추해볼 수 있다.
multi-oom은 메모리 누수(memory leak)를 check하는데 추가해준 코드와 정확하게 어떤 연관관계로 통과하게 되었을까? 이 코드를 수정하기 전에 분명 모든 palloc_get_page
에 대해 palloc_free_page
을 해주었다.
tests/userprog/no-vm/muti-oom.c
를 들어가보면 주석에
/* Open as many files as we can, up to fdmax.
Depending on how file descriptors are allocated inside
the kernel, open() may fail if the kernel is low on memory.
A low-memory condition in open() should not lead to the
termination of the process. */
라고 써있는데,
재귀적으로 child가 fork를 실패할 때까지 돌린다.
fdmax까지 file을 계속 open하는데, 이때 중복되는 fd에서 문제가 생기는 것으로 유추해볼 수 있다.
multi-oom에서 memory leak을 측정하는 방식이 신기했다. file을 계속 열다보면 kernel의 memory가 꽉 차게 되어서 못 여는 순간이 찾아오고, 이 때 kernel이 매번 동일한 수준의 깊이를 허용하는지 측정한다고 한다.
tests/userprog/exec-read ✔
exec-read.output을 살펴보면 다음과 같다.
Boot complete.
Putting 'exec-read' into the file system...
Putting 'sample.txt' into the file system...
Putting 'child-read' into the file system...
Executing 'exec-read':
(exec-read) begin
(exec-read) open "sample.txt"
(exec-read) read "sample.txt" first 20 bytes
(child-read) begin
(child-read) open "sample.txt"
(child-read) open "sample.txt": FAILED
child-read: exit(1)
(exec-read) Parent success
(exec-read) end
exec-read: exit(0)
Execution of 'exec-read' complete.
얘는 한번 연 파일을 다른 thread가 또 여니까 failed 가 떴다... ?
→ open-twice test 해결하니까 해결됨
tests/userprog/no-vm/multi-oom ✔
pintos -v -k -T 600 -m 20 -m 20 --fs-disk=10 -p tests/userprog/no-vm/multi-oom:multi-oom -- -q -f run multi-oom < /dev/null 2> tests/userprog/no-vm/multi-oom.errors > tests/userprog/no-vm/multi-oom.output
여기도 시간 오래걸리는데, multi-oom은 뭐하는 놈일까??
multi-oom은 메모리 누수를 검사한다.
그렇기 때문에 여기서는 palloc_get_page
에 대해서 palloc_free_page
을 꼭 해줘야한다.
process_exit()에서 받아온 palloc을 해제해준다.
void process_exit(void)
{
...
// for multi-oom(메모리 누수)
palloc_free_multiple(cur->fd_table, FDT_PAGES);
...
}
→ open-twice test 해결하니까 해결됨
FAIL tests/userprog/rox-simple ✔
FAIL tests/userprog/rox-child ✔
FAIL tests/userprog/rox-multichild ✔
현재 실행중인 파일을 쓰지 못하게 해준다.
// project 2 : system call
// 현재 실행중인 파일의 경우 write 할 수 없도록 설정
t->running = file;
file_deny_write(file);
load에서 file_close(file)을 해주면 file이 닫히면서 lock이 풀리게 된다. 따라서 load에서 닫지 말고(주석처리)
// userprog/process.c
static bool
load(const char *file_name, struct intr_frame *if_){
...
done:
// file_close(file);
return success;
}
process_exit()에서 닫아준다.
void process_exit(void)
{
...
// for rox- (실행중에 수정 못하도록)
file_close(cur->running);
...
}