From 62869605c565855e3293809a9974846fa50c423f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 23:54:48 +0200 Subject: [PATCH] nfs4: Add proper lock owners management --- .../kernel/file_systems/nfs4/Cookie.cpp | 116 ++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Cookie.h | 34 ++++- .../kernel/file_systems/nfs4/Inode.cpp | 91 +++++++------- .../kernel/file_systems/nfs4/NFS4Server.cpp | 7 ++ .../file_systems/nfs4/ReplyInterpreter.cpp | 18 +-- .../file_systems/nfs4/ReplyInterpreter.h | 2 +- .../file_systems/nfs4/RequestBuilder.cpp | 51 +++++--- 7 files changed, 250 insertions(+), 69 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 38e6b311c5..ba0398e0d0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -16,6 +16,50 @@ 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(lock.l_start); + uint64 len = static_cast(lock.l_len); + + return fStart == start && fLength == len || eof && fLength == UINT64_MAX; +} + + Cookie::Cookie() : fRequests(NULL), @@ -89,13 +133,85 @@ Cookie::CancelAll() OpenFileCookie::OpenFileCookie() + : + fLockOwners(NULL) { mutex_init(&fLocksLock, NULL); + mutex_init(&fOwnerLock, NULL); } OpenFileCookie::~OpenFileCookie() { 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; + } } diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index e1d9badd4b..d9711a6f5a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -14,18 +14,39 @@ #include "Filesystem.h" -struct LockInfo { +struct LockOwner { + uint64 fClientId; + uint32 fStateId[3]; uint32 fStateSeq; - uint32 fSequence; uint32 fOwner; + + uint32 fUseCount; + + mutex fLock; + + LockOwner* fNext; + LockOwner* fPrev; + + LockOwner(uint32 owner); + ~LockOwner(); +}; + +struct LockInfo { + LockOwner* fOwner; + uint64 fStart; uint64 fLength; LockType fType; LockInfo* fNext; + + LockInfo(LockOwner* owner); + ~LockInfo(); + + bool operator==(const struct flock& lock) const; }; struct Cookie { @@ -65,11 +86,20 @@ struct OpenFileCookie : public Cookie { LockInfo* fLocks; mutex fLocksLock; + LockOwner* fLockOwners; + mutex fOwnerLock; + OpenFileCookie* fNext; OpenFileCookie* fPrev; OpenFileCookie(); ~OpenFileCookie(); + + LockOwner* GetLockOwner(uint32 owner); + + void AddLock(LockInfo* lock); + void RemoveLock(LockInfo* lock, LockInfo* prev); + void DeleteLock(LockInfo* lock); }; struct OpenDirCookie : public Cookie { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index dd7ade5340..0856e4d017 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -733,11 +733,16 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, if (result != B_OK) 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) return B_NO_MEMORY; - linfo->fSequence = 0; linfo->fStart = lock->l_start; if (lock->l_len + lock->l_start == OFF_MAX) linfo->fLength = UINT64_MAX; @@ -745,11 +750,9 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, linfo->fLength = lock->l_len; linfo->fType = sGetLockType(lock->l_type, wait); - thread_info info; - get_thread_info(find_thread(NULL), &info); - linfo->fOwner = info.team; - do { + MutexLocker ownerLocker(linfo->fOwner->fLock); + RPC::Server* serv = fFilesystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -759,32 +762,33 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, status_t result = request.Send(); if (result != B_OK) { - delete linfo; + cookie->DeleteLock(linfo); return result; } 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(); 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) { - delete linfo; + cookie->DeleteLock(linfo); return result; } - break; } while (true); MutexLocker _(cookie->fLocksLock); - linfo->fNext = cookie->fLocks; - cookie->fLocks = linfo; + cookie->AddLock(linfo); return B_OK; } @@ -794,19 +798,16 @@ status_t Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) { 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); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { - if (linfo->fOwner == owner && - linfo->fStart == static_cast(lock->l_start) && - (linfo->fLength == static_cast(lock->l_len) || - (linfo->fLength == UINT64_MAX && lock->l_len == OFF_MAX))) { - if (prev != NULL) - prev->fNext = linfo->fNext; - else - cookie->fLocks = linfo->fNext; + if (linfo->fOwner->fOwner == owner && *linfo == *lock) { + cookie->RemoveLock(linfo, prev); break; } @@ -819,6 +820,8 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) return B_BAD_VALUE; do { + MutexLocker ownerLocker(linfo->fOwner->fLock); + RPC::Server* serv = fFilesystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -827,23 +830,29 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) req.LockU(linfo); status_t result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + cookie->DeleteLock(linfo); return result; + } ReplyInterpreter &reply = request.Reply(); + reply.PutFH(); + result = reply.LockU(linfo); + + ownerLocker.Unlock(); if (_HandleErrors(reply.NFS4Error(), serv, cookie)) continue; - reply.PutFH(); - result = reply.LockU(); - if (result != B_OK) + if (result != B_OK) { + cookie->DeleteLock(linfo); return result; + } break; } while (true); - delete linfo; + cookie->DeleteLock(linfo); return B_OK; } @@ -855,6 +864,8 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) MutexLocker _(cookie->fLocksLock); while (cookie->fLocks != NULL) { do { + MutexLocker ownerLocker(cookie->fLocks->fOwner->fLock); + RPC::Server* serv = fFilesystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -868,20 +879,18 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) ReplyInterpreter &reply = request.Reply(); + reply.PutFH(); + reply.LockU(cookie->fLocks); + + ownerLocker.Unlock(); if (_HandleErrors(reply.NFS4Error(), serv, cookie)) continue; - reply.PutFH(); - result = reply.LockU(); - if (result != B_OK) - return result; - - break; } while (true); - LockInfo* linfo = cookie->fLocks->fNext; - delete cookie->fLocks; - cookie->fLocks = linfo; + LockInfo* linfo = cookie->fLocks; + cookie->RemoveLock(linfo, NULL); + cookie->DeleteLock(linfo); } return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 6fd109e7b3..17908e7fa3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -121,6 +121,12 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) MutexLocker _(cookie->fLocksLock); LockInfo* linfo = cookie->fLocks; 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 { Request request(fServer); RequestBuilder& req = request.Builder(); @@ -139,6 +145,7 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) break; } while (true); + locker.Unlock(); linfo = linfo->fNext; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 471b709016..c5c97c84c5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -208,10 +208,10 @@ ReplyInterpreter::Lock(LockInfo* linfo) if (res != B_OK) return res; - linfo->fStateSeq = fReply->Stream().GetUInt(); - linfo->fStateId[0] = fReply->Stream().GetUInt(); - linfo->fStateId[1] = fReply->Stream().GetUInt(); - linfo->fStateId[2] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateSeq = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt(); return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } @@ -236,16 +236,16 @@ ReplyInterpreter::LockT(uint64* pos, uint64* len, LockType* type) status_t -ReplyInterpreter::LockU() +ReplyInterpreter::LockU(LockInfo* linfo) { status_t res = _OperationError(OpLockU); if (res != B_OK) return res; - fReply->Stream().GetUInt(); - fReply->Stream().GetUInt(); - fReply->Stream().GetUInt(); - fReply->Stream().GetUInt(); + linfo->fOwner->fStateSeq = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt(); return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index b96499f995..c0cbb1dd4d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -74,7 +74,7 @@ public: status_t Link(); status_t Lock(LockInfo* linfo); status_t LockT(uint64* pos, uint64* len, LockType* type); - status_t LockU(); + status_t LockU(LockInfo* linfo); inline status_t LookUp(); inline status_t LookUpUp(); inline status_t Nverify(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 5654c94835..77883fa637 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -164,19 +164,38 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim) fRequest->Stream().AddUHyper(lock->fStart); 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().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]); + fRequest->Stream().AddBoolean(true); // new lock owner - // lock seq owner - fRequest->Stream().AddUInt(lock->fSequence++); - fRequest->Stream().AddUHyper(cookie->fClientId); - fRequest->Stream().AddOpaque(&lock->fOwner, sizeof(lock->fOwner)); + // open seq stateid + 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 + 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++; @@ -223,11 +242,11 @@ RequestBuilder::LockU(LockInfo* lock) fRequest->Stream().AddInt(lock->fType); - fRequest->Stream().AddUInt(lock->fSequence++); - fRequest->Stream().AddUInt(lock->fStateSeq); - fRequest->Stream().AddUInt(lock->fStateId[0]); - fRequest->Stream().AddUInt(lock->fStateId[1]); - fRequest->Stream().AddUInt(lock->fStateId[2]); + fRequest->Stream().AddUInt(lock->fOwner->fSequence++); + 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().AddUHyper(lock->fStart); fRequest->Stream().AddUHyper(lock->fLength);