18ccbb781SIngo Weinhold /* 24535495dSIngo Weinhold * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 38ccbb781SIngo Weinhold * Distributed under the terms of the MIT License. 48ccbb781SIngo Weinhold */ 58ccbb781SIngo Weinhold #ifndef VNODE_H 68ccbb781SIngo Weinhold #define VNODE_H 78ccbb781SIngo Weinhold 88ccbb781SIngo Weinhold 98ccbb781SIngo Weinhold #include <fs_interface.h> 108ccbb781SIngo Weinhold 118ccbb781SIngo Weinhold #include <util/DoublyLinkedList.h> 128ccbb781SIngo Weinhold #include <util/list.h> 138ccbb781SIngo Weinhold 148ccbb781SIngo Weinhold #include <lock.h> 158ccbb781SIngo Weinhold #include <thread.h> 168ccbb781SIngo Weinhold 178ccbb781SIngo Weinhold 188ccbb781SIngo Weinhold struct advisory_locking; 198ccbb781SIngo Weinhold struct file_descriptor; 208ccbb781SIngo Weinhold struct fs_mount; 218ccbb781SIngo Weinhold struct VMCache; 228ccbb781SIngo Weinhold 238ccbb781SIngo Weinhold typedef struct vnode Vnode; 248ccbb781SIngo Weinhold 258ccbb781SIngo Weinhold 268ccbb781SIngo Weinhold struct vnode : fs_vnode, DoublyLinkedListLinkImpl<vnode> { 278ccbb781SIngo Weinhold struct vnode* next; 288ccbb781SIngo Weinhold VMCache* cache; 298ccbb781SIngo Weinhold struct fs_mount* mount; 308ccbb781SIngo Weinhold struct vnode* covered_by; 31*02be66caSIngo Weinhold struct vnode* covers; 328ccbb781SIngo Weinhold struct advisory_locking* advisory_locking; 338ccbb781SIngo Weinhold struct file_descriptor* mandatory_locked_by; 348ccbb781SIngo Weinhold list_link unused_link; 358ccbb781SIngo Weinhold ino_t id; 368ccbb781SIngo Weinhold dev_t device; 378ccbb781SIngo Weinhold int32 ref_count; 388ccbb781SIngo Weinhold 398ccbb781SIngo Weinhold public: 408ccbb781SIngo Weinhold inline bool IsBusy() const; 418ccbb781SIngo Weinhold inline void SetBusy(bool busy); 428ccbb781SIngo Weinhold 438ccbb781SIngo Weinhold inline bool IsRemoved() const; 448ccbb781SIngo Weinhold inline void SetRemoved(bool removed); 458ccbb781SIngo Weinhold 468ccbb781SIngo Weinhold inline bool IsUnpublished() const; 478ccbb781SIngo Weinhold inline void SetUnpublished(bool unpublished); 488ccbb781SIngo Weinhold 4954848900SIngo Weinhold inline bool IsUnused() const; 5054848900SIngo Weinhold inline void SetUnused(bool unused); 5154848900SIngo Weinhold 5254848900SIngo Weinhold inline bool IsHot() const; 5354848900SIngo Weinhold inline void SetHot(bool hot); 5454848900SIngo Weinhold 558ccbb781SIngo Weinhold inline uint32 Type() const; 568ccbb781SIngo Weinhold inline void SetType(uint32 type); 578ccbb781SIngo Weinhold 588ccbb781SIngo Weinhold inline bool Lock(); 598ccbb781SIngo Weinhold inline void Unlock(); 608ccbb781SIngo Weinhold 618ccbb781SIngo Weinhold static void StaticInit(); 628ccbb781SIngo Weinhold 638ccbb781SIngo Weinhold private: 648ccbb781SIngo Weinhold static const uint32 kFlagsLocked = 0x00000001; 658ccbb781SIngo Weinhold static const uint32 kFlagsWaitingLocker = 0x00000002; 668ccbb781SIngo Weinhold static const uint32 kFlagsBusy = 0x00000004; 678ccbb781SIngo Weinhold static const uint32 kFlagsRemoved = 0x00000008; 688ccbb781SIngo Weinhold static const uint32 kFlagsUnpublished = 0x00000010; 6954848900SIngo Weinhold static const uint32 kFlagsUnused = 0x00000020; 7054848900SIngo Weinhold static const uint32 kFlagsHot = 0x00000040; 718ccbb781SIngo Weinhold static const uint32 kFlagsType = 0xfffff000; 728ccbb781SIngo Weinhold 738ccbb781SIngo Weinhold static const uint32 kBucketCount = 32; 748ccbb781SIngo Weinhold 758ccbb781SIngo Weinhold struct LockWaiter : DoublyLinkedListLinkImpl<LockWaiter> { 768ccbb781SIngo Weinhold LockWaiter* next; 774535495dSIngo Weinhold Thread* thread; 788ccbb781SIngo Weinhold struct vnode* vnode; 798ccbb781SIngo Weinhold }; 808ccbb781SIngo Weinhold 818ccbb781SIngo Weinhold typedef DoublyLinkedList<LockWaiter> LockWaiterList; 828ccbb781SIngo Weinhold 838ccbb781SIngo Weinhold struct Bucket { 848ccbb781SIngo Weinhold mutex lock; 858ccbb781SIngo Weinhold LockWaiterList waiters; 868ccbb781SIngo Weinhold 878ccbb781SIngo Weinhold Bucket(); 888ccbb781SIngo Weinhold }; 898ccbb781SIngo Weinhold 908ccbb781SIngo Weinhold private: 918ccbb781SIngo Weinhold inline Bucket& _Bucket() const; 928ccbb781SIngo Weinhold 938ccbb781SIngo Weinhold void _WaitForLock(); 948ccbb781SIngo Weinhold void _WakeUpLocker(); 958ccbb781SIngo Weinhold 968ccbb781SIngo Weinhold private: 978ccbb781SIngo Weinhold vint32 fFlags; 988ccbb781SIngo Weinhold 998ccbb781SIngo Weinhold static Bucket sBuckets[kBucketCount]; 1008ccbb781SIngo Weinhold }; 1018ccbb781SIngo Weinhold 1028ccbb781SIngo Weinhold 1038ccbb781SIngo Weinhold bool 1048ccbb781SIngo Weinhold vnode::IsBusy() const 1058ccbb781SIngo Weinhold { 1068ccbb781SIngo Weinhold return (fFlags & kFlagsBusy) != 0; 1078ccbb781SIngo Weinhold } 1088ccbb781SIngo Weinhold 1098ccbb781SIngo Weinhold 1108ccbb781SIngo Weinhold void 1118ccbb781SIngo Weinhold vnode::SetBusy(bool busy) 1128ccbb781SIngo Weinhold { 1138ccbb781SIngo Weinhold if (busy) 1148ccbb781SIngo Weinhold atomic_or(&fFlags, kFlagsBusy); 1158ccbb781SIngo Weinhold else 1168ccbb781SIngo Weinhold atomic_and(&fFlags, ~kFlagsBusy); 1178ccbb781SIngo Weinhold } 1188ccbb781SIngo Weinhold 1198ccbb781SIngo Weinhold 1208ccbb781SIngo Weinhold bool 1218ccbb781SIngo Weinhold vnode::IsRemoved() const 1228ccbb781SIngo Weinhold { 1238ccbb781SIngo Weinhold return (fFlags & kFlagsRemoved) != 0; 1248ccbb781SIngo Weinhold } 1258ccbb781SIngo Weinhold 1268ccbb781SIngo Weinhold 1278ccbb781SIngo Weinhold void 1288ccbb781SIngo Weinhold vnode::SetRemoved(bool removed) 1298ccbb781SIngo Weinhold { 1308ccbb781SIngo Weinhold if (removed) 1318ccbb781SIngo Weinhold atomic_or(&fFlags, kFlagsRemoved); 1328ccbb781SIngo Weinhold else 1338ccbb781SIngo Weinhold atomic_and(&fFlags, ~kFlagsRemoved); 1348ccbb781SIngo Weinhold } 1358ccbb781SIngo Weinhold 1368ccbb781SIngo Weinhold 1378ccbb781SIngo Weinhold bool 1388ccbb781SIngo Weinhold vnode::IsUnpublished() const 1398ccbb781SIngo Weinhold { 1408ccbb781SIngo Weinhold return (fFlags & kFlagsUnpublished) != 0; 1418ccbb781SIngo Weinhold } 1428ccbb781SIngo Weinhold 1438ccbb781SIngo Weinhold 1448ccbb781SIngo Weinhold void 1458ccbb781SIngo Weinhold vnode::SetUnpublished(bool unpublished) 1468ccbb781SIngo Weinhold { 1478ccbb781SIngo Weinhold if (unpublished) 1488ccbb781SIngo Weinhold atomic_or(&fFlags, kFlagsUnpublished); 1498ccbb781SIngo Weinhold else 1508ccbb781SIngo Weinhold atomic_and(&fFlags, ~kFlagsUnpublished); 1518ccbb781SIngo Weinhold } 1528ccbb781SIngo Weinhold 1538ccbb781SIngo Weinhold 15454848900SIngo Weinhold bool 15554848900SIngo Weinhold vnode::IsUnused() const 15654848900SIngo Weinhold { 15754848900SIngo Weinhold return (fFlags & kFlagsUnused) != 0; 15854848900SIngo Weinhold } 15954848900SIngo Weinhold 16054848900SIngo Weinhold 16154848900SIngo Weinhold void 16254848900SIngo Weinhold vnode::SetUnused(bool unused) 16354848900SIngo Weinhold { 16454848900SIngo Weinhold if (unused) 16554848900SIngo Weinhold atomic_or(&fFlags, kFlagsUnused); 16654848900SIngo Weinhold else 16754848900SIngo Weinhold atomic_and(&fFlags, ~kFlagsUnused); 16854848900SIngo Weinhold } 16954848900SIngo Weinhold 17054848900SIngo Weinhold 17154848900SIngo Weinhold bool 17254848900SIngo Weinhold vnode::IsHot() const 17354848900SIngo Weinhold { 17454848900SIngo Weinhold return (fFlags & kFlagsHot) != 0; 17554848900SIngo Weinhold } 17654848900SIngo Weinhold 17754848900SIngo Weinhold 17854848900SIngo Weinhold void 17954848900SIngo Weinhold vnode::SetHot(bool hot) 18054848900SIngo Weinhold { 18154848900SIngo Weinhold if (hot) 18254848900SIngo Weinhold atomic_or(&fFlags, kFlagsHot); 18354848900SIngo Weinhold else 18454848900SIngo Weinhold atomic_and(&fFlags, ~kFlagsHot); 18554848900SIngo Weinhold } 18654848900SIngo Weinhold 18754848900SIngo Weinhold 1888ccbb781SIngo Weinhold uint32 1898ccbb781SIngo Weinhold vnode::Type() const 1908ccbb781SIngo Weinhold { 1918ccbb781SIngo Weinhold return (uint32)fFlags & kFlagsType; 1928ccbb781SIngo Weinhold } 1938ccbb781SIngo Weinhold 1948ccbb781SIngo Weinhold 1958ccbb781SIngo Weinhold void 1968ccbb781SIngo Weinhold vnode::SetType(uint32 type) 1978ccbb781SIngo Weinhold { 1988ccbb781SIngo Weinhold atomic_and(&fFlags, ~kFlagsType); 1998ccbb781SIngo Weinhold atomic_or(&fFlags, type & kFlagsType); 2008ccbb781SIngo Weinhold } 2018ccbb781SIngo Weinhold 2028ccbb781SIngo Weinhold 2038ccbb781SIngo Weinhold /*! Locks the vnode. 2048ccbb781SIngo Weinhold The caller must hold sVnodeLock (at least read locked) and must continue to 2058ccbb781SIngo Weinhold hold it until calling Unlock(). After acquiring the lock the caller is 2068ccbb781SIngo Weinhold allowed to write access the vnode's mutable fields, if it hasn't been marked 2078ccbb781SIngo Weinhold busy by someone else. 2088ccbb781SIngo Weinhold Due to the condition of holding sVnodeLock at least read locked, write 2098ccbb781SIngo Weinhold locking it grants the same write access permission to *any* vnode. 2108ccbb781SIngo Weinhold 2118ccbb781SIngo Weinhold The vnode's lock should be held only for a short time. It can be held over 2128ccbb781SIngo Weinhold sUnusedVnodesLock. 2138ccbb781SIngo Weinhold 2148ccbb781SIngo Weinhold \return Always \c true. 2158ccbb781SIngo Weinhold */ 2168ccbb781SIngo Weinhold bool 2178ccbb781SIngo Weinhold vnode::Lock() 2188ccbb781SIngo Weinhold { 2198ccbb781SIngo Weinhold if ((atomic_or(&fFlags, kFlagsLocked) 2208ccbb781SIngo Weinhold & (kFlagsLocked | kFlagsWaitingLocker)) != 0) { 2218ccbb781SIngo Weinhold _WaitForLock(); 2228ccbb781SIngo Weinhold } 2238ccbb781SIngo Weinhold 2248ccbb781SIngo Weinhold return true; 2258ccbb781SIngo Weinhold } 2268ccbb781SIngo Weinhold 2278ccbb781SIngo Weinhold void 2288ccbb781SIngo Weinhold vnode::Unlock() 2298ccbb781SIngo Weinhold { 2308ccbb781SIngo Weinhold if ((atomic_and(&fFlags, ~kFlagsLocked) & kFlagsWaitingLocker) != 0) 2318ccbb781SIngo Weinhold _WakeUpLocker(); 2328ccbb781SIngo Weinhold } 2338ccbb781SIngo Weinhold 2348ccbb781SIngo Weinhold 2358ccbb781SIngo Weinhold vnode::Bucket& 2368ccbb781SIngo Weinhold vnode::_Bucket() const 2378ccbb781SIngo Weinhold { 2388ccbb781SIngo Weinhold return sBuckets[((addr_t)this / 64) % kBucketCount]; 2398ccbb781SIngo Weinhold // The vnode structure is somewhat larger than 64 bytes (on 32 bit 2408ccbb781SIngo Weinhold // archs), so subsequently allocated vnodes fall into different 2418ccbb781SIngo Weinhold // buckets. How exactly the vnodes are distributed depends on the 2428ccbb781SIngo Weinhold // allocator -- a dedicated slab would be perfect. 2438ccbb781SIngo Weinhold } 2448ccbb781SIngo Weinhold 2458ccbb781SIngo Weinhold 2468ccbb781SIngo Weinhold #endif // VNODE_H 247