In cache_io(): Don't keep the cache locked while doing a
user_{memcpy,memset}(), since that can cause a page fault, which needs
pages and might try to steal some from our cache.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26700 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+34
-21
@@ -626,38 +626,51 @@ cache_io(void *_cacheRef, void *cookie, off_t offset, addr_t buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t bytesInPage = min_c(size_t(B_PAGE_SIZE - pageOffset), bytesLeft);
|
size_t bytesInPage = min_c(size_t(B_PAGE_SIZE - pageOffset), bytesLeft);
|
||||||
addr_t virtualAddress;
|
|
||||||
|
|
||||||
TRACE(("lookup page from offset %Ld: %p, size = %lu, pageOffset "
|
TRACE(("lookup page from offset %Ld: %p, size = %lu, pageOffset "
|
||||||
"= %lu\n", offset, page, bytesLeft, pageOffset));
|
"= %lu\n", offset, page, bytesLeft, pageOffset));
|
||||||
|
|
||||||
if (page != NULL) {
|
if (page != NULL) {
|
||||||
vm_get_physical_page(page->physical_page_number * B_PAGE_SIZE,
|
|
||||||
&virtualAddress, PHYSICAL_PAGE_CAN_WAIT);
|
|
||||||
|
|
||||||
// Since we don't actually map pages as part of an area, we have
|
// Since we don't actually map pages as part of an area, we have
|
||||||
// to manually maintain its usage_count
|
// to manually maintain their usage_count
|
||||||
page->usage_count = 2;
|
page->usage_count = 2;
|
||||||
|
|
||||||
// and copy the contents of the page already in memory
|
if (doWrite || useBuffer) {
|
||||||
if (doWrite) {
|
// Since the following user_mem{cpy,set}() might cause a page
|
||||||
if (useBuffer) {
|
// fault, which in turn might cause pages to be reserved, we
|
||||||
user_memcpy((void *)(virtualAddress + pageOffset),
|
// need to unlock the cache temporarily to avoid a potential
|
||||||
(void *)buffer, bytesInPage);
|
// deadlock. To make sure that our page doesn't go away, we mark
|
||||||
} else {
|
// it busy for the time.
|
||||||
user_memset((void *)(virtualAddress + pageOffset),
|
uint8 oldPageState = page->state;
|
||||||
0, bytesInPage);
|
page->state = PAGE_STATE_BUSY;
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
addr_t virtualAddress;
|
||||||
|
vm_get_physical_page(page->physical_page_number * B_PAGE_SIZE,
|
||||||
|
&virtualAddress, PHYSICAL_PAGE_CAN_WAIT);
|
||||||
|
|
||||||
|
// copy the contents of the page already in memory
|
||||||
|
if (doWrite) {
|
||||||
|
if (useBuffer) {
|
||||||
|
user_memcpy((void *)(virtualAddress + pageOffset),
|
||||||
|
(void *)buffer, bytesInPage);
|
||||||
|
} else {
|
||||||
|
user_memset((void *)(virtualAddress + pageOffset),
|
||||||
|
0, bytesInPage);
|
||||||
|
}
|
||||||
|
} else if (useBuffer) {
|
||||||
|
user_memcpy((void *)buffer,
|
||||||
|
(void *)(virtualAddress + pageOffset), bytesInPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the page is in the modified list
|
vm_put_physical_page(virtualAddress);
|
||||||
if (page->state != PAGE_STATE_MODIFIED)
|
|
||||||
vm_page_set_state(page, PAGE_STATE_MODIFIED);
|
|
||||||
} else if (useBuffer) {
|
|
||||||
user_memcpy((void *)buffer,
|
|
||||||
(void *)(virtualAddress + pageOffset), bytesInPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_put_physical_page(virtualAddress);
|
locker.Lock();
|
||||||
|
|
||||||
|
page->state = oldPageState;
|
||||||
|
if (doWrite && page->state != PAGE_STATE_MODIFIED)
|
||||||
|
vm_page_set_state(page, PAGE_STATE_MODIFIED);
|
||||||
|
}
|
||||||
|
|
||||||
if (bytesLeft <= bytesInPage) {
|
if (bytesLeft <= bytesInPage) {
|
||||||
// we've read the last page, so we're done!
|
// we've read the last page, so we're done!
|
||||||
|
|||||||
Reference in New Issue
Block a user