First steps towards being able of collapse vm_cache objects after forking:
* a vm_cache now maintains a list of its "consumer" caches. * introduced to new functions that add/remove consumer to a cache (instead of only maintaining the vm_cache::source field). * fixed the incorrect reference counting when doing copy-on-write; we kept one ref too many of the lower cache. * minor cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19035 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -27,6 +27,8 @@ void vm_cache_release_ref(vm_cache_ref *cache_ref);
|
|||||||
vm_page *vm_cache_lookup_page(vm_cache_ref *cacheRef, off_t page);
|
vm_page *vm_cache_lookup_page(vm_cache_ref *cacheRef, off_t page);
|
||||||
void vm_cache_insert_page(vm_cache_ref *cacheRef, vm_page *page, off_t offset);
|
void vm_cache_insert_page(vm_cache_ref *cacheRef, vm_page *page, off_t offset);
|
||||||
void vm_cache_remove_page(vm_cache_ref *cacheRef, vm_page *page);
|
void vm_cache_remove_page(vm_cache_ref *cacheRef, vm_page *page);
|
||||||
|
void vm_cache_remove_consumer(vm_cache_ref *cacheRef, vm_cache *consumer);
|
||||||
|
void vm_cache_add_consumer(vm_cache_ref *cacheRef, vm_cache *consumer);
|
||||||
status_t vm_cache_write_modified(vm_cache_ref *ref, bool fsReenter);
|
status_t vm_cache_write_modified(vm_cache_ref *ref, bool fsReenter);
|
||||||
status_t vm_cache_set_minimal_commitment(vm_cache_ref *ref, off_t commitment);
|
status_t vm_cache_set_minimal_commitment(vm_cache_ref *ref, off_t commitment);
|
||||||
status_t vm_cache_resize(vm_cache_ref *cacheRef, off_t newSize);
|
status_t vm_cache_resize(vm_cache_ref *cacheRef, off_t newSize);
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ typedef struct vm_cache_ref {
|
|||||||
|
|
||||||
// vm_cache
|
// vm_cache
|
||||||
typedef struct vm_cache {
|
typedef struct vm_cache {
|
||||||
|
struct list_link consumer_link;
|
||||||
|
struct list consumers;
|
||||||
|
// list of caches that use this cache as a source
|
||||||
vm_page *page_list;
|
vm_page *page_list;
|
||||||
vm_cache_ref *ref;
|
vm_cache_ref *ref;
|
||||||
struct vm_cache *source;
|
struct vm_cache *source;
|
||||||
|
|||||||
@@ -552,11 +552,10 @@ map_backing_store(vm_address_space *addressSpace, vm_store *store, void **_virtu
|
|||||||
newCache->temporary = 1;
|
newCache->temporary = 1;
|
||||||
newCache->scan_skip = cache->scan_skip;
|
newCache->scan_skip = cache->scan_skip;
|
||||||
|
|
||||||
newCache->source = cache;
|
vm_cache_add_consumer(cacheRef, newCache);
|
||||||
vm_cache_acquire_ref(cacheRef);
|
|
||||||
|
|
||||||
cache = newCache;
|
cache = newCache;
|
||||||
cacheRef = cache->ref;
|
cacheRef = newCache->ref;
|
||||||
store = newStore;
|
store = newStore;
|
||||||
cache->virtual_size = offset + size;
|
cache->virtual_size = offset + size;
|
||||||
}
|
}
|
||||||
@@ -1479,13 +1478,12 @@ vm_copy_on_write_area(vm_area *area)
|
|||||||
upperCache->temporary = 1;
|
upperCache->temporary = 1;
|
||||||
upperCache->scan_skip = lowerCache->scan_skip;
|
upperCache->scan_skip = lowerCache->scan_skip;
|
||||||
upperCache->source = lowerCache;
|
upperCache->source = lowerCache;
|
||||||
|
list_add_item(&lowerCache->consumers, upperCache);
|
||||||
upperCache->ref = upperCacheRef;
|
upperCache->ref = upperCacheRef;
|
||||||
upperCacheRef->cache = upperCache;
|
upperCacheRef->cache = upperCache;
|
||||||
|
|
||||||
// we need to manually alter the ref_count
|
// we need to manually alter the ref_count (divide it between the two)
|
||||||
// ToDo: investigate a bit deeper if this is really correct
|
lowerCacheRef->ref_count = upperCacheRef->ref_count - 1;
|
||||||
// (doesn't look like it, but it works)
|
|
||||||
lowerCacheRef->ref_count = upperCacheRef->ref_count;
|
|
||||||
upperCacheRef->ref_count = 1;
|
upperCacheRef->ref_count = 1;
|
||||||
|
|
||||||
// grab a ref to the cache object we're now linked to as a source
|
// grab a ref to the cache object we're now linked to as a source
|
||||||
|
|||||||
@@ -20,7 +20,8 @@
|
|||||||
#include <smp.h>
|
#include <smp.h>
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
//#define TRACE_VM_CACHE
|
//#define TRACE_VM_CACHE
|
||||||
#ifdef TRACE_VM_CACHE
|
#ifdef TRACE_VM_CACHE
|
||||||
@@ -73,11 +74,9 @@ page_hash_func(void *_p, const void *_key, uint32 range)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
vm_cache_init(kernel_args *ka)
|
vm_cache_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
vm_page p;
|
page_cache_table = hash_init(PAGE_TABLE_SIZE, offsetof(vm_page, hash_next),
|
||||||
|
|
||||||
page_cache_table = hash_init(PAGE_TABLE_SIZE, (int)&p.hash_next - (int)&p,
|
|
||||||
&page_compare_func, &page_hash_func);
|
&page_compare_func, &page_hash_func);
|
||||||
if (!page_cache_table)
|
if (!page_cache_table)
|
||||||
panic("vm_cache_init: cannot allocate memory for page cache hash table\n");
|
panic("vm_cache_init: cannot allocate memory for page cache hash table\n");
|
||||||
@@ -101,6 +100,7 @@ vm_cache_create(vm_store *store)
|
|||||||
if (cache == NULL)
|
if (cache == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
list_init(&cache->consumers);
|
||||||
cache->page_list = NULL;
|
cache->page_list = NULL;
|
||||||
cache->ref = NULL;
|
cache->ref = NULL;
|
||||||
cache->source = NULL;
|
cache->source = NULL;
|
||||||
@@ -211,7 +211,7 @@ vm_cache_release_ref(vm_cache_ref *cache_ref)
|
|||||||
|
|
||||||
// remove the ref to the source
|
// remove the ref to the source
|
||||||
if (cache_ref->cache->source)
|
if (cache_ref->cache->source)
|
||||||
vm_cache_release_ref(cache_ref->cache->source->ref);
|
vm_cache_remove_consumer(cache_ref->cache->source->ref, cache_ref->cache);
|
||||||
|
|
||||||
mutex_destroy(&cache_ref->lock);
|
mutex_destroy(&cache_ref->lock);
|
||||||
free(cache_ref->cache);
|
free(cache_ref->cache);
|
||||||
@@ -391,6 +391,56 @@ vm_cache_resize(vm_cache_ref *cacheRef, off_t newSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Removes the \a consumer from the \a cacheRef's cache.
|
||||||
|
It will also release the reference to the cacheRef owned by the consumer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
vm_cache_remove_consumer(vm_cache_ref *cacheRef, vm_cache *consumer)
|
||||||
|
{
|
||||||
|
vm_cache *cache = cacheRef->cache;
|
||||||
|
TRACE(("remove consumer vm cache %p from cache %p\n", consumer, cache));
|
||||||
|
|
||||||
|
mutex_lock(&cacheRef->lock);
|
||||||
|
|
||||||
|
list_remove_item(&cache->consumers, consumer);
|
||||||
|
consumer->source = NULL;
|
||||||
|
|
||||||
|
if (cacheRef->areas == NULL && cache->source != NULL
|
||||||
|
&& !list_is_empty(&cache->consumers)
|
||||||
|
&& cache->consumers.link.next == cache->consumers.link.prev) {
|
||||||
|
// The cache is not really needed anymore - it can be merged with its only
|
||||||
|
// consumer left.
|
||||||
|
// TODO!
|
||||||
|
TRACE(("merge vm cache %p (ref == %ld) with vm cache %p\n",
|
||||||
|
cache, cacheRef->ref_count, cache->consumers.link.next));
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&cacheRef->lock);
|
||||||
|
vm_cache_release_ref(cacheRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Marks the \a cacheRef's cache as source of the \a consumer cache,
|
||||||
|
and adds the \a consumer to its list.
|
||||||
|
This also grabs a reference to the source cache.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
vm_cache_add_consumer(vm_cache_ref *cacheRef, vm_cache *consumer)
|
||||||
|
{
|
||||||
|
TRACE(("add consumer vm cache %p to cache %p\n", consumer, cacheRef->cache));
|
||||||
|
mutex_lock(&cacheRef->lock);
|
||||||
|
|
||||||
|
consumer->source = cacheRef->cache;
|
||||||
|
list_add_item(&cacheRef->cache->consumers, consumer);
|
||||||
|
|
||||||
|
mutex_unlock(&cacheRef->lock);
|
||||||
|
|
||||||
|
vm_cache_acquire_ref(cacheRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
vm_cache_insert_area(vm_cache_ref *cache_ref, vm_area *area)
|
vm_cache_insert_area(vm_cache_ref *cache_ref, vm_area *area)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user