/* * lpage_evict: Evict an lpage from physical memory. * * Synchronization: lock the lpage while evicting it. We come here * from the coremap and should * have pinned the physical page. This is why we must not hold lpage * locks while entering the coremap code. */ void lpage_evict(struct lpage *lp) { KASSERT(lp != NULL); lpage_lock(lp); KASSERT(lp->lp_paddr != INVALID_PADDR); KASSERT(lp->lp_swapaddr != INVALID_SWAPADDR); /* if the page is dirty, swap_pageout */ if (LP_ISDIRTY(lp)) { lpage_unlock(lp); // release lock before doing I/O KASSERT(lock_do_i_hold(global_paging_lock)); KASSERT(coremap_pageispinned(lp->lp_paddr)); swap_pageout((lp->lp_paddr & PAGE_FRAME), lp->lp_swapaddr); lpage_lock(lp); KASSERT((lp->lp_paddr & PAGE_FRAME) != INVALID_PADDR); /* update stats */ spinlock_acquire(&stats_spinlock); ct_write_evictions++; DEBUG (DB_VM, "lpage_evict: evicting Dirty page 0x%x\n", (lp->lp_paddr & PAGE_FRAME)); spinlock_release(&stats_spinlock); } else { /* if page is clean, just update stats */ spinlock_acquire(&stats_spinlock); ct_discard_evictions++; DEBUG (DB_VM, "lpage_evict: evicting Clean page 0x%x\n", (lp->lp_paddr & PAGE_FRAME)); spinlock_release(&stats_spinlock); } /* modify PTE to indicate that the page is no longer in memory. */ lp->lp_paddr = INVALID_PADDR; lpage_unlock(lp); }
/* * lpage_evict: Evict an lpage from physical memory. * * Synchronization: lock the lpage while accessing it. We come here * from the coremap and should have the global paging lock and should * have pinned the physical page (see coremap.c:do_evict()). * This is why we must not hold lpage locks while entering the coremap code. * * Similar to lpage_fault, the lpage lock should not be held while performing * the page out (if one is needed). */ void lpage_evict(struct lpage *lp) { paddr_t pa; off_t swapaddr; KASSERT(lock_do_i_hold(global_paging_lock)); KASSERT(lp != NULL); lpage_lock(lp); swapaddr = lp->lp_swapaddr; pa = lp->lp_paddr & PAGE_FRAME; KASSERT(pa != INVALID_PADDR); if (LP_ISDIRTY(lp)) { lpage_unlock(lp); LP_CLEAR(lp, LPF_DIRTY); swap_pageout(pa, swapaddr); lpage_lock(lp); } lp->lp_paddr = INVALID_PADDR; lpage_unlock(lp); }
/* * lpage_evict: Evict an lpage from physical memory. * * Synchronization: lock the lpage while accessing it. We come here * from the coremap and should have the global paging lock and should * have pinned the physical page (see coremap.c:do_evict()). * This is why we must not hold lpage locks while entering the coremap code. * * Similar to lpage_fault, the lpage lock should not be held while performing * the page out (if one is needed). */ void lpage_evict(struct lpage *lp) { paddr_t physical_address; off_t swap_address; // Lock the lpage while accessing it. KASSERT(lp != NULL); lpage_lock(lp); // Obtain the physical & swap address' physical_address = lp->lp_paddr & PAGE_FRAME; swap_address = lp->lp_swapaddr; // If the page is stored in RAM memory... if (physical_address != INVALID_PADDR) { DEBUG(DB_VM, "lpage_evict: Moving page from paddr 0x%x to swapaddr 0x%llx\n", physical_address, swap_address); // If page is dirty.. if (LP_ISDIRTY(lp)) { // Move page into swapspace. lpage_unlock(lp); swap_pageout(physical_address, swap_address); LP_CLEAR(lp, LPF_DIRTY); lpage_lock(lp); } // Remove page from physical memory. lp->lp_paddr = INVALID_PADDR; lpage_unlock(lp); } else { lpage_unlock(lp); } }
/* * lpage_copy: create a new lpage and copy data from another lpage. * * The synchronization for this is kind of unpleasant. We do it like * this: * * 1. Create newlp. * 2. Materialize a page for newlp, so it's locked and pinned. * 3. Lock and pin oldlp. * 4. Extract the physical address and swap address. * 5. If oldlp wasn't present, * 5a. Unlock oldlp. * 5b. Page in. * 5c. This pins the page in the coremap. * 5d. Leave the page pinned and relock oldlp. * 5e. Assert nobody else paged the page in. * 6. Copy. * 7. Unlock the lpages first, so we can enter the coremap. * 8. Unpin the physical pages. * */ int lpage_copy(struct lpage *oldlp, struct lpage **lpret) { struct lpage *newlp; paddr_t newpa, oldpa; off_t swa; int result; result = lpage_materialize(&newlp, &newpa); if (result) { return result; } KASSERT(coremap_pageispinned(newpa)); /* Pin the physical page and lock the lpage. */ lpage_lock_and_pin(oldlp); oldpa = oldlp->lp_paddr & PAGE_FRAME; /* * If there is no physical page, we allocate one, which pins * it, and then (re)lock the lpage. Since we are single- * threaded (if we weren't, we'd hold the address space lock * to exclude sibling threads) nobody else should have paged * the page in behind our back. */ if (oldpa == INVALID_PADDR) { /* * XXX this is mostly copied from lpage_fault */ swa = oldlp->lp_swapaddr; lpage_unlock(oldlp); oldpa = coremap_allocuser(oldlp); if (oldpa == INVALID_PADDR) { coremap_unpin(newlp->lp_paddr & PAGE_FRAME); lpage_destroy(newlp); return ENOMEM; } KASSERT(coremap_pageispinned(oldpa)); lock_acquire(global_paging_lock); swap_pagein(oldpa, swa); lpage_lock(oldlp); lock_release(global_paging_lock); /* Assert nobody else did the pagein. */ KASSERT((oldlp->lp_paddr & PAGE_FRAME) == INVALID_PADDR); oldlp->lp_paddr = oldpa; } KASSERT(coremap_pageispinned(oldpa)); coremap_copy_page(oldpa, newpa); KASSERT(LP_ISDIRTY(newlp)); lpage_unlock(oldlp); lpage_unlock(newlp); coremap_unpin(newpa); coremap_unpin(oldpa); *lpret = newlp; return 0; }