void buf_free_pages(struct buf *bp) { struct uvm_object *uobj = bp->b_pobj; struct vm_page *pg; voff_t off, i; int s; KASSERT(bp->b_data == NULL); KASSERT(uobj != NULL); s = splbio(); off = bp->b_poffs; bp->b_pobj = NULL; bp->b_poffs = 0; mtx_enter(&uobj->vmobjlock); for (i = 0; i < atop(bp->b_bufsize); i++) { pg = uvm_pagelookup(uobj, off + ptoa(i)); KASSERT(pg != NULL); KASSERT(pg->wire_count == 1); pg->wire_count = 0; /* Never on a pageq, no pageqlock needed. */ uvm_pagefree(pg); bcstats.numbufpages--; } mtx_leave(&uobj->vmobjlock); splx(s); }
/* * Return true if we freed it, false if we didn't. */ bool cpu_uarea_free(void *va) { #ifdef _LP64 if (!MIPS_XKPHYS_P(va)) return false; paddr_t pa = MIPS_XKPHYS_TO_PHYS(va); #else if (!MIPS_KSEG0_P(va)) return false; paddr_t pa = MIPS_KSEG0_TO_PHYS(va); #endif #ifdef MIPS3_PLUS if (MIPS_CACHE_VIRTUAL_ALIAS) mips_dcache_inv_range((vaddr_t)va, USPACE); #endif for (const paddr_t epa = pa + USPACE; pa < epa; pa += PAGE_SIZE) { struct vm_page * const pg = PHYS_TO_VM_PAGE(pa); KASSERT(pg != NULL); uvm_pagefree(pg); } return true; }
/* * uvm_km_pgremove: remove pages from a kernel uvm_object. * * => when you unmap a part of anonymous kernel memory you want to toss * the pages right away. (this gets called from uvm_unmap_...). */ void uvm_km_pgremove(struct uvm_object *uobj, vaddr_t start, vaddr_t end) { struct vm_page *pp; voff_t curoff; UVMHIST_FUNC("uvm_km_pgremove"); UVMHIST_CALLED(maphist); KASSERT(uobj->pgops == &aobj_pager); for (curoff = start ; curoff < end ; curoff += PAGE_SIZE) { pp = uvm_pagelookup(uobj, curoff); if (pp == NULL) continue; UVMHIST_LOG(maphist," page %p, busy=%ld", pp, pp->pg_flags & PG_BUSY, 0, 0); if (pp->pg_flags & PG_BUSY) { /* owner must check for this when done */ atomic_setbits_int(&pp->pg_flags, PG_RELEASED); } else { /* free the swap slot... */ uao_dropswap(uobj, curoff >> PAGE_SHIFT); /* * ...and free the page; note it may be on the * active or inactive queues. */ uvm_lock_pageq(); uvm_pagefree(pp); uvm_unlock_pageq(); } } }
void buf_free_pages(struct buf *bp) { struct uvm_object *uobj = bp->b_pobj; struct vm_page *pg; voff_t off, i; int s; KASSERT(bp->b_data == NULL); KASSERT(uobj != NULL); s = splbio(); off = bp->b_poffs; bp->b_pobj = NULL; bp->b_poffs = 0; for (i = 0; i < atop(bp->b_bufsize); i++) { pg = uvm_pagelookup(uobj, off + ptoa(i)); KASSERT(pg != NULL); KASSERT(pg->wire_count == 1); pg->wire_count = 0; uvm_pagefree(pg); bcstats.numbufpages--; } splx(s); }
void uvm_km_pgremove_intrsafe(vaddr_t start, vaddr_t end) { struct vm_page *pg; vaddr_t va; paddr_t pa; for (va = start; va < end; va += PAGE_SIZE) { if (!pmap_extract(pmap_kernel(), va, &pa)) continue; pg = PHYS_TO_VM_PAGE(pa); if (pg == NULL) panic("uvm_km_pgremove_intrsafe: no page"); uvm_pagefree(pg); } }
static int ao_put(struct uvm_object *uobj, voff_t start, voff_t stop, int flags) { struct vm_page *pg; /* we only free all pages for now */ if ((flags & PGO_FREE) == 0 || (flags & PGO_ALLPAGES) == 0) { mutex_exit(&uobj->vmobjlock); return 0; } while ((pg = TAILQ_FIRST(&uobj->memq)) != NULL) uvm_pagefree(pg); mutex_exit(&uobj->vmobjlock); return 0; }
/* * Return true if we freed it, false if we didn't. */ bool cpu_uarea_free(void *vva) { vaddr_t va = (vaddr_t) vva; if (va >= VM_MIN_KERNEL_ADDRESS && va < VM_MAX_KERNEL_ADDRESS) return false; /* * Since the pages are physically contiguous, the vm_page structure * will be as well. */ struct vm_page *pg = PHYS_TO_VM_PAGE(PMAP_UNMAP_POOLPAGE(va)); KASSERT(pg != NULL); for (size_t i = 0; i < UPAGES; i++, pg++) { uvm_pagefree(pg); } return true; }
/* ARGSUSED */ vaddr_t uvm_km_alloc_poolpage1(struct vm_map *map, struct uvm_object *obj, boolean_t waitok) { #if defined(__HAVE_PMAP_DIRECT) struct vm_page *pg; vaddr_t va; again: pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE); if (__predict_false(pg == NULL)) { if (waitok) { uvm_wait("plpg"); goto again; } else return (0); } va = pmap_map_direct(pg); if (__predict_false(va == 0)) uvm_pagefree(pg); return (va); #else vaddr_t va; int s; /* * NOTE: We may be called with a map that doesn't require splvm * protection (e.g. kernel_map). However, it does not hurt to * go to splvm in this case (since unprotected maps will never be * accessed in interrupt context). * * XXX We may want to consider changing the interface to this * XXX function. */ s = splvm(); va = uvm_km_kmemalloc(map, obj, PAGE_SIZE, waitok ? 0 : UVM_KMF_NOWAIT); splx(s); return (va); #endif /* __HAVE_PMAP_DIRECT */ }
/* ARGSUSED */ void uvm_km_free_poolpage1(struct vm_map *map, vaddr_t addr) { #if defined(__HAVE_PMAP_DIRECT) uvm_pagefree(pmap_unmap_direct(addr)); #else int s; /* * NOTE: We may be called with a map that doesn't require splvm * protection (e.g. kernel_map). However, it does not hurt to * go to splvm in this case (since unprocted maps will never be * accessed in interrupt context). * * XXX We may want to consider changing the interface to this * XXX function. */ s = splvm(); uvm_km_free(map, addr, PAGE_SIZE); splx(s); #endif /* __HAVE_PMAP_DIRECT */ }
static void uvm_unloanpage(struct vm_page **ploans, int npages) { struct vm_page *pg; kmutex_t *slock; mutex_enter(&uvm_pageqlock); while (npages-- > 0) { pg = *ploans++; /* * do a little dance to acquire the object or anon lock * as appropriate. we are locking in the wrong order, * so we have to do a try-lock here. */ slock = NULL; while (pg->uobject != NULL || pg->uanon != NULL) { if (pg->uobject != NULL) { slock = &pg->uobject->vmobjlock; } else { slock = &pg->uanon->an_lock; } if (mutex_tryenter(slock)) { break; } mutex_exit(&uvm_pageqlock); /* XXX Better than yielding but inadequate. */ kpause("livelock", false, 1, NULL); mutex_enter(&uvm_pageqlock); slock = NULL; } /* * drop our loan. if page is owned by an anon but * PQ_ANON is not set, the page was loaned to the anon * from an object which dropped ownership, so resolve * this by turning the anon's loan into real ownership * (ie. decrement loan_count again and set PQ_ANON). * after all this, if there are no loans left, put the * page back a paging queue (if the page is owned by * an anon) or free it (if the page is now unowned). */ KASSERT(pg->loan_count > 0); pg->loan_count--; if (pg->uobject == NULL && pg->uanon != NULL && (pg->pqflags & PQ_ANON) == 0) { KASSERT(pg->loan_count > 0); pg->loan_count--; pg->pqflags |= PQ_ANON; } if (pg->loan_count == 0 && pg->uobject == NULL && pg->uanon == NULL) { KASSERT((pg->flags & PG_BUSY) == 0); uvm_pagefree(pg); } if (slock != NULL) { mutex_exit(slock); } } mutex_exit(&uvm_pageqlock); }
static int uvm_loanuobj(struct uvm_faultinfo *ufi, void ***output, int flags, vaddr_t va) { struct vm_amap *amap = ufi->entry->aref.ar_amap; struct uvm_object *uobj = ufi->entry->object.uvm_obj; struct vm_page *pg; struct vm_anon *anon; int error, npages; bool locked; UVMHIST_FUNC(__func__); UVMHIST_CALLED(loanhist); /* * first we must make sure the page is resident. * * XXXCDC: duplicate code with uvm_fault(). */ mutex_enter(&uobj->vmobjlock); if (uobj->pgops->pgo_get) { /* try locked pgo_get */ npages = 1; pg = NULL; error = (*uobj->pgops->pgo_get)(uobj, va - ufi->entry->start + ufi->entry->offset, &pg, &npages, 0, VM_PROT_READ, MADV_NORMAL, PGO_LOCKED); } else { error = EIO; /* must have pgo_get op */ } /* * check the result of the locked pgo_get. if there is a problem, * then we fail the loan. */ if (error && error != EBUSY) { uvmfault_unlockall(ufi, amap, uobj, NULL); return (-1); } /* * if we need to unlock for I/O, do so now. */ if (error == EBUSY) { uvmfault_unlockall(ufi, amap, NULL, NULL); /* locked: uobj */ npages = 1; error = (*uobj->pgops->pgo_get)(uobj, va - ufi->entry->start + ufi->entry->offset, &pg, &npages, 0, VM_PROT_READ, MADV_NORMAL, PGO_SYNCIO); /* locked: <nothing> */ if (error) { if (error == EAGAIN) { tsleep(&lbolt, PVM, "fltagain2", 0); return (0); } return (-1); } /* * pgo_get was a success. attempt to relock everything. */ locked = uvmfault_relock(ufi); if (locked && amap) amap_lock(amap); uobj = pg->uobject; mutex_enter(&uobj->vmobjlock); /* * verify that the page has not be released and re-verify * that amap slot is still free. if there is a problem we * drop our lock (thus force a lookup refresh/retry). */ if ((pg->flags & PG_RELEASED) != 0 || (locked && amap && amap_lookup(&ufi->entry->aref, ufi->orig_rvaddr - ufi->entry->start))) { if (locked) uvmfault_unlockall(ufi, amap, NULL, NULL); locked = false; } /* * didn't get the lock? release the page and retry. */ if (locked == false) { if (pg->flags & PG_WANTED) { wakeup(pg); } if (pg->flags & PG_RELEASED) { mutex_enter(&uvm_pageqlock); uvm_pagefree(pg); mutex_exit(&uvm_pageqlock); mutex_exit(&uobj->vmobjlock); return (0); } mutex_enter(&uvm_pageqlock); uvm_pageactivate(pg); mutex_exit(&uvm_pageqlock); pg->flags &= ~(PG_BUSY|PG_WANTED); UVM_PAGE_OWN(pg, NULL); mutex_exit(&uobj->vmobjlock); return (0); } } KASSERT(uobj == pg->uobject); /* * at this point we have the page we want ("pg") marked PG_BUSY for us * and we have all data structures locked. do the loanout. page can * not be PG_RELEASED (we caught this above). */ if ((flags & UVM_LOAN_TOANON) == 0) { if (uvm_loanpage(&pg, 1)) { uvmfault_unlockall(ufi, amap, uobj, NULL); return (-1); } mutex_exit(&uobj->vmobjlock); **output = pg; (*output)++; return (1); } /* * must be a loan to an anon. check to see if there is already * an anon associated with this page. if so, then just return * a reference to this object. the page should already be * mapped read-only because it is already on loan. */ if (pg->uanon) { anon = pg->uanon; mutex_enter(&anon->an_lock); anon->an_ref++; mutex_exit(&anon->an_lock); if (pg->flags & PG_WANTED) { wakeup(pg); } pg->flags &= ~(PG_WANTED|PG_BUSY); UVM_PAGE_OWN(pg, NULL); mutex_exit(&uobj->vmobjlock); **output = anon; (*output)++; return (1); } /* * need to allocate a new anon */ anon = uvm_analloc(); if (anon == NULL) { goto fail; } anon->an_page = pg; pg->uanon = anon; mutex_enter(&uvm_pageqlock); if (pg->wire_count > 0) { mutex_exit(&uvm_pageqlock); UVMHIST_LOG(loanhist, "wired %p", pg,0,0,0); pg->uanon = NULL; anon->an_page = NULL; anon->an_ref--; mutex_exit(&anon->an_lock); uvm_anfree(anon); goto fail; } if (pg->loan_count == 0) { pmap_page_protect(pg, VM_PROT_READ); } pg->loan_count++; uvm_pageactivate(pg); mutex_exit(&uvm_pageqlock); if (pg->flags & PG_WANTED) { wakeup(pg); } pg->flags &= ~(PG_WANTED|PG_BUSY); UVM_PAGE_OWN(pg, NULL); mutex_exit(&uobj->vmobjlock); mutex_exit(&anon->an_lock); **output = anon; (*output)++; return (1); fail: UVMHIST_LOG(loanhist, "fail", 0,0,0,0); /* * unlock everything and bail out. */ if (pg->flags & PG_WANTED) { wakeup(pg); } pg->flags &= ~(PG_WANTED|PG_BUSY); UVM_PAGE_OWN(pg, NULL); uvmfault_unlockall(ufi, amap, uobj, NULL); return (-1); }
int uvmfault_anonget(struct uvm_faultinfo *ufi, struct vm_amap *amap, struct vm_anon *anon) { boolean_t we_own; /* we own anon's page? */ boolean_t locked; /* did we relock? */ struct vm_page *pg; int result; result = 0; /* XXX shut up gcc */ uvmexp.fltanget++; /* bump rusage counters */ if (anon->an_page) curproc->p_ru.ru_minflt++; else curproc->p_ru.ru_majflt++; /* * loop until we get it, or fail. */ while (1) { we_own = FALSE; /* TRUE if we set PG_BUSY on a page */ pg = anon->an_page; /* * if there is a resident page and it is loaned, then anon * may not own it. call out to uvm_anon_lockpage() to ensure * the real owner of the page has been identified and locked. */ if (pg && pg->loan_count) pg = uvm_anon_lockloanpg(anon); /* * page there? make sure it is not busy/released. */ if (pg) { /* * at this point, if the page has a uobject [meaning * we have it on loan], then that uobject is locked * by us! if the page is busy, we drop all the * locks (including uobject) and try again. */ if ((pg->pg_flags & (PG_BUSY|PG_RELEASED)) == 0) { return (VM_PAGER_OK); } atomic_setbits_int(&pg->pg_flags, PG_WANTED); uvmexp.fltpgwait++; /* * the last unlock must be an atomic unlock+wait on * the owner of page */ if (pg->uobject) { /* owner is uobject ? */ uvmfault_unlockall(ufi, amap, NULL, anon); UVM_UNLOCK_AND_WAIT(pg, &pg->uobject->vmobjlock, FALSE, "anonget1",0); } else { /* anon owns page */ uvmfault_unlockall(ufi, amap, NULL, NULL); UVM_UNLOCK_AND_WAIT(pg,&anon->an_lock,0, "anonget2",0); } /* ready to relock and try again */ } else { /* * no page, we must try and bring it in. */ pg = uvm_pagealloc(NULL, 0, anon, 0); if (pg == NULL) { /* out of RAM. */ uvmfault_unlockall(ufi, amap, NULL, anon); uvmexp.fltnoram++; uvm_wait("flt_noram1"); /* ready to relock and try again */ } else { /* we set the PG_BUSY bit */ we_own = TRUE; uvmfault_unlockall(ufi, amap, NULL, anon); /* * we are passing a PG_BUSY+PG_FAKE+PG_CLEAN * page into the uvm_swap_get function with * all data structures unlocked. note that * it is ok to read an_swslot here because * we hold PG_BUSY on the page. */ uvmexp.pageins++; result = uvm_swap_get(pg, anon->an_swslot, PGO_SYNCIO); /* * we clean up after the i/o below in the * "we_own" case */ /* ready to relock and try again */ } } /* * now relock and try again */ locked = uvmfault_relock(ufi); if (locked || we_own) simple_lock(&anon->an_lock); /* * if we own the page (i.e. we set PG_BUSY), then we need * to clean up after the I/O. there are three cases to * consider: * [1] page released during I/O: free anon and ReFault. * [2] I/O not OK. free the page and cause the fault * to fail. * [3] I/O OK! activate the page and sync with the * non-we_own case (i.e. drop anon lock if not locked). */ if (we_own) { if (pg->pg_flags & PG_WANTED) { /* still holding object lock */ wakeup(pg); } /* un-busy! */ atomic_clearbits_int(&pg->pg_flags, PG_WANTED|PG_BUSY|PG_FAKE); UVM_PAGE_OWN(pg, NULL); /* * if we were RELEASED during I/O, then our anon is * no longer part of an amap. we need to free the * anon and try again. */ if (pg->pg_flags & PG_RELEASED) { pmap_page_protect(pg, VM_PROT_NONE); simple_unlock(&anon->an_lock); uvm_anfree(anon); /* frees page for us */ if (locked) uvmfault_unlockall(ufi, amap, NULL, NULL); uvmexp.fltpgrele++; return (VM_PAGER_REFAULT); /* refault! */ } if (result != VM_PAGER_OK) { KASSERT(result != VM_PAGER_PEND); /* remove page from anon */ anon->an_page = NULL; /* * remove the swap slot from the anon * and mark the anon as having no real slot. * don't free the swap slot, thus preventing * it from being used again. */ uvm_swap_markbad(anon->an_swslot, 1); anon->an_swslot = SWSLOT_BAD; /* * note: page was never !PG_BUSY, so it * can't be mapped and thus no need to * pmap_page_protect it... */ uvm_lock_pageq(); uvm_pagefree(pg); uvm_unlock_pageq(); if (locked) uvmfault_unlockall(ufi, amap, NULL, anon); else simple_unlock(&anon->an_lock); return (VM_PAGER_ERROR); } /* * must be OK, clear modify (already PG_CLEAN) * and activate */ pmap_clear_modify(pg); uvm_lock_pageq(); uvm_pageactivate(pg); uvm_unlock_pageq(); if (!locked) simple_unlock(&anon->an_lock); } /* * we were not able to relock. restart fault. */ if (!locked) return (VM_PAGER_REFAULT); /* * verify no one has touched the amap and moved the anon on us. */ if (ufi != NULL && amap_lookup(&ufi->entry->aref, ufi->orig_rvaddr - ufi->entry->start) != anon) { uvmfault_unlockall(ufi, amap, NULL, anon); return (VM_PAGER_REFAULT); } /* * try it again! */ uvmexp.fltanretry++; continue; } /* while (1) */ /*NOTREACHED*/ }
/* * This is a slightly strangely structured routine. It always puts * all the pages for a vnode. It starts by releasing pages which * are clean and simultaneously looks up the smallest offset for a * dirty page beloning to the object. If there is no smallest offset, * all pages have been cleaned. Otherwise, it finds a contiguous range * of dirty pages starting from the smallest offset and writes them out. * After this the scan is restarted. */ int genfs_do_putpages(struct vnode *vp, off_t startoff, off_t endoff, int flags, struct vm_page **busypg) { char databuf[MAXPHYS]; struct uvm_object *uobj = &vp->v_uobj; struct vm_page *pg, *pg_next; voff_t smallest; voff_t curoff, bufoff; off_t eof; size_t xfersize; int bshift = vp->v_mount->mnt_fs_bshift; int bsize = 1 << bshift; #if 0 int async = (flags & PGO_SYNCIO) == 0; #else int async = 0; #endif restart: /* check if all pages are clean */ smallest = -1; for (pg = TAILQ_FIRST(&uobj->memq); pg; pg = pg_next) { pg_next = TAILQ_NEXT(pg, listq.queue); /* * XXX: this is not correct at all. But it's based on * assumptions we can make when accessing the pages * only through the file system and not through the * virtual memory subsystem. Well, at least I hope * so ;) */ KASSERT((pg->flags & PG_BUSY) == 0); /* If we can just dump the page, do so */ if (pg->flags & PG_CLEAN || flags & PGO_FREE) { uvm_pagefree(pg); continue; } if (pg->offset < smallest || smallest == -1) smallest = pg->offset; } /* all done? */ if (TAILQ_EMPTY(&uobj->memq)) { vp->v_iflag &= ~VI_ONWORKLST; mutex_exit(&uobj->vmobjlock); return 0; } /* we need to flush */ GOP_SIZE(vp, vp->v_writesize, &eof, 0); for (curoff = smallest; curoff < eof; curoff += PAGE_SIZE) { void *curva; if (curoff - smallest >= MAXPHYS) break; pg = uvm_pagelookup(uobj, curoff); if (pg == NULL) break; /* XXX: see comment about above KASSERT */ KASSERT((pg->flags & PG_BUSY) == 0); curva = databuf + (curoff-smallest); memcpy(curva, (void *)pg->uanon, PAGE_SIZE); rumpvm_enterva((vaddr_t)curva, pg); pg->flags |= PG_CLEAN; } KASSERT(curoff > smallest); mutex_exit(&uobj->vmobjlock); /* then we write */ for (bufoff = 0; bufoff < MIN(curoff-smallest,eof); bufoff+=xfersize) { struct buf *bp; struct vnode *devvp; daddr_t bn, lbn; int run, error; lbn = (smallest + bufoff) >> bshift; error = VOP_BMAP(vp, lbn, &devvp, &bn, &run); if (error) panic("%s: VOP_BMAP failed: %d", __func__, error); xfersize = MIN(((lbn+1+run) << bshift) - (smallest+bufoff), curoff - (smallest+bufoff)); /* * We might run across blocks which aren't allocated yet. * A reason might be e.g. the write operation being still * in the kernel page cache while truncate has already * enlarged the file. So just ignore those ranges. */ if (bn == -1) continue; bp = getiobuf(vp, true); /* only write max what we are allowed to write */ bp->b_bcount = xfersize; if (smallest + bufoff + xfersize > eof) bp->b_bcount -= (smallest+bufoff+xfersize) - eof; bp->b_bcount = (bp->b_bcount + DEV_BSIZE-1) & ~(DEV_BSIZE-1); KASSERT(bp->b_bcount > 0); KASSERT(smallest >= 0); DPRINTF(("putpages writing from %x to %x (vp size %x)\n", (int)(smallest + bufoff), (int)(smallest + bufoff + bp->b_bcount), (int)eof)); bp->b_bufsize = round_page(bp->b_bcount); bp->b_lblkno = 0; bp->b_blkno = bn + (((smallest+bufoff)&(bsize-1))>>DEV_BSHIFT); bp->b_data = databuf + bufoff; bp->b_flags = B_WRITE; bp->b_cflags |= BC_BUSY; if (async) { bp->b_flags |= B_ASYNC; bp->b_iodone = uvm_aio_biodone; } vp->v_numoutput++; VOP_STRATEGY(devvp, bp); if (bp->b_error) panic("%s: VOP_STRATEGY lazy bum %d", __func__, bp->b_error); if (!async) putiobuf(bp); } rumpvm_flushva(); mutex_enter(&uobj->vmobjlock); goto restart; }