ramfs: Properly acquire/release references to the vnode in VMCache.
This is what AcquireStoreRef/ReleaseStoreRef are for. We don't use
VMVnodeCache here because that is a non-"temporary" cache that
writes its pages back to disk, while we need a store for the pages
that won't discard unmodified ones when memory is low.
Add a close() to the mmap_cut_tests, which triggers the case where
this is important (a file is unlinked, mmap'ed, and then the lone
FD referring to it is closed, triggering the file's deletion unless
the mmap also acquired a reference to the vnode.)
Fixes KDLs with Firefox test builds.
(cherry picked from commit c0a12a6b7d697382511ff36e7815aad6a379b3a7)
Change-Id: I589325966f7b8eb837750aea1f5adbdd94e06aeb
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8028
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
Diff
src/system/kernel/vm/VMAnonymousNoSwapCache.h | 2 +-
src/tests/system/kernel/mmap_cut_tests.cpp | 3 +++
src/add-ons/kernel/file_systems/ramfs/DataContainer.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++--
src/add-ons/kernel/file_systems/ramfs/DataContainer.h | 2 +-
src/add-ons/kernel/file_systems/ramfs/Jamfile | 1 +
src/add-ons/kernel/file_systems/ramfs/kernel_interface.cpp | 2 +-
6 files changed, 54 insertions(+), 6 deletions(-)
@@ -13,7 +13,7 @@
#include <vm/VMCache.h>
class VMAnonymousNoSwapCache final : public VMCache {
class VMAnonymousNoSwapCache : public VMCache {
public:
virtual ~VMAnonymousNoSwapCache();
@@ -94,6 +94,9 @@
uint8* ptr = (uint8*)mmap(NULL, B_PAGE_SIZE * 4, PROT_NONE, MAP_PRIVATE,
fd, 0);
close(fd);
mprotect(ptr, B_PAGE_SIZE, PROT_READ | PROT_WRITE);
@@ -8,9 +8,12 @@
#include <StackOrHeapArray.h>
#include <util/AutoLock.h>
#include <util/BitUtils.h>
#include <slab/Slab.h>
#include <vfs.h>
#include <vm/VMCache.h>
#include <vm/vm_page.h>
#include "VMAnonymousNoSwapCache.h"
#include "AllocationInfo.h"
#include "DebugSupport.h"
@@ -42,6 +45,42 @@
static const off_t kMaximumSmallBufferSize = (B_PAGE_SIZE / 4);
class VMForVnodeCache final : public VMAnonymousNoSwapCache {
public:
status_t Init()
{
fVnode = NULL;
return VMAnonymousNoSwapCache::Init(false, 0, 0, 0);
}
status_t AcquireUnreferencedStoreRef() override
{
return B_NOT_SUPPORTED;
}
void AcquireStoreRef() override
{
vfs_acquire_vnode(fVnode);
}
void ReleaseStoreRef() override
{
vfs_put_vnode(fVnode);
}
protected:
virtual void DeleteObject()
{
object_cache_delete(gVnodeCacheObjectCache, this);
}
private:
friend class DataContainer;
struct vnode* fVnode;
};
DataContainer::DataContainer(Volume *volume)
: fVolume(volume),
@@ -75,12 +114,13 @@
VMCache*
DataContainer::GetCache()
DataContainer::GetCache(struct vnode* vnode)
{
if (!_IsCacheMode())
_SwitchToCacheMode();
((VMForVnodeCache*)fCache)->fVnode = vnode;
return fCache;
}
@@ -249,11 +289,15 @@
status_t
DataContainer::_SwitchToCacheMode()
{
status_t error = VMCacheFactory::CreateAnonymousCache(fCache, false, 0,
0, false, VM_PRIORITY_USER);
VMForVnodeCache* cache = new(gVnodeCacheObjectCache, 0) VMForVnodeCache;
if (cache == NULL)
return B_NO_MEMORY;
status_t error = cache->Init();
if (error != B_OK)
return error;
fCache = cache;
fCache->temporary = 1;
fCache->unmergeable = 1;
fCache->virtual_end = fSize;
@@ -28,7 +28,7 @@
status_t Resize(off_t newSize);
off_t GetSize() const { return fSize; }
VMCache* GetCache();
VMCache* GetCache(struct vnode* vnode);
virtual status_t ReadAt(off_t offset, void *buffer, size_t size,
size_t *bytesRead);
@@ -1,8 +1,9 @@
SubDir HAIKU_TOP src add-ons kernel file_systems ramfs ;
UsePrivateKernelHeaders ;
UsePrivateHeaders file_systems storage ;
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel drivers disk virtual ram_disk ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src system kernel vm ] ;
DEFINES += DEBUG_APP="\\\"ramfs\\\"" ;
@@ -856,7 +856,7 @@
struct vnode* vnode;
if (vfs_lookup_vnode(_volume->id, node->GetID(), &vnode) == B_OK) {
vfs_set_vnode_cache(vnode, file->GetCache());
vfs_set_vnode_cache(vnode, file->GetCache(vnode));
}
}
}