kernel/vm: Add discard_address_range that discards pages.
Pages in the given range are unmapped and freed without getting written back anywhere. It can be used whenever a caller does not care about the data in the given range anymore and wants to reduce page pressure. Change-Id: I8bcce68fab278efef710d3714677e1d463504a56 Reviewed-on: https://review.haiku-os.org/c/haiku/+/2843 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
4bfc0072e3
commit
8e74e30784
@@ -135,6 +135,8 @@ public:
|
|||||||
virtual status_t Adopt(VMCache* source, off_t offset, off_t size,
|
virtual status_t Adopt(VMCache* source, off_t offset, off_t size,
|
||||||
off_t newOffset);
|
off_t newOffset);
|
||||||
|
|
||||||
|
virtual status_t Discard(off_t offset, off_t size);
|
||||||
|
|
||||||
status_t FlushAndRemoveAllPages();
|
status_t FlushAndRemoveAllPages();
|
||||||
|
|
||||||
void* UserData() { return fUserData; }
|
void* UserData() { return fUserData; }
|
||||||
|
|||||||
@@ -554,6 +554,14 @@ VMAnonymousCache::Rebase(off_t newBase, int priority)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
VMAnonymousCache::Discard(off_t offset, off_t size)
|
||||||
|
{
|
||||||
|
_FreeSwapPageRange(offset, offset + size);
|
||||||
|
return VMCache::Discard(offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Moves the swap pages for the given range from the source cache into this
|
/*! Moves the swap pages for the given range from the source cache into this
|
||||||
cache. Both caches must be locked.
|
cache. Both caches must be locked.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ public:
|
|||||||
virtual status_t Adopt(VMCache* source, off_t offset,
|
virtual status_t Adopt(VMCache* source, off_t offset,
|
||||||
off_t size, off_t newOffset);
|
off_t size, off_t newOffset);
|
||||||
|
|
||||||
|
virtual status_t Discard(off_t offset, off_t size);
|
||||||
|
|
||||||
virtual status_t Commit(off_t size, int priority);
|
virtual status_t Commit(off_t size, int priority);
|
||||||
virtual bool HasPage(off_t offset);
|
virtual bool HasPage(off_t offset);
|
||||||
virtual bool DebugHasPage(off_t offset);
|
virtual bool DebugHasPage(off_t offset);
|
||||||
|
|||||||
@@ -1254,6 +1254,19 @@ VMCache::Adopt(VMCache* source, off_t offset, off_t size, off_t newOffset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Discards pages in the given range. */
|
||||||
|
status_t
|
||||||
|
VMCache::Discard(off_t offset, off_t size)
|
||||||
|
{
|
||||||
|
page_num_t startPage = offset >> PAGE_SHIFT;
|
||||||
|
page_num_t endPage = (offset + size + B_PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||||
|
while (_FreePageRange(pages.GetIterator(startPage, true, true), &endPage))
|
||||||
|
;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! You have to call this function with the VMCache lock held. */
|
/*! You have to call this function with the VMCache lock held. */
|
||||||
status_t
|
status_t
|
||||||
VMCache::FlushAndRemoveAllPages()
|
VMCache::FlushAndRemoveAllPages()
|
||||||
|
|||||||
@@ -865,6 +865,52 @@ unmap_address_range(VMAddressSpace* addressSpace, addr_t address, addr_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
discard_area_range(VMArea* area, addr_t address, addr_t size)
|
||||||
|
{
|
||||||
|
addr_t offset;
|
||||||
|
if (!intersect_area(area, address, size, offset))
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
// If someone else uses the area's cache or it's not an anonymous cache, we
|
||||||
|
// can't discard.
|
||||||
|
VMCache* cache = vm_area_get_locked_cache(area);
|
||||||
|
if (cache->areas != area || area->cache_next != NULL
|
||||||
|
|| !cache->consumers.IsEmpty() || cache->type != CACHE_TYPE_RAM) {
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
VMCacheChainLocker cacheChainLocker(cache);
|
||||||
|
cacheChainLocker.LockAllSourceCaches();
|
||||||
|
|
||||||
|
unmap_pages(area, address, size);
|
||||||
|
|
||||||
|
// Since VMCache::Discard() can temporarily drop the lock, we must
|
||||||
|
// unlock all lower caches to prevent locking order inversion.
|
||||||
|
cacheChainLocker.Unlock(cache);
|
||||||
|
cache->Discard(cache->virtual_base + offset, size);
|
||||||
|
cache->ReleaseRefAndUnlock();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
discard_address_range(VMAddressSpace* addressSpace, addr_t address, addr_t size,
|
||||||
|
bool kernel)
|
||||||
|
{
|
||||||
|
for (VMAddressSpace::AreaRangeIterator it
|
||||||
|
= addressSpace->GetAreaRangeIterator(address, size);
|
||||||
|
VMArea* area = it.Next();) {
|
||||||
|
status_t error = discard_area_range(area, address, size);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! You need to hold the lock of the cache and the write lock of the address
|
/*! You need to hold the lock of the cache and the write lock of the address
|
||||||
space when calling this function.
|
space when calling this function.
|
||||||
Note, that in case of error your cache will be temporarily unlocked.
|
Note, that in case of error your cache will be temporarily unlocked.
|
||||||
|
|||||||
Reference in New Issue
Block a user