lab10 mmap

lab10 mmap

实验结果

实验

编程前的思考以及解决方法

思考1

mmap返回了一个虚拟地址,但是看hints不分配实际的物理地址,但虚拟地址就确定了PTE,是否需要在PTE中做标记,否则usertrap怎么知道你这个page fault是啥原因?

lazy allocation is a win: the kernel doesn’t have to do any work at all for pages that the application never uses。真的不需要做任何工作?

操作系统怎么为lazy page分配一段连续的page ?

看到下一个hints,在proc的结构体中存储一个结构体数组,对应着这个进程锁分配的mmpages。usertrap时获取一下本进程可以分配。

所以在proc结构体中存储一个结构体数组来保存要mmap的地址,在结构体数组的元素的地址范围内有STAVAL的地址,说明是mmap产生的page fault。

思考2

2:mmap最后一个参数offset一定要page alined吗?感觉不page alined也可以读,为啥linux要限制它为page alined?xv6有限制吗?有也或者好像没有。
which takes an offset argument at which to read in the file (but you will have to lock/unlock the inode passed to readi)

readi是从文件中读取信息的,假设是inode文件,从either_copyout读。看二者的处理程序,either_copyout对于kernel和process的offsset,是没有page algned的限制的,所以我们也不要。

device文件提供的接口是没有offset的,这种page fault要怎么处理?pipe也没有?

ip->type == pipe,则应该返回错误,因为pipe文件弄完就消失,munmap,然后shared那怎么写回,应该是不行的。

取巧了,优点面向测试编程,mmaptest中测试的文件好像没有device文件,所以先考虑是device文件也返回错误。

思考3

长度+offset要是超过文件的末尾了怎么办?我要提供对这种情况的处理程序吗?还是有编程规范,肯定不会出现这种情况

length是要读的长度,可以不page alinged。

无论mmaptest有没有意识到这种情况,就算编写者遵循这种情况,但是编写程序时也可能不小心写出了这种情况。

用filestat获取文件大小,如果长度+offset大于文件大小,则返回错误。

思考4

怎么找到一段足够长,而且没有使用过的虚拟地址用于mmap的使用

一个process 一共有512512512个page,如果循环读写,判断每个page的valid位和下一个page的valid位,那么会浪费很多时间,且也不一定足够长。

参考linux内核中mmap的布局,从上一节得知一个inode所对应的文件长度最大应该为268kb,简单认为有512KB,512*16=8M。

因为有sbrk,即可以拓展。所以这一段区域布置在TRAPFRAME下两个page(no valid作为guard page)到8M的地方,(在两个page作为guard page)。。。。。面向测试编程

思考5

unmmap的add参数是否要page aligned呢?linux是要的,xv6要不要

linux是一定要page aligned的,看xv6的测试,也是page aligned的,所以选择page aligned,否则有点难。

思考6

port为没有写权限,测试写了,那么这种异常情况我要怎么办?杀死进程??

看了测试代码,发现没有这种极端情况。

代码

下面是问题相关的重要代码,可能是头文件嵌套原因,所以一些头文件得用#ifndef xxxx #define xxx #ednif。一些地方也得补上这些头文件,但是这些我不展示了。

我主要思路还是跟cow有点像,每一mmap在有读写时,就把这一个page mmap,然后把文件内容读到这一页。

mmap结构体定义,记录mmap,unmmap的一些重要信息

比如这个结构体有没有用过,记录port,flag,初始开始地址,初始长度,现在的长度和地址,偏移。

要用初始开始的地址和长度来确定每一page要从文件的哪里开始读,读多少,所以用两个变量来记录它们。

在kernel/proc.h中定义

struct __MmapStruct
{
  int Port; 
  int Flag;
  uint32 IsMaped;//0代表这个结构体没有map,1代表有。
  uint64 StartVaAdd; //0xffffffffffffffff和下面length为0代表没有map,需要page aligned。
  uint64 InitAdd;//unmmap可能会导致start改变,每页根file的offset是根据start弄的
  uint64 InitLen;//与上面initAdd类似
  uint64 Length;//实际mmap区域还剩下的长度
  uint64 Offset;
  struct file* MapMpedFile;//为0代表没有
};

// Per-process state
struct proc {
  struct spinlock lock;

  // p->lock must be held when using these:
  enum procstate state;        // Process state
  void *chan;                  // If non-zero, sleeping on chan
  int killed;                  // If non-zero, have been killed
  int xstate;                  // Exit status to be returned to parent's wait
  int pid;                     // Process ID

  // wait_lock must be held when using this:
  struct proc *parent;         // Parent process

  // these are private to the process, so p->lock need not be held.
  struct __MmapStruct  MapS[PROCESS_MMAPNUM];//16
  uint64 kstack;               // Virtual address of kernel stack
  uint64 sz;                   // Size of process memory (bytes)
  pagetable_t pagetable;       // User page table
  struct trapframe *trapframe; // data page for trampoline.S
  struct context context;      // swtch() here to run process
  struct file *ofile[NOFILE];  // Open files
  struct inode *cwd;           // Current directory
  char name[16];               // Process name (debugging)
};

mmap系统调用的具体实现

在进程进程结构体中找到没有使用过的mmap结构体,根据参数来设置mmap结构体的值,增加mmap文件中inode的引用次数。

/** 
 *@brief 
*/
uint64 sys_mmap(void)
{
  struct proc* CurrentProc ;
  struct file* UseFile;
  struct stat UseFileSt;
  uint64 Len;
  int Port;
  int Flag;
  int Fd;
  uint64 Offset;
  int i;

  Len = argraw(1);//修改这个,不static了。
  argint(2, &Port);
  argint(3, &Flag);
  argint(4, &Fd);
  Offset = argraw(5);

  CurrentProc =  myproc();
  if ((Fd < 0) || (Fd >= NOFILE))
  {
    return 0xffffffffffffffff;
  }
  UseFile = CurrentProc->ofile[Fd];
  if((UseFile->ip  == 0))//device pipe, none不行
  {
    return 0xffffffffffffffff;
  }
  if (UseFile->readable == 0)
  {
    return 0xffffffffffffffff;
  }
  if (Flag == MAP_SHARED)
  {
    if ((UseFile->writable == 0) && ((Port & PROT_WRITE) != 0))
    {
      return 0xffffffffffffffff;
    }
  }
  // filestat是用于进程,这里是kernel
  ilock(UseFile->ip);
  stati(UseFile->ip, &UseFileSt);
  iunlock(UseFile->ip);
  
  if ((Len + Offset) < UseFileSt.size)//偏移加要映射的长度小于文件大小,交给上一层处理
  {
    return 0xffffffffffffffff;
  }
 
  for(i = 0; i < 16; i++)
  {
    if (CurrentProc->MapS[i].IsMaped == 0)
    {
      CurrentProc->MapS[i].IsMaped = 1;
      CurrentProc->MapS[i].Flag = Flag;
      CurrentProc->MapS[i].Length = Len;
      CurrentProc->MapS[i].MapMpedFile = UseFile;
      CurrentProc->MapS[i].Port = Port;
      CurrentProc->MapS[i].StartVaAdd = MMAPSTART + (PGSIZE * 128 *i);
      CurrentProc->MapS[i].InitAdd = CurrentProc->MapS[i].StartVaAdd;
      CurrentProc->MapS[i].InitLen = CurrentProc->MapS[i].Length;
      CurrentProc->MapS[i].Offset = Offset;
      filedup( CurrentProc->MapS[i].MapMpedFile);
      break;
    }
  }

  if (i == 16)//16个mmap不够用了
  {
    return 0xffffffffffffffff;
  }

  return CurrentProc->MapS[i].StartVaAdd;
}

trap函数的具体实现

在usertrap函数里,判断如果中断来自load pagefault或者store pagefault,就调用MmapHandler函数。如果失败,杀死该进程。

MmapHandler首先判断是进程哪个mmap结构体的mmap引起的pagefault,然后根port和flag设置权限,并将文件对应的数据读到该page对应的地方。

usertrap函数里。

  if(r_scause() == 8){
    // system call

    if(p->killed)
      exit(-1);

    // sepc points to the ecall instruction,
    // but we want to return to the next instruction.
    p->trapframe->epc += 4;

    // an interrupt will change sstatus &c registers,
    // so don't enable until done with those registers.
    intr_on();

    syscall();
  }
  else if ((r_scause() == 13) || (r_scause() == 15))
  {
    uint64 Scause = r_scause();
    uint64 Staval = r_stval();

    if (MmapHandler(Scause, Staval) < 0)
    {
      p->killed = 1;//杀死该进程。
    }
  }
   else if((which_dev = devintr()) != 0){
    // ok
/**
 * @brief 
 */
int    MmapHandler(uint64 Scause, uint64 Stval)
{
  uint64 ThePage;
  int i = 0;
  struct proc *p = myproc();
  uint32 PageStartOffset = 0;
  int PageRemainLen = 0;
  uint64* pa;
  int flag;

  ThePage = PGROUNDDOWN(Stval); //那一页的头
  for(i = 0; i < 16; i++)
  {
    if (p->MapS[i].IsMaped != 0)
    {
      if ((p->MapS[i].StartVaAdd <= ThePage) && ((p->MapS[i].StartVaAdd + p->MapS[i].Length) >= ThePage))
      {
        break;
      }
    }
  }
  if (16 == i)
  {
    return -1;//不是mmap的地方引起的page fault,个人决定引起这样的page fault,要杀掉。
  }

  

  pa = kalloc();
  if (0 == pa)
  {
    return -1;
  }
  flag = 0;
  if ((p->MapS[i].Port & PROT_READ) != 0)
  {
    flag |= PTE_R;
  }
  if ((p->MapS[i].Port & PROT_WRITE) != 0)
  {
    flag |= PTE_W;
  }
  flag |= PTE_U;
  if (mappages(p->pagetable, ThePage, PGSIZE, (uint64)pa, flag ) < 0)
  {
    return -1;
  }

  //文件读到这一页上面。
  PageStartOffset = ThePage - p->MapS[i].InitAdd;
  PageRemainLen = p->MapS[i].InitLen - PageStartOffset;
  PageStartOffset = PageStartOffset + p->MapS[i].Offset;
  if (PageRemainLen > PGSIZE)
  {
    PageRemainLen = PGSIZE;
  }
  begin_op();
  ilock(p->MapS[i].MapMpedFile->ip);
  if (readi(p->MapS[i].MapMpedFile->ip, 1, ThePage, PageStartOffset, PageRemainLen) < 0)
  {
    iunlock(p->MapS[i].MapMpedFile->ip);
    end_op();
    return -1;
  }
  iunlock(p->MapS[i].MapMpedFile->ip);
  end_op();

  return 0;
}

munmap系统调用的具体实现

判断输入参数add和len是否对(比如add要page aligned,unmmap的区域要mmap过等),然后判断是否要shared,是的话写回文件,然后对页表释放映射,释放内存。

/** 
 *@brief 
*/
uint64 sys_munmap(void)
{
  uint64 UmmapAdd;
  uint64 Length;
  int i;
  struct proc* CurrentProc;
  uint64 TempAdd;
  pte_t* TempAddp;
  uint32 PageStartOffset = 0;
  int PageRemainLen = 0;


  argaddr(0, &UmmapAdd);
  Length = argraw(1);
  CurrentProc = myproc();

  for(i = 0; i < 16; i++)
  {
    if(CurrentProc->MapS[i].IsMaped != 0)
    {
      if((UmmapAdd >= CurrentProc->MapS[i].StartVaAdd) && (UmmapAdd <= (CurrentProc->MapS[i].StartVaAdd + CurrentProc->MapS[i].Length)))
      {
        //满足这个条件代表ummap的是这个结构体

        if (((CurrentProc->MapS[i].StartVaAdd) != UmmapAdd) &&   \
         ((UmmapAdd + Length) < (CurrentProc->MapS[i].StartVaAdd + CurrentProc->MapS[i].Length)))
         {
          return -1;//不能挖中断这段
         }

         if ((UmmapAdd + Length) > (CurrentProc->MapS[i].StartVaAdd + CurrentProc->MapS[i].Length))
         {
          return -1;//挖的不止这个区域。
         }

         break;
      }
    }
  }

  if (16 == i)//没有找到
  {
    return -1;
  }

  if ((UmmapAdd % PGSIZE) != 0)
  {
    return -1;//必须要page aligned.
  }

  //哪怕len+add没满那个page,只要涉及了,也回写到file,就释放掉
  for (TempAdd = UmmapAdd; TempAdd < (UmmapAdd + Length); TempAdd = TempAdd + PGSIZE)
  {
    TempAddp = walk(CurrentProc->pagetable, TempAdd, 1);

    if (TempAddp == 0)
    {
      continue;
    }
    if (((*TempAddp) & PTE_V) == 0)
    {
      continue;;//要unmmap的区域PTE居然不是有效的。没有读写,直接调用了
    }

    if ((CurrentProc->MapS[i].Flag == MAP_SHARED) && ((CurrentProc->MapS[i].Port & PROT_WRITE) != 0) )//把MMAP写的东西回写到文件
    {
      PageStartOffset = TempAdd - CurrentProc->MapS[i].InitAdd;
      PageRemainLen = CurrentProc->MapS[i].InitLen - PageStartOffset;
      PageStartOffset = PageStartOffset + CurrentProc->MapS[i].Offset;
      if (PageRemainLen > PGSIZE)
      {
        PageRemainLen = PGSIZE;
      }

      begin_op();
      ilock(CurrentProc->MapS[i].MapMpedFile->ip);
      writei(CurrentProc->MapS[i].MapMpedFile->ip, 1, TempAdd,  PageStartOffset, PageRemainLen);
      iunlock(CurrentProc->MapS[i].MapMpedFile->ip);
      end_op();
    }
    uvmunmap(CurrentProc->pagetable, TempAdd, 1, 1);
  }

  //更新现在映射的地址和长度
  if ((UmmapAdd == CurrentProc->MapS[i].StartVaAdd) && (CurrentProc->MapS[i].Length == Length))//这一块全部unmmap完了
  {
    fileclose(CurrentProc->MapS[i].MapMpedFile);
    CurrentProc->MapS[i].IsMaped = 0;
    CurrentProc->MapS[i].Flag = 0;
    CurrentProc->MapS[i].InitAdd = 0;
    CurrentProc->MapS[i].Length = 0;
    CurrentProc->MapS[i].MapMpedFile = 0;
    CurrentProc->MapS[i].Port = 0;
    CurrentProc->MapS[i].StartVaAdd = 0;
  }
  else if ((UmmapAdd == CurrentProc->MapS[i].StartVaAdd) && (Length < CurrentProc->MapS[i].Length))//覆盖前半段
  {
    TempAdd = PGROUNDUP((UmmapAdd + Length));
    CurrentProc->MapS[i].Length = CurrentProc->MapS[i].Length - (TempAdd - CurrentProc->MapS[i].StartVaAdd);
    CurrentProc->MapS[i].StartVaAdd = TempAdd;
  }
  else if ((UmmapAdd > CurrentProc->MapS[i].StartVaAdd) && ((UmmapAdd + Length) == (CurrentProc->MapS[i].StartVaAdd + CurrentProc->MapS[i].Length)))//后半段,除了这3种,没有别的可能了
  {
    CurrentProc->MapS[i].Length = CurrentProc->MapS[i].Length - (CurrentProc->MapS[i].StartVaAdd + CurrentProc->MapS[i].Length - UmmapAdd);
  }

  return 0;
}

allocproc的相关实现

增加对mmap结构体的初始化

found:
  p->pid = allocpid();
  p->state = USED;

  // Allocate a trapframe page.
  if((p->trapframe = (struct trapframe *)kalloc()) == 0){
    freeproc(p);
    release(&p->lock);
    return 0;
  }

  // An empty user page table.
  p->pagetable = proc_pagetable(p);
  if(p->pagetable == 0){
    freeproc(p);
    release(&p->lock);
    return 0;
  }

  // Set up new context to start executing at forkret,
  // which returns to user space.
  memset(&p->context, 0, sizeof(p->context));
  p->context.ra = (uint64)forkret;
  p->context.sp = p->kstack + PGSIZE;

  //初始化mmap的所有结构体
  for(int i = 0; i < 16; i++)
  {
    p->MapS[i].Flag = 0;
    p->MapS[i].InitAdd = 0;
    p->MapS[i].InitLen = 0;
    p->MapS[i].IsMaped = 0;
    p->MapS[i].Length = 0;
    p->MapS[i].MapMpedFile = 0;
    p->MapS[i].Offset = 0;
    p->MapS[i].Port = 0;
    p->MapS[i].StartVaAdd = 0;    
  }

  return p;
}

fork系统调用的具体实现

把proc上mmap结构体的值复制到子进程的mmap结构体上。如果有mmap的区域,需要增加对应文件inode的引用次数,映射子进程需要的mmap page,并且把父进程的内容复制到上面。

// Create a new process, copying the parent.
// Sets up child kernel stack to return as if from fork() system call.
int
fork(void)
{
  int i, pid;
  struct proc *np;
  struct proc *p = myproc();

  // Allocate process.
  if((np = allocproc()) == 0){
    return -1;
  }

  // Copy user memory from parent to child.
  if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
    freeproc(np);
    release(&np->lock);
    return -1;
  }
  np->sz = p->sz;

  // copy saved user registers.
  *(np->trapframe) = *(p->trapframe);

  // Cause fork to return 0 in the child.
  np->trapframe->a0 = 0;

  // increment reference counts on open file descriptors.
  for(i = 0; i < NOFILE; i++)
    if(p->ofile[i])
      np->ofile[i] = filedup(p->ofile[i]);
  np->cwd = idup(p->cwd);

  safestrcpy(np->name, p->name, sizeof(p->name));

  pid = np->pid;

  release(&np->lock);

  acquire(&wait_lock);
  np->parent = p;
  release(&wait_lock);

  acquire(&np->lock);
  np->state = RUNNABLE;
  release(&np->lock);

  //复制结构体,分配页面并复制
  uint64 TempAdd;
  uint64* PaP;
  pte_t *pte;
  uint64 OldPa, NewPa;
  int TheFlag;
  for(int i = 0; i < 16; i++)
  {
    np->MapS[i].Flag = p->MapS[i].Flag;
    np->MapS[i].Port = p->MapS[i].Port;
    np->MapS[i].IsMaped = p->MapS[i].IsMaped;
    np->MapS[i].StartVaAdd = p->MapS[i].StartVaAdd;
    np->MapS[i].InitAdd = p->MapS[i].InitAdd;
    np->MapS[i].InitLen = p->MapS[i].InitLen;
    np->MapS[i].Length = p->MapS[i].Length;
    np->MapS[i].Offset = p->MapS[i].Offset;
    np->MapS[i].MapMpedFile = p->MapS[i].MapMpedFile;

    if (np->MapS[i].IsMaped != 0)
    {
      filedup(np->MapS[i].MapMpedFile);

      TempAdd = PGROUNDDOWN(np->MapS[i].StartVaAdd);
      for(; TempAdd < PGROUNDUP(np->MapS[i].StartVaAdd + np->MapS[i].Length);TempAdd += PGSIZE)
      {
        pte = walk(p->pagetable, TempAdd, 1);
        OldPa = PTE2PA(*pte);  
        if (0 == OldPa)//mmap以后,没有读写该page就fork了。
        {
          continue;
        }

        PaP = kalloc();
        if (PaP == 0)
        {
          return -1;
        }
        TheFlag = 0;
        if ((p->MapS[i].Port & PROT_READ) != 0)
        {
          TheFlag |= PTE_R;
        }
        if ((p->MapS[i].Port & PROT_WRITE) != 0)
        {
          TheFlag |= PTE_W;
        }
        TheFlag |= PTE_U;        
        if (mappages(np->pagetable, TempAdd, PGSIZE, (uint64)(PaP), TheFlag) < 0)
        {
          return -1;
        }

        pte = walk(np->pagetable, TempAdd, 1);
        NewPa = PTE2PA(*pte);
        pte = walk(p->pagetable, TempAdd, 1);
        OldPa = PTE2PA(*pte);  
        memmove((char*)NewPa, (char*)OldPa, PGSIZE);     
        
      }
    }

  }

  return pid;
}

exit系统调用的具体实现

与munmap类似,把所有未unmap得unmap掉,有满足回写条件的要回写。

// Exit the current process.  Does not return.
// An exited process remains in the zombie state
// until its parent calls wait().
void
exit(int status)
{
  struct proc *p = myproc();

  if(p == initproc)
    panic("init exiting");

  // Close all open files.
  for(int fd = 0; fd < NOFILE; fd++){
    if(p->ofile[fd]){
      struct file *f = p->ofile[fd];
      fileclose(f);
      p->ofile[fd] = 0;
    }
  }

  //释放掉unmmap
  uint64 TempAdd;
  uint32 PageStartOffset = 0;
  int PageRemainLen = 0;
  pte_t *pte;
  uint64 ThePa;
  for(int i = 0; i < 16; i++)
  {
    if (p->MapS[i].IsMaped != 0)//没有释放掉
    {
      TempAdd = PGROUNDDOWN(p->MapS[i].StartVaAdd);
      for(; TempAdd <= (p->MapS[i].StartVaAdd + p->MapS[i].Length); TempAdd = TempAdd + PGSIZE)
      {
        pte = walk(p->pagetable, TempAdd, 1);
        ThePa = PTE2PA(*pte);
        if (ThePa == 0)
        {
          continue;//这一页没有读写,实际都没分配过。
        }
        if ((p->MapS[i].Flag == MAP_SHARED) && ((p->MapS[i].Port & PROT_WRITE) != 0))//要写回文件
        {
          PageStartOffset = TempAdd - p->MapS[i].InitAdd;
          PageRemainLen = p->MapS[i].InitLen - PageStartOffset;
          PageStartOffset = PageStartOffset + p->MapS[i].Offset;
          if (PageRemainLen > PGSIZE)
          {
            PageRemainLen = PGSIZE;
          }

          begin_op();
          ilock(p->MapS[i].MapMpedFile->ip);
          writei(p->MapS[i].MapMpedFile->ip, 1, TempAdd, PageStartOffset, PageRemainLen);
          iunlock(p->MapS[i].MapMpedFile->ip);
          end_op();
        }

        uvmunmap(p->pagetable, TempAdd, 1, 1);
      }

      fileclose(p->MapS[i].MapMpedFile);
      p->MapS[i].Flag = 0;
      p->MapS[i].InitAdd = 0;
      p->MapS[i].InitLen = 0;
      p->MapS[i].IsMaped = 0;
      p->MapS[i].Length = 0;
      p->MapS[i].MapMpedFile = 0;
      p->MapS[i].Offset = 0;
      p->MapS[i].Port = 0;
      p->MapS[i].StartVaAdd = 0;
    }
  }

  begin_op();
  iput(p->cwd);
  end_op();
  p->cwd = 0;

  acquire(&wait_lock);

  // Give any children to init.
  reparent(p);

  // Parent might be sleeping in wait().
  wakeup(p->parent);
  
  acquire(&p->lock);

  p->xstate = status;
  p->state = ZOMBIE;

  release(&wait_lock);

  // Jump into the scheduler, never to return.
  sched();
  panic("zombie exit");
}

问题

问题2

test mmap f不通过

原因:在sys_mmap中调用了filestat获取文件的信息,非法调用。观察下面的3个函数,你会发现filestat中,传入的st地址应是为当前进程中的虚拟地址,我却用在了kernel中。

uint64
sys_fstat(void)
{
  struct file *f;
  uint64 st; // user pointer to struct stat

  if(argfd(0, 0, &f) < 0 || argaddr(1, &st) < 0)
    return -1;
  return filestat(f, st);
}

int
filestat(struct file *f, uint64 addr)
{
  struct proc *p = myproc();
  struct stat st;
  
  if(f->type == FD_INODE || f->type == FD_DEVICE){
    ilock(f->ip);
    stati(f->ip, &st);
    iunlock(f->ip);
    if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
      return -1;
    return 0;
  }
  return -1;
}

int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
{
  uint64 n, va0, pa0;

  while(len > 0){
    va0 = PGROUNDDOWN(dstva);
    pa0 = walkaddr(pagetable, va0);
    if(pa0 == 0)
      return -1;
    n = PGSIZE - (dstva - va0);
    if(n > len)
      n = len;
    memmove((void *)(pa0 + (dstva - va0)), src, n);

    len -= n;
    src += n;
    dstva = va0 + PGSIZE;
  }
  return 0;
}

问题3

want zero,but got 5

首先觉得是file没有读到mmap的区域,于是重点整理了一下trap的逻辑,感觉没有问题。

然后想起kalloc分配后,置那个page的就是0x05。难道我没把file 0的部分写到mmap区域吗?
那个页肯定有写的,否则1.5page的A就错误了,那么redi长度有问题吗?理了一下逻辑,也没发现问题。

看了一下测试代码,发现它没写0,直接就默认后面open 文件后半页的就是0,其实后半页还是0x05;


//
// create a file to be mapped, containing
// 1.5 pages of 'A' and half a page of zeros.
//
void
makefile(const char *f)
{
  int i;
  int n = PGSIZE/BSIZE;

  unlink(f);
  int fd = open(f, O_WRONLY | O_CREATE);
  if (fd == -1)
    err("open");
  memset(buf, 'A', BSIZE);
  // write 1.5 page
  for (i = 0; i < n + n/2; i++) {
    if (write(fd, buf, BSIZE) != BSIZE)
      err("write 0 makefile");
  }
  if (close(fd) == -1)
    err("close");
}

更改一下kalloc的置5,改成了置7
于是就出现了wanted zero, got 0x7。
个人觉得是测试的写法不对,要么补充测试写法,要么kalloc改成置0

测试通过

问题4

mmap call should have failed, pid=3

  // check that mmap does allow read/write mapping of a
  // file opened read/write.
  if ((fd = open(f, O_RDONLY)) == -1)
    err("open");
  p = mmap(0, PGSIZE*3, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (p != MAP_FAILED)
    err("mmap call should have failed");
  if (close(fd) == -1)
    err("close");

通过上面的代码可以看出,是mmap返回(void*)-1导致的,但是为啥前面通过了,这边没有通过。

是这个参数设置特殊吗?并没有,那么就是前面的积累导致的,应该是unmmap的问题。但unmmap也才3个,就算没unmmap掉也没问题。

仔细发现测试是要等于(void*)(-1)才通过?

没考虑到file属性与port属性不一致情况。

file 不可读,返回(void*)-1;

flag private,file可不可写与port可读可写无所谓,都可以mmap出来。但port没有可读却读了,要杀死进程?port没可写却写了要杀死进程,这个的情况不知道要怎么处理,杀死呢?还是panic?trap也没处理?

flag shared,file 不可写,那么port也不可写。

问题5

fork引起kernel trap.

pte = walk(np->pagetable, TempAdd, 1);
NewPa = PTE2PA(*pte);
pte = walk(p->pagetable, TempAdd, 1);
OldPa = PTE2PA(*pte);  
printf("old %p   new %p\n", OldPa, NewPa);
memmove((char*)NewPa, (char*)OldPa, PGSIZE);     

打印OldPa,发现值是0,代表旧进程的页表没有映射实际物理地址,是0?
发现忘考虑了,mmap后,没有读写那个区域立即fork后的可能。

posted @ 2025-02-10 23:18  我们的歌谣  阅读(12)  评论(0)    收藏  举报