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