diff --git a/headers/private/kernel/vm_types.h b/headers/private/kernel/vm_types.h index d530e9fda8..cc733f1b8c 100644 --- a/headers/private/kernel/vm_types.h +++ b/headers/private/kernel/vm_types.h @@ -219,19 +219,20 @@ struct vm_store { }; typedef struct vm_store_ops { - void (*destroy)(struct vm_store *backing_store); - status_t (*commit)(struct vm_store *backing_store, off_t size); - bool (*has_page)(struct vm_store *backing_store, off_t offset); - status_t (*read)(struct vm_store *backing_store, off_t offset, + void (*destroy)(struct vm_store *backingStore); + status_t (*commit)(struct vm_store *backingStore, off_t size); + bool (*has_page)(struct vm_store *backingStore, off_t offset); + status_t (*read)(struct vm_store *backingStore, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter); - status_t (*write)(struct vm_store *backing_store, off_t offset, + status_t (*write)(struct vm_store *backingStore, off_t offset, const iovec *vecs, size_t count, size_t *_numBytes, bool mayBlock, bool fsReenter); - status_t (*fault)(struct vm_store *backing_store, + status_t (*fault)(struct vm_store *backingStore, struct vm_address_space *aspace, off_t offset); - void (*acquire_ref)(struct vm_store *backing_store); - void (*release_ref)(struct vm_store *backing_store); + status_t (*acquire_unreferenced_ref)(struct vm_store *backingStore); + void (*acquire_ref)(struct vm_store *backingStore); + void (*release_ref)(struct vm_store *backingStore); } vm_store_ops; #endif /* _KERNEL_VM_TYPES_H */ diff --git a/src/system/kernel/cache/vnode_store.cpp b/src/system/kernel/cache/vnode_store.cpp index 0c49d65fbc..c17af2f97e 100644 --- a/src/system/kernel/cache/vnode_store.cpp +++ b/src/system/kernel/cache/vnode_store.cpp @@ -83,6 +83,15 @@ store_write(struct vm_store *_store, off_t offset, const iovec *vecs, } +static status_t +store_acquire_unreferenced_ref(struct vm_store *_store) +{ + vnode_store *store = (vnode_store *)_store; + struct vnode *vnode; + return vfs_get_vnode(store->device, store->inode, &vnode); +} + + static void store_acquire_ref(struct vm_store *_store) { @@ -106,6 +115,7 @@ static vm_store_ops sStoreOps = { &store_read, &store_write, NULL, /* fault */ + &store_acquire_unreferenced_ref, &store_acquire_ref, &store_release_ref }; @@ -128,6 +138,7 @@ vm_create_vnode_store(struct vnode *vnode) store->vnode = vnode; store->file_cache_ref = NULL; + vfs_vnode_to_node_ref(vnode, &store->device, &store->inode); return &store->vm; } diff --git a/src/system/kernel/cache/vnode_store.h b/src/system/kernel/cache/vnode_store.h index b3a18e2b64..12464ccd3a 100644 --- a/src/system/kernel/cache/vnode_store.h +++ b/src/system/kernel/cache/vnode_store.h @@ -12,6 +12,8 @@ struct vnode_store { vm_store vm; struct vnode* vnode; + dev_t device; + ino_t inode; void* file_cache_ref; }; diff --git a/src/system/kernel/vm/vm_page.cpp b/src/system/kernel/vm/vm_page.cpp index 54adf080c5..d2a2e9d090 100644 --- a/src/system/kernel/vm/vm_page.cpp +++ b/src/system/kernel/vm/vm_page.cpp @@ -665,6 +665,15 @@ page_writer(void* /*unused*/) if (!cacheLocker.IsLocked()) continue; + vm_cache *cache = page->cache; + if (cache->store->ops->acquire_unreferenced_ref != NULL) { + // we need our own reference to the store, as it might + // currently be destructed + if (cache->store->ops->acquire_unreferenced_ref(cache->store) + != B_OK) + continue; + } + locker.Lock(); remove_page_from_queue(&sModifiedPageQueue, page); page->state = PAGE_STATE_BUSY; @@ -675,7 +684,7 @@ page_writer(void* /*unused*/) //dprintf("write page %p, cache %p (%ld)\n", page, page->cache, page->cache->ref_count); vm_clear_map_flags(page, PAGE_MODIFIED); - vm_cache_acquire_ref(page->cache); + vm_cache_acquire_ref(cache); pages[numPages++] = page; } @@ -711,6 +720,8 @@ page_writer(void* /*unused*/) busyConditions[i].Unpublish(); mutex_unlock(&cache->lock); + if (cache->store->ops->release_ref != NULL) + cache->store->ops->release_ref(cache->store); vm_cache_release_ref(cache); } } diff --git a/src/system/kernel/vm/vm_store_anonymous_noswap.cpp b/src/system/kernel/vm/vm_store_anonymous_noswap.cpp index 6b8e8ef2fd..c6e679d2fa 100644 --- a/src/system/kernel/vm/vm_store_anonymous_noswap.cpp +++ b/src/system/kernel/vm/vm_store_anonymous_noswap.cpp @@ -154,6 +154,7 @@ static vm_store_ops anonymous_ops = { &anonymous_read, &anonymous_write, &anonymous_fault, + NULL, // acquire unreferenced ref NULL, // acquire ref NULL // release ref }; diff --git a/src/system/kernel/vm/vm_store_device.c b/src/system/kernel/vm/vm_store_device.c index 44502cb1c8..cca74f7ffb 100644 --- a/src/system/kernel/vm/vm_store_device.c +++ b/src/system/kernel/vm/vm_store_device.c @@ -78,8 +78,9 @@ static vm_store_ops device_ops = { &device_read, &device_write, &device_fault, - NULL, - NULL + NULL, // acquire unreferenced ref + NULL, // acquire ref + NULL // release ref }; diff --git a/src/system/kernel/vm/vm_store_null.c b/src/system/kernel/vm/vm_store_null.c index 1013c45dce..883eafa908 100644 --- a/src/system/kernel/vm/vm_store_null.c +++ b/src/system/kernel/vm/vm_store_null.c @@ -67,8 +67,9 @@ static vm_store_ops null_ops = { &null_read, &null_write, &null_fault, - NULL, - NULL + NULL, // acquire unreferenced ref + NULL, // acquire ref + NULL // release ref };