From d5ad762913429ae34478222a0c87199be0709439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 30 Apr 2009 15:53:41 +0000 Subject: [PATCH] Fixed several problems of the prefetching code: * Did claim to have reserved pages when calling vm_page_allocate_page(), but didn't have any (copy&paste bug). We cannot use it without reserved pages, as we need to call vm_page_allocate_page() with a cache locked. * No longer use low_resource_state() to determine whether to precache or not, but use the new vm_page_num_used_pages() instead. * Also don't (try to) precache when the cache already has more than 2/3 of its pages to safe some unnecessary work. * The size to precache was limited to the file size incorrectly. * When precaching failed, the cache reference was not released. * The precaching started one page too late, causing bug #3835. * Reenabled precaching. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30515 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/cache/file_cache.cpp | 33 +++++++++++++++----------- src/system/kernel/vm/vm.cpp | 6 +---- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/system/kernel/cache/file_cache.cpp b/src/system/kernel/cache/file_cache.cpp index cc7960d7fc..3716c76b55 100644 --- a/src/system/kernel/cache/file_cache.cpp +++ b/src/system/kernel/cache/file_cache.cpp @@ -164,17 +164,16 @@ PrecacheIO::Start() uint32 vecCount = 0; uint32 i = 0; for (size_t pos = 0; pos < fSize; pos += B_PAGE_SIZE) { - vm_page* page = fPages[i++] = vm_page_allocate_page( - PAGE_STATE_FREE, true); + vm_page* page = vm_page_allocate_page(PAGE_STATE_FREE, true); if (page == NULL) break; - fBusyConditions[i - 1].Publish(page, "page"); - + fBusyConditions[i].Publish(page, "page"); fCache->InsertPage(page, fOffset + pos); add_to_iovec(fVecs, vecCount, fPageCount, page->physical_page_number * B_PAGE_SIZE, B_PAGE_SIZE); + fPages[i++] = page; } if (i != fPageCount) { @@ -903,10 +902,8 @@ file_cache_control(const char *subsystem, uint32 function, void *buffer, extern "C" void cache_prefetch_vnode(struct vnode *vnode, off_t offset, size_t size) { - if (low_resource_state(B_KERNEL_RESOURCE_PAGES) != B_NO_LOW_RESOURCE) { - // don't do anything if we don't have the resources left + if (size == 0) return; - } vm_cache *cache; if (vfs_get_vnode_cache(vnode, &cache, false) != B_OK) @@ -915,12 +912,17 @@ cache_prefetch_vnode(struct vnode *vnode, off_t offset, size_t size) file_cache_ref *ref = ((VMVnodeCache*)cache)->FileCacheRef(); off_t fileSize = cache->virtual_end; - if (offset >= fileSize) { + if (offset + size > fileSize) + size = fileSize - offset; + size_t reservePages = size / B_PAGE_SIZE; + + // Don't do anything if we don't have the resources left, or the cache + // already contains more than 2/3 of its pages + if (offset >= fileSize || vm_page_num_unused_pages() < 2 * reservePages + || 3 * cache->page_count > 2 * fileSize / B_PAGE_SIZE) { cache->ReleaseRef(); return; } - if (offset + size > fileSize) - size = offset - fileSize; // "offset" and "size" are always aligned to B_PAGE_SIZE, offset &= ~(B_PAGE_SIZE - 1); @@ -929,7 +931,9 @@ cache_prefetch_vnode(struct vnode *vnode, off_t offset, size_t size) size_t bytesToRead = 0; off_t lastOffset = offset; - AutoLocker locker(cache); + vm_page_reserve_pages(reservePages); + + cache->Lock(); while (true) { // check if this page is already in memory @@ -950,7 +954,7 @@ cache_prefetch_vnode(struct vnode *vnode, off_t offset, size_t size) = new(std::nothrow) PrecacheIO(ref, lastOffset, bytesToRead); if (io == NULL || io->Init() != B_OK || io->Start() != B_OK) { delete io; - return; + break; } bytesToRead = 0; @@ -961,10 +965,11 @@ cache_prefetch_vnode(struct vnode *vnode, off_t offset, size_t size) break; } - lastOffset = offset + B_PAGE_SIZE; + lastOffset = offset; } - cache->ReleaseRefLocked(); + cache->ReleaseRefAndUnlock(); + vm_page_unreserve_pages(reservePages); } diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 6d4d9309b4..4b6ace396b 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -2362,16 +2362,12 @@ _vm_map_file(team_id team, const char* name, void** _address, cache->Unlock(); -#if 0 -// TODO: Fix ticket #3835 before enabling pre-fetching -// http://dev.haiku-os.org/ticket/3835 if (status == B_OK) { // TODO: this probably deserves a smarter solution, ie. don't always - // prefetch stuff + // prefetch stuff, and also, probably don't trigger it at this place. cache_prefetch_vnode(vnode, offset, min_c(size, 10LL * 1024 * 1024)); // prefetches at max 10 MB starting from "offset" } -#endif if (status != B_OK) return status;