xref: /haiku/src/system/kernel/fs/Vnode.h (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 #ifndef VNODE_H
6 #define VNODE_H
7 
8 
9 #include <fs_interface.h>
10 
11 #include <util/DoublyLinkedList.h>
12 #include <util/list.h>
13 
14 #include <lock.h>
15 #include <thread.h>
16 
17 
18 struct advisory_locking;
19 struct file_descriptor;
20 struct fs_mount;
21 struct VMCache;
22 
23 typedef struct vnode Vnode;
24 
25 
26 struct vnode : fs_vnode, DoublyLinkedListLinkImpl<vnode> {
27 			struct vnode*		next;
28 			VMCache*			cache;
29 			struct fs_mount*	mount;
30 			struct vnode*		covered_by;
31 			struct advisory_locking* advisory_locking;
32 			struct file_descriptor* mandatory_locked_by;
33 			list_link			unused_link;
34 			ino_t				id;
35 			dev_t				device;
36 			int32				ref_count;
37 
38 public:
39 	inline	bool				IsBusy() const;
40 	inline	void				SetBusy(bool busy);
41 
42 	inline	bool				IsRemoved() const;
43 	inline	void				SetRemoved(bool removed);
44 
45 	inline	bool				IsUnpublished() const;
46 	inline	void				SetUnpublished(bool unpublished);
47 
48 	inline	bool				IsUnused() const;
49 	inline	void				SetUnused(bool unused);
50 
51 	inline	bool				IsHot() const;
52 	inline	void				SetHot(bool hot);
53 
54 	inline	uint32				Type() const;
55 	inline	void				SetType(uint32 type);
56 
57 	inline	bool				Lock();
58 	inline	void				Unlock();
59 
60 	static	void				StaticInit();
61 
62 private:
63 	static	const uint32		kFlagsLocked		= 0x00000001;
64 	static	const uint32		kFlagsWaitingLocker	= 0x00000002;
65 	static	const uint32		kFlagsBusy			= 0x00000004;
66 	static	const uint32		kFlagsRemoved		= 0x00000008;
67 	static	const uint32		kFlagsUnpublished	= 0x00000010;
68 	static	const uint32		kFlagsUnused		= 0x00000020;
69 	static	const uint32		kFlagsHot			= 0x00000040;
70 	static	const uint32		kFlagsType			= 0xfffff000;
71 
72 	static	const uint32		kBucketCount		 = 32;
73 
74 			struct LockWaiter : DoublyLinkedListLinkImpl<LockWaiter> {
75 				LockWaiter*		next;
76 				struct thread*	thread;
77 				struct vnode*	vnode;
78 			};
79 
80 			typedef DoublyLinkedList<LockWaiter> LockWaiterList;
81 
82 			struct Bucket {
83 				mutex			lock;
84 				LockWaiterList	waiters;
85 
86 				Bucket();
87 			};
88 
89 private:
90 	inline	Bucket&				_Bucket() const;
91 
92 			void				_WaitForLock();
93 			void				_WakeUpLocker();
94 
95 private:
96 			vint32				fFlags;
97 
98 	static	Bucket				sBuckets[kBucketCount];
99 };
100 
101 
102 bool
103 vnode::IsBusy() const
104 {
105 	return (fFlags & kFlagsBusy) != 0;
106 }
107 
108 
109 void
110 vnode::SetBusy(bool busy)
111 {
112 	if (busy)
113 		atomic_or(&fFlags, kFlagsBusy);
114 	else
115 		atomic_and(&fFlags, ~kFlagsBusy);
116 }
117 
118 
119 bool
120 vnode::IsRemoved() const
121 {
122 	return (fFlags & kFlagsRemoved) != 0;
123 }
124 
125 
126 void
127 vnode::SetRemoved(bool removed)
128 {
129 	if (removed)
130 		atomic_or(&fFlags, kFlagsRemoved);
131 	else
132 		atomic_and(&fFlags, ~kFlagsRemoved);
133 }
134 
135 
136 bool
137 vnode::IsUnpublished() const
138 {
139 	return (fFlags & kFlagsUnpublished) != 0;
140 }
141 
142 
143 void
144 vnode::SetUnpublished(bool unpublished)
145 {
146 	if (unpublished)
147 		atomic_or(&fFlags, kFlagsUnpublished);
148 	else
149 		atomic_and(&fFlags, ~kFlagsUnpublished);
150 }
151 
152 
153 bool
154 vnode::IsUnused() const
155 {
156 	return (fFlags & kFlagsUnused) != 0;
157 }
158 
159 
160 void
161 vnode::SetUnused(bool unused)
162 {
163 	if (unused)
164 		atomic_or(&fFlags, kFlagsUnused);
165 	else
166 		atomic_and(&fFlags, ~kFlagsUnused);
167 }
168 
169 
170 bool
171 vnode::IsHot() const
172 {
173 	return (fFlags & kFlagsHot) != 0;
174 }
175 
176 
177 void
178 vnode::SetHot(bool hot)
179 {
180 	if (hot)
181 		atomic_or(&fFlags, kFlagsHot);
182 	else
183 		atomic_and(&fFlags, ~kFlagsHot);
184 }
185 
186 
187 uint32
188 vnode::Type() const
189 {
190 	return (uint32)fFlags & kFlagsType;
191 }
192 
193 
194 void
195 vnode::SetType(uint32 type)
196 {
197 	atomic_and(&fFlags, ~kFlagsType);
198 	atomic_or(&fFlags, type & kFlagsType);
199 }
200 
201 
202 /*!	Locks the vnode.
203 	The caller must hold sVnodeLock (at least read locked) and must continue to
204 	hold it until calling Unlock(). After acquiring the lock the caller is
205 	allowed to write access the vnode's mutable fields, if it hasn't been marked
206 	busy by someone else.
207 	Due to the condition of holding sVnodeLock at least read locked, write
208 	locking it grants the same write access permission to *any* vnode.
209 
210 	The vnode's lock should be held only for a short time. It can be held over
211 	sUnusedVnodesLock.
212 
213 	\return Always \c true.
214 */
215 bool
216 vnode::Lock()
217 {
218 	if ((atomic_or(&fFlags, kFlagsLocked)
219 			& (kFlagsLocked | kFlagsWaitingLocker)) != 0) {
220 		_WaitForLock();
221 	}
222 
223 	return true;
224 }
225 
226 void
227 vnode::Unlock()
228 {
229 	if ((atomic_and(&fFlags, ~kFlagsLocked) & kFlagsWaitingLocker) != 0)
230 		_WakeUpLocker();
231 }
232 
233 
234 vnode::Bucket&
235 vnode::_Bucket() const
236 {
237 	return sBuckets[((addr_t)this / 64) % kBucketCount];
238 		// The vnode structure is somewhat larger than 64 bytes (on 32 bit
239 		// archs), so subsequently allocated vnodes fall into different
240 		// buckets. How exactly the vnodes are distributed depends on the
241 		// allocator -- a dedicated slab would be perfect.
242 }
243 
244 
245 #endif	// VNODE_H
246