Exemplo n.º 1
0
static mapid_t syscall_mmap (int fd, void *addr) 
{
  if(fd == 0 || fd == 1 || addr == NULL || (int) addr % PGSIZE != 0) {
    return MAP_FAILED;
  }

  struct mmap_entry *mme = mmap_entry_from_fd (fd);
  if (mme == NULL) return MAP_FAILED;

  mme->uaddr = addr;
  struct supp_page_table *spt = thread_current ()->spt;
  unsigned i = 0;
  for(; i < mme->num_pages; i++) {
    if (!is_user_vaddr ((char *)addr + i * PGSIZE)||
        supp_page_lookup (spt, (char *)addr + i * PGSIZE) != NULL) {
      free (mme);
      return MAP_FAILED;
    }
  }

  lock_acquire (&filesys_lock);
  file_reopen (mme->fp);
  lock_release (&filesys_lock);
 
  mme->map_id = (mapid_t) get_new_fd (fm, mme->fp, FM_MODE_MMAP);

  i = 0;
  for(; i < mme->num_pages; i++) {
    supp_page_insert (spt, (char *)addr + i * PGSIZE,
                      FRAME_MMAP, mme, false);
  }


  mmap_table_insert (thread_current ()->mmt, mme);
  return mme->map_id;
}
Exemplo n.º 2
0
/* Maps the file open as FD into the process' virtual address space - entire
   file mapped into consecutive virtual pages starting at ADDR. (Lazy load
   pages in mmap regions). (Evicting a page mapped by mmap writes it back to
   the actual file it was mapped from). (Set spare bytes on final page to zero
   when that page is faulted in the file system, and ignore these bytes when
   page is written back to disk). Returns mapid_t for the mapping, or -1 on
   failure. Failure occurs when file has length 0, if addr is not page aligned,
   if range of pages mapped overlaps any existing mapped pages (including the
   stack or pages mapped at executable load time), if addr is 0, or if fd
   is 0 or 1. */
static mapid_t
sys_mmap(int fd, void *addr)
{
  /* Check that fd is a valid file descriptor. */
  check_fd(fd);

  /* Cannot map stdin or stdout. */
  if (fd == STDIN_FILENO || fd == STDOUT_FILENO) {
    return ERROR;
  }

  /* Address to map to cannot be 0, because some Pintos code assumes virtual
     page 0 is not mapped. */
  if (addr == 0) {
    return ERROR;
  }

  int size = sys_filesize(fd);

  /* Cannot map a file of size 0 bytes. */
  if (size == 0) {
    return ERROR;
  }

  /* ADDR must be page-aligned. */
  if (pg_ofs(addr) != 0) {
    return ERROR;
  }

  /* If ADDR is not in user/process address space, we cannot map
     the file there. */
  if (!is_user_vaddr(addr)) {
    sys_exit(ERROR);
  }

  /* Pages is number of pages needed to map file.
     (size % PGSIZE) gives the number of spare bytes on the final page.
     This is necessary because the division is integer division, and so
     will round down, but we want it to round up. */
  int pages = size / PGSIZE;
  if ((size % PGSIZE) != 0) {
    pages++;
  }

  struct thread *cur = thread_current();
  struct hash *mmap_table = &cur->mmap_table;
  struct hash *spt = &cur->supp_pt;

  lock_acquire(&secure_file);
  struct file *old_file = get_file(fd);
  if (!old_file) {
    lock_release(&secure_file);
    sys_exit(ERROR);
  }
  /* Must use file_reopen() to get independent 'struct file *' for same file
     (with same inode) because the file could be being read at different points
     (file->pos could be different) and they could have different
     file->deny_write (file_deny_write() could be called on one struct file but
     not another of same file (inode) but different struct file). */
  struct file *file = file_reopen(old_file);
  lock_release(&secure_file);

  int i;
  int bytes_to_write;
  void *cur_page;
  /* Check that the contiguous range of pages to be mapped doesn't overlap
     any existing set of mapped pages (Not including stack). Can then add
     these pages to the supplementary page table. */
  for (i = 0; i < pages; i++) {
    cur_page = (void *) ((uint8_t *) addr) + (i * PGSIZE);
    /* Check to see if there is an existing mapped page at what would be the
       i'th page of this mapped file. */
    if (get_spt_entry(spt, cur_page) != NULL) {
      return ERROR;
    }
    /* Only on the last page do we potentially not fill up whole page with
       part of file. */
    bytes_to_write = (i == (pages - 1)) ? (size % PGSIZE) : PGSIZE;
    /* Add current page to the supplementary page table. */
    spt_insert_file(cur_page, file, bytes_to_write,
                       PGSIZE - bytes_to_write, i * PGSIZE, true, true, false);
  }

  mapid_t mapid = cur->next_mapid;

  /* Lock must be acquired to call hash_insert() in mmap_table_insert(), and
     since we have thread_current() here already it makes sense to lock here
     rather than in mmap_table_insert() in mmap.c. */
  lock_acquire(&cur->mmap_table_lock);
  bool success = mmap_table_insert(mmap_table, addr, addr + size, pages,
                                     mapid, file);
  lock_release(&cur->mmap_table_lock);

  /* Return -1 if mmap_table_insert wasn't successful (meaning there isn't
     enough space to malloc for a struct mmap_mapping *). */
  if (!success) {
    return ERROR;
  }

  /* Increment next_mapid for this thread, so that the next mmap will have a
     different mapid, ensuring unique mapids for all mappings for a process.
     Increment after checking for mmap_table_insert() success status, because
     in the case of failure, we can reuse the mapid that the failed mapping
     would have had. */
  cur->next_mapid++;

  /* If successful, function returns the mapid that uniquely identifies
     the mapping within the process. */
  return mapid;
}