1e50cf876SIngo Weinhold /* 2be7328a9SIngo Weinhold * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3e50cf876SIngo Weinhold * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. 4e50cf876SIngo Weinhold * Distributed under the terms of the MIT License. 5e50cf876SIngo Weinhold * 6e50cf876SIngo Weinhold * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7e50cf876SIngo Weinhold * Distributed under the terms of the NewOS License. 8e50cf876SIngo Weinhold */ 9e50cf876SIngo Weinhold #ifndef _KERNEL_VM_VM_CACHE_H 10e50cf876SIngo Weinhold #define _KERNEL_VM_VM_CACHE_H 11e50cf876SIngo Weinhold 12e50cf876SIngo Weinhold 13355dc6beSIngo Weinhold #include <debug.h> 14e50cf876SIngo Weinhold #include <kernel.h> 15e50cf876SIngo Weinhold #include <vm/vm.h> 16be7328a9SIngo Weinhold #include <vm/vm_types.h> 17be7328a9SIngo Weinhold 18be7328a9SIngo Weinhold #include "kernel_debug_config.h" 19e50cf876SIngo Weinhold 20e50cf876SIngo Weinhold 21e50cf876SIngo Weinhold struct kernel_args; 22e50cf876SIngo Weinhold 23e50cf876SIngo Weinhold 24be7328a9SIngo Weinhold enum { 25be7328a9SIngo Weinhold CACHE_TYPE_RAM = 0, 26be7328a9SIngo Weinhold CACHE_TYPE_VNODE, 27be7328a9SIngo Weinhold CACHE_TYPE_DEVICE, 28be7328a9SIngo Weinhold CACHE_TYPE_NULL 29be7328a9SIngo Weinhold }; 30be7328a9SIngo Weinhold 31522c2f19SIngo Weinhold enum { 32522c2f19SIngo Weinhold PAGE_EVENT_NOT_BUSY = 0x01 // page not busy anymore 33522c2f19SIngo Weinhold }; 34522c2f19SIngo Weinhold 35522c2f19SIngo Weinhold 36be7328a9SIngo Weinhold struct VMCachePagesTreeDefinition { 37be7328a9SIngo Weinhold typedef page_num_t KeyType; 38be7328a9SIngo Weinhold typedef vm_page NodeType; 39be7328a9SIngo Weinhold 40be7328a9SIngo Weinhold static page_num_t GetKey(const NodeType* node) 41be7328a9SIngo Weinhold { 42be7328a9SIngo Weinhold return node->cache_offset; 43be7328a9SIngo Weinhold } 44be7328a9SIngo Weinhold 45be7328a9SIngo Weinhold static SplayTreeLink<NodeType>* GetLink(NodeType* node) 46be7328a9SIngo Weinhold { 47be7328a9SIngo Weinhold return &node->cache_link; 48be7328a9SIngo Weinhold } 49be7328a9SIngo Weinhold 50be7328a9SIngo Weinhold static int Compare(page_num_t key, const NodeType* node) 51be7328a9SIngo Weinhold { 52be7328a9SIngo Weinhold return key == node->cache_offset ? 0 53be7328a9SIngo Weinhold : (key < node->cache_offset ? -1 : 1); 54be7328a9SIngo Weinhold } 55be7328a9SIngo Weinhold 56be7328a9SIngo Weinhold static NodeType** GetListLink(NodeType* node) 57be7328a9SIngo Weinhold { 58be7328a9SIngo Weinhold return &node->cache_next; 59be7328a9SIngo Weinhold } 60be7328a9SIngo Weinhold }; 61be7328a9SIngo Weinhold 62be7328a9SIngo Weinhold typedef IteratableSplayTree<VMCachePagesTreeDefinition> VMCachePagesTree; 63be7328a9SIngo Weinhold 646379e53eSIngo Weinhold 65be7328a9SIngo Weinhold struct VMCache { 66be7328a9SIngo Weinhold public: 67be7328a9SIngo Weinhold VMCache(); 68be7328a9SIngo Weinhold virtual ~VMCache(); 69be7328a9SIngo Weinhold 70deee8524SIngo Weinhold status_t Init(uint32 cacheType, uint32 allocationFlags); 71be7328a9SIngo Weinhold 72be7328a9SIngo Weinhold virtual void Delete(); 73be7328a9SIngo Weinhold 74355dc6beSIngo Weinhold inline bool Lock(); 75355dc6beSIngo Weinhold inline bool TryLock(); 76355dc6beSIngo Weinhold inline bool SwitchLock(mutex* from); 7777690f28SIngo Weinhold inline bool SwitchFromReadLock(rw_lock* from); 783632eeedSIngo Weinhold void Unlock(bool consumerLocked = false); 79355dc6beSIngo Weinhold inline void AssertLocked(); 80be7328a9SIngo Weinhold 81355dc6beSIngo Weinhold inline void AcquireRefLocked(); 82355dc6beSIngo Weinhold inline void AcquireRef(); 83355dc6beSIngo Weinhold inline void ReleaseRefLocked(); 84355dc6beSIngo Weinhold inline void ReleaseRef(); 853632eeedSIngo Weinhold inline void ReleaseRefAndUnlock( 863632eeedSIngo Weinhold bool consumerLocked = false); 87be7328a9SIngo Weinhold 88cf99b9abSIngo Weinhold inline VMCacheRef* CacheRef() const { return fCacheRef; } 89cf99b9abSIngo Weinhold 90522c2f19SIngo Weinhold void WaitForPageEvents(vm_page* page, uint32 events, 91522c2f19SIngo Weinhold bool relock); 92522c2f19SIngo Weinhold void NotifyPageEvents(vm_page* page, uint32 events) 93522c2f19SIngo Weinhold { if (fPageEventWaiters != NULL) 94522c2f19SIngo Weinhold _NotifyPageEvents(page, events); } 9572382fa6SIngo Weinhold inline void MarkPageUnbusy(vm_page* page); 96522c2f19SIngo Weinhold 97be7328a9SIngo Weinhold vm_page* LookupPage(off_t offset); 98be7328a9SIngo Weinhold void InsertPage(vm_page* page, off_t offset); 99be7328a9SIngo Weinhold void RemovePage(vm_page* page); 100eb8dc1ebSIngo Weinhold void MovePage(vm_page* page); 101eb8dc1ebSIngo Weinhold void MoveAllPages(VMCache* fromCache); 102be7328a9SIngo Weinhold 103be7328a9SIngo Weinhold void AddConsumer(VMCache* consumer); 104be7328a9SIngo Weinhold 105be7328a9SIngo Weinhold status_t InsertAreaLocked(VMArea* area); 106be7328a9SIngo Weinhold status_t RemoveArea(VMArea* area); 1072e74d74fSIngo Weinhold void TransferAreas(VMCache* fromCache); 1082e74d74fSIngo Weinhold uint32 CountWritableAreas(VMArea* ignoreArea) const; 109be7328a9SIngo Weinhold 110be7328a9SIngo Weinhold status_t WriteModified(); 111cff6e9e4SIngo Weinhold status_t SetMinimalCommitment(off_t commitment, 112cff6e9e4SIngo Weinhold int priority); 113efeca209SIngo Weinhold virtual status_t Resize(off_t newSize, int priority); 114be7328a9SIngo Weinhold 115be7328a9SIngo Weinhold status_t FlushAndRemoveAllPages(); 116be7328a9SIngo Weinhold 1173632eeedSIngo Weinhold void* UserData() { return fUserData; } 1183632eeedSIngo Weinhold void SetUserData(void* data) { fUserData = data; } 1193632eeedSIngo Weinhold // Settable by the lock owner and valid as 1203632eeedSIngo Weinhold // long as the lock is owned. 1213632eeedSIngo Weinhold 122be7328a9SIngo Weinhold // for debugging only 123be7328a9SIngo Weinhold mutex* GetLock() 124be7328a9SIngo Weinhold { return &fLock; } 125be7328a9SIngo Weinhold int32 RefCount() const 126be7328a9SIngo Weinhold { return fRefCount; } 127be7328a9SIngo Weinhold 128be7328a9SIngo Weinhold // backing store operations 129cff6e9e4SIngo Weinhold virtual status_t Commit(off_t size, int priority); 130be7328a9SIngo Weinhold virtual bool HasPage(off_t offset); 131be7328a9SIngo Weinhold 132*435c43f5SIngo Weinhold virtual status_t Read(off_t offset, const generic_io_vec *vecs, 1336440406aSIngo Weinhold size_t count,uint32 flags, 134*435c43f5SIngo Weinhold generic_size_t *_numBytes); 135*435c43f5SIngo Weinhold virtual status_t Write(off_t offset, const generic_io_vec *vecs, 136*435c43f5SIngo Weinhold size_t count, uint32 flags, 137*435c43f5SIngo Weinhold generic_size_t *_numBytes); 138*435c43f5SIngo Weinhold virtual status_t WriteAsync(off_t offset, 139*435c43f5SIngo Weinhold const generic_io_vec* vecs, size_t count, 140*435c43f5SIngo Weinhold generic_size_t numBytes, uint32 flags, 141be7328a9SIngo Weinhold AsyncIOCallback* callback); 142be7328a9SIngo Weinhold virtual bool CanWritePage(off_t offset); 143be7328a9SIngo Weinhold 144be7328a9SIngo Weinhold virtual int32 MaxPagesPerWrite() const 145be7328a9SIngo Weinhold { return -1; } // no restriction 146be7328a9SIngo Weinhold virtual int32 MaxPagesPerAsyncWrite() const 147be7328a9SIngo Weinhold { return -1; } // no restriction 148be7328a9SIngo Weinhold 149be7328a9SIngo Weinhold virtual status_t Fault(struct VMAddressSpace *aspace, 150be7328a9SIngo Weinhold off_t offset); 151be7328a9SIngo Weinhold 152be7328a9SIngo Weinhold virtual void Merge(VMCache* source); 153be7328a9SIngo Weinhold 154be7328a9SIngo Weinhold virtual status_t AcquireUnreferencedStoreRef(); 155be7328a9SIngo Weinhold virtual void AcquireStoreRef(); 156be7328a9SIngo Weinhold virtual void ReleaseStoreRef(); 157be7328a9SIngo Weinhold 15886875ad9SIngo Weinhold virtual bool DebugHasPage(off_t offset); 15986875ad9SIngo Weinhold vm_page* DebugLookupPage(off_t offset); 16086875ad9SIngo Weinhold 161be7328a9SIngo Weinhold public: 1626440406aSIngo Weinhold VMArea* areas; 1636440406aSIngo Weinhold list_link consumer_link; 1646440406aSIngo Weinhold list consumers; 165be7328a9SIngo Weinhold // list of caches that use this cache as a source 166be7328a9SIngo Weinhold VMCachePagesTree pages; 167be7328a9SIngo Weinhold VMCache* source; 168be7328a9SIngo Weinhold off_t virtual_base; 169be7328a9SIngo Weinhold off_t virtual_end; 170be7328a9SIngo Weinhold off_t committed_size; 171be7328a9SIngo Weinhold // TODO: Remove! 172be7328a9SIngo Weinhold uint32 page_count; 173be7328a9SIngo Weinhold uint32 temporary : 1; 174be7328a9SIngo Weinhold uint32 scan_skip : 1; 175be7328a9SIngo Weinhold uint32 type : 6; 176be7328a9SIngo Weinhold 177be7328a9SIngo Weinhold #if DEBUG_CACHE_LIST 1786440406aSIngo Weinhold VMCache* debug_previous; 1796440406aSIngo Weinhold VMCache* debug_next; 180be7328a9SIngo Weinhold #endif 181be7328a9SIngo Weinhold 182be7328a9SIngo Weinhold private: 183522c2f19SIngo Weinhold struct PageEventWaiter; 1846379e53eSIngo Weinhold friend struct VMCacheRef; 185522c2f19SIngo Weinhold 186522c2f19SIngo Weinhold private: 187522c2f19SIngo Weinhold void _NotifyPageEvents(vm_page* page, uint32 events); 188522c2f19SIngo Weinhold 1896440406aSIngo Weinhold inline bool _IsMergeable() const; 1906440406aSIngo Weinhold 1913632eeedSIngo Weinhold void _MergeWithOnlyConsumer(bool consumerLocked); 1926440406aSIngo Weinhold void _RemoveConsumer(VMCache* consumer); 1936440406aSIngo Weinhold 1946440406aSIngo Weinhold private: 195be7328a9SIngo Weinhold int32 fRefCount; 196be7328a9SIngo Weinhold mutex fLock; 197522c2f19SIngo Weinhold PageEventWaiter* fPageEventWaiters; 1983632eeedSIngo Weinhold void* fUserData; 1996379e53eSIngo Weinhold VMCacheRef* fCacheRef; 200be7328a9SIngo Weinhold }; 201be7328a9SIngo Weinhold 202be7328a9SIngo Weinhold 203be7328a9SIngo Weinhold #if DEBUG_CACHE_LIST 204be7328a9SIngo Weinhold extern VMCache* gDebugCacheList; 205be7328a9SIngo Weinhold #endif 206be7328a9SIngo Weinhold 207be7328a9SIngo Weinhold 208be7328a9SIngo Weinhold class VMCacheFactory { 209be7328a9SIngo Weinhold public: 210be7328a9SIngo Weinhold static status_t CreateAnonymousCache(VMCache*& cache, 211be7328a9SIngo Weinhold bool canOvercommit, int32 numPrecommittedPages, 212cff6e9e4SIngo Weinhold int32 numGuardPages, bool swappable, 213cff6e9e4SIngo Weinhold int priority); 214be7328a9SIngo Weinhold static status_t CreateVnodeCache(VMCache*& cache, 215be7328a9SIngo Weinhold struct vnode* vnode); 216be7328a9SIngo Weinhold static status_t CreateDeviceCache(VMCache*& cache, 217be7328a9SIngo Weinhold addr_t baseAddress); 218cff6e9e4SIngo Weinhold static status_t CreateNullCache(int priority, VMCache*& cache); 219be7328a9SIngo Weinhold }; 220be7328a9SIngo Weinhold 221be7328a9SIngo Weinhold 222355dc6beSIngo Weinhold 223355dc6beSIngo Weinhold bool 224355dc6beSIngo Weinhold VMCache::Lock() 225355dc6beSIngo Weinhold { 226355dc6beSIngo Weinhold return mutex_lock(&fLock) == B_OK; 227355dc6beSIngo Weinhold } 228355dc6beSIngo Weinhold 229355dc6beSIngo Weinhold 230355dc6beSIngo Weinhold bool 231355dc6beSIngo Weinhold VMCache::TryLock() 232355dc6beSIngo Weinhold { 233355dc6beSIngo Weinhold return mutex_trylock(&fLock) == B_OK; 234355dc6beSIngo Weinhold } 235355dc6beSIngo Weinhold 236355dc6beSIngo Weinhold 237355dc6beSIngo Weinhold bool 238355dc6beSIngo Weinhold VMCache::SwitchLock(mutex* from) 239355dc6beSIngo Weinhold { 240355dc6beSIngo Weinhold return mutex_switch_lock(from, &fLock) == B_OK; 241355dc6beSIngo Weinhold } 242355dc6beSIngo Weinhold 243355dc6beSIngo Weinhold 24477690f28SIngo Weinhold bool 24577690f28SIngo Weinhold VMCache::SwitchFromReadLock(rw_lock* from) 24677690f28SIngo Weinhold { 24777690f28SIngo Weinhold return mutex_switch_from_read_lock(from, &fLock) == B_OK; 24877690f28SIngo Weinhold } 24977690f28SIngo Weinhold 25077690f28SIngo Weinhold 251355dc6beSIngo Weinhold void 252355dc6beSIngo Weinhold VMCache::AssertLocked() 253355dc6beSIngo Weinhold { 254355dc6beSIngo Weinhold ASSERT_LOCKED_MUTEX(&fLock); 255355dc6beSIngo Weinhold } 256355dc6beSIngo Weinhold 257355dc6beSIngo Weinhold 258355dc6beSIngo Weinhold void 259355dc6beSIngo Weinhold VMCache::AcquireRefLocked() 260355dc6beSIngo Weinhold { 261355dc6beSIngo Weinhold ASSERT_LOCKED_MUTEX(&fLock); 262355dc6beSIngo Weinhold 263355dc6beSIngo Weinhold fRefCount++; 264355dc6beSIngo Weinhold } 265355dc6beSIngo Weinhold 266355dc6beSIngo Weinhold 267355dc6beSIngo Weinhold void 268355dc6beSIngo Weinhold VMCache::AcquireRef() 269355dc6beSIngo Weinhold { 270355dc6beSIngo Weinhold Lock(); 271355dc6beSIngo Weinhold fRefCount++; 272355dc6beSIngo Weinhold Unlock(); 273355dc6beSIngo Weinhold } 274355dc6beSIngo Weinhold 275355dc6beSIngo Weinhold 276355dc6beSIngo Weinhold void 277355dc6beSIngo Weinhold VMCache::ReleaseRefLocked() 278355dc6beSIngo Weinhold { 279355dc6beSIngo Weinhold ASSERT_LOCKED_MUTEX(&fLock); 280355dc6beSIngo Weinhold 281355dc6beSIngo Weinhold fRefCount--; 282355dc6beSIngo Weinhold } 283355dc6beSIngo Weinhold 284355dc6beSIngo Weinhold 285355dc6beSIngo Weinhold void 286355dc6beSIngo Weinhold VMCache::ReleaseRef() 287355dc6beSIngo Weinhold { 288355dc6beSIngo Weinhold Lock(); 289355dc6beSIngo Weinhold fRefCount--; 290355dc6beSIngo Weinhold Unlock(); 291355dc6beSIngo Weinhold } 292355dc6beSIngo Weinhold 293355dc6beSIngo Weinhold 294355dc6beSIngo Weinhold void 2953632eeedSIngo Weinhold VMCache::ReleaseRefAndUnlock(bool consumerLocked) 296355dc6beSIngo Weinhold { 297355dc6beSIngo Weinhold ReleaseRefLocked(); 2983632eeedSIngo Weinhold Unlock(consumerLocked); 299355dc6beSIngo Weinhold } 300355dc6beSIngo Weinhold 301355dc6beSIngo Weinhold 30272382fa6SIngo Weinhold void 30372382fa6SIngo Weinhold VMCache::MarkPageUnbusy(vm_page* page) 30472382fa6SIngo Weinhold { 3054bb4f793SIngo Weinhold ASSERT(page->busy); 30672382fa6SIngo Weinhold page->busy = false; 30772382fa6SIngo Weinhold NotifyPageEvents(page, PAGE_EVENT_NOT_BUSY); 30872382fa6SIngo Weinhold } 30972382fa6SIngo Weinhold 31072382fa6SIngo Weinhold 311e50cf876SIngo Weinhold #ifdef __cplusplus 312e50cf876SIngo Weinhold extern "C" { 313e50cf876SIngo Weinhold #endif 314e50cf876SIngo Weinhold 315e50cf876SIngo Weinhold status_t vm_cache_init(struct kernel_args *args); 3162e74d74fSIngo Weinhold void vm_cache_init_post_heap(); 317e50cf876SIngo Weinhold struct VMCache *vm_cache_acquire_locked_page_cache(struct vm_page *page, 318e50cf876SIngo Weinhold bool dontWait); 319e50cf876SIngo Weinhold 320e50cf876SIngo Weinhold #ifdef __cplusplus 321e50cf876SIngo Weinhold } 322e50cf876SIngo Weinhold #endif 323e50cf876SIngo Weinhold 324be7328a9SIngo Weinhold 325e50cf876SIngo Weinhold #endif /* _KERNEL_VM_VM_CACHE_H */ 326