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> {
27*2f37cef1SAugustin Cavalier struct vnode* hash_next;
288ccbb781SIngo Weinhold VMCache* cache;
298ccbb781SIngo Weinhold struct fs_mount* mount;
308ccbb781SIngo Weinhold struct vnode* covered_by;
3102be66caSIngo Weinhold struct vnode* covers;
328ccbb781SIngo Weinhold struct advisory_locking* advisory_locking;
338ccbb781SIngo Weinhold struct file_descriptor* mandatory_locked_by;
34*2f37cef1SAugustin Cavalier DoublyLinkedListLink<struct vnode> 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
5547ea54c5SIngo Weinhold // setter requires sVnodeLock write-locked, getter is lockless
5647ea54c5SIngo Weinhold inline bool IsCovered() const;
5747ea54c5SIngo Weinhold inline void SetCovered(bool covered);
5847ea54c5SIngo Weinhold
5947ea54c5SIngo Weinhold // setter requires sVnodeLock write-locked, getter is lockless
6047ea54c5SIngo Weinhold inline bool IsCovering() const;
6147ea54c5SIngo Weinhold inline void SetCovering(bool covering);
6247ea54c5SIngo Weinhold
638ccbb781SIngo Weinhold inline uint32 Type() const;
648ccbb781SIngo Weinhold inline void SetType(uint32 type);
658ccbb781SIngo Weinhold
668ccbb781SIngo Weinhold inline bool Lock();
678ccbb781SIngo Weinhold inline void Unlock();
688ccbb781SIngo Weinhold
698ccbb781SIngo Weinhold static void StaticInit();
708ccbb781SIngo Weinhold
718ccbb781SIngo Weinhold private:
728ccbb781SIngo Weinhold static const uint32 kFlagsLocked = 0x00000001;
738ccbb781SIngo Weinhold static const uint32 kFlagsWaitingLocker = 0x00000002;
748ccbb781SIngo Weinhold static const uint32 kFlagsBusy = 0x00000004;
758ccbb781SIngo Weinhold static const uint32 kFlagsRemoved = 0x00000008;
768ccbb781SIngo Weinhold static const uint32 kFlagsUnpublished = 0x00000010;
7754848900SIngo Weinhold static const uint32 kFlagsUnused = 0x00000020;
7854848900SIngo Weinhold static const uint32 kFlagsHot = 0x00000040;
7947ea54c5SIngo Weinhold static const uint32 kFlagsCovered = 0x00000080;
8047ea54c5SIngo Weinhold static const uint32 kFlagsCovering = 0x00000100;
818ccbb781SIngo Weinhold static const uint32 kFlagsType = 0xfffff000;
828ccbb781SIngo Weinhold
838ccbb781SIngo Weinhold static const uint32 kBucketCount = 32;
848ccbb781SIngo Weinhold
858ccbb781SIngo Weinhold struct LockWaiter : DoublyLinkedListLinkImpl<LockWaiter> {
864535495dSIngo Weinhold Thread* thread;
878ccbb781SIngo Weinhold struct vnode* vnode;
888ccbb781SIngo Weinhold };
898ccbb781SIngo Weinhold
908ccbb781SIngo Weinhold typedef DoublyLinkedList<LockWaiter> LockWaiterList;
918ccbb781SIngo Weinhold
928ccbb781SIngo Weinhold struct Bucket {
938ccbb781SIngo Weinhold mutex lock;
948ccbb781SIngo Weinhold LockWaiterList waiters;
958ccbb781SIngo Weinhold
968ccbb781SIngo Weinhold Bucket();
978ccbb781SIngo Weinhold };
988ccbb781SIngo Weinhold
998ccbb781SIngo Weinhold private:
1008ccbb781SIngo Weinhold inline Bucket& _Bucket() const;
1018ccbb781SIngo Weinhold
1028ccbb781SIngo Weinhold void _WaitForLock();
1038ccbb781SIngo Weinhold void _WakeUpLocker();
1048ccbb781SIngo Weinhold
1058ccbb781SIngo Weinhold private:
10673ad2473SPawel Dziepak int32 fFlags;
1078ccbb781SIngo Weinhold
1088ccbb781SIngo Weinhold static Bucket sBuckets[kBucketCount];
1098ccbb781SIngo Weinhold };
1108ccbb781SIngo Weinhold
1118ccbb781SIngo Weinhold
1128ccbb781SIngo Weinhold bool
IsBusy()1138ccbb781SIngo Weinhold vnode::IsBusy() const
1148ccbb781SIngo Weinhold {
1158ccbb781SIngo Weinhold return (fFlags & kFlagsBusy) != 0;
1168ccbb781SIngo Weinhold }
1178ccbb781SIngo Weinhold
1188ccbb781SIngo Weinhold
1198ccbb781SIngo Weinhold void
SetBusy(bool busy)1208ccbb781SIngo Weinhold vnode::SetBusy(bool busy)
1218ccbb781SIngo Weinhold {
1228ccbb781SIngo Weinhold if (busy)
1238ccbb781SIngo Weinhold atomic_or(&fFlags, kFlagsBusy);
1248ccbb781SIngo Weinhold else
1258ccbb781SIngo Weinhold atomic_and(&fFlags, ~kFlagsBusy);
1268ccbb781SIngo Weinhold }
1278ccbb781SIngo Weinhold
1288ccbb781SIngo Weinhold
1298ccbb781SIngo Weinhold bool
IsRemoved()1308ccbb781SIngo Weinhold vnode::IsRemoved() const
1318ccbb781SIngo Weinhold {
1328ccbb781SIngo Weinhold return (fFlags & kFlagsRemoved) != 0;
1338ccbb781SIngo Weinhold }
1348ccbb781SIngo Weinhold
1358ccbb781SIngo Weinhold
1368ccbb781SIngo Weinhold void
SetRemoved(bool removed)1378ccbb781SIngo Weinhold vnode::SetRemoved(bool removed)
1388ccbb781SIngo Weinhold {
1398ccbb781SIngo Weinhold if (removed)
1408ccbb781SIngo Weinhold atomic_or(&fFlags, kFlagsRemoved);
1418ccbb781SIngo Weinhold else
1428ccbb781SIngo Weinhold atomic_and(&fFlags, ~kFlagsRemoved);
1438ccbb781SIngo Weinhold }
1448ccbb781SIngo Weinhold
1458ccbb781SIngo Weinhold
1468ccbb781SIngo Weinhold bool
IsUnpublished()1478ccbb781SIngo Weinhold vnode::IsUnpublished() const
1488ccbb781SIngo Weinhold {
1498ccbb781SIngo Weinhold return (fFlags & kFlagsUnpublished) != 0;
1508ccbb781SIngo Weinhold }
1518ccbb781SIngo Weinhold
1528ccbb781SIngo Weinhold
1538ccbb781SIngo Weinhold void
SetUnpublished(bool unpublished)1548ccbb781SIngo Weinhold vnode::SetUnpublished(bool unpublished)
1558ccbb781SIngo Weinhold {
1568ccbb781SIngo Weinhold if (unpublished)
1578ccbb781SIngo Weinhold atomic_or(&fFlags, kFlagsUnpublished);
1588ccbb781SIngo Weinhold else
1598ccbb781SIngo Weinhold atomic_and(&fFlags, ~kFlagsUnpublished);
1608ccbb781SIngo Weinhold }
1618ccbb781SIngo Weinhold
1628ccbb781SIngo Weinhold
16354848900SIngo Weinhold bool
IsUnused()16454848900SIngo Weinhold vnode::IsUnused() const
16554848900SIngo Weinhold {
16654848900SIngo Weinhold return (fFlags & kFlagsUnused) != 0;
16754848900SIngo Weinhold }
16854848900SIngo Weinhold
16954848900SIngo Weinhold
17054848900SIngo Weinhold void
SetUnused(bool unused)17154848900SIngo Weinhold vnode::SetUnused(bool unused)
17254848900SIngo Weinhold {
17354848900SIngo Weinhold if (unused)
17454848900SIngo Weinhold atomic_or(&fFlags, kFlagsUnused);
17554848900SIngo Weinhold else
17654848900SIngo Weinhold atomic_and(&fFlags, ~kFlagsUnused);
17754848900SIngo Weinhold }
17854848900SIngo Weinhold
17954848900SIngo Weinhold
18054848900SIngo Weinhold bool
IsHot()18154848900SIngo Weinhold vnode::IsHot() const
18254848900SIngo Weinhold {
18354848900SIngo Weinhold return (fFlags & kFlagsHot) != 0;
18454848900SIngo Weinhold }
18554848900SIngo Weinhold
18654848900SIngo Weinhold
18754848900SIngo Weinhold void
SetHot(bool hot)18854848900SIngo Weinhold vnode::SetHot(bool hot)
18954848900SIngo Weinhold {
19054848900SIngo Weinhold if (hot)
19154848900SIngo Weinhold atomic_or(&fFlags, kFlagsHot);
19254848900SIngo Weinhold else
19354848900SIngo Weinhold atomic_and(&fFlags, ~kFlagsHot);
19454848900SIngo Weinhold }
19554848900SIngo Weinhold
19654848900SIngo Weinhold
19747ea54c5SIngo Weinhold bool
IsCovered()19847ea54c5SIngo Weinhold vnode::IsCovered() const
19947ea54c5SIngo Weinhold {
20047ea54c5SIngo Weinhold return (fFlags & kFlagsCovered) != 0;
20147ea54c5SIngo Weinhold }
20247ea54c5SIngo Weinhold
20347ea54c5SIngo Weinhold
20447ea54c5SIngo Weinhold void
SetCovered(bool covered)20547ea54c5SIngo Weinhold vnode::SetCovered(bool covered)
20647ea54c5SIngo Weinhold {
20747ea54c5SIngo Weinhold if (covered)
20847ea54c5SIngo Weinhold atomic_or(&fFlags, kFlagsCovered);
20947ea54c5SIngo Weinhold else
21047ea54c5SIngo Weinhold atomic_and(&fFlags, ~kFlagsCovered);
21147ea54c5SIngo Weinhold }
21247ea54c5SIngo Weinhold
21347ea54c5SIngo Weinhold
21447ea54c5SIngo Weinhold bool
IsCovering()21547ea54c5SIngo Weinhold vnode::IsCovering() const
21647ea54c5SIngo Weinhold {
21747ea54c5SIngo Weinhold return (fFlags & kFlagsCovering) != 0;
21847ea54c5SIngo Weinhold }
21947ea54c5SIngo Weinhold
22047ea54c5SIngo Weinhold
22147ea54c5SIngo Weinhold void
SetCovering(bool covering)22247ea54c5SIngo Weinhold vnode::SetCovering(bool covering)
22347ea54c5SIngo Weinhold {
22447ea54c5SIngo Weinhold if (covering)
22547ea54c5SIngo Weinhold atomic_or(&fFlags, kFlagsCovering);
22647ea54c5SIngo Weinhold else
22747ea54c5SIngo Weinhold atomic_and(&fFlags, ~kFlagsCovering);
22847ea54c5SIngo Weinhold }
22947ea54c5SIngo Weinhold
23047ea54c5SIngo Weinhold
2318ccbb781SIngo Weinhold uint32
Type()2328ccbb781SIngo Weinhold vnode::Type() const
2338ccbb781SIngo Weinhold {
2348ccbb781SIngo Weinhold return (uint32)fFlags & kFlagsType;
2358ccbb781SIngo Weinhold }
2368ccbb781SIngo Weinhold
2378ccbb781SIngo Weinhold
2388ccbb781SIngo Weinhold void
SetType(uint32 type)2398ccbb781SIngo Weinhold vnode::SetType(uint32 type)
2408ccbb781SIngo Weinhold {
2418ccbb781SIngo Weinhold atomic_and(&fFlags, ~kFlagsType);
2428ccbb781SIngo Weinhold atomic_or(&fFlags, type & kFlagsType);
2438ccbb781SIngo Weinhold }
2448ccbb781SIngo Weinhold
2458ccbb781SIngo Weinhold
2468ccbb781SIngo Weinhold /*! Locks the vnode.
2478ccbb781SIngo Weinhold The caller must hold sVnodeLock (at least read locked) and must continue to
2488ccbb781SIngo Weinhold hold it until calling Unlock(). After acquiring the lock the caller is
2498ccbb781SIngo Weinhold allowed to write access the vnode's mutable fields, if it hasn't been marked
2508ccbb781SIngo Weinhold busy by someone else.
2518ccbb781SIngo Weinhold Due to the condition of holding sVnodeLock at least read locked, write
2528ccbb781SIngo Weinhold locking it grants the same write access permission to *any* vnode.
2538ccbb781SIngo Weinhold
2548ccbb781SIngo Weinhold The vnode's lock should be held only for a short time. It can be held over
2558ccbb781SIngo Weinhold sUnusedVnodesLock.
2568ccbb781SIngo Weinhold
2578ccbb781SIngo Weinhold \return Always \c true.
2588ccbb781SIngo Weinhold */
2598ccbb781SIngo Weinhold bool
Lock()2608ccbb781SIngo Weinhold vnode::Lock()
2618ccbb781SIngo Weinhold {
2628ccbb781SIngo Weinhold if ((atomic_or(&fFlags, kFlagsLocked)
2638ccbb781SIngo Weinhold & (kFlagsLocked | kFlagsWaitingLocker)) != 0) {
2648ccbb781SIngo Weinhold _WaitForLock();
2658ccbb781SIngo Weinhold }
2668ccbb781SIngo Weinhold
2678ccbb781SIngo Weinhold return true;
2688ccbb781SIngo Weinhold }
2698ccbb781SIngo Weinhold
2708ccbb781SIngo Weinhold void
Unlock()2718ccbb781SIngo Weinhold vnode::Unlock()
2728ccbb781SIngo Weinhold {
2738ccbb781SIngo Weinhold if ((atomic_and(&fFlags, ~kFlagsLocked) & kFlagsWaitingLocker) != 0)
2748ccbb781SIngo Weinhold _WakeUpLocker();
2758ccbb781SIngo Weinhold }
2768ccbb781SIngo Weinhold
2778ccbb781SIngo Weinhold
2788ccbb781SIngo Weinhold vnode::Bucket&
_Bucket()2798ccbb781SIngo Weinhold vnode::_Bucket() const
2808ccbb781SIngo Weinhold {
2818ccbb781SIngo Weinhold return sBuckets[((addr_t)this / 64) % kBucketCount];
2828ccbb781SIngo Weinhold // The vnode structure is somewhat larger than 64 bytes (on 32 bit
2838ccbb781SIngo Weinhold // archs), so subsequently allocated vnodes fall into different
2848ccbb781SIngo Weinhold // buckets. How exactly the vnodes are distributed depends on the
2858ccbb781SIngo Weinhold // allocator -- a dedicated slab would be perfect.
2868ccbb781SIngo Weinhold }
2878ccbb781SIngo Weinhold
2888ccbb781SIngo Weinhold
2898ccbb781SIngo Weinhold #endif // VNODE_H
290