From a5dbd78b7af2bb7ca38be351331943ef4bc0089e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 5 May 2009 10:13:55 +0000 Subject: [PATCH] * Since PrecacheIO is used as asynchronous callback object, we must not access it anymore after having called vfs_asynchronous_read_pages(). * Now, Prepare() does all the preparation work, and ReadAsync() does the actual work - this must be called without having the cache locked. This also fixes another bug where the callback would be deleted twice in case the I/O request failed. * This fixes bug #3847. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30632 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/cache/file_cache.cpp | 43 +++++++++++++------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/system/kernel/cache/file_cache.cpp b/src/system/kernel/cache/file_cache.cpp index 3716c76b55..d7039c189c 100644 --- a/src/system/kernel/cache/file_cache.cpp +++ b/src/system/kernel/cache/file_cache.cpp @@ -75,8 +75,8 @@ public: size_t size); ~PrecacheIO(); - status_t Init(); - status_t Start(); + status_t Prepare(); + void ReadAsync(); virtual void IOFinished(status_t status, bool partialTransfer, @@ -90,6 +90,7 @@ private: ConditionVariable* fBusyConditions; iovec* fVecs; off_t fOffset; + uint32 fVecCount; size_t fSize; }; @@ -116,6 +117,7 @@ PrecacheIO::PrecacheIO(file_cache_ref* ref, off_t offset, size_t size) fBusyConditions(NULL), fVecs(NULL), fOffset(offset), + fVecCount(0), fSize(size) { fPageCount = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE; @@ -133,7 +135,7 @@ PrecacheIO::~PrecacheIO() status_t -PrecacheIO::Init() +PrecacheIO::Prepare() { if (fPageCount == 0) return B_BAD_VALUE; @@ -150,18 +152,7 @@ PrecacheIO::Init() if (fVecs == NULL) return B_NO_MEMORY; - return B_OK; -} - - -/*! Cache has to be locked when calling this method, but it will be temporarily - unlocked during execution. -*/ -status_t -PrecacheIO::Start() -{ // allocate pages for the cache and mark them busy - uint32 vecCount = 0; uint32 i = 0; for (size_t pos = 0; pos < fSize; pos += B_PAGE_SIZE) { vm_page* page = vm_page_allocate_page(PAGE_STATE_FREE, true); @@ -171,7 +162,7 @@ PrecacheIO::Start() fBusyConditions[i].Publish(page, "page"); fCache->InsertPage(page, fOffset + pos); - add_to_iovec(fVecs, vecCount, fPageCount, + add_to_iovec(fVecs, fVecCount, fPageCount, page->physical_page_number * B_PAGE_SIZE, B_PAGE_SIZE); fPages[i++] = page; } @@ -186,14 +177,17 @@ PrecacheIO::Start() return B_NO_MEMORY; } - fCache->Unlock(); + return B_OK; +} - status_t status = vfs_asynchronous_read_pages(fRef->vnode, NULL, fOffset, - fVecs, vecCount, fSize, B_PHYSICAL_IO_REQUEST, this); - fCache->Lock(); - - return status; +void +PrecacheIO::ReadAsync() +{ + // This object is going to be deleted after the I/O request has been + // fulfilled + vfs_asynchronous_read_pages(fRef->vnode, NULL, fOffset, fVecs, fVecCount, + fSize, B_PHYSICAL_IO_REQUEST, this); } @@ -952,11 +946,16 @@ cache_prefetch_vnode(struct vnode *vnode, off_t offset, size_t size) // read the part before the current page (or the end of the request) PrecacheIO* io = new(std::nothrow) PrecacheIO(ref, lastOffset, bytesToRead); - if (io == NULL || io->Init() != B_OK || io->Start() != B_OK) { + if (io == NULL || io->Prepare() != B_OK) { delete io; break; } + // we must not have the cache locked during I/O + cache->Unlock(); + io->ReadAsync(); + cache->Lock(); + bytesToRead = 0; }