BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / file_systems / nfs4 / OpenState.cpp
blob73df95155a1242f204412882b44cecc59249d127
1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
10 #include "OpenState.h"
12 #include <util/AutoLock.h>
14 #include "FileSystem.h"
15 #include "Request.h"
16 #include "WorkQueue.h"
19 OpenState::OpenState()
21 fOpened(false),
22 fDelegation(NULL),
23 fLocks(NULL),
24 fLockOwners(NULL)
26 mutex_init(&fLock, NULL);
28 mutex_init(&fLocksLock, NULL);
29 mutex_init(&fOwnerLock, NULL);
33 OpenState::~OpenState()
35 if (fOpened)
36 fFileSystem->RemoveOpenFile(this);
37 Close();
39 mutex_destroy(&fLock);
41 mutex_destroy(&fLocksLock);
42 mutex_destroy(&fOwnerLock);
46 LockOwner*
47 OpenState::GetLockOwner(uint32 owner)
49 LockOwner* current = fLockOwners;
50 while (current != NULL) {
51 if (current->fOwner == owner)
52 return current;
54 current = current->fNext;
57 current = new LockOwner(owner);
58 if (current == NULL)
59 return NULL;
61 current->fNext = fLockOwners;
62 if (fLockOwners != NULL)
63 fLockOwners->fPrev = current;
64 fLockOwners = current;
66 return current;
70 // Caller must hold fLocksLock
71 void
72 OpenState::AddLock(LockInfo* lock)
74 lock->fNext = fLocks;
75 fLocks = lock;
79 // Caller must hold fLocksLock
80 void
81 OpenState::RemoveLock(LockInfo* lock, LockInfo* prev)
83 if (prev != NULL)
84 prev->fNext = lock->fNext;
85 else
86 fLocks = lock->fNext;
90 void
91 OpenState::DeleteLock(LockInfo* lock)
93 MutexLocker _(fOwnerLock);
95 LockOwner* owner = lock->fOwner;
96 delete lock;
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;
106 _ReleaseLockOwner(owner);
107 delete owner;
112 status_t
113 OpenState::_ReleaseLockOwner(LockOwner* owner)
115 ASSERT(owner != NULL);
117 uint32 attempt = 0;
118 do {
119 RPC::Server* server = fFileSystem->Server();
120 Request request(server, fFileSystem);
121 RequestBuilder& req = request.Builder();
123 req.ReleaseLockOwner(this, owner);
125 status_t result = request.Send();
126 if (result != B_OK)
127 return result;
129 ReplyInterpreter& reply = request.Reply();
131 if (HandleErrors(attempt, reply.NFS4Error(), server))
132 continue;
134 return reply.ReleaseLockOwner();
135 } while (true);
139 status_t
140 OpenState::Reclaim(uint64 newClientID)
142 if (!fOpened)
143 return B_OK;
145 MutexLocker _(fLock);
147 if (fClientID == newClientID)
148 return B_OK;
149 fClientID = newClientID;
151 _ReclaimOpen(newClientID);
152 _ReclaimLocks(newClientID);
154 return B_OK;
158 status_t
159 OpenState::_ReclaimOpen(uint64 newClientID)
161 bool confirm;
162 OpenDelegationData delegation;
163 delegation.fType = OPEN_DELEGATE_NONE;
164 delegation.fRecall = false;
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();
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);
181 result = request.Send();
182 if (result != B_OK) {
183 fFileSystem->OpenOwnerSequenceUnlock(sequence);
184 return result;
187 ReplyInterpreter& reply = request.Reply();
189 result = reply.PutFH();
190 if (result == B_OK)
191 sequence += IncrementSequence(reply.NFS4Error());
193 if (reply.NFS4Error() != NFS4ERR_STALE_CLIENTID
194 && HandleErrors(attempt, reply.NFS4Error(), server, NULL, NULL,
195 &sequence)) {
196 continue;
199 result = reply.Open(fStateID, &fStateSeq, &confirm, &delegation);
200 if (result != B_OK) {
201 fFileSystem->OpenOwnerSequenceUnlock(sequence);
202 return result;
205 break;
206 } while (true);
208 if (fDelegation != NULL)
209 fDelegation->SetData(delegation);
211 if (delegation.fRecall) {
212 DelegationRecallArgs* args = new(std::nothrow) DelegationRecallArgs;
213 args->fDelegation = fDelegation;
214 args->fTruncate = false;
215 gWorkQueue->EnqueueJob(DelegationRecall, args);
218 if (confirm)
219 result = ConfirmOpen(fInfo.fHandle, this, &sequence);
221 fFileSystem->OpenOwnerSequenceUnlock(sequence);
222 return result;
226 status_t
227 OpenState::_ReclaimLocks(uint64 newClientID)
229 MutexLocker _(fLocksLock);
230 LockInfo* linfo = fLocks;
231 while (linfo != NULL) {
232 MutexLocker locker(linfo->fOwner->fLock);
234 if (linfo->fOwner->fClientId != newClientID) {
235 memset(linfo->fOwner->fStateId, 0, sizeof(linfo->fOwner->fStateId));
236 linfo->fOwner->fClientId = newClientID;
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();
246 req.PutFH(fInfo.fHandle);
247 req.Lock(this, linfo, &sequence, true);
249 status_t result = request.Send();
250 if (result != B_OK) {
251 fFileSystem->OpenOwnerSequenceUnlock(sequence);
252 break;
255 ReplyInterpreter& reply = request.Reply();
257 result = reply.PutFH();
258 if (result == B_OK)
259 sequence += IncrementSequence(reply.NFS4Error());
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;
268 reply.Lock(linfo);
270 fFileSystem->OpenOwnerSequenceUnlock(sequence);
271 break;
272 } while (true);
273 locker.Unlock();
275 linfo = linfo->fNext;
278 return B_OK;
282 status_t
283 OpenState::Close()
285 if (!fOpened)
286 return B_OK;
288 MutexLocker _(fLock);
289 fOpened = false;
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();
298 req.PutFH(fInfo.fHandle);
299 req.Close(sequence, fStateID, fStateSeq);
301 status_t result = request.Send();
302 if (result != B_OK) {
303 fFileSystem->OpenOwnerSequenceUnlock(sequence);
304 return result;
307 ReplyInterpreter& reply = request.Reply();
309 result = reply.PutFH();
310 if (result == B_OK)
311 sequence += IncrementSequence(reply.NFS4Error());
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;
321 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, this,
322 &sequence)) {
323 continue;
325 fFileSystem->OpenOwnerSequenceUnlock(sequence);
327 return reply.Close();
328 } while (true);