nfs4: Add proper lock owners management

This commit is contained in:
Pawel Dziepak
2012-07-02 23:54:48 +02:00
parent 43975b3d03
commit 62869605c5
7 changed files with 250 additions and 69 deletions
@@ -16,6 +16,50 @@
vint64 OpenFileCookie::fLastOwnerId = 0; vint64 OpenFileCookie::fLastOwnerId = 0;
LockOwner::LockOwner(uint32 owner)
:
fSequence(0),
fOwner(owner),
fUseCount(0),
fNext(NULL),
fPrev(NULL)
{
memset(fStateId, 0, sizeof(fStateId));
mutex_init(&fLock, NULL);
}
LockOwner::~LockOwner()
{
mutex_destroy(&fLock);
}
LockInfo::LockInfo(LockOwner* owner)
:
fOwner(owner)
{
fOwner->fUseCount++;
}
LockInfo::~LockInfo()
{
fOwner->fUseCount--;
}
bool
LockInfo::operator==(const struct flock& lock) const
{
bool eof = lock.l_len + lock.l_start == OFF_MAX;
uint64 start = static_cast<uint64>(lock.l_start);
uint64 len = static_cast<uint64>(lock.l_len);
return fStart == start && fLength == len || eof && fLength == UINT64_MAX;
}
Cookie::Cookie() Cookie::Cookie()
: :
fRequests(NULL), fRequests(NULL),
@@ -89,13 +133,85 @@ Cookie::CancelAll()
OpenFileCookie::OpenFileCookie() OpenFileCookie::OpenFileCookie()
:
fLockOwners(NULL)
{ {
mutex_init(&fLocksLock, NULL); mutex_init(&fLocksLock, NULL);
mutex_init(&fOwnerLock, NULL);
} }
OpenFileCookie::~OpenFileCookie() OpenFileCookie::~OpenFileCookie()
{ {
mutex_destroy(&fLocksLock); mutex_destroy(&fLocksLock);
mutex_destroy(&fOwnerLock);
}
LockOwner*
OpenFileCookie::GetLockOwner(uint32 owner)
{
MutexLocker _(fOwnerLock);
LockOwner* current = fLockOwners;
while (current != NULL) {
if (current->fOwner == owner)
return current;
current = current->fNext;
}
current = new LockOwner(owner);
if (current == NULL)
return NULL;
current->fClientId = fClientId;
current->fNext = fLockOwners;
if (fLockOwners != NULL)
fLockOwners->fPrev = current;
fLockOwners = current;
return current;
}
// Caller must hold fLocksLock
void
OpenFileCookie::AddLock(LockInfo* lock)
{
lock->fNext = fLocks;
fLocks = lock;
}
// Caller must hold fLocksLock
void
OpenFileCookie::RemoveLock(LockInfo* lock, LockInfo* prev)
{
if (prev != NULL)
prev->fNext = lock->fNext;
else
fLocks = lock->fNext;
}
void
OpenFileCookie::DeleteLock(LockInfo* lock)
{
MutexLocker _(fOwnerLock);
LockOwner* owner = lock->fOwner;
delete lock;
if (owner->fUseCount == 0) {
if (owner->fPrev)
owner->fPrev->fNext = owner->fNext;
else
fLockOwners = owner->fNext;
if (owner->fNext)
owner->fNext->fPrev = owner->fPrev;
delete owner;
}
} }
+32 -2
View File
@@ -14,18 +14,39 @@
#include "Filesystem.h" #include "Filesystem.h"
struct LockInfo { struct LockOwner {
uint64 fClientId;
uint32 fStateId[3]; uint32 fStateId[3];
uint32 fStateSeq; uint32 fStateSeq;
uint32 fSequence; uint32 fSequence;
uint32 fOwner; uint32 fOwner;
uint32 fUseCount;
mutex fLock;
LockOwner* fNext;
LockOwner* fPrev;
LockOwner(uint32 owner);
~LockOwner();
};
struct LockInfo {
LockOwner* fOwner;
uint64 fStart; uint64 fStart;
uint64 fLength; uint64 fLength;
LockType fType; LockType fType;
LockInfo* fNext; LockInfo* fNext;
LockInfo(LockOwner* owner);
~LockInfo();
bool operator==(const struct flock& lock) const;
}; };
struct Cookie { struct Cookie {
@@ -65,11 +86,20 @@ struct OpenFileCookie : public Cookie {
LockInfo* fLocks; LockInfo* fLocks;
mutex fLocksLock; mutex fLocksLock;
LockOwner* fLockOwners;
mutex fOwnerLock;
OpenFileCookie* fNext; OpenFileCookie* fNext;
OpenFileCookie* fPrev; OpenFileCookie* fPrev;
OpenFileCookie(); OpenFileCookie();
~OpenFileCookie(); ~OpenFileCookie();
LockOwner* GetLockOwner(uint32 owner);
void AddLock(LockInfo* lock);
void RemoveLock(LockInfo* lock, LockInfo* prev);
void DeleteLock(LockInfo* lock);
}; };
struct OpenDirCookie : public Cookie { struct OpenDirCookie : public Cookie {
+50 -41
View File
@@ -733,11 +733,16 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock,
if (result != B_OK) if (result != B_OK)
return result; return result;
LockInfo* linfo = new LockInfo; thread_info info;
get_thread_info(find_thread(NULL), &info);
LockOwner* owner = cookie->GetLockOwner(info.team);
if (owner == NULL)
return B_NO_MEMORY;
LockInfo* linfo = new LockInfo(owner);
if (linfo == NULL) if (linfo == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
linfo->fSequence = 0;
linfo->fStart = lock->l_start; linfo->fStart = lock->l_start;
if (lock->l_len + lock->l_start == OFF_MAX) if (lock->l_len + lock->l_start == OFF_MAX)
linfo->fLength = UINT64_MAX; linfo->fLength = UINT64_MAX;
@@ -745,11 +750,9 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock,
linfo->fLength = lock->l_len; linfo->fLength = lock->l_len;
linfo->fType = sGetLockType(lock->l_type, wait); linfo->fType = sGetLockType(lock->l_type, wait);
thread_info info;
get_thread_info(find_thread(NULL), &info);
linfo->fOwner = info.team;
do { do {
MutexLocker ownerLocker(linfo->fOwner->fLock);
RPC::Server* serv = fFilesystem->Server(); RPC::Server* serv = fFilesystem->Server();
Request request(serv); Request request(serv);
RequestBuilder& req = request.Builder(); RequestBuilder& req = request.Builder();
@@ -759,32 +762,33 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock,
status_t result = request.Send(); status_t result = request.Send();
if (result != B_OK) { if (result != B_OK) {
delete linfo; cookie->DeleteLock(linfo);
return result; return result;
} }
ReplyInterpreter &reply = request.Reply(); ReplyInterpreter &reply = request.Reply();
if (wait && reply.NFS4Error() == NFS4ERR_DENIED) {
snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
continue;
}
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
continue;
reply.PutFH(); reply.PutFH();
result = reply.Lock(linfo); result = reply.Lock(linfo);
ownerLocker.Unlock();
if (wait && reply.NFS4Error() == NFS4ERR_DENIED) {
snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE,
B_RELATIVE_TIMEOUT);
continue;
}
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
continue;
if (result != B_OK) { if (result != B_OK) {
delete linfo; cookie->DeleteLock(linfo);
return result; return result;
} }
break; break;
} while (true); } while (true);
MutexLocker _(cookie->fLocksLock); MutexLocker _(cookie->fLocksLock);
linfo->fNext = cookie->fLocks; cookie->AddLock(linfo);
cookie->fLocks = linfo;
return B_OK; return B_OK;
} }
@@ -794,19 +798,16 @@ status_t
Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock)
{ {
LockInfo* prev = NULL; LockInfo* prev = NULL;
uint32 owner = find_thread(NULL);
thread_info info;
get_thread_info(find_thread(NULL), &info);
uint32 owner = info.team;
MutexLocker locker(cookie->fLocksLock); MutexLocker locker(cookie->fLocksLock);
LockInfo* linfo = cookie->fLocks; LockInfo* linfo = cookie->fLocks;
while (linfo != NULL) { while (linfo != NULL) {
if (linfo->fOwner == owner && if (linfo->fOwner->fOwner == owner && *linfo == *lock) {
linfo->fStart == static_cast<uint64>(lock->l_start) && cookie->RemoveLock(linfo, prev);
(linfo->fLength == static_cast<uint64>(lock->l_len) ||
(linfo->fLength == UINT64_MAX && lock->l_len == OFF_MAX))) {
if (prev != NULL)
prev->fNext = linfo->fNext;
else
cookie->fLocks = linfo->fNext;
break; break;
} }
@@ -819,6 +820,8 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock)
return B_BAD_VALUE; return B_BAD_VALUE;
do { do {
MutexLocker ownerLocker(linfo->fOwner->fLock);
RPC::Server* serv = fFilesystem->Server(); RPC::Server* serv = fFilesystem->Server();
Request request(serv); Request request(serv);
RequestBuilder& req = request.Builder(); RequestBuilder& req = request.Builder();
@@ -827,23 +830,29 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock)
req.LockU(linfo); req.LockU(linfo);
status_t result = request.Send(); status_t result = request.Send();
if (result != B_OK) if (result != B_OK) {
cookie->DeleteLock(linfo);
return result; return result;
}
ReplyInterpreter &reply = request.Reply(); ReplyInterpreter &reply = request.Reply();
reply.PutFH();
result = reply.LockU(linfo);
ownerLocker.Unlock();
if (_HandleErrors(reply.NFS4Error(), serv, cookie)) if (_HandleErrors(reply.NFS4Error(), serv, cookie))
continue; continue;
reply.PutFH(); if (result != B_OK) {
result = reply.LockU(); cookie->DeleteLock(linfo);
if (result != B_OK)
return result; return result;
}
break; break;
} while (true); } while (true);
delete linfo; cookie->DeleteLock(linfo);
return B_OK; return B_OK;
} }
@@ -855,6 +864,8 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie)
MutexLocker _(cookie->fLocksLock); MutexLocker _(cookie->fLocksLock);
while (cookie->fLocks != NULL) { while (cookie->fLocks != NULL) {
do { do {
MutexLocker ownerLocker(cookie->fLocks->fOwner->fLock);
RPC::Server* serv = fFilesystem->Server(); RPC::Server* serv = fFilesystem->Server();
Request request(serv); Request request(serv);
RequestBuilder& req = request.Builder(); RequestBuilder& req = request.Builder();
@@ -868,20 +879,18 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie)
ReplyInterpreter &reply = request.Reply(); ReplyInterpreter &reply = request.Reply();
reply.PutFH();
reply.LockU(cookie->fLocks);
ownerLocker.Unlock();
if (_HandleErrors(reply.NFS4Error(), serv, cookie)) if (_HandleErrors(reply.NFS4Error(), serv, cookie))
continue; continue;
reply.PutFH();
result = reply.LockU();
if (result != B_OK)
return result;
break;
} while (true); } while (true);
LockInfo* linfo = cookie->fLocks->fNext; LockInfo* linfo = cookie->fLocks;
delete cookie->fLocks; cookie->RemoveLock(linfo, NULL);
cookie->fLocks = linfo; cookie->DeleteLock(linfo);
} }
return B_OK; return B_OK;
@@ -121,6 +121,12 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie)
MutexLocker _(cookie->fLocksLock); MutexLocker _(cookie->fLocksLock);
LockInfo* linfo = cookie->fLocks; LockInfo* linfo = cookie->fLocks;
while (linfo != NULL) { while (linfo != NULL) {
MutexLocker locker(linfo->fOwner->fLock);
if (linfo->fOwner->fClientId != fClientId) {
memset(linfo->fOwner->fStateId, 0, sizeof(linfo->fOwner->fStateId));
linfo->fOwner->fClientId = fClientId;
}
do { do {
Request request(fServer); Request request(fServer);
RequestBuilder& req = request.Builder(); RequestBuilder& req = request.Builder();
@@ -139,6 +145,7 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie)
break; break;
} while (true); } while (true);
locker.Unlock();
linfo = linfo->fNext; linfo = linfo->fNext;
} }
@@ -208,10 +208,10 @@ ReplyInterpreter::Lock(LockInfo* linfo)
if (res != B_OK) if (res != B_OK)
return res; return res;
linfo->fStateSeq = fReply->Stream().GetUInt(); linfo->fOwner->fStateSeq = fReply->Stream().GetUInt();
linfo->fStateId[0] = fReply->Stream().GetUInt(); linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt();
linfo->fStateId[1] = fReply->Stream().GetUInt(); linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt();
linfo->fStateId[2] = fReply->Stream().GetUInt(); linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt();
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
} }
@@ -236,16 +236,16 @@ ReplyInterpreter::LockT(uint64* pos, uint64* len, LockType* type)
status_t status_t
ReplyInterpreter::LockU() ReplyInterpreter::LockU(LockInfo* linfo)
{ {
status_t res = _OperationError(OpLockU); status_t res = _OperationError(OpLockU);
if (res != B_OK) if (res != B_OK)
return res; return res;
fReply->Stream().GetUInt(); linfo->fOwner->fStateSeq = fReply->Stream().GetUInt();
fReply->Stream().GetUInt(); linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt();
fReply->Stream().GetUInt(); linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt();
fReply->Stream().GetUInt(); linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt();
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
} }
@@ -74,7 +74,7 @@ public:
status_t Link(); status_t Link();
status_t Lock(LockInfo* linfo); status_t Lock(LockInfo* linfo);
status_t LockT(uint64* pos, uint64* len, LockType* type); status_t LockT(uint64* pos, uint64* len, LockType* type);
status_t LockU(); status_t LockU(LockInfo* linfo);
inline status_t LookUp(); inline status_t LookUp();
inline status_t LookUpUp(); inline status_t LookUpUp();
inline status_t Nverify(); inline status_t Nverify();
@@ -164,19 +164,38 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim)
fRequest->Stream().AddUHyper(lock->fStart); fRequest->Stream().AddUHyper(lock->fStart);
fRequest->Stream().AddUHyper(lock->fLength); fRequest->Stream().AddUHyper(lock->fLength);
fRequest->Stream().AddBoolean(true); // new lock owner if (lock->fOwner->fStateId[0] == 0 && lock->fOwner->fStateId[1] == 0
&& lock->fOwner->fStateId[2] == 0) {
// open seq stateid fRequest->Stream().AddBoolean(true); // new lock owner
fRequest->Stream().AddUInt(cookie->fSequence++);
fRequest->Stream().AddUInt(cookie->fStateSeq);
fRequest->Stream().AddUInt(cookie->fStateId[0]);
fRequest->Stream().AddUInt(cookie->fStateId[1]);
fRequest->Stream().AddUInt(cookie->fStateId[2]);
// lock seq owner // open seq stateid
fRequest->Stream().AddUInt(lock->fSequence++); fRequest->Stream().AddUInt(cookie->fSequence++);
fRequest->Stream().AddUHyper(cookie->fClientId); fRequest->Stream().AddUInt(cookie->fStateSeq);
fRequest->Stream().AddOpaque(&lock->fOwner, sizeof(lock->fOwner)); fRequest->Stream().AddUInt(cookie->fStateId[0]);
fRequest->Stream().AddUInt(cookie->fStateId[1]);
fRequest->Stream().AddUInt(cookie->fStateId[2]);
// lock seq owner
fRequest->Stream().AddUInt(lock->fOwner->fSequence++);
fRequest->Stream().AddUHyper(cookie->fClientId);
uint64 owner[2];
owner[0] = lock->fOwner->fOwner;
owner[1] = cookie->fOwnerId;
fRequest->Stream().AddOpaque(owner, sizeof(owner));
} else {
fRequest->Stream().AddBoolean(false); // old lock owner
// lock stateid seq
fRequest->Stream().AddUInt(lock->fOwner->fStateSeq);
fRequest->Stream().AddUInt(lock->fOwner->fStateId[0]);
fRequest->Stream().AddUInt(lock->fOwner->fStateId[1]);
fRequest->Stream().AddUInt(lock->fOwner->fStateId[2]);
fRequest->Stream().AddUInt(lock->fOwner->fSequence++);
}
fOpCount++; fOpCount++;
@@ -223,11 +242,11 @@ RequestBuilder::LockU(LockInfo* lock)
fRequest->Stream().AddInt(lock->fType); fRequest->Stream().AddInt(lock->fType);
fRequest->Stream().AddUInt(lock->fSequence++); fRequest->Stream().AddUInt(lock->fOwner->fSequence++);
fRequest->Stream().AddUInt(lock->fStateSeq); fRequest->Stream().AddUInt(lock->fOwner->fStateSeq);
fRequest->Stream().AddUInt(lock->fStateId[0]); fRequest->Stream().AddUInt(lock->fOwner->fStateId[0]);
fRequest->Stream().AddUInt(lock->fStateId[1]); fRequest->Stream().AddUInt(lock->fOwner->fStateId[1]);
fRequest->Stream().AddUInt(lock->fStateId[2]); fRequest->Stream().AddUInt(lock->fOwner->fStateId[2]);
fRequest->Stream().AddUHyper(lock->fStart); fRequest->Stream().AddUHyper(lock->fStart);
fRequest->Stream().AddUHyper(lock->fLength); fRequest->Stream().AddUHyper(lock->fLength);