nfs4: Fix server reboot recovery
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user