/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* uvm_anfree: free a single anon structure
*
* => anon must be removed from the amap (if anon was in an amap).
* => amap must be locked, if anon was owned by amap.
* => we may drop and re-acquire the lock here (to break loans).
*/
void
uvm_anfree(struct vm_anon *anon)
{
struct vm_page *pg = anon->an_page, *pg2 __diagused;
if (__predict_true(pg != NULL)) {
KASSERT(anon->an_lock != NULL);
/*
* If there is a resident page and it is loaned, then anon
* may not own it. Call out to uvm_anon_lockloanpg() to
* identify and lock the real owner of the page.
*/
/*
* uvm_anon_lockloanpg: given a locked anon, lock its resident page owner.
*
* => anon is locked by caller
* => on return: anon is locked
* if there is a resident page:
* if it has a uobject, it is locked by us
* if it is ownerless, we take over as owner
* we return the resident page (it can change during
* this function)
* => note that the only time an anon has an ownerless resident page
* is if the page was loaned from a uvm_object and the uvm_object
* disowned it
* => this only needs to be called when you want to do an operation
* on an anon's resident page and that page has a non-zero loan
* count.
*/
struct vm_page *
uvm_anon_lockloanpg(struct vm_anon *anon)
{
struct vm_page *pg;
krw_t op;
KASSERT(rw_lock_held(anon->an_lock));
/*
* loop while we have a resident page that has a non-zero loan count.
* if we successfully get our lock, we will "break" the loop.
* note that the test for pg->loan_count is not protected -- this
* may produce false positive results. note that a false positive
* result may cause us to do more work than we need to, but it will
* not produce an incorrect result.
*/
while (((pg = anon->an_page) != NULL) && pg->loan_count != 0) {
mutex_enter(&pg->interlock);
if (pg->uobject) {
/*
* if we didn't get a lock (try lock failed), then we
* toggle our anon lock and try again
*/
if (!rw_tryenter(pg->uobject->vmobjlock, RW_WRITER)) {
/*
* someone locking the object has a chance to
* lock us right now
*
* XXX Better than yielding but inadequate.
*/
mutex_exit(&pg->interlock);
op = rw_lock_op(anon->an_lock);
rw_exit(anon->an_lock);
kpause("lkloanpg", false, 1, NULL);
rw_enter(anon->an_lock, op);
continue;
}
}
/*
* If page is un-owned i.e. the object dropped its ownership,
* then we have to take the ownership.
*/
/*
* uvm_anon_pagein: fetch an anon's page.
*
* => anon must be locked, and is unlocked upon return.
* => returns true if pagein was aborted due to lack of memory.
*/
switch (uvmfault_anonget(NULL, amap, anon)) {
case 0:
/* Success - we have the page. */
KASSERT(rw_write_held(anon->an_lock));
break;
case EIO:
case ERESTART:
/*
* Nothing more to do on errors. ERESTART means that the
* anon was freed.
*/
return false;
case ENOLCK:
panic("uvm_anon_pagein");
default:
return true;
}
/*
* Mark the page as dirty and clear its swslot.
*/
/*
* uvm_anon_dropswap: release any swap resources from this anon.
*
* => anon must be locked or have a reference count of 0.
*/
void
uvm_anon_dropswap(struct vm_anon *anon)
{
UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist);
if (anon->an_swslot == 0)
return;
UVMHIST_LOG(maphist,"freeing swap for anon %#jx, paged to swslot %#jx",
(uintptr_t)anon, anon->an_swslot, 0, 0);
uvm_swap_free(anon->an_swslot, 1);
anon->an_swslot = 0;
}
#endif
/*
* uvm_anon_release: release an anon and its page.
*
* => anon should not have any references.
* => anon must be locked.
*/