nfs4: Fix server reboot recovery

This commit is contained in:
Pawel Dziepak
2012-08-10 02:34:41 +02:00
parent 0e0d53c799
commit b1fd656d45
14 changed files with 73 additions and 41 deletions
@@ -53,7 +53,7 @@ Delegation::ReturnDelegation()
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv)) if (HandleErrors(reply.NFS4Error(), serv, NULL, fInode->GetOpenState()))
continue; continue;
reply.PutFH(); reply.PutFH();
@@ -25,6 +25,7 @@ public:
status_t GiveUp(bool truncate = false); status_t GiveUp(bool truncate = false);
inline void SetData(const OpenDelegationData& data);
inline Inode* GetInode(); inline Inode* GetInode();
inline OpenDelegation Type(); inline OpenDelegation Type();
@@ -39,6 +40,13 @@ private:
}; };
inline void
Delegation::SetData(const OpenDelegationData& data)
{
fData = data;
}
inline Inode* inline Inode*
Delegation::GetInode() Delegation::GetInode()
{ {
@@ -25,7 +25,6 @@ FileSystem::FileSystem()
: :
fNext(NULL), fNext(NULL),
fPrev(NULL), fPrev(NULL),
fOpenFiles(NULL),
fOpenCount(0), fOpenCount(0),
fOpenOwnerSequence(0), fOpenOwnerSequence(0),
fPath(NULL), fPath(NULL),
@@ -267,7 +266,7 @@ FileSystem::Migrate(const RPC::Server* serv)
} }
OpenState* DoublyLinkedList<OpenState>&
FileSystem::OpenFilesLock() FileSystem::OpenFilesLock()
{ {
mutex_lock(&fOpenLock); mutex_lock(&fOpenLock);
@@ -287,11 +286,8 @@ FileSystem::AddOpenFile(OpenState* state)
{ {
MutexLocker _(fOpenLock); MutexLocker _(fOpenLock);
state->fPrev = NULL; fOpenFiles.InsertBefore(fOpenFiles.Head(), state);
state->fNext = fOpenFiles;
if (fOpenFiles != NULL)
fOpenFiles->fPrev = state;
fOpenFiles = state;
NFSServer()->IncUsage(); NFSServer()->IncUsage();
} }
@@ -300,13 +296,9 @@ void
FileSystem::RemoveOpenFile(OpenState* state) FileSystem::RemoveOpenFile(OpenState* state)
{ {
MutexLocker _(fOpenLock); MutexLocker _(fOpenLock);
if (state == fOpenFiles)
fOpenFiles = state->fNext;
if (state->fNext) fOpenFiles.Remove(state);
state->fNext->fPrev = state->fPrev;
if (state->fPrev)
state->fPrev->fNext = state->fNext;
NFSServer()->DecUsage(); NFSServer()->DecUsage();
} }
@@ -335,8 +327,6 @@ FileSystem::AddDelegation(Delegation* delegation)
fHandleToDelegation.Remove(delegation->fInfo.fHandle); fHandleToDelegation.Remove(delegation->fInfo.fHandle);
fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation); fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation);
NFSServer()->IncUsage();
} }
@@ -347,8 +337,6 @@ FileSystem::RemoveDelegation(Delegation* delegation)
fDelegationList.Remove(delegation); fDelegationList.Remove(delegation);
fHandleToDelegation.Remove(delegation->fInfo.fHandle); fHandleToDelegation.Remove(delegation->fInfo.fHandle);
NFSServer()->DecUsage();
} }
@@ -30,7 +30,7 @@ public:
status_t Migrate(const RPC::Server* serv); status_t Migrate(const RPC::Server* serv);
OpenState* OpenFilesLock(); DoublyLinkedList<OpenState>& OpenFilesLock();
void OpenFilesUnlock(); void OpenFilesUnlock();
inline uint32 OpenFilesCount(); inline uint32 OpenFilesCount();
void AddOpenFile(OpenState* state); void AddOpenFile(OpenState* state);
@@ -73,7 +73,7 @@ private:
DoublyLinkedList<Delegation> fDelegationList; DoublyLinkedList<Delegation> fDelegationList;
AVLTreeMap<FileHandle, Delegation*> fHandleToDelegation; AVLTreeMap<FileHandle, Delegation*> fHandleToDelegation;
OpenState* fOpenFiles; DoublyLinkedList<OpenState> fOpenFiles;
uint32 fOpenCount; uint32 fOpenCount;
mutex fOpenLock; mutex fOpenLock;
@@ -857,9 +857,9 @@ Inode::RecallReadDelegation()
void void
Inode::ReturnDelegation(bool truncate) Inode::ReturnDelegation(bool truncate)
{ {
fMetaCache.UnlockValid();
fDelegation->GiveUp(truncate); fDelegation->GiveUp(truncate);
fMetaCache.UnlockValid();
fFileSystem->RemoveDelegation(fDelegation); fFileSystem->RemoveDelegation(fDelegation);
MutexLocker stateLocker(fStateLock); MutexLocker stateLocker(fStateLock);
@@ -874,10 +874,8 @@ Inode::ReturnDelegation(bool truncate)
void void
Inode::ReleaseOpenState() Inode::ReleaseOpenState()
{ {
if (fOpenState->ReleaseReference() == 1) { if (fOpenState->ReleaseReference() == 1)
fFileSystem->RemoveOpenFile(fOpenState);
fOpenState = NULL; fOpenState = NULL;
}
} }
@@ -37,6 +37,8 @@ public:
inline uint64 Change(); inline uint64 Change();
inline bool Dirty(); inline bool Dirty();
inline OpenState* GetOpenState();
void SetDelegation(Delegation* delegation); void SetDelegation(Delegation* delegation);
void RecallDelegation(bool truncate = false); void RecallDelegation(bool truncate = false);
void RecallReadDelegation(); void RecallReadDelegation();
@@ -230,5 +232,12 @@ Inode::Dirty()
} }
inline OpenState*
Inode::GetOpenState()
{
return fOpenState;
}
#endif // INODE_H #endif // INODE_H
@@ -252,7 +252,6 @@ Inode::CloseAttr(OpenAttrCookie* cookie)
fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation); fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation);
delete cookie->fOpenState->fDelegation; delete cookie->fOpenState->fDelegation;
delete cookie->fOpenState; delete cookie->fOpenState;
return B_OK; return B_OK;
} }
@@ -553,7 +553,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence))
continue; continue;
fFileSystem->OpenOwnerSequenceUnlock(); fFileSystem->OpenOwnerSequenceUnlock();
@@ -16,7 +16,7 @@
bool bool
NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
OpenStateCookie* cookie, OpenState* state) OpenStateCookie* cookie, OpenState* state, uint32* sequence)
{ {
uint32 leaseTime; uint32 leaseTime;
@@ -67,7 +67,14 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
case NFS4ERR_STALE_CLIENTID: case NFS4ERR_STALE_CLIENTID:
case NFS4ERR_STALE_STATEID: case NFS4ERR_STALE_STATEID:
if (state != NULL) { if (state != NULL) {
if (sequence != NULL)
fFileSystem->OpenOwnerSequenceUnlock(false);
fFileSystem->NFSServer()->ServerRebooted(state->fClientID); fFileSystem->NFSServer()->ServerRebooted(state->fClientID);
dprintf("returned rebooted\n");
if (sequence != NULL)
*sequence = fFileSystem->OpenOwnerSequenceLock();
dprintf("locked again\n");
return true; return true;
} }
return false; return false;
@@ -19,7 +19,8 @@ class OpenState;
class NFS4Object { class NFS4Object {
public: public:
bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, bool HandleErrors(uint32 nfs4Error, RPC::Server* serv,
OpenStateCookie* cookie = NULL, OpenState* state = NULL); OpenStateCookie* cookie = NULL, OpenState* state = NULL,
uint32* sequence = NULL);
status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state); status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state);
@@ -58,11 +58,13 @@ NFS4Server::ServerRebooted(uint64 clientId)
MutexLocker _(fFSLock); MutexLocker _(fFSLock);
FileSystem* fs = fFileSystems; FileSystem* fs = fFileSystems;
while (fs != NULL) { while (fs != NULL) {
OpenState* current = fs->OpenFilesLock(); DoublyLinkedList<OpenState>::Iterator iterator
= fs->OpenFilesLock().GetIterator();
OpenState* current = iterator.Next();
while (current != NULL) { while (current != NULL) {
current->Reclaim(fClientId); current->Reclaim(fClientId);
current = current->fNext; current = iterator.Next();
} }
fs->OpenFilesUnlock(); fs->OpenFilesUnlock();
@@ -13,6 +13,7 @@
#include "FileSystem.h" #include "FileSystem.h"
#include "Request.h" #include "Request.h"
#include "WorkQueue.h"
OpenState::OpenState() OpenState::OpenState()
@@ -31,7 +32,9 @@ OpenState::OpenState()
OpenState::~OpenState() OpenState::~OpenState()
{ {
fFileSystem->RemoveOpenFile(this);
Close(); Close();
mutex_destroy(&fLock); mutex_destroy(&fLock);
mutex_destroy(&fLocksLock); mutex_destroy(&fLocksLock);
@@ -140,9 +143,10 @@ OpenState::Reclaim(uint64 newClientID)
if (fClientID == newClientID) if (fClientID == newClientID)
return B_OK; return B_OK;
fClientID = newClientID; fClientID = newClientID;
dprintf("reclaim start\n");
_ReclaimOpen(newClientID); _ReclaimOpen(newClientID);
_ReclaimLocks(newClientID); _ReclaimLocks(newClientID);
dprintf("reclaim end\n");
return B_OK; return B_OK;
} }
@@ -150,10 +154,16 @@ OpenState::Reclaim(uint64 newClientID)
status_t status_t
OpenState::_ReclaimOpen(uint64 newClientID) OpenState::_ReclaimOpen(uint64 newClientID)
{ {
dprintf("reclaim %s\n", fInfo.fName);
bool confirm; bool confirm;
OpenDelegationData delegation; OpenDelegationData delegation;
delegation.fType = OPEN_DELEGATE_NONE;
delegation.fRecall = false;
uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
OpenDelegation delegType = fDelegation != NULL ? fDelegation->Type()
: OPEN_DELEGATE_NONE;
do { do {
RPC::Server* server = fFileSystem->Server(); RPC::Server* server = fFileSystem->Server();
Request request(server); Request request(server);
@@ -162,7 +172,7 @@ OpenState::_ReclaimOpen(uint64 newClientID)
req.PutFH(fInfo.fHandle); req.PutFH(fInfo.fHandle);
req.Open(CLAIM_PREVIOUS, sequence, sModeToAccess(fMode), newClientID, req.Open(CLAIM_PREVIOUS, sequence, sModeToAccess(fMode), newClientID,
OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL, NULL, 0, false, OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL, NULL, 0, false,
fDelegation->Type()); delegType);
status_t result = request.Send(); status_t result = request.Send();
if (result != B_OK) { if (result != B_OK) {
@@ -172,7 +182,7 @@ OpenState::_ReclaimOpen(uint64 newClientID)
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), server)) if (HandleErrors(reply.NFS4Error(), server, NULL, NULL, &sequence))
continue; continue;
fFileSystem->OpenOwnerSequenceUnlock(); fFileSystem->OpenOwnerSequenceUnlock();
@@ -182,10 +192,19 @@ OpenState::_ReclaimOpen(uint64 newClientID)
result = reply.Open(fStateID, &fStateSeq, &confirm, &delegation); result = reply.Open(fStateID, &fStateSeq, &confirm, &delegation);
if (result != B_OK) if (result != B_OK)
return result; return result;
break;
} while (true); } while (true);
if (delegation.fRecall) if (fDelegation != NULL)
fDelegation->GiveUp(); fDelegation->SetData(delegation);
if (delegation.fRecall) {
DelegationRecallArgs* args = new(std::nothrow) DelegationRecallArgs;
args->fDelegation = fDelegation;
args->fTruncate = false;
gWorkQueue->EnqueueJob(DelegationRecall, args);
}
if (confirm) if (confirm)
return ConfirmOpen(fInfo.fHandle, this); return ConfirmOpen(fInfo.fHandle, this);
@@ -197,6 +216,8 @@ OpenState::_ReclaimOpen(uint64 newClientID)
status_t status_t
OpenState::_ReclaimLocks(uint64 newClientID) OpenState::_ReclaimLocks(uint64 newClientID)
{ {
dprintf("reclaim locks %s\n", fInfo.fName);
MutexLocker _(fLocksLock); MutexLocker _(fLocksLock);
LockInfo* linfo = fLocks; LockInfo* linfo = fLocks;
while (linfo != NULL) { while (linfo != NULL) {
@@ -264,7 +285,7 @@ OpenState::Close()
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv, NULL, this)) if (HandleErrors(reply.NFS4Error(), serv, NULL, this, &sequence))
continue; continue;
fFileSystem->OpenOwnerSequenceUnlock(); fFileSystem->OpenOwnerSequenceUnlock();
@@ -17,7 +17,8 @@
#include "NFS4Object.h" #include "NFS4Object.h"
struct OpenState : public NFS4Object, public KernelReferenceable { struct OpenState : public NFS4Object, public KernelReferenceable,
public DoublyLinkedListLinkImpl<OpenState> {
OpenState(); OpenState();
~OpenState(); ~OpenState();
@@ -38,9 +39,6 @@ struct OpenState : public NFS4Object, public KernelReferenceable {
LockOwner* fLockOwners; LockOwner* fLockOwners;
mutex fOwnerLock; mutex fOwnerLock;
OpenState* fNext;
OpenState* fPrev;
LockOwner* GetLockOwner(uint32 owner); LockOwner* GetLockOwner(uint32 owner);
void AddLock(LockInfo* lock); void AddLock(LockInfo* lock);
@@ -827,6 +827,7 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x)
case NFS4ERR_ISDIR: return B_IS_A_DIRECTORY; case NFS4ERR_ISDIR: return B_IS_A_DIRECTORY;
case NFS4ERR_INVAL: return B_BAD_VALUE; case NFS4ERR_INVAL: return B_BAD_VALUE;
case NFS4ERR_FBIG: return B_FILE_TOO_LARGE; case NFS4ERR_FBIG: return B_FILE_TOO_LARGE;
case NFS4ERR_NOTSUPP: return B_UNSUPPORTED;
// ... // ...
case NFS4ERR_DELAY: case NFS4ERR_DELAY:
case NFS4ERR_DENIED: case NFS4ERR_DENIED: