deallocuvm 在 Xv6 中如何工作?

How does deallocuvm work in Xv6?

根据源代码中的注释,deallocate 确实解除分配用户页面,将进程大小从 oldsz 带到 newsz

我的问题是当 pte 不存在时,它应该继续搜索下一个页面目录条目,但是为什么 PGADDR(PDX(a) + 1, 0, 0) 应该在这里减去 PGSIZE。

 if(!pte)
          a = PGADDR(PDX(a) + 1, 0, 0) - PGSIZE;

这是来自 Xv6 的源代码:

int
deallocuvm(pde_t *pgdir, uint oldsz, uint newsz)
{
  pte_t *pte;
  uint a, pa;

  if(newsz >= oldsz)
    return oldsz;

  a = PGROUNDUP(newsz);
  for(; a  < oldsz; a += PGSIZE){
    pte = walkpgdir(pgdir, (char*)a, 0);
    // pte not exists to next page table dir
    // do not understand why should minus PGSIZE
    if(!pte)
      a = PGADDR(PDX(a) + 1, 0, 0) - PGSIZE;
    // pte exists
    else if((*pte & PTE_P) != 0){
      pa = PTE_ADDR(*pte);
      if(pa == 0)
        panic("kfree");
      char *v = P2V(pa);
      kfree(v);
      *pte = 0;
    }
  }
  return newsz;
}

for 循环执行 a += PGSIZE。每次循环迭代时它都会这样做。

如果在进入下一个 PDE 时未减去 PGSIZE,则 a 将在下一次迭代中减少 PGSIZE 个元素。