2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Paweł Dziepak, pdziepak@quarnos.org
10 #include "OpenState.h"
12 #include <util/AutoLock.h>
14 #include "FileSystem.h"
16 #include "WorkQueue.h"
19 OpenState::OpenState()
26 mutex_init(&fLock
, NULL
);
28 mutex_init(&fLocksLock
, NULL
);
29 mutex_init(&fOwnerLock
, NULL
);
33 OpenState::~OpenState()
36 fFileSystem
->RemoveOpenFile(this);
39 mutex_destroy(&fLock
);
41 mutex_destroy(&fLocksLock
);
42 mutex_destroy(&fOwnerLock
);
47 OpenState::GetLockOwner(uint32 owner
)
49 LockOwner
* current
= fLockOwners
;
50 while (current
!= NULL
) {
51 if (current
->fOwner
== owner
)
54 current
= current
->fNext
;
57 current
= new LockOwner(owner
);
61 current
->fNext
= fLockOwners
;
62 if (fLockOwners
!= NULL
)
63 fLockOwners
->fPrev
= current
;
64 fLockOwners
= current
;
70 // Caller must hold fLocksLock
72 OpenState::AddLock(LockInfo
* lock
)
79 // Caller must hold fLocksLock
81 OpenState::RemoveLock(LockInfo
* lock
, LockInfo
* prev
)
84 prev
->fNext
= lock
->fNext
;
91 OpenState::DeleteLock(LockInfo
* lock
)
93 MutexLocker
_(fOwnerLock
);
95 LockOwner
* owner
= lock
->fOwner
;
98 if (owner
->fUseCount
== 0) {
100 owner
->fPrev
->fNext
= owner
->fNext
;
102 fLockOwners
= owner
->fNext
;
104 owner
->fNext
->fPrev
= owner
->fPrev
;
106 _ReleaseLockOwner(owner
);
113 OpenState::_ReleaseLockOwner(LockOwner
* owner
)
115 ASSERT(owner
!= NULL
);
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();
129 ReplyInterpreter
& reply
= request
.Reply();
131 if (HandleErrors(attempt
, reply
.NFS4Error(), server
))
134 return reply
.ReleaseLockOwner();
140 OpenState::Reclaim(uint64 newClientID
)
145 MutexLocker
_(fLock
);
147 if (fClientID
== newClientID
)
149 fClientID
= newClientID
;
151 _ReclaimOpen(newClientID
);
152 _ReclaimLocks(newClientID
);
159 OpenState::_ReclaimOpen(uint64 newClientID
)
162 OpenDelegationData delegation
;
163 delegation
.fType
= OPEN_DELEGATE_NONE
;
164 delegation
.fRecall
= false;
167 uint32 sequence
= fFileSystem
->OpenOwnerSequenceLock();
168 OpenDelegation delegType
= fDelegation
!= NULL
? fDelegation
->Type()
169 : OPEN_DELEGATE_NONE
;
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,
181 result
= request
.Send();
182 if (result
!= B_OK
) {
183 fFileSystem
->OpenOwnerSequenceUnlock(sequence
);
187 ReplyInterpreter
& reply
= request
.Reply();
189 result
= reply
.PutFH();
191 sequence
+= IncrementSequence(reply
.NFS4Error());
193 if (reply
.NFS4Error() != NFS4ERR_STALE_CLIENTID
194 && HandleErrors(attempt
, reply
.NFS4Error(), server
, NULL
, NULL
,
199 result
= reply
.Open(fStateID
, &fStateSeq
, &confirm
, &delegation
);
200 if (result
!= B_OK
) {
201 fFileSystem
->OpenOwnerSequenceUnlock(sequence
);
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
);
219 result
= ConfirmOpen(fInfo
.fHandle
, this, &sequence
);
221 fFileSystem
->OpenOwnerSequenceUnlock(sequence
);
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
;
240 uint32 sequence
= fFileSystem
->OpenOwnerSequenceLock();
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
);
255 ReplyInterpreter
& reply
= request
.Reply();
257 result
= reply
.PutFH();
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
,
270 fFileSystem
->OpenOwnerSequenceUnlock(sequence
);
275 linfo
= linfo
->fNext
;
288 MutexLocker
_(fLock
);
292 uint32 sequence
= fFileSystem
->OpenOwnerSequenceLock();
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
);
307 ReplyInterpreter
& reply
= request
.Reply();
309 result
= reply
.PutFH();
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
);
321 if (HandleErrors(attempt
, reply
.NFS4Error(), serv
, NULL
, this,
325 fFileSystem
->OpenOwnerSequenceUnlock(sequence
);
327 return reply
.Close();