2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
9 #include <fs_interface.h>
11 #include <util/DoublyLinkedList.h>
12 #include <util/list.h>
18 struct advisory_locking
;
19 struct file_descriptor
;
23 typedef struct vnode Vnode
;
26 struct vnode
: fs_vnode
, DoublyLinkedListLinkImpl
<vnode
> {
29 struct fs_mount
* mount
;
30 struct vnode
* covered_by
;
32 struct advisory_locking
* advisory_locking
;
33 struct file_descriptor
* mandatory_locked_by
;
34 list_link unused_link
;
40 inline bool IsBusy() const;
41 inline void SetBusy(bool busy
);
43 inline bool IsRemoved() const;
44 inline void SetRemoved(bool removed
);
46 inline bool IsUnpublished() const;
47 inline void SetUnpublished(bool unpublished
);
49 inline bool IsUnused() const;
50 inline void SetUnused(bool unused
);
52 inline bool IsHot() const;
53 inline void SetHot(bool hot
);
55 // setter requires sVnodeLock write-locked, getter is lockless
56 inline bool IsCovered() const;
57 inline void SetCovered(bool covered
);
59 // setter requires sVnodeLock write-locked, getter is lockless
60 inline bool IsCovering() const;
61 inline void SetCovering(bool covering
);
63 inline uint32
Type() const;
64 inline void SetType(uint32 type
);
69 static void StaticInit();
72 static const uint32 kFlagsLocked
= 0x00000001;
73 static const uint32 kFlagsWaitingLocker
= 0x00000002;
74 static const uint32 kFlagsBusy
= 0x00000004;
75 static const uint32 kFlagsRemoved
= 0x00000008;
76 static const uint32 kFlagsUnpublished
= 0x00000010;
77 static const uint32 kFlagsUnused
= 0x00000020;
78 static const uint32 kFlagsHot
= 0x00000040;
79 static const uint32 kFlagsCovered
= 0x00000080;
80 static const uint32 kFlagsCovering
= 0x00000100;
81 static const uint32 kFlagsType
= 0xfffff000;
83 static const uint32 kBucketCount
= 32;
85 struct LockWaiter
: DoublyLinkedListLinkImpl
<LockWaiter
> {
91 typedef DoublyLinkedList
<LockWaiter
> LockWaiterList
;
95 LockWaiterList waiters
;
101 inline Bucket
& _Bucket() const;
104 void _WakeUpLocker();
109 static Bucket sBuckets
[kBucketCount
];
114 vnode::IsBusy() const
116 return (fFlags
& kFlagsBusy
) != 0;
121 vnode::SetBusy(bool busy
)
124 atomic_or(&fFlags
, kFlagsBusy
);
126 atomic_and(&fFlags
, ~kFlagsBusy
);
131 vnode::IsRemoved() const
133 return (fFlags
& kFlagsRemoved
) != 0;
138 vnode::SetRemoved(bool removed
)
141 atomic_or(&fFlags
, kFlagsRemoved
);
143 atomic_and(&fFlags
, ~kFlagsRemoved
);
148 vnode::IsUnpublished() const
150 return (fFlags
& kFlagsUnpublished
) != 0;
155 vnode::SetUnpublished(bool unpublished
)
158 atomic_or(&fFlags
, kFlagsUnpublished
);
160 atomic_and(&fFlags
, ~kFlagsUnpublished
);
165 vnode::IsUnused() const
167 return (fFlags
& kFlagsUnused
) != 0;
172 vnode::SetUnused(bool unused
)
175 atomic_or(&fFlags
, kFlagsUnused
);
177 atomic_and(&fFlags
, ~kFlagsUnused
);
184 return (fFlags
& kFlagsHot
) != 0;
189 vnode::SetHot(bool hot
)
192 atomic_or(&fFlags
, kFlagsHot
);
194 atomic_and(&fFlags
, ~kFlagsHot
);
199 vnode::IsCovered() const
201 return (fFlags
& kFlagsCovered
) != 0;
206 vnode::SetCovered(bool covered
)
209 atomic_or(&fFlags
, kFlagsCovered
);
211 atomic_and(&fFlags
, ~kFlagsCovered
);
216 vnode::IsCovering() const
218 return (fFlags
& kFlagsCovering
) != 0;
223 vnode::SetCovering(bool covering
)
226 atomic_or(&fFlags
, kFlagsCovering
);
228 atomic_and(&fFlags
, ~kFlagsCovering
);
235 return (uint32
)fFlags
& kFlagsType
;
240 vnode::SetType(uint32 type
)
242 atomic_and(&fFlags
, ~kFlagsType
);
243 atomic_or(&fFlags
, type
& kFlagsType
);
248 The caller must hold sVnodeLock (at least read locked) and must continue to
249 hold it until calling Unlock(). After acquiring the lock the caller is
250 allowed to write access the vnode's mutable fields, if it hasn't been marked
251 busy by someone else.
252 Due to the condition of holding sVnodeLock at least read locked, write
253 locking it grants the same write access permission to *any* vnode.
255 The vnode's lock should be held only for a short time. It can be held over
258 \return Always \c true.
263 if ((atomic_or(&fFlags
, kFlagsLocked
)
264 & (kFlagsLocked
| kFlagsWaitingLocker
)) != 0) {
274 if ((atomic_and(&fFlags
, ~kFlagsLocked
) & kFlagsWaitingLocker
) != 0)
280 vnode::_Bucket() const
282 return sBuckets
[((addr_t
)this / 64) % kBucketCount
];
283 // The vnode structure is somewhat larger than 64 bytes (on 32 bit
284 // archs), so subsequently allocated vnodes fall into different
285 // buckets. How exactly the vnodes are distributed depends on the
286 // allocator -- a dedicated slab would be perfect.