* 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
This commit is contained in:
+21
-22
@@ -75,8 +75,8 @@ public:
|
|||||||
size_t size);
|
size_t size);
|
||||||
~PrecacheIO();
|
~PrecacheIO();
|
||||||
|
|
||||||
status_t Init();
|
status_t Prepare();
|
||||||
status_t Start();
|
void ReadAsync();
|
||||||
|
|
||||||
virtual void IOFinished(status_t status,
|
virtual void IOFinished(status_t status,
|
||||||
bool partialTransfer,
|
bool partialTransfer,
|
||||||
@@ -90,6 +90,7 @@ private:
|
|||||||
ConditionVariable* fBusyConditions;
|
ConditionVariable* fBusyConditions;
|
||||||
iovec* fVecs;
|
iovec* fVecs;
|
||||||
off_t fOffset;
|
off_t fOffset;
|
||||||
|
uint32 fVecCount;
|
||||||
size_t fSize;
|
size_t fSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -116,6 +117,7 @@ PrecacheIO::PrecacheIO(file_cache_ref* ref, off_t offset, size_t size)
|
|||||||
fBusyConditions(NULL),
|
fBusyConditions(NULL),
|
||||||
fVecs(NULL),
|
fVecs(NULL),
|
||||||
fOffset(offset),
|
fOffset(offset),
|
||||||
|
fVecCount(0),
|
||||||
fSize(size)
|
fSize(size)
|
||||||
{
|
{
|
||||||
fPageCount = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE;
|
fPageCount = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE;
|
||||||
@@ -133,7 +135,7 @@ PrecacheIO::~PrecacheIO()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
PrecacheIO::Init()
|
PrecacheIO::Prepare()
|
||||||
{
|
{
|
||||||
if (fPageCount == 0)
|
if (fPageCount == 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -150,18 +152,7 @@ PrecacheIO::Init()
|
|||||||
if (fVecs == NULL)
|
if (fVecs == NULL)
|
||||||
return B_NO_MEMORY;
|
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
|
// allocate pages for the cache and mark them busy
|
||||||
uint32 vecCount = 0;
|
|
||||||
uint32 i = 0;
|
uint32 i = 0;
|
||||||
for (size_t pos = 0; pos < fSize; pos += B_PAGE_SIZE) {
|
for (size_t pos = 0; pos < fSize; pos += B_PAGE_SIZE) {
|
||||||
vm_page* page = vm_page_allocate_page(PAGE_STATE_FREE, true);
|
vm_page* page = vm_page_allocate_page(PAGE_STATE_FREE, true);
|
||||||
@@ -171,7 +162,7 @@ PrecacheIO::Start()
|
|||||||
fBusyConditions[i].Publish(page, "page");
|
fBusyConditions[i].Publish(page, "page");
|
||||||
fCache->InsertPage(page, fOffset + pos);
|
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);
|
page->physical_page_number * B_PAGE_SIZE, B_PAGE_SIZE);
|
||||||
fPages[i++] = page;
|
fPages[i++] = page;
|
||||||
}
|
}
|
||||||
@@ -186,14 +177,17 @@ PrecacheIO::Start()
|
|||||||
return B_NO_MEMORY;
|
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();
|
void
|
||||||
|
PrecacheIO::ReadAsync()
|
||||||
return status;
|
{
|
||||||
|
// 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)
|
// read the part before the current page (or the end of the request)
|
||||||
PrecacheIO* io
|
PrecacheIO* io
|
||||||
= new(std::nothrow) PrecacheIO(ref, lastOffset, bytesToRead);
|
= 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;
|
delete io;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we must not have the cache locked during I/O
|
||||||
|
cache->Unlock();
|
||||||
|
io->ReadAsync();
|
||||||
|
cache->Lock();
|
||||||
|
|
||||||
bytesToRead = 0;
|
bytesToRead = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user