// swap_out_vma - try unmap pte & move pages into swap active list. static int swap_out_vma(struct mm_struct *mm, struct vma_struct *vma, uintptr_t addr, size_t require) { if (require == 0 || !(addr >= vma->vm_start && addr < vma->vm_end)) { return 0; } uintptr_t end; size_t free_count = 0; addr = ROUNDDOWN(addr, PGSIZE), end = ROUNDUP(vma->vm_end, PGSIZE); while (addr < end && require != 0) { pte_t *ptep = get_pte(mm->pgdir, addr, 0); if (ptep == NULL) { if (get_pud(mm->pgdir, addr, 0) == NULL) { addr = ROUNDDOWN(addr + PUSIZE, PUSIZE); } else if (get_pmd(mm->pgdir, addr, 0) == NULL) { addr = ROUNDDOWN(addr + PMSIZE, PMSIZE); } else { addr = ROUNDDOWN(addr + PTSIZE, PTSIZE); } continue ; } if (ptep_present(ptep)) { struct Page *page = pte2page(*ptep); assert(!PageReserved(page)); if (ptep_accessed(ptep)) { ptep_unset_accessed(ptep); mp_tlb_invalidate(mm->pgdir, addr); goto try_next_entry; } if (!PageSwap(page)) { if (!swap_page_add(page, 0)) { goto try_next_entry; } swap_active_list_add(page); } else if (ptep_dirty(ptep)) { SetPageDirty(page); } swap_entry_t entry = page->index; swap_duplicate(entry); page_ref_dec(page); ptep_copy(ptep, &entry); mp_tlb_invalidate(mm->pgdir, addr); mm->swap_address = addr + PGSIZE; free_count ++, require --; if ((vma->vm_flags & VM_SHARE) && page_ref(page) == 1) { uintptr_t shmem_addr = addr - vma->vm_start + vma->shmem_off; pte_t *sh_ptep = shmem_get_entry(vma->shmem, shmem_addr, 0); assert(sh_ptep != NULL && ! ptep_invalid(sh_ptep)); if (ptep_present(sh_ptep)) { shmem_insert_entry(vma->shmem, shmem_addr, entry); } } } try_next_entry: addr += PGSIZE; } return free_count; }
static inline void shmem_remove_entry_pte(pte_t * ptep) { //TODO //assert(0); assert(ptep != NULL); if (ptep_present(ptep)) { struct Page *page = pte2page(*ptep); #ifdef UCONFIG_SWAP if (!PageSwap(page)) { if (page_ref_dec(page) == 0) { free_page(page); } } else { if (ptep_dirty(ptep)) { SetPageDirty(page); } page_ref_dec(page); } #else if (page_ref_dec(page) == 0) { free_page(page); } #endif /* UCONFIG_SWAP */ ptep_unmap(ptep); } else if (!ptep_invalid(ptep)) { #ifdef UCONFIG_SWAP swap_remove_entry(*ptep); ptep_unmap(ptep); #else assert(0); #endif } }
/** * page_remove_pte - free an Page sturct which is related linear address la * - and clean(invalidate) pte which is related linear address la * @param pgdir page directory (not used) * @param la logical address of the page to be removed * @param page table entry of the page to be removed * note: PT is changed, so the TLB need to be invalidate */ void page_remove_pte(pgd_t *pgdir, uintptr_t la, pte_t *ptep) { if (ptep_present(ptep)) { struct Page *page = pte2page(*ptep); if (!PageSwap(page)) { if (page_ref_dec(page) == 0) { //Don't free dma pages if (!PageIO(page)) free_page(page); } } else { if (ptep_dirty(ptep)) { SetPageDirty(page); } page_ref_dec(page); } ptep_unmap(ptep); mp_tlb_invalidate(pgdir, la); } else if (! ptep_invalid(ptep)) { #ifndef CONFIG_NO_SWAP swap_remove_entry(*ptep); #endif ptep_unmap(ptep); } }
static inline void shmem_remove_entry_pte(pte_t *ptep) { assert(ptep != NULL); if (ptep_present(ptep)) { struct Page *page = pte2page(*ptep); if (!PageSwap(page)) { if (page_ref_dec(page) == 0) { free_page(page); } } else { if (ptep_dirty(ptep)) { SetPageDirty(page); } page_ref_dec(page); } ptep_unmap(ptep); } else if (! ptep_invalid(ptep)) { swap_remove_entry(*ptep); ptep_unmap(ptep); } }