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 "Cookie.h" 11 12 #include "Inode.h" 13 #include "Request.h" 14 15 16 vint64 OpenFileCookie::fLastOwnerId = 0; 17 18 19 LockOwner::LockOwner(uint32 owner) 20 : 21 fSequence(0), 22 fOwner(owner), 23 fUseCount(0), 24 fNext(NULL), 25 fPrev(NULL) 26 { 27 memset(fStateId, 0, sizeof(fStateId)); 28 mutex_init(&fLock, NULL); 29 } 30 31 32 LockOwner::~LockOwner() 33 { 34 mutex_destroy(&fLock); 35 } 36 37 38 LockInfo::LockInfo(LockOwner* owner) 39 : 40 fOwner(owner) 41 { 42 fOwner->fUseCount++; 43 } 44 45 46 LockInfo::~LockInfo() 47 { 48 fOwner->fUseCount--; 49 } 50 51 52 bool 53 LockInfo::operator==(const struct flock& lock) const 54 { 55 bool eof = lock.l_len + lock.l_start == OFF_MAX; 56 uint64 start = static_cast<uint64>(lock.l_start); 57 uint64 len = static_cast<uint64>(lock.l_len); 58 59 return fStart == start && fLength == len || eof && fLength == UINT64_MAX; 60 } 61 62 63 Cookie::Cookie() 64 : 65 fRequests(NULL), 66 fSnoozeCancel(create_sem(1, NULL)) 67 { 68 acquire_sem(fSnoozeCancel); 69 mutex_init(&fRequestLock, NULL); 70 } 71 72 73 Cookie::~Cookie() 74 { 75 delete_sem(fSnoozeCancel); 76 mutex_destroy(&fRequestLock); 77 } 78 79 80 status_t 81 Cookie::RegisterRequest(RPC::Request* req) 82 { 83 RequestEntry* ent = new RequestEntry; 84 if (ent == NULL) 85 return B_NO_MEMORY; 86 87 MutexLocker _(fRequestLock); 88 ent->fRequest = req; 89 ent->fNext = fRequests; 90 fRequests = ent; 91 92 return B_OK; 93 } 94 95 96 status_t 97 Cookie::UnregisterRequest(RPC::Request* req) 98 { 99 MutexLocker _(fRequestLock); 100 RequestEntry* ent = fRequests; 101 RequestEntry* prev = NULL; 102 while (ent != NULL) { 103 if (ent->fRequest == req) { 104 if (prev == NULL) 105 fRequests = ent->fNext; 106 else 107 prev->fNext = ent->fNext; 108 delete ent; 109 } 110 111 prev = ent; 112 ent = ent->fNext; 113 } 114 115 return B_OK; 116 } 117 118 119 status_t 120 Cookie::CancelAll() 121 { 122 release_sem(fSnoozeCancel); 123 124 MutexLocker _(fRequestLock); 125 RequestEntry* ent = fRequests; 126 while (ent != NULL) { 127 fFileSystem->Server()->WakeCall(ent->fRequest); 128 ent = ent->fNext; 129 } 130 131 return B_OK; 132 } 133 134 135 OpenFileCookie::OpenFileCookie() 136 : 137 fLocks(NULL), 138 fLockOwners(NULL) 139 { 140 mutex_init(&fLocksLock, NULL); 141 mutex_init(&fOwnerLock, NULL); 142 } 143 144 145 OpenFileCookie::~OpenFileCookie() 146 { 147 mutex_destroy(&fLocksLock); 148 mutex_destroy(&fOwnerLock); 149 } 150 151 152 LockOwner* 153 OpenFileCookie::GetLockOwner(uint32 owner) 154 { 155 LockOwner* current = fLockOwners; 156 while (current != NULL) { 157 if (current->fOwner == owner) 158 return current; 159 160 current = current->fNext; 161 } 162 163 current = new LockOwner(owner); 164 if (current == NULL) 165 return NULL; 166 167 current->fClientId = fClientId; 168 current->fNext = fLockOwners; 169 if (fLockOwners != NULL) 170 fLockOwners->fPrev = current; 171 fLockOwners = current; 172 173 return current; 174 } 175 176 177 // Caller must hold fLocksLock 178 void 179 OpenFileCookie::AddLock(LockInfo* lock) 180 { 181 lock->fNext = fLocks; 182 fLocks = lock; 183 } 184 185 186 // Caller must hold fLocksLock 187 void 188 OpenFileCookie::RemoveLock(LockInfo* lock, LockInfo* prev) 189 { 190 if (prev != NULL) 191 prev->fNext = lock->fNext; 192 else 193 fLocks = lock->fNext; 194 } 195 196 197 void 198 OpenFileCookie::DeleteLock(LockInfo* lock) 199 { 200 MutexLocker _(fOwnerLock); 201 202 LockOwner* owner = lock->fOwner; 203 delete lock; 204 205 if (owner->fUseCount == 0) { 206 if (owner->fPrev) 207 owner->fPrev->fNext = owner->fNext; 208 else 209 fLockOwners = owner->fNext; 210 if (owner->fNext) 211 owner->fNext->fPrev = owner->fPrev; 212 213 _ReleaseLockOwner(owner); 214 delete owner; 215 } 216 } 217 218 219 status_t 220 OpenFileCookie::_ReleaseLockOwner(LockOwner* owner) 221 { 222 Request request(fFileSystem->Server()); 223 RequestBuilder& req = request.Builder(); 224 225 req.ReleaseLockOwner(this, owner); 226 227 status_t result = request.Send(); 228 if (result != B_OK) 229 return result; 230 231 ReplyInterpreter &reply = request.Reply(); 232 233 return reply.ReleaseLockOwner(); 234 } 235 236