1/* 2 * Copyright 2009-2011, 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 18struct advisory_locking; 19struct file_descriptor; 20struct fs_mount; 21struct VMCache; 22 23typedef struct vnode Vnode; 24 25 26struct vnode : fs_vnode, DoublyLinkedListLinkImpl<vnode> { 27 struct vnode* next; 28 VMCache* cache; 29 struct fs_mount* mount; 30 struct vnode* covered_by; 31 struct vnode* covers; 32 struct advisory_locking* advisory_locking; 33 struct file_descriptor* mandatory_locked_by; 34 list_link unused_link; 35 ino_t id; 36 dev_t device; 37 int32 ref_count; 38 39public: 40 inline bool IsBusy() const; 41 inline void SetBusy(bool busy); 42 43 inline bool IsRemoved() const; 44 inline void SetRemoved(bool removed); 45 46 inline bool IsUnpublished() const; 47 inline void SetUnpublished(bool unpublished); 48 49 inline bool IsUnused() const; 50 inline void SetUnused(bool unused); 51 52 inline bool IsHot() const; 53 inline void SetHot(bool hot); 54 55 // setter requires sVnodeLock write-locked, getter is lockless 56 inline bool IsCovered() const; 57 inline void SetCovered(bool covered); 58 59 // setter requires sVnodeLock write-locked, getter is lockless 60 inline bool IsCovering() const; 61 inline void SetCovering(bool covering); 62 63 inline uint32 Type() const; 64 inline void SetType(uint32 type); 65 66 inline bool Lock(); 67 inline void Unlock(); 68 69 static void StaticInit(); 70 71private: 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; 82 83 static const uint32 kBucketCount = 32; 84 85 struct LockWaiter : DoublyLinkedListLinkImpl<LockWaiter> { 86 LockWaiter* next; 87 Thread* thread; 88 struct vnode* vnode; 89 }; 90 91 typedef DoublyLinkedList<LockWaiter> LockWaiterList; 92 93 struct Bucket { 94 mutex lock; 95 LockWaiterList waiters; 96 97 Bucket(); 98 }; 99 100private: 101 inline Bucket& _Bucket() const; 102 103 void _WaitForLock(); 104 void _WakeUpLocker(); 105 106private: 107 int32 fFlags; 108 109 static Bucket sBuckets[kBucketCount]; 110}; 111 112 113bool 114vnode::IsBusy() const 115{ 116 return (fFlags & kFlagsBusy) != 0; 117} 118 119 120void 121vnode::SetBusy(bool busy) 122{ 123 if (busy) 124 atomic_or(&fFlags, kFlagsBusy); 125 else 126 atomic_and(&fFlags, ~kFlagsBusy); 127} 128 129 130bool 131vnode::IsRemoved() const 132{ 133 return (fFlags & kFlagsRemoved) != 0; 134} 135 136 137void 138vnode::SetRemoved(bool removed) 139{ 140 if (removed) 141 atomic_or(&fFlags, kFlagsRemoved); 142 else 143 atomic_and(&fFlags, ~kFlagsRemoved); 144} 145 146 147bool 148vnode::IsUnpublished() const 149{ 150 return (fFlags & kFlagsUnpublished) != 0; 151} 152 153 154void 155vnode::SetUnpublished(bool unpublished) 156{ 157 if (unpublished) 158 atomic_or(&fFlags, kFlagsUnpublished); 159 else 160 atomic_and(&fFlags, ~kFlagsUnpublished); 161} 162 163 164bool 165vnode::IsUnused() const 166{ 167 return (fFlags & kFlagsUnused) != 0; 168} 169 170 171void 172vnode::SetUnused(bool unused) 173{ 174 if (unused) 175 atomic_or(&fFlags, kFlagsUnused); 176 else 177 atomic_and(&fFlags, ~kFlagsUnused); 178} 179 180 181bool 182vnode::IsHot() const 183{ 184 return (fFlags & kFlagsHot) != 0; 185} 186 187 188void 189vnode::SetHot(bool hot) 190{ 191 if (hot) 192 atomic_or(&fFlags, kFlagsHot); 193 else 194 atomic_and(&fFlags, ~kFlagsHot); 195} 196 197 198bool 199vnode::IsCovered() const 200{ 201 return (fFlags & kFlagsCovered) != 0; 202} 203 204 205void 206vnode::SetCovered(bool covered) 207{ 208 if (covered) 209 atomic_or(&fFlags, kFlagsCovered); 210 else 211 atomic_and(&fFlags, ~kFlagsCovered); 212} 213 214 215bool 216vnode::IsCovering() const 217{ 218 return (fFlags & kFlagsCovering) != 0; 219} 220 221 222void 223vnode::SetCovering(bool covering) 224{ 225 if (covering) 226 atomic_or(&fFlags, kFlagsCovering); 227 else 228 atomic_and(&fFlags, ~kFlagsCovering); 229} 230 231 232uint32 233vnode::Type() const 234{ 235 return (uint32)fFlags & kFlagsType; 236} 237 238 239void 240vnode::SetType(uint32 type) 241{ 242 atomic_and(&fFlags, ~kFlagsType); 243 atomic_or(&fFlags, type & kFlagsType); 244} 245 246 247/*! Locks the vnode. 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. 254 255 The vnode's lock should be held only for a short time. It can be held over 256 sUnusedVnodesLock. 257 258 \return Always \c true. 259*/ 260bool 261vnode::Lock() 262{ 263 if ((atomic_or(&fFlags, kFlagsLocked) 264 & (kFlagsLocked | kFlagsWaitingLocker)) != 0) { 265 _WaitForLock(); 266 } 267 268 return true; 269} 270 271void 272vnode::Unlock() 273{ 274 if ((atomic_and(&fFlags, ~kFlagsLocked) & kFlagsWaitingLocker) != 0) 275 _WakeUpLocker(); 276} 277 278 279vnode::Bucket& 280vnode::_Bucket() const 281{ 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. 287} 288 289 290#endif // VNODE_H 291