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
This commit is contained in:
@@ -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.
|
/*! 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
|
The file will be mirrored beginning at the specified \a offset. The
|
||||||
\a offset and \a size arguments have to be page aligned.
|
\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;
|
return status;
|
||||||
CObjectDeleter<struct vnode> vnodePutter(vnode, vfs_put_vnode);
|
CObjectDeleter<struct vnode> 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);
|
AddressSpaceWriteLocker locker(team);
|
||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
return B_BAD_TEAM_ID;
|
return B_BAD_TEAM_ID;
|
||||||
@@ -2161,6 +2220,9 @@ _vm_map_file(team_id team, const char *name, void **_address, uint32 addressSpec
|
|||||||
cache->ReleaseRefLocked();
|
cache->ReleaseRefLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status == B_OK && (protection & B_READ_AREA) != 0)
|
||||||
|
pre_map_area_pages(area, cache);
|
||||||
|
|
||||||
cache->Unlock();
|
cache->Unlock();
|
||||||
|
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
|
|||||||
Reference in New Issue
Block a user