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