xref: /haiku/headers/private/kernel/vm/VMCache.h (revision 6379e53e2dd7021ba0e35d41c276dfe94c079596)
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 
64*6379e53eSIngo Weinhold 
65be7328a9SIngo Weinhold struct VMCache {
66be7328a9SIngo Weinhold public:
67be7328a9SIngo Weinhold 								VMCache();
68be7328a9SIngo Weinhold 	virtual						~VMCache();
69be7328a9SIngo Weinhold 
70be7328a9SIngo Weinhold 			status_t			Init(uint32 cacheType);
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 
88522c2f19SIngo Weinhold 			void				WaitForPageEvents(vm_page* page, uint32 events,
89522c2f19SIngo Weinhold 									bool relock);
90522c2f19SIngo Weinhold 			void				NotifyPageEvents(vm_page* page, uint32 events)
91522c2f19SIngo Weinhold 									{ if (fPageEventWaiters != NULL)
92522c2f19SIngo Weinhold 										_NotifyPageEvents(page, events); }
93522c2f19SIngo Weinhold 
94be7328a9SIngo Weinhold 			vm_page*			LookupPage(off_t offset);
95be7328a9SIngo Weinhold 			void				InsertPage(vm_page* page, off_t offset);
96be7328a9SIngo Weinhold 			void				RemovePage(vm_page* page);
97eb8dc1ebSIngo Weinhold 			void				MovePage(vm_page* page);
98eb8dc1ebSIngo Weinhold 			void				MoveAllPages(VMCache* fromCache);
99be7328a9SIngo Weinhold 
100be7328a9SIngo Weinhold 			void				AddConsumer(VMCache* consumer);
101be7328a9SIngo Weinhold 
102be7328a9SIngo Weinhold 			status_t			InsertAreaLocked(VMArea* area);
103be7328a9SIngo Weinhold 			status_t			RemoveArea(VMArea* area);
1042e74d74fSIngo Weinhold 			void				TransferAreas(VMCache* fromCache);
1052e74d74fSIngo Weinhold 			uint32				CountWritableAreas(VMArea* ignoreArea) const;
106be7328a9SIngo Weinhold 
107be7328a9SIngo Weinhold 			status_t			WriteModified();
108be7328a9SIngo Weinhold 			status_t			SetMinimalCommitment(off_t commitment);
109be7328a9SIngo Weinhold 			status_t			Resize(off_t newSize);
110be7328a9SIngo Weinhold 
111be7328a9SIngo Weinhold 			status_t			FlushAndRemoveAllPages();
112be7328a9SIngo Weinhold 
1133632eeedSIngo Weinhold 			void*				UserData()	{ return fUserData; }
1143632eeedSIngo Weinhold 			void				SetUserData(void* data)	{ fUserData = data; }
1153632eeedSIngo Weinhold 									// Settable by the lock owner and valid as
1163632eeedSIngo Weinhold 									// long as the lock is owned.
1173632eeedSIngo Weinhold 
118be7328a9SIngo Weinhold 			// for debugging only
119be7328a9SIngo Weinhold 			mutex*				GetLock()
120be7328a9SIngo Weinhold 									{ return &fLock; }
121be7328a9SIngo Weinhold 			int32				RefCount() const
122be7328a9SIngo Weinhold 									{ return fRefCount; }
123be7328a9SIngo Weinhold 
124be7328a9SIngo Weinhold 	// backing store operations
125be7328a9SIngo Weinhold 	virtual	status_t			Commit(off_t size);
126be7328a9SIngo Weinhold 	virtual	bool				HasPage(off_t offset);
127be7328a9SIngo Weinhold 
1286440406aSIngo Weinhold 	virtual	status_t			Read(off_t offset, const iovec *vecs,
1296440406aSIngo Weinhold 									size_t count,uint32 flags,
1306440406aSIngo Weinhold 									size_t *_numBytes);
131be7328a9SIngo Weinhold 	virtual	status_t			Write(off_t offset, const iovec *vecs, size_t count,
132be7328a9SIngo Weinhold 									uint32 flags, size_t *_numBytes);
133be7328a9SIngo Weinhold 	virtual	status_t			WriteAsync(off_t offset, const iovec* vecs,
134be7328a9SIngo Weinhold 									size_t count, size_t numBytes, uint32 flags,
135be7328a9SIngo Weinhold 									AsyncIOCallback* callback);
136be7328a9SIngo Weinhold 	virtual	bool				CanWritePage(off_t offset);
137be7328a9SIngo Weinhold 
138be7328a9SIngo Weinhold 	virtual	int32				MaxPagesPerWrite() const
139be7328a9SIngo Weinhold 									{ return -1; } // no restriction
140be7328a9SIngo Weinhold 	virtual	int32				MaxPagesPerAsyncWrite() const
141be7328a9SIngo Weinhold 									{ return -1; } // no restriction
142be7328a9SIngo Weinhold 
143be7328a9SIngo Weinhold 	virtual	status_t			Fault(struct VMAddressSpace *aspace,
144be7328a9SIngo Weinhold 									off_t offset);
145be7328a9SIngo Weinhold 
146be7328a9SIngo Weinhold 	virtual	void				Merge(VMCache* source);
147be7328a9SIngo Weinhold 
148be7328a9SIngo Weinhold 	virtual	status_t			AcquireUnreferencedStoreRef();
149be7328a9SIngo Weinhold 	virtual	void				AcquireStoreRef();
150be7328a9SIngo Weinhold 	virtual	void				ReleaseStoreRef();
151be7328a9SIngo Weinhold 
152be7328a9SIngo Weinhold public:
1536440406aSIngo Weinhold 			VMArea*				areas;
1546440406aSIngo Weinhold 			list_link			consumer_link;
1556440406aSIngo Weinhold 			list				consumers;
156be7328a9SIngo Weinhold 				// list of caches that use this cache as a source
157be7328a9SIngo Weinhold 			VMCachePagesTree	pages;
158be7328a9SIngo Weinhold 			VMCache*			source;
159be7328a9SIngo Weinhold 			off_t				virtual_base;
160be7328a9SIngo Weinhold 			off_t				virtual_end;
161be7328a9SIngo Weinhold 			off_t				committed_size;
162be7328a9SIngo Weinhold 				// TODO: Remove!
163be7328a9SIngo Weinhold 			uint32				page_count;
164be7328a9SIngo Weinhold 			uint32				temporary : 1;
165be7328a9SIngo Weinhold 			uint32				scan_skip : 1;
166be7328a9SIngo Weinhold 			uint32				type : 6;
167be7328a9SIngo Weinhold 
168be7328a9SIngo Weinhold #if DEBUG_CACHE_LIST
1696440406aSIngo Weinhold 			VMCache*			debug_previous;
1706440406aSIngo Weinhold 			VMCache*			debug_next;
171be7328a9SIngo Weinhold #endif
172be7328a9SIngo Weinhold 
173be7328a9SIngo Weinhold private:
174522c2f19SIngo Weinhold 			struct PageEventWaiter;
175*6379e53eSIngo Weinhold 			friend struct VMCacheRef;
176522c2f19SIngo Weinhold 
177522c2f19SIngo Weinhold private:
178522c2f19SIngo Weinhold 			void				_NotifyPageEvents(vm_page* page, uint32 events);
179522c2f19SIngo Weinhold 
1806440406aSIngo Weinhold 	inline	bool				_IsMergeable() const;
1816440406aSIngo Weinhold 
1823632eeedSIngo Weinhold 			void				_MergeWithOnlyConsumer(bool consumerLocked);
1836440406aSIngo Weinhold 			void				_RemoveConsumer(VMCache* consumer);
1846440406aSIngo Weinhold 
1856440406aSIngo Weinhold private:
186be7328a9SIngo Weinhold 			int32				fRefCount;
187be7328a9SIngo Weinhold 			mutex				fLock;
188522c2f19SIngo Weinhold 			PageEventWaiter*	fPageEventWaiters;
1893632eeedSIngo Weinhold 			void*				fUserData;
190*6379e53eSIngo Weinhold 			VMCacheRef*			fCacheRef;
191be7328a9SIngo Weinhold };
192be7328a9SIngo Weinhold 
193be7328a9SIngo Weinhold 
194be7328a9SIngo Weinhold #if DEBUG_CACHE_LIST
195be7328a9SIngo Weinhold extern VMCache* gDebugCacheList;
196be7328a9SIngo Weinhold #endif
197be7328a9SIngo Weinhold 
198be7328a9SIngo Weinhold 
199be7328a9SIngo Weinhold class VMCacheFactory {
200be7328a9SIngo Weinhold public:
201be7328a9SIngo Weinhold 	static	status_t		CreateAnonymousCache(VMCache*& cache,
202be7328a9SIngo Weinhold 								bool canOvercommit, int32 numPrecommittedPages,
203be7328a9SIngo Weinhold 								int32 numGuardPages, bool swappable);
204be7328a9SIngo Weinhold 	static	status_t		CreateVnodeCache(VMCache*& cache,
205be7328a9SIngo Weinhold 								struct vnode* vnode);
206be7328a9SIngo Weinhold 	static	status_t		CreateDeviceCache(VMCache*& cache,
207be7328a9SIngo Weinhold 								addr_t baseAddress);
208be7328a9SIngo Weinhold 	static	status_t		CreateNullCache(VMCache*& cache);
209be7328a9SIngo Weinhold };
210be7328a9SIngo Weinhold 
211be7328a9SIngo Weinhold 
212355dc6beSIngo Weinhold 
213355dc6beSIngo Weinhold bool
214355dc6beSIngo Weinhold VMCache::Lock()
215355dc6beSIngo Weinhold {
216355dc6beSIngo Weinhold 	return mutex_lock(&fLock) == B_OK;
217355dc6beSIngo Weinhold }
218355dc6beSIngo Weinhold 
219355dc6beSIngo Weinhold 
220355dc6beSIngo Weinhold bool
221355dc6beSIngo Weinhold VMCache::TryLock()
222355dc6beSIngo Weinhold {
223355dc6beSIngo Weinhold 	return mutex_trylock(&fLock) == B_OK;
224355dc6beSIngo Weinhold }
225355dc6beSIngo Weinhold 
226355dc6beSIngo Weinhold 
227355dc6beSIngo Weinhold bool
228355dc6beSIngo Weinhold VMCache::SwitchLock(mutex* from)
229355dc6beSIngo Weinhold {
230355dc6beSIngo Weinhold 	return mutex_switch_lock(from, &fLock) == B_OK;
231355dc6beSIngo Weinhold }
232355dc6beSIngo Weinhold 
233355dc6beSIngo Weinhold 
23477690f28SIngo Weinhold bool
23577690f28SIngo Weinhold VMCache::SwitchFromReadLock(rw_lock* from)
23677690f28SIngo Weinhold {
23777690f28SIngo Weinhold 	return mutex_switch_from_read_lock(from, &fLock) == B_OK;
23877690f28SIngo Weinhold }
23977690f28SIngo Weinhold 
24077690f28SIngo Weinhold 
241355dc6beSIngo Weinhold void
242355dc6beSIngo Weinhold VMCache::AssertLocked()
243355dc6beSIngo Weinhold {
244355dc6beSIngo Weinhold 	ASSERT_LOCKED_MUTEX(&fLock);
245355dc6beSIngo Weinhold }
246355dc6beSIngo Weinhold 
247355dc6beSIngo Weinhold 
248355dc6beSIngo Weinhold void
249355dc6beSIngo Weinhold VMCache::AcquireRefLocked()
250355dc6beSIngo Weinhold {
251355dc6beSIngo Weinhold 	ASSERT_LOCKED_MUTEX(&fLock);
252355dc6beSIngo Weinhold 
253355dc6beSIngo Weinhold 	fRefCount++;
254355dc6beSIngo Weinhold }
255355dc6beSIngo Weinhold 
256355dc6beSIngo Weinhold 
257355dc6beSIngo Weinhold void
258355dc6beSIngo Weinhold VMCache::AcquireRef()
259355dc6beSIngo Weinhold {
260355dc6beSIngo Weinhold 	Lock();
261355dc6beSIngo Weinhold 	fRefCount++;
262355dc6beSIngo Weinhold 	Unlock();
263355dc6beSIngo Weinhold }
264355dc6beSIngo Weinhold 
265355dc6beSIngo Weinhold 
266355dc6beSIngo Weinhold void
267355dc6beSIngo Weinhold VMCache::ReleaseRefLocked()
268355dc6beSIngo Weinhold {
269355dc6beSIngo Weinhold 	ASSERT_LOCKED_MUTEX(&fLock);
270355dc6beSIngo Weinhold 
271355dc6beSIngo Weinhold 	fRefCount--;
272355dc6beSIngo Weinhold }
273355dc6beSIngo Weinhold 
274355dc6beSIngo Weinhold 
275355dc6beSIngo Weinhold void
276355dc6beSIngo Weinhold VMCache::ReleaseRef()
277355dc6beSIngo Weinhold {
278355dc6beSIngo Weinhold 	Lock();
279355dc6beSIngo Weinhold 	fRefCount--;
280355dc6beSIngo Weinhold 	Unlock();
281355dc6beSIngo Weinhold }
282355dc6beSIngo Weinhold 
283355dc6beSIngo Weinhold 
284355dc6beSIngo Weinhold void
2853632eeedSIngo Weinhold VMCache::ReleaseRefAndUnlock(bool consumerLocked)
286355dc6beSIngo Weinhold {
287355dc6beSIngo Weinhold 	ReleaseRefLocked();
2883632eeedSIngo Weinhold 	Unlock(consumerLocked);
289355dc6beSIngo Weinhold }
290355dc6beSIngo Weinhold 
291355dc6beSIngo Weinhold 
292e50cf876SIngo Weinhold #ifdef __cplusplus
293e50cf876SIngo Weinhold extern "C" {
294e50cf876SIngo Weinhold #endif
295e50cf876SIngo Weinhold 
296e50cf876SIngo Weinhold status_t vm_cache_init(struct kernel_args *args);
2972e74d74fSIngo Weinhold void vm_cache_init_post_heap();
298e50cf876SIngo Weinhold struct VMCache *vm_cache_acquire_locked_page_cache(struct vm_page *page,
299e50cf876SIngo Weinhold 	bool dontWait);
300e50cf876SIngo Weinhold 
301e50cf876SIngo Weinhold #ifdef __cplusplus
302e50cf876SIngo Weinhold }
303e50cf876SIngo Weinhold #endif
304e50cf876SIngo Weinhold 
305be7328a9SIngo Weinhold 
306e50cf876SIngo Weinhold #endif	/* _KERNEL_VM_VM_CACHE_H */
307