09_pintos_VM

신치우·2022년 12월 11일

data_structure_and_Pintos

목록 보기
26/36

Pintos project 1~3까지 진행이 됐다.
project 2 - system call을 할땐 system call이 제일 힘든건줄 알았는데 project 3- vm을 하니 vm이 가장 힘든거라는걸 알게 됐다.
project 4 는 더 힘들 것인가...

일단 결과를 먼저 공유한다.

VM을 시작하기 전에 syn-read 혹은 multi-oom 등을 수백번 돌려보면서 lock이 정상적으로 동작하는지 꼭 확인해보길 바란다.
나는 중간에 lock이 정상동작하지 않아 fail case 가 있었다. lock을 수정한 후에 pass하였으니 꼭 lock을 수정해야한다.

나의 경우
fork_sema가 __do_fork 가 끝난 후에도 되고, process_exit에서도 진행이 되어서 sema_up 이 두번이 중복적으로 일어나 fail이 된 경우였다. (문제는 당시에 발견되지 않고 VM을 한창 진행중에 발견됐다는 것이다.)

__do_fork 안에 있는 // sema_up (&current->fork_sema); 로 주석처리 하였더니 정상 동작하는 것을 확인하였다.

혹시 모르니 __do_fork 함수를 아래 다시 올려놓겠다.

코드를 gitbook의 순서에 맞춰 올리도록 하겠다.

// process.c 
static void
__do_fork (void *aux) {
  struct intr_frame if_;
  // struct thread *parent = (struct thread *) aux;

  struct argv *fork_argv = (struct argv *) aux;
  struct thread *parent = fork_argv->fork_thread;
  struct thread *current = thread_current ();
  /* TODO: somehow pass the parent_if. (i.e. process_fork()'s if_) */
  struct intr_frame *parent_if;
  parent_if = fork_argv->fork_if;
  bool succ = true;

  /* 1. Read the cpu context to local stack. */
  memcpy (&if_, parent_if, sizeof (struct intr_frame));
  if_.R.rax = 0; // 자식 process는 항상 0을 return 하기 때문에 if_R.rax = 0을 넣어줌 --> git book 내용과 함께 작성

  /* 2. Duplicate PT */
  current->pml4 = pml4_create ();
  if (current->pml4 == NULL)
    goto error;

  process_activate (current);
#ifdef VM
  supplemental_page_table_init (&current->spt);
  if (!supplemental_page_table_copy (&current->spt, &parent->spt))
    goto error;
#else
  if (!pml4_for_each (parent->pml4, duplicate_pte, fork_argv)) // pte_entry table에 duplicate_pte 함수를 적용함 --> 실패하면 error로 가고 아니면 진행
    goto error;
#endif

  /* TODO: Your code goes here.
   * TODO: Hint) To duplicate the file object, use `file_duplicate`
   * TODO:       in include/filesys/file.h. Note that parent should not return
   * TODO:       from the fork() until this function successfully duplicates
   * TODO:       the resources of parent.*/
  if (parent->fd_idx >= FD_COUNT_LIMT) // 만일 할당한 fd_idx가 FD_COUNT_LIMIT 보다 크다면 error로 감 (공간 초과)
    goto error;


  // 부모 process가 가지고 있는 열린 파일의 정보는 자식 process에게 상속됨
  current->fd_table[0] = parent->fd_table[0]; // 처음 0과 1은 정해져있으니 그 둘을 그대로 복사해옴
  current->fd_table[1] = parent->fd_table[1];

  for (int i = 2; i < FD_COUNT_LIMT; i++) { // 남은 부분들도 복사
    struct file *temp_file = parent->fd_table[i];
    if (temp_file == NULL)
      continue;
    current->fd_table[i] = file_duplicate (temp_file); // temp file의 속성을 포함한 개체를 복사하고 File과 동일한 inode에 대한 새 파일을 반환 --> 실패하면 NULL을 반환
  }
  
  current->fd_idx = parent->fd_idx; // 위 정보를 상속 받기 때문에 열린 파일의 개수도 같이 넘겨줌

  // sema_up (&current->fork_sema); // 그리고 sema_up으로 fork_sema는 풀어줌

  // process_init (); // process를 초기화

  /* Finally, switch to the newly created process. */
  free (fork_argv); // fork_argv의 역할은 끝났으니깐 free 해줌

  /*
  do_iret을 통해서 interrupt frame에 있는 정보를 register로 보내줌
  if_.rip 의 시작주소를 따로 저장해주는 작업이 없는 이유는 (process_exe의 load에서 하는 작업)
  duplicate_pte 와 file_duplicate 등을 통해서 interrupt frame의 모든 정보를 자식 process에 복사를 해주었기 때문임
  그래서 그냥 register에 올려주기만 하면됨
  */
  if (succ)
    do_iret (&if_);

error:
  current->exit_status = TID_ERROR;
  sema_up(&current->fork_sema);
  free (fork_argv);
  exit_handler (TID_ERROR);
}

앞선 project에서 사용했던 check_add를 수정하고 buffer를 check하는 것을 추가해줌

check_add,check_buff 를 추가함

struct page *check_add (void *add) {
  if (is_kernel_vaddr (add) || add == NULL || spt_find_page(&thread_current()->spt,add) == NULL || !(&thread_current()->pml4)) 
  {
    exit_handler(-1);
  }
  return spt_find_page(&thread_current()->spt, add);
}

void
check_buff (void * buffer, unsigned size, void *rsp, bool to_write){
  for(int i=0; i<size; i++){
    struct page *page = check_add(buffer + i);
    if(page ==NULL)
      exit_handler(-1);
    if(to_write == true && page->writable == false)
      exit_handler(-1);
  }
}

SYS_READSYS_WRITE는 buffer check가 필요함 - buffer 단위로 읽고 쓰고 할거니
그래서 해당 systemcall을 받으면 점검을 해줌

    case SYS_READ:
      check_buff(f->R.rsi, f->R.rdx, f->rsp, 1);
      f->R.rax = read_handler (a1, a2, a3);
      break;
    case SYS_WRITE:
      check_buff(f->R.rsi, f->R.rdx, f->rsp, 0);
      f->R.rax = write_handler (a1, a2, a3);
      break;
profile
https://shin8037.tistory.com/

0개의 댓글