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 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 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* 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 72 OpenState::AddLock(LockInfo* lock) 73 { 74 lock->fNext = fLocks; 75 fLocks = lock; 76 } 77 78 79 // Caller must hold fLocksLock 80 void 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 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 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 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 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 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 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