xref: /haiku/headers/private/kernel/vm/VMCache.h (revision 435c43f5912b109e7d5cf682865d2061e62fad8c)
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