1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
8
9
10 #include "OpenState.h"
11
12 #include <util/AutoLock.h>
13
14 #include "FileSystem.h"
15 #include "Request.h"
16 #include "WorkQueue.h"
17
18
OpenState()19 OpenState::OpenState()
20 :
21 fOpened(false),
22 fDelegation(NULL),
23 fLocks(NULL),
24 fLockOwners(NULL)
25 {
26 mutex_init(&fLock, NULL);
27
28 mutex_init(&fLocksLock, NULL);
29 mutex_init(&fOwnerLock, NULL);
30 }
31
32
~OpenState()33 OpenState::~OpenState()
34 {
35 if (fOpened)
36 fFileSystem->RemoveOpenFile(this);
37 Close();
38
39 mutex_destroy(&fLock);
40
41 mutex_destroy(&fLocksLock);
42 mutex_destroy(&fOwnerLock);
43 }
44
45
46 LockOwner*
GetLockOwner(uint32 owner)47 OpenState::GetLockOwner(uint32 owner)
48 {
49 LockOwner* current = fLockOwners;
50 while (current != NULL) {
51 if (current->fOwner == owner)
52 return current;
53
54 current = current->fNext;
55 }
56
57 current = new LockOwner(owner);
58 if (current == NULL)
59 return NULL;
60
61 current->fNext = fLockOwners;
62 if (fLockOwners != NULL)
63 fLockOwners->fPrev = current;
64 fLockOwners = current;
65
66 return current;
67 }
68
69
70 // Caller must hold fLocksLock
71 void
AddLock(LockInfo * lock)72 OpenState::AddLock(LockInfo* lock)
73 {
74 lock->fNext = fLocks;
75 fLocks = lock;
76 }
77
78
79 // Caller must hold fLocksLock
80 void
RemoveLock(LockInfo * lock,LockInfo * prev)81 OpenState::RemoveLock(LockInfo* lock, LockInfo* prev)
82 {
83 if (prev != NULL)
84 prev->fNext = lock->fNext;
85 else
86 fLocks = lock->fNext;
87 }
88
89
90 void
DeleteLock(LockInfo * lock)91 OpenState::DeleteLock(LockInfo* lock)
92 {
93 MutexLocker _(fOwnerLock);
94
95 LockOwner* owner = lock->fOwner;
96 delete lock;
97
98 if (owner->fUseCount == 0) {
99 if (owner->fPrev)
100 owner->fPrev->fNext = owner->fNext;
101 else
102 fLockOwners = owner->fNext;
103 if (owner->fNext)
104 owner->fNext->fPrev = owner->fPrev;
105
106 _ReleaseLockOwner(owner);
107 delete owner;
108 }
109 }
110
111
112 status_t
_ReleaseLockOwner(LockOwner * owner)113 OpenState::_ReleaseLockOwner(LockOwner* owner)
114 {
115 ASSERT(owner != NULL);
116
117 uint32 attempt = 0;
118 do {
119 RPC::Server* server = fFileSystem->Server();
120 Request request(server, fFileSystem);
121 RequestBuilder& req = request.Builder();
122
123 req.ReleaseLockOwner(this, owner);
124
125 status_t result = request.Send();
126 if (result != B_OK)
127 return result;
128
129 ReplyInterpreter& reply = request.Reply();
130
131 if (HandleErrors(attempt, reply.NFS4Error(), server))
132 continue;
133
134 return reply.ReleaseLockOwner();
135 } while (true);
136 }
137
138
139 status_t
Reclaim(uint64 newClientID)140 OpenState::Reclaim(uint64 newClientID)
141 {
142 if (!fOpened)
143 return B_OK;
144
145 MutexLocker _(fLock);
146
147 if (fClientID == newClientID)
148 return B_OK;
149 fClientID = newClientID;
150
151 _ReclaimOpen(newClientID);
152 _ReclaimLocks(newClientID);
153
154 return B_OK;
155 }
156
157
158 status_t
_ReclaimOpen(uint64 newClientID)159 OpenState::_ReclaimOpen(uint64 newClientID)
160 {
161 bool confirm;
162 OpenDelegationData delegation;
163 delegation.fType = OPEN_DELEGATE_NONE;
164 delegation.fRecall = false;
165
166 status_t result;
167 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
168 OpenDelegation delegType = fDelegation != NULL ? fDelegation->Type()
169 : OPEN_DELEGATE_NONE;
170 uint32 attempt = 0;
171 do {
172 RPC::Server* server = fFileSystem->Server();
173 Request request(server, fFileSystem);
174 RequestBuilder& req = request.Builder();
175
176 req.PutFH(fInfo.fHandle);
177 req.Open(CLAIM_PREVIOUS, sequence, sModeToAccess(fMode), newClientID,
178 OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL, NULL, 0, false,
179 delegType);
180
181 result = request.Send();
182 if (result != B_OK) {
183 fFileSystem->OpenOwnerSequenceUnlock(sequence);
184 return result;
185 }
186
187 ReplyInterpreter& reply = request.Reply();
188
189 result = reply.PutFH();
190 if (result == B_OK)
191 sequence += IncrementSequence(reply.NFS4Error());
192
193 if (reply.NFS4Error() != NFS4ERR_STALE_CLIENTID
194 && HandleErrors(attempt, reply.NFS4Error(), server, NULL, NULL,
195 &sequence)) {
196 continue;
197 }
198
199 result = reply.Open(fStateID, &fStateSeq, &confirm, &delegation);
200 if (result != B_OK) {
201 fFileSystem->OpenOwnerSequenceUnlock(sequence);
202 return result;
203 }
204
205 break;
206 } while (true);
207
208 if (fDelegation != NULL)
209 fDelegation->SetData(delegation);
210
211 if (delegation.fRecall) {
212 DelegationRecallArgs* args = new(std::nothrow) DelegationRecallArgs;
213 args->fDelegation = fDelegation;
214 args->fTruncate = false;
215 gWorkQueue->EnqueueJob(DelegationRecall, args);
216 }
217
218 if (confirm)
219 result = ConfirmOpen(fInfo.fHandle, this, &sequence);
220
221 fFileSystem->OpenOwnerSequenceUnlock(sequence);
222 return result;
223 }
224
225
226 status_t
_ReclaimLocks(uint64 newClientID)227 OpenState::_ReclaimLocks(uint64 newClientID)
228 {
229 MutexLocker _(fLocksLock);
230 LockInfo* linfo = fLocks;
231 while (linfo != NULL) {
232 MutexLocker locker(linfo->fOwner->fLock);
233
234 if (linfo->fOwner->fClientId != newClientID) {
235 memset(linfo->fOwner->fStateId, 0, sizeof(linfo->fOwner->fStateId));
236 linfo->fOwner->fClientId = newClientID;
237 }
238
239 uint32 attempt = 0;
240 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
241 do {
242 RPC::Server* server = fFileSystem->Server();
243 Request request(server, fFileSystem);
244 RequestBuilder& req = request.Builder();
245
246 req.PutFH(fInfo.fHandle);
247 req.Lock(this, linfo, &sequence, true);
248
249 status_t result = request.Send();
250 if (result != B_OK) {
251 fFileSystem->OpenOwnerSequenceUnlock(sequence);
252 break;
253 }
254
255 ReplyInterpreter& reply = request.Reply();
256
257 result = reply.PutFH();
258 if (result == B_OK)
259 sequence += IncrementSequence(reply.NFS4Error());
260
261 if (reply.NFS4Error() != NFS4ERR_STALE_CLIENTID
262 && reply.NFS4Error() != NFS4ERR_STALE_STATEID
263 && HandleErrors(attempt, reply.NFS4Error(), server, NULL, NULL,
264 &sequence)) {
265 continue;
266 }
267
268 reply.Lock(linfo);
269
270 fFileSystem->OpenOwnerSequenceUnlock(sequence);
271 break;
272 } while (true);
273 locker.Unlock();
274
275 linfo = linfo->fNext;
276 }
277
278 return B_OK;
279 }
280
281
282 status_t
Close()283 OpenState::Close()
284 {
285 if (!fOpened)
286 return B_OK;
287
288 MutexLocker _(fLock);
289 fOpened = false;
290
291 uint32 attempt = 0;
292 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
293 do {
294 RPC::Server* serv = fFileSystem->Server();
295 Request request(serv, fFileSystem);
296 RequestBuilder& req = request.Builder();
297
298 req.PutFH(fInfo.fHandle);
299 req.Close(sequence, fStateID, fStateSeq);
300
301 status_t result = request.Send();
302 if (result != B_OK) {
303 fFileSystem->OpenOwnerSequenceUnlock(sequence);
304 return result;
305 }
306
307 ReplyInterpreter& reply = request.Reply();
308
309 result = reply.PutFH();
310 if (result == B_OK)
311 sequence += IncrementSequence(reply.NFS4Error());
312
313 // RFC 3530 8.10.1. Some servers does not do anything to help client
314 // recognize retried CLOSE requests so we just assume that BAD_STATEID
315 // on CLOSE request is just a result of retransmission.
316 if (reply.NFS4Error() == NFS4ERR_BAD_STATEID) {
317 fFileSystem->OpenOwnerSequenceUnlock(sequence);
318 return B_OK;
319 }
320
321 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, this,
322 &sequence)) {
323 continue;
324 }
325 fFileSystem->OpenOwnerSequenceUnlock(sequence);
326
327 return reply.Close();
328 } while (true);
329 }
330
331