From 6f3ee1f1670b8cb3d3981d5769d866a2e69c8ef5 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 8 Sep 2008 13:45:27 +0000 Subject: [PATCH] When mapping a file into memory we do now immediately map all active pages into the team's address space. Doing that is relatively cheap and saves later page faults. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27380 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/vm/vm.cpp | 62 +++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 209077e3c8..f144bfa571 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -2087,6 +2087,33 @@ vm_create_vnode_cache(struct vnode *vnode, struct VMCache **cache) } +/*! \a cache must be locked. The area's address space must be read-locked. +*/ +static void +pre_map_area_pages(vm_area* area, VMCache* cache) +{ + addr_t baseAddress = area->base; + addr_t cacheOffset = area->cache_offset; + page_num_t firstPage = cacheOffset / B_PAGE_SIZE; + page_num_t endPage = firstPage + area->size / B_PAGE_SIZE; + + for (VMCachePagesTree::Iterator it + = cache->pages.GetIterator(firstPage, true, true); + vm_page *page = it.Next();) { + if (page->cache_offset >= endPage) + break; + + // skip inactive pages + if (page->state == PAGE_STATE_BUSY || page->usage_count <= 0) + continue; + + vm_map_page(area, page, + baseAddress + (page->cache_offset * B_PAGE_SIZE - cacheOffset), + B_READ_AREA | B_KERNEL_READ_AREA); + } +} + + /*! Will map the file specified by \a fd to an area in memory. The file will be mirrored beginning at the specified \a offset. The \a offset and \a size arguments have to be page aligned. @@ -2139,6 +2166,38 @@ _vm_map_file(team_id team, const char *name, void **_address, uint32 addressSpec return status; CObjectDeleter vnodePutter(vnode, vfs_put_vnode); + // If we're going to pre-map pages, we need to reserve the pages needed by + // the mapping backend upfront. + page_num_t reservedPreMapPages = 0; + if ((protection & B_READ_AREA) != 0) { + AddressSpaceWriteLocker locker; + status = locker.SetTo(team); + if (status != B_OK) + return status; + + vm_translation_map *map = &locker.AddressSpace()->translation_map; + reservedPreMapPages = map->ops->map_max_pages_need(map, 0, size - 1); + + locker.Unlock(); + + vm_page_reserve_pages(reservedPreMapPages); + } + + struct PageUnreserver { + PageUnreserver(page_num_t count) + : fCount(count) + { + } + + ~PageUnreserver() + { + if (fCount > 0) + vm_page_unreserve_pages(fCount); + } + + page_num_t fCount; + } pageUnreserver(reservedPreMapPages); + AddressSpaceWriteLocker locker(team); if (!locker.IsLocked()) return B_BAD_TEAM_ID; @@ -2161,6 +2220,9 @@ _vm_map_file(team_id team, const char *name, void **_address, uint32 addressSpec cache->ReleaseRefLocked(); } + if (status == B_OK && (protection & B_READ_AREA) != 0) + pre_map_area_pages(area, cache); + cache->Unlock(); if (status < B_OK)