xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/NodeHandleMap.cpp (revision 4052469d007d17112b0fdf8814c92c77414a1398)
1 // NodeHandleMap.cpp
2 
3 #include "NodeHandleMap.h"
4 
5 #include "AutoLocker.h"
6 #include "GlobalBlockerPool.h"
7 
8 
9 // constructor
10 NodeHandleMap::NodeHandleMap(const char* name)
11 	: Locker(name),
12 	  fNextNodeHandleCookie(0)
13 {
14 }
15 
16 // destructor
17 NodeHandleMap::~NodeHandleMap()
18 {
19 }
20 
21 // Init
22 status_t
23 NodeHandleMap::Init()
24 {
25 	// check semaphore
26 	if (Sem() < 0)
27 		return Sem();
28 
29 	return B_OK;
30 }
31 
32 // AddNodeHandle
33 status_t
34 NodeHandleMap::AddNodeHandle(NodeHandle* handle)
35 {
36 	if (!handle)
37 		return B_BAD_VALUE;
38 
39 	AutoLocker<Locker> _(this);
40 
41 	handle->SetCookie(_NextNodeHandleCookie());
42 
43 	status_t error = Put(handle->GetCookie(), handle);
44 	if (error == B_OK)
45 		handle->AddReference();
46 
47 	return error;
48 }
49 
50 // RemoveNodeHandle
51 bool
52 NodeHandleMap::RemoveNodeHandle(NodeHandle* handle)
53 {
54 	if (!handle)
55 		return false;
56 
57 	AutoLocker<Locker> _(this);
58 
59 	if (Get(handle->GetCookie()) != handle)
60 		return false;
61 
62 	Remove(handle->GetCookie());
63 	handle->RemoveReference();
64 	return true;
65 }
66 
67 // LockNodeHandle
68 //
69 // VolumeManager must NOT be locked.
70 status_t
71 NodeHandleMap::LockNodeHandle(int32 cookie, NodeHandle** _handle)
72 {
73 	if (!_handle)
74 		return B_BAD_VALUE;
75 
76 	NodeHandle* handle;
77 	{
78 		AutoLocker<Locker> _(this);
79 
80 		// get the node handle
81 		handle = Get(cookie);
82 		if (!handle)
83 			return B_ENTRY_NOT_FOUND;
84 		handle->AddReference();
85 
86 		// first attempt: we just try to lock the node handle, which will fail,
87 		// if someone else has the lock at the momemt
88 		if (handle->Lock()) {
89 			*_handle = handle;
90 			return B_OK;
91 		}
92 	}
93 
94 	// someone else is locking, get a blocker and wait for the lock
95 	BlockerPool* blockerPool = GlobalBlockerPool::GetDefault();
96 	Blocker blocker = blockerPool->GetBlocker();
97 	BlockerPutter blockerPutter(*blockerPool, blocker);
98 	LockerCandidate lockerCandidate(blocker);
99 	{
100 		AutoLocker<Locker> _(this);
101 
102 		if (handle->Lock()) {
103 			*_handle = handle;
104 			return B_OK;
105 		}
106 		handle->QueueLockerCandidate(&lockerCandidate);
107 	}
108 
109 	// wait for the lock
110 	status_t error = lockerCandidate.Block();
111 	if (error != B_OK) {
112 		handle->RemoveReference();
113 		return error;
114 	}
115 
116 	*_handle = handle;
117 	return B_OK;
118 }
119 
120 // UnlockNodeHandle
121 //
122 // VolumeManager may or may not be locked.
123 void
124 NodeHandleMap::UnlockNodeHandle(NodeHandle* nodeHandle)
125 {
126 	if (!nodeHandle)
127 		return;
128 
129 	if (nodeHandle->IsLocked()) {
130 		AutoLocker<Locker> _(this);
131 
132 		nodeHandle->Unlock();
133 		nodeHandle->RemoveReference();
134 	}
135 }
136 
137 // _NextNodeHandleCookie
138 int32
139 NodeHandleMap::_NextNodeHandleCookie()
140 {
141 	int32 cookie;
142 
143 	do {
144 		if (fNextNodeHandleCookie < 0)
145 			fNextNodeHandleCookie = 0;
146 		cookie = fNextNodeHandleCookie++;
147 	} while (ContainsKey(cookie));
148 
149 	return cookie;
150 }
151 
152