From aab58d8730c95bb3f82ec4060a4c3476d421024b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 20 Aug 2008 11:44:23 +0000 Subject: [PATCH] Implemented (a simple) WriteAsync(), i.e. swap pages are now written asynchronously, too. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27077 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/vm/VMAnonymousCache.cpp | 100 ++++++++++++++++++++++ src/system/kernel/vm/VMAnonymousCache.h | 6 ++ 2 files changed, 106 insertions(+) diff --git a/src/system/kernel/vm/VMAnonymousCache.cpp b/src/system/kernel/vm/VMAnonymousCache.cpp index 2b2af2de18..9521314ed9 100644 --- a/src/system/kernel/vm/VMAnonymousCache.cpp +++ b/src/system/kernel/vm/VMAnonymousCache.cpp @@ -33,6 +33,8 @@ #include #include +#include "io_requests.h" + #if ENABLE_SWAP_SUPPORT @@ -315,6 +317,51 @@ swap_space_unreserve(off_t amount) // #pragma mark - +class VMAnonymousCache::WriteCallback : public StackableAsyncIOCallback { +public: + WriteCallback(VMAnonymousCache* cache, AsyncIOCallback* callback) + : + StackableAsyncIOCallback(callback), + fCache(cache) + { + } + + void SetTo(page_num_t pageIndex, swap_addr_t slotIndex, bool newSlot) + { + fPageIndex = pageIndex; + fSlotIndex = slotIndex; + fNewSlot = newSlot; + } + + virtual void IOFinished(status_t status, bool partialTransfer, + size_t bytesTransferred) + { + if (fNewSlot) { + if (status == B_OK) { + fCache->_SwapBlockBuild(fPageIndex, fSlotIndex, 1); + } else { + AutoLocker locker(fCache); + fCache->fAllocatedSwapSize -= B_PAGE_SIZE; + locker.Unlock(); + + swap_slot_dealloc(fSlotIndex, 1); + } + } + + fNextCallback->IOFinished(status, partialTransfer, bytesTransferred); + } + +private: + VMAnonymousCache* fCache; + page_num_t fPageIndex; + swap_addr_t fSlotIndex; + bool fNewSlot; +}; + + +// #pragma mark - + + VMAnonymousCache::~VMAnonymousCache() { // free allocated swap space and swap block @@ -467,6 +514,59 @@ VMAnonymousCache::Write(off_t offset, const iovec *vecs, size_t count, } +status_t +VMAnonymousCache::WriteAsync(off_t offset, const iovec* vecs, size_t count, + size_t numBytes, uint32 flags, AsyncIOCallback* _callback) +{ + // TODO: Currently this method is only used for single pages. Either make + // more flexible use of it or change the interface! + // This implementation relies on the current usage! + ASSERT(count == 1); + ASSERT(numBytes <= B_PAGE_SIZE); + + page_num_t pageIndex = offset >> PAGE_SHIFT; + swap_addr_t slotIndex = _SwapBlockGetAddress(pageIndex); + bool newSlot = slotIndex == SWAP_SLOT_NONE; + + // If the page doesn't have any swap space yet, allocate it. + if (newSlot) { + AutoLocker locker(this); + if (fAllocatedSwapSize + B_PAGE_SIZE > fCommittedSwapSize) + return B_ERROR; + + fAllocatedSwapSize += B_PAGE_SIZE; + + slotIndex = swap_slot_alloc(1); + } + + // create our callback + WriteCallback* callback = (flags & B_VIP_IO_REQUEST != 0) + ? new(vip_io_alloc) WriteCallback(this, _callback) + : new(std::nothrow) WriteCallback(this, _callback); + if (callback == NULL) { + if (newSlot) { + AutoLocker locker(this); + fAllocatedSwapSize -= B_PAGE_SIZE; + locker.Unlock(); + + swap_slot_dealloc(slotIndex, 1); + } + return B_NO_MEMORY; + } +// TODO: If the page already had swap space assigned, we don't need an own +// callback. + + callback->SetTo(pageIndex, slotIndex, newSlot); + + // write the page asynchrounously + swap_file* swapFile = find_swap_file(slotIndex); + off_t pos = (slotIndex - swapFile->first_slot) * B_PAGE_SIZE; + + return vfs_asynchronous_write_pages(swapFile->vnode, NULL, pos, vecs, 1, + numBytes, flags, callback); +} + + status_t VMAnonymousCache::Fault(struct vm_address_space *aspace, off_t offset) { diff --git a/src/system/kernel/vm/VMAnonymousCache.h b/src/system/kernel/vm/VMAnonymousCache.h index 4ce820a7d2..ef92ea446c 100644 --- a/src/system/kernel/vm/VMAnonymousCache.h +++ b/src/system/kernel/vm/VMAnonymousCache.h @@ -40,12 +40,18 @@ public: size_t *_numBytes); virtual status_t Write(off_t offset, const iovec *vecs, size_t count, uint32 flags, size_t *_numBytes); + virtual status_t WriteAsync(off_t offset, const iovec* vecs, + size_t count, size_t numBytes, uint32 flags, + AsyncIOCallback* callback); virtual status_t Fault(struct vm_address_space *aspace, off_t offset); virtual void MergeStore(VMCache* source); private: + class WriteCallback; + friend class WriteCallback; + void _SwapBlockBuild(off_t pageIndex, swap_addr_t slotIndex, uint32 count); void _SwapBlockFree(off_t pageIndex, uint32 count);