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> 15f8154d17SIngo Weinhold #include <util/DoublyLinkedList.h> 16e50cf876SIngo Weinhold #include <vm/vm.h> 17be7328a9SIngo Weinhold #include <vm/vm_types.h> 18be7328a9SIngo Weinhold 19be7328a9SIngo Weinhold #include "kernel_debug_config.h" 20e50cf876SIngo Weinhold 21e50cf876SIngo Weinhold 22e50cf876SIngo Weinhold struct kernel_args; 2330c9d3c0SAugustin Cavalier struct ObjectCache; 24e50cf876SIngo Weinhold 25e50cf876SIngo Weinhold 26be7328a9SIngo Weinhold enum { 27be7328a9SIngo Weinhold CACHE_TYPE_RAM = 0, 28be7328a9SIngo Weinhold CACHE_TYPE_VNODE, 29be7328a9SIngo Weinhold CACHE_TYPE_DEVICE, 30be7328a9SIngo Weinhold CACHE_TYPE_NULL 31be7328a9SIngo Weinhold }; 32be7328a9SIngo Weinhold 33522c2f19SIngo Weinhold enum { 34522c2f19SIngo Weinhold PAGE_EVENT_NOT_BUSY = 0x01 // page not busy anymore 35522c2f19SIngo Weinhold }; 36522c2f19SIngo Weinhold 37522c2f19SIngo Weinhold 38f8154d17SIngo Weinhold extern ObjectCache* gCacheRefObjectCache; 39f8154d17SIngo Weinhold extern ObjectCache* gAnonymousCacheObjectCache; 40f8154d17SIngo Weinhold extern ObjectCache* gAnonymousNoSwapCacheObjectCache; 41f8154d17SIngo Weinhold extern ObjectCache* gVnodeCacheObjectCache; 42f8154d17SIngo Weinhold extern ObjectCache* gDeviceCacheObjectCache; 43f8154d17SIngo Weinhold extern ObjectCache* gNullCacheObjectCache; 44f8154d17SIngo Weinhold 45f8154d17SIngo Weinhold 46be7328a9SIngo Weinhold struct VMCachePagesTreeDefinition { 47be7328a9SIngo Weinhold typedef page_num_t KeyType; 48be7328a9SIngo Weinhold typedef vm_page NodeType; 49be7328a9SIngo Weinhold 50be7328a9SIngo Weinhold static page_num_t GetKey(const NodeType* node) 51be7328a9SIngo Weinhold { 52be7328a9SIngo Weinhold return node->cache_offset; 53be7328a9SIngo Weinhold } 54be7328a9SIngo Weinhold 55be7328a9SIngo Weinhold static SplayTreeLink<NodeType>* GetLink(NodeType* node) 56be7328a9SIngo Weinhold { 57be7328a9SIngo Weinhold return &node->cache_link; 58be7328a9SIngo Weinhold } 59be7328a9SIngo Weinhold 60be7328a9SIngo Weinhold static int Compare(page_num_t key, const NodeType* node) 61be7328a9SIngo Weinhold { 62be7328a9SIngo Weinhold return key == node->cache_offset ? 0 63be7328a9SIngo Weinhold : (key < node->cache_offset ? -1 : 1); 64be7328a9SIngo Weinhold } 65be7328a9SIngo Weinhold 66be7328a9SIngo Weinhold static NodeType** GetListLink(NodeType* node) 67be7328a9SIngo Weinhold { 68be7328a9SIngo Weinhold return &node->cache_next; 69be7328a9SIngo Weinhold } 70be7328a9SIngo Weinhold }; 71be7328a9SIngo Weinhold 72be7328a9SIngo Weinhold typedef IteratableSplayTree<VMCachePagesTreeDefinition> VMCachePagesTree; 73be7328a9SIngo Weinhold 746379e53eSIngo Weinhold 75f8154d17SIngo Weinhold struct VMCache : public DoublyLinkedListLinkImpl<VMCache> { 76f8154d17SIngo Weinhold public: 77f8154d17SIngo Weinhold typedef DoublyLinkedList<VMCache> ConsumerList; 78f8154d17SIngo Weinhold 79be7328a9SIngo Weinhold public: 80be7328a9SIngo Weinhold VMCache(); 81be7328a9SIngo Weinhold virtual ~VMCache(); 82be7328a9SIngo Weinhold 83deee8524SIngo Weinhold status_t Init(uint32 cacheType, uint32 allocationFlags); 84be7328a9SIngo Weinhold 85be7328a9SIngo Weinhold virtual void Delete(); 86be7328a9SIngo Weinhold 87355dc6beSIngo Weinhold inline bool Lock(); 88355dc6beSIngo Weinhold inline bool TryLock(); 89355dc6beSIngo Weinhold inline bool SwitchLock(mutex* from); 9077690f28SIngo Weinhold inline bool SwitchFromReadLock(rw_lock* from); 913632eeedSIngo Weinhold void Unlock(bool consumerLocked = false); 92355dc6beSIngo Weinhold inline void AssertLocked(); 93be7328a9SIngo Weinhold 94355dc6beSIngo Weinhold inline void AcquireRefLocked(); 95355dc6beSIngo Weinhold inline void AcquireRef(); 96355dc6beSIngo Weinhold inline void ReleaseRefLocked(); 97355dc6beSIngo Weinhold inline void ReleaseRef(); 983632eeedSIngo Weinhold inline void ReleaseRefAndUnlock( 993632eeedSIngo Weinhold bool consumerLocked = false); 100be7328a9SIngo Weinhold 101cf99b9abSIngo Weinhold inline VMCacheRef* CacheRef() const { return fCacheRef; } 102cf99b9abSIngo Weinhold 103522c2f19SIngo Weinhold void WaitForPageEvents(vm_page* page, uint32 events, 104522c2f19SIngo Weinhold bool relock); 105522c2f19SIngo Weinhold void NotifyPageEvents(vm_page* page, uint32 events) 106522c2f19SIngo Weinhold { if (fPageEventWaiters != NULL) 107522c2f19SIngo Weinhold _NotifyPageEvents(page, events); } 10872382fa6SIngo Weinhold inline void MarkPageUnbusy(vm_page* page); 109522c2f19SIngo Weinhold 110be7328a9SIngo Weinhold vm_page* LookupPage(off_t offset); 111be7328a9SIngo Weinhold void InsertPage(vm_page* page, off_t offset); 112be7328a9SIngo Weinhold void RemovePage(vm_page* page); 113c6657ffeSHamish Morrison void MovePage(vm_page* page, off_t offset); 114eb8dc1ebSIngo Weinhold void MovePage(vm_page* page); 115eb8dc1ebSIngo Weinhold void MoveAllPages(VMCache* fromCache); 116be7328a9SIngo Weinhold 117b9447668SIngo Weinhold inline page_num_t WiredPagesCount() const; 118b9447668SIngo Weinhold inline void IncrementWiredPagesCount(); 119b9447668SIngo Weinhold inline void DecrementWiredPagesCount(); 120b9447668SIngo Weinhold 121d1f280c8SHamish Morrison virtual int32 GuardSize() { return 0; } 122d1f280c8SHamish Morrison 123be7328a9SIngo Weinhold void AddConsumer(VMCache* consumer); 124be7328a9SIngo Weinhold 125be7328a9SIngo Weinhold status_t InsertAreaLocked(VMArea* area); 126be7328a9SIngo Weinhold status_t RemoveArea(VMArea* area); 1272e74d74fSIngo Weinhold void TransferAreas(VMCache* fromCache); 1282e74d74fSIngo Weinhold uint32 CountWritableAreas(VMArea* ignoreArea) const; 129be7328a9SIngo Weinhold 130be7328a9SIngo Weinhold status_t WriteModified(); 131cff6e9e4SIngo Weinhold status_t SetMinimalCommitment(off_t commitment, 132cff6e9e4SIngo Weinhold int priority); 133efeca209SIngo Weinhold virtual status_t Resize(off_t newSize, int priority); 134c6657ffeSHamish Morrison virtual status_t Rebase(off_t newBase, int priority); 135*4e2b49bcSMichael Lotz virtual status_t Adopt(VMCache* source, off_t offset, off_t size, 136*4e2b49bcSMichael Lotz off_t newOffset); 137be7328a9SIngo Weinhold 138be7328a9SIngo Weinhold status_t FlushAndRemoveAllPages(); 139be7328a9SIngo Weinhold 1403632eeedSIngo Weinhold void* UserData() { return fUserData; } 1413632eeedSIngo Weinhold void SetUserData(void* data) { fUserData = data; } 1423632eeedSIngo Weinhold // Settable by the lock owner and valid as 1433632eeedSIngo Weinhold // long as the lock is owned. 1443632eeedSIngo Weinhold 145be7328a9SIngo Weinhold // for debugging only 146be7328a9SIngo Weinhold int32 RefCount() const 147be7328a9SIngo Weinhold { return fRefCount; } 148be7328a9SIngo Weinhold 149be7328a9SIngo Weinhold // backing store operations 150cff6e9e4SIngo Weinhold virtual status_t Commit(off_t size, int priority); 151be7328a9SIngo Weinhold virtual bool HasPage(off_t offset); 152be7328a9SIngo Weinhold 153435c43f5SIngo Weinhold virtual status_t Read(off_t offset, const generic_io_vec *vecs, 1546440406aSIngo Weinhold size_t count, uint32 flags, 155435c43f5SIngo Weinhold generic_size_t *_numBytes); 156435c43f5SIngo Weinhold virtual status_t Write(off_t offset, const generic_io_vec *vecs, 157435c43f5SIngo Weinhold size_t count, uint32 flags, 158435c43f5SIngo Weinhold generic_size_t *_numBytes); 159435c43f5SIngo Weinhold virtual status_t WriteAsync(off_t offset, 160435c43f5SIngo Weinhold const generic_io_vec* vecs, size_t count, 161435c43f5SIngo Weinhold generic_size_t numBytes, uint32 flags, 162be7328a9SIngo Weinhold AsyncIOCallback* callback); 163be7328a9SIngo Weinhold virtual bool CanWritePage(off_t offset); 164be7328a9SIngo Weinhold 165be7328a9SIngo Weinhold virtual int32 MaxPagesPerWrite() const 166be7328a9SIngo Weinhold { return -1; } // no restriction 167be7328a9SIngo Weinhold virtual int32 MaxPagesPerAsyncWrite() const 168be7328a9SIngo Weinhold { return -1; } // no restriction 169be7328a9SIngo Weinhold 170be7328a9SIngo Weinhold virtual status_t Fault(struct VMAddressSpace *aspace, 171be7328a9SIngo Weinhold off_t offset); 172be7328a9SIngo Weinhold 173be7328a9SIngo Weinhold virtual void Merge(VMCache* source); 174be7328a9SIngo Weinhold 175be7328a9SIngo Weinhold virtual status_t AcquireUnreferencedStoreRef(); 176be7328a9SIngo Weinhold virtual void AcquireStoreRef(); 177be7328a9SIngo Weinhold virtual void ReleaseStoreRef(); 178be7328a9SIngo Weinhold 17986875ad9SIngo Weinhold virtual bool DebugHasPage(off_t offset); 18086875ad9SIngo Weinhold vm_page* DebugLookupPage(off_t offset); 18186875ad9SIngo Weinhold 182f8e263c1SIngo Weinhold virtual void Dump(bool showPages) const; 183f8e263c1SIngo Weinhold 184f8154d17SIngo Weinhold protected: 185f8154d17SIngo Weinhold virtual void DeleteObject() = 0; 186f8154d17SIngo Weinhold 187be7328a9SIngo Weinhold public: 1886440406aSIngo Weinhold VMArea* areas; 189f8154d17SIngo Weinhold ConsumerList consumers; 190be7328a9SIngo Weinhold // list of caches that use this cache as a source 191be7328a9SIngo Weinhold VMCachePagesTree pages; 192be7328a9SIngo Weinhold VMCache* source; 193be7328a9SIngo Weinhold off_t virtual_base; 194be7328a9SIngo Weinhold off_t virtual_end; 195be7328a9SIngo Weinhold off_t committed_size; 196be7328a9SIngo Weinhold // TODO: Remove! 197be7328a9SIngo Weinhold uint32 page_count; 198be7328a9SIngo Weinhold uint32 temporary : 1; 199be7328a9SIngo Weinhold uint32 type : 6; 200be7328a9SIngo Weinhold 201be7328a9SIngo Weinhold #if DEBUG_CACHE_LIST 2026440406aSIngo Weinhold VMCache* debug_previous; 2036440406aSIngo Weinhold VMCache* debug_next; 204be7328a9SIngo Weinhold #endif 205be7328a9SIngo Weinhold 206be7328a9SIngo Weinhold private: 207522c2f19SIngo Weinhold struct PageEventWaiter; 2086379e53eSIngo Weinhold friend struct VMCacheRef; 209522c2f19SIngo Weinhold 210522c2f19SIngo Weinhold private: 211522c2f19SIngo Weinhold void _NotifyPageEvents(vm_page* page, uint32 events); 212522c2f19SIngo Weinhold 2136440406aSIngo Weinhold inline bool _IsMergeable() const; 2146440406aSIngo Weinhold 215a0d93d14SIngo Weinhold void _MergeWithOnlyConsumer(); 2166440406aSIngo Weinhold void _RemoveConsumer(VMCache* consumer); 2176440406aSIngo Weinhold 2186440406aSIngo Weinhold private: 219be7328a9SIngo Weinhold int32 fRefCount; 220be7328a9SIngo Weinhold mutex fLock; 221522c2f19SIngo Weinhold PageEventWaiter* fPageEventWaiters; 2223632eeedSIngo Weinhold void* fUserData; 2236379e53eSIngo Weinhold VMCacheRef* fCacheRef; 224b9447668SIngo Weinhold page_num_t fWiredPagesCount; 225be7328a9SIngo Weinhold }; 226be7328a9SIngo Weinhold 227be7328a9SIngo Weinhold 228be7328a9SIngo Weinhold #if DEBUG_CACHE_LIST 229be7328a9SIngo Weinhold extern VMCache* gDebugCacheList; 230be7328a9SIngo Weinhold #endif 231be7328a9SIngo Weinhold 232be7328a9SIngo Weinhold 233be7328a9SIngo Weinhold class VMCacheFactory { 234be7328a9SIngo Weinhold public: 235be7328a9SIngo Weinhold static status_t CreateAnonymousCache(VMCache*& cache, 236be7328a9SIngo Weinhold bool canOvercommit, int32 numPrecommittedPages, 237cff6e9e4SIngo Weinhold int32 numGuardPages, bool swappable, 238cff6e9e4SIngo Weinhold int priority); 239be7328a9SIngo Weinhold static status_t CreateVnodeCache(VMCache*& cache, 240be7328a9SIngo Weinhold struct vnode* vnode); 241be7328a9SIngo Weinhold static status_t CreateDeviceCache(VMCache*& cache, 242be7328a9SIngo Weinhold addr_t baseAddress); 243cff6e9e4SIngo Weinhold static status_t CreateNullCache(int priority, VMCache*& cache); 244be7328a9SIngo Weinhold }; 245be7328a9SIngo Weinhold 246be7328a9SIngo Weinhold 247355dc6beSIngo Weinhold 248355dc6beSIngo Weinhold bool 249355dc6beSIngo Weinhold VMCache::Lock() 250355dc6beSIngo Weinhold { 251355dc6beSIngo Weinhold return mutex_lock(&fLock) == B_OK; 252355dc6beSIngo Weinhold } 253355dc6beSIngo Weinhold 254355dc6beSIngo Weinhold 255355dc6beSIngo Weinhold bool 256355dc6beSIngo Weinhold VMCache::TryLock() 257355dc6beSIngo Weinhold { 258355dc6beSIngo Weinhold return mutex_trylock(&fLock) == B_OK; 259355dc6beSIngo Weinhold } 260355dc6beSIngo Weinhold 261355dc6beSIngo Weinhold 262355dc6beSIngo Weinhold bool 263355dc6beSIngo Weinhold VMCache::SwitchLock(mutex* from) 264355dc6beSIngo Weinhold { 265355dc6beSIngo Weinhold return mutex_switch_lock(from, &fLock) == B_OK; 266355dc6beSIngo Weinhold } 267355dc6beSIngo Weinhold 268355dc6beSIngo Weinhold 26977690f28SIngo Weinhold bool 27077690f28SIngo Weinhold VMCache::SwitchFromReadLock(rw_lock* from) 27177690f28SIngo Weinhold { 27277690f28SIngo Weinhold return mutex_switch_from_read_lock(from, &fLock) == B_OK; 27377690f28SIngo Weinhold } 27477690f28SIngo Weinhold 27577690f28SIngo Weinhold 276355dc6beSIngo Weinhold void 277355dc6beSIngo Weinhold VMCache::AssertLocked() 278355dc6beSIngo Weinhold { 279355dc6beSIngo Weinhold ASSERT_LOCKED_MUTEX(&fLock); 280355dc6beSIngo Weinhold } 281355dc6beSIngo Weinhold 282355dc6beSIngo Weinhold 283355dc6beSIngo Weinhold void 284355dc6beSIngo Weinhold VMCache::AcquireRefLocked() 285355dc6beSIngo Weinhold { 286355dc6beSIngo Weinhold ASSERT_LOCKED_MUTEX(&fLock); 287355dc6beSIngo Weinhold 288355dc6beSIngo Weinhold fRefCount++; 289355dc6beSIngo Weinhold } 290355dc6beSIngo Weinhold 291355dc6beSIngo Weinhold 292355dc6beSIngo Weinhold void 293355dc6beSIngo Weinhold VMCache::AcquireRef() 294355dc6beSIngo Weinhold { 295355dc6beSIngo Weinhold Lock(); 296355dc6beSIngo Weinhold fRefCount++; 297355dc6beSIngo Weinhold Unlock(); 298355dc6beSIngo Weinhold } 299355dc6beSIngo Weinhold 300355dc6beSIngo Weinhold 301355dc6beSIngo Weinhold void 302355dc6beSIngo Weinhold VMCache::ReleaseRefLocked() 303355dc6beSIngo Weinhold { 304355dc6beSIngo Weinhold ASSERT_LOCKED_MUTEX(&fLock); 305355dc6beSIngo Weinhold 306355dc6beSIngo Weinhold fRefCount--; 307355dc6beSIngo Weinhold } 308355dc6beSIngo Weinhold 309355dc6beSIngo Weinhold 310355dc6beSIngo Weinhold void 311355dc6beSIngo Weinhold VMCache::ReleaseRef() 312355dc6beSIngo Weinhold { 313355dc6beSIngo Weinhold Lock(); 314355dc6beSIngo Weinhold fRefCount--; 315355dc6beSIngo Weinhold Unlock(); 316355dc6beSIngo Weinhold } 317355dc6beSIngo Weinhold 318355dc6beSIngo Weinhold 319355dc6beSIngo Weinhold void 3203632eeedSIngo Weinhold VMCache::ReleaseRefAndUnlock(bool consumerLocked) 321355dc6beSIngo Weinhold { 322355dc6beSIngo Weinhold ReleaseRefLocked(); 3233632eeedSIngo Weinhold Unlock(consumerLocked); 324355dc6beSIngo Weinhold } 325355dc6beSIngo Weinhold 326355dc6beSIngo Weinhold 32772382fa6SIngo Weinhold void 32872382fa6SIngo Weinhold VMCache::MarkPageUnbusy(vm_page* page) 32972382fa6SIngo Weinhold { 3304bb4f793SIngo Weinhold ASSERT(page->busy); 33172382fa6SIngo Weinhold page->busy = false; 33272382fa6SIngo Weinhold NotifyPageEvents(page, PAGE_EVENT_NOT_BUSY); 33372382fa6SIngo Weinhold } 33472382fa6SIngo Weinhold 33572382fa6SIngo Weinhold 336b9447668SIngo Weinhold page_num_t 337b9447668SIngo Weinhold VMCache::WiredPagesCount() const 338b9447668SIngo Weinhold { 339b9447668SIngo Weinhold return fWiredPagesCount; 340b9447668SIngo Weinhold } 341b9447668SIngo Weinhold 342b9447668SIngo Weinhold 343b9447668SIngo Weinhold void 344b9447668SIngo Weinhold VMCache::IncrementWiredPagesCount() 345b9447668SIngo Weinhold { 346b9447668SIngo Weinhold ASSERT(fWiredPagesCount < page_count); 347b9447668SIngo Weinhold 348b9447668SIngo Weinhold fWiredPagesCount++; 349b9447668SIngo Weinhold } 350b9447668SIngo Weinhold 351b9447668SIngo Weinhold 352b9447668SIngo Weinhold void 353b9447668SIngo Weinhold VMCache::DecrementWiredPagesCount() 354b9447668SIngo Weinhold { 355b9447668SIngo Weinhold ASSERT(fWiredPagesCount > 0); 356b9447668SIngo Weinhold 357b9447668SIngo Weinhold fWiredPagesCount--; 358b9447668SIngo Weinhold } 359b9447668SIngo Weinhold 360b9447668SIngo Weinhold 361b9447668SIngo Weinhold // vm_page methods implemented here to avoid VMCache.h inclusion in vm_types.h 362b9447668SIngo Weinhold 363b9447668SIngo Weinhold inline void 364b9447668SIngo Weinhold vm_page::IncrementWiredCount() 365b9447668SIngo Weinhold { 366b9447668SIngo Weinhold if (fWiredCount++ == 0) 367b9447668SIngo Weinhold cache_ref->cache->IncrementWiredPagesCount(); 368b9447668SIngo Weinhold } 369b9447668SIngo Weinhold 370b9447668SIngo Weinhold 371b9447668SIngo Weinhold inline void 372b9447668SIngo Weinhold vm_page::DecrementWiredCount() 373b9447668SIngo Weinhold { 3742cdd33d4SMichael Lotz ASSERT(fWiredCount > 0); 3752cdd33d4SMichael Lotz 376b9447668SIngo Weinhold if (--fWiredCount == 0) 377b9447668SIngo Weinhold cache_ref->cache->DecrementWiredPagesCount(); 378b9447668SIngo Weinhold } 379b9447668SIngo Weinhold 380b9447668SIngo Weinhold 381e50cf876SIngo Weinhold #ifdef __cplusplus 382e50cf876SIngo Weinhold extern "C" { 383e50cf876SIngo Weinhold #endif 384e50cf876SIngo Weinhold 385e50cf876SIngo Weinhold status_t vm_cache_init(struct kernel_args *args); 3862e74d74fSIngo Weinhold void vm_cache_init_post_heap(); 387e50cf876SIngo Weinhold struct VMCache *vm_cache_acquire_locked_page_cache(struct vm_page *page, 388e50cf876SIngo Weinhold bool dontWait); 389e50cf876SIngo Weinhold 390e50cf876SIngo Weinhold #ifdef __cplusplus 391e50cf876SIngo Weinhold } 392e50cf876SIngo Weinhold #endif 393e50cf876SIngo Weinhold 394be7328a9SIngo Weinhold 395e50cf876SIngo Weinhold #endif /* _KERNEL_VM_VM_CACHE_H */ 396