nfs4: Use one open state per inode
This commit is contained in:
@@ -161,7 +161,6 @@ OpenFileCookie::GetLockOwner(uint32 owner)
|
||||
if (current == NULL)
|
||||
return NULL;
|
||||
|
||||
current->fClientId = fClientID;
|
||||
current->fNext = fLockOwners;
|
||||
if (fLockOwners != NULL)
|
||||
fLockOwners->fPrev = current;
|
||||
|
||||
@@ -71,10 +71,7 @@ struct Cookie {
|
||||
};
|
||||
|
||||
struct OpenFileCookie : public Cookie {
|
||||
uint64 fClientID;
|
||||
|
||||
OpenState* fReadState;
|
||||
OpenState* fWriteState;
|
||||
OpenState* fOpenState;
|
||||
|
||||
uint32 fMode;
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Paweł Dziepak, [email protected]
|
||||
*/
|
||||
#ifndef DELEGATION_H
|
||||
#define DELEGATION_H
|
||||
|
||||
|
||||
#include <lock.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "NFS4Object.h"
|
||||
|
||||
|
||||
class Delegation : public NFS4Object {
|
||||
public:
|
||||
Delegation(OpenDelegationData data, Inode* inode,
|
||||
uint64 clientID);
|
||||
~Delegation();
|
||||
|
||||
status_t Write(void* buffer, uint32* size);
|
||||
status_t Read(void* buffer, uint32* size);
|
||||
|
||||
// TODO: locks
|
||||
|
||||
status_t Reclaim(uint64 newClientID);
|
||||
|
||||
status_t GiveUp(bool flush);
|
||||
|
||||
private:
|
||||
uint64 fClientID;
|
||||
OpenDelegationData fData;
|
||||
Inode* fInode;
|
||||
|
||||
rw_lock fLock;
|
||||
};
|
||||
|
||||
|
||||
#endif // DELEGATION_H
|
||||
|
||||
@@ -24,8 +24,7 @@ Inode::Inode()
|
||||
:
|
||||
fCache(NULL),
|
||||
fFileCache(NULL),
|
||||
fWriteState(NULL),
|
||||
fReadState(NULL),
|
||||
fOpenState(NULL),
|
||||
fWriteDirty(false)
|
||||
{
|
||||
mutex_init(&fStateLock, NULL);
|
||||
@@ -530,7 +529,7 @@ Inode::WriteStat(const struct stat* st, uint32 mask)
|
||||
}
|
||||
|
||||
MutexLocker stateLocker(fStateLock);
|
||||
result = NFS4Inode::WriteStat(fWriteState, attr, i);
|
||||
result = NFS4Inode::WriteStat(fOpenState, attr, i);
|
||||
stateLocker.Unlock();
|
||||
|
||||
fMetaCache.InvalidateStat();
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "OpenState.h"
|
||||
|
||||
|
||||
class Delegation;
|
||||
|
||||
class Inode : public NFS4Inode {
|
||||
public:
|
||||
static status_t CreateInode(FileSystem* fs, const FileInfo& fi,
|
||||
@@ -25,6 +27,8 @@ public:
|
||||
inline const char* Name() const;
|
||||
inline FileSystem* GetFileSystem() const;
|
||||
|
||||
inline void SetOpenState(OpenState* state);
|
||||
|
||||
inline void* FileCache();
|
||||
status_t RevalidateFileCache();
|
||||
|
||||
@@ -93,17 +97,20 @@ protected:
|
||||
|
||||
static inline ino_t FileIdToInoT(uint64 fileid);
|
||||
|
||||
private:
|
||||
uint32 fType;
|
||||
|
||||
MetadataCache fMetaCache;
|
||||
DirectoryCache* fCache;
|
||||
|
||||
rw_lock fDelegationLock;
|
||||
Delegation* fDelegation;
|
||||
|
||||
uint64 fChange;
|
||||
void* fFileCache;
|
||||
mutex fFileCacheLock;
|
||||
|
||||
OpenState* fWriteState;
|
||||
OpenState* fReadState;
|
||||
OpenState* fOpenState;
|
||||
mutex fStateLock;
|
||||
|
||||
bool fWriteDirty;
|
||||
@@ -156,5 +163,13 @@ Inode::FileCache()
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
Inode::SetOpenState(OpenState* state)
|
||||
{
|
||||
MutexLocker _(fStateLock);
|
||||
fOpenState = state;
|
||||
}
|
||||
|
||||
|
||||
#endif // INODE_H
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ inline status_t
|
||||
InodeIdMap::AddEntry(const FileInfo& fi, ino_t id)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
fMap.Remove(id);
|
||||
return fMap.Insert(id, fi);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,44 +70,19 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
|
||||
cookie->fLocks = NULL;
|
||||
|
||||
MutexLocker _(fStateLock);
|
||||
int openMode = mode & O_RWMASK;
|
||||
|
||||
if (openMode == O_WRONLY || openMode == O_RDWR) {
|
||||
OpenState* state = new OpenState;
|
||||
status_t result = CreateState(name, O_WRONLY, perms, state);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
OpenState* state = new OpenState;
|
||||
status_t result = CreateState(name, mode, perms, state);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fWriteState = state;
|
||||
*id = FileIdToInoT(cookie->fWriteState->fInfo.fFileId);
|
||||
cookie->fWriteState = fWriteState;
|
||||
}
|
||||
cookie->fOpenState = state;
|
||||
fOpenState = state;
|
||||
|
||||
if (openMode == O_RDONLY || openMode == O_RDWR) {
|
||||
OpenState* state = new OpenState;
|
||||
state->fInfo = fInfo;
|
||||
state->fFileSystem = fFileSystem;
|
||||
|
||||
status_t result;
|
||||
if (openMode == O_RDWR)
|
||||
result = OpenFile(state, O_RDONLY);
|
||||
else
|
||||
result = CreateState(name, O_RDONLY, perms, state);
|
||||
|
||||
if (result != B_OK) {
|
||||
if (fWriteState != NULL)
|
||||
if (fWriteState->ReleaseReference() == 1)
|
||||
fWriteState = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
fReadState = state;
|
||||
*id = FileIdToInoT(cookie->fReadState->fInfo.fFileId);
|
||||
cookie->fReadState = fReadState;
|
||||
}
|
||||
*id = FileIdToInoT(state->fInfo.fFileId);
|
||||
cookie->fOpenState = fOpenState;
|
||||
|
||||
cookie->fFileSystem = fFileSystem;
|
||||
cookie->fClientID = fFileSystem->NFSServer()->ClientId();
|
||||
|
||||
fFileSystem->AddOpenFile(cookie);
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
@@ -120,55 +95,33 @@ status_t
|
||||
Inode::Open(int mode, OpenFileCookie* cookie)
|
||||
{
|
||||
MutexLocker _(fStateLock);
|
||||
int openMode = mode & O_RWMASK;
|
||||
|
||||
if (openMode == O_WRONLY || openMode == O_RDWR) {
|
||||
if (fWriteState == NULL) {
|
||||
OpenState* state = new OpenState;
|
||||
if (state == NULL)
|
||||
return B_NO_MEMORY;
|
||||
if (fOpenState == NULL) {
|
||||
OpenState* state = new OpenState;
|
||||
if (state == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
state->fInfo = fInfo;
|
||||
state->fFileSystem = fFileSystem;
|
||||
status_t result = OpenFile(state, O_WRONLY);
|
||||
state->fInfo = fInfo;
|
||||
state->fFileSystem = fFileSystem;
|
||||
status_t result = OpenFile(state, mode, NULL);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fOpenState = state;
|
||||
} else {
|
||||
int newMode = mode & O_RWMASK;
|
||||
int oldMode = fOpenState->fMode & O_RWMASK;
|
||||
if (oldMode != newMode && oldMode != O_RDWR) {
|
||||
status_t result = OpenFile(fOpenState, O_RDWR, NULL);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fWriteState = state;
|
||||
} else
|
||||
fWriteState->AcquireReference();
|
||||
|
||||
cookie->fWriteState = fWriteState;
|
||||
fOpenState->fMode = O_RDWR;
|
||||
}
|
||||
fOpenState->AcquireReference();
|
||||
}
|
||||
|
||||
if (openMode == O_RDONLY || openMode == O_RDWR) {
|
||||
if (fReadState == NULL) {
|
||||
OpenState* state = new OpenState;
|
||||
if (state == NULL) {
|
||||
if (fWriteState != NULL)
|
||||
if (fWriteState->ReleaseReference() == 1)
|
||||
fWriteState = NULL;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
cookie->fOpenState = fOpenState;
|
||||
|
||||
state->fInfo = fInfo;
|
||||
state->fFileSystem = fFileSystem;
|
||||
status_t result = OpenFile(state, O_RDONLY);
|
||||
if (result != B_OK) {
|
||||
if (fWriteState != NULL)
|
||||
if (fWriteState->ReleaseReference() == 1)
|
||||
fWriteState = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
fReadState = state;
|
||||
} else
|
||||
fReadState->AcquireReference();
|
||||
|
||||
cookie->fReadState = fReadState;
|
||||
}
|
||||
|
||||
cookie->fClientID = fFileSystem->NFSServer()->ClientId();
|
||||
cookie->fFileSystem = fFileSystem;
|
||||
cookie->fMode = mode;
|
||||
cookie->fLocks = NULL;
|
||||
@@ -185,13 +138,9 @@ Inode::Close(OpenFileCookie* cookie)
|
||||
fFileSystem->RemoveOpenFile(cookie);
|
||||
|
||||
MutexLocker _(fStateLock);
|
||||
if (cookie->fWriteState != NULL)
|
||||
if (cookie->fWriteState->ReleaseReference() == 1)
|
||||
fWriteState = NULL;
|
||||
|
||||
if (cookie->fReadState != NULL)
|
||||
if (cookie->fReadState->ReleaseReference() == 1)
|
||||
fReadState = NULL;
|
||||
if (cookie->fOpenState != NULL)
|
||||
if (cookie->fOpenState->ReleaseReference() == 1)
|
||||
fOpenState = NULL;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -207,7 +156,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length,
|
||||
status_t result;
|
||||
while (size < *_length && !*eof) {
|
||||
uint32 len = *_length - size;
|
||||
result = ReadFile(cookie, fReadState, pos + size, &len,
|
||||
result = ReadFile(cookie, fOpenState, pos + size, &len,
|
||||
reinterpret_cast<char*>(buffer) + size, eof);
|
||||
if (result != B_OK) {
|
||||
if (size == 0)
|
||||
@@ -236,7 +185,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
|
||||
while (size < *_length) {
|
||||
uint32 len = *_length - size;
|
||||
status_t result = WriteFile(cookie, fWriteState, pos + size, &len,
|
||||
status_t result = WriteFile(cookie, fOpenState, pos + size, &len,
|
||||
buffer + size);
|
||||
if (result != B_OK) {
|
||||
if (size == 0)
|
||||
|
||||
@@ -493,9 +493,8 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms,
|
||||
|
||||
|
||||
status_t
|
||||
NFS4Inode::OpenFile(OpenState* state, int mode)
|
||||
NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
|
||||
{
|
||||
OpenDelegationData delegation;
|
||||
bool confirm;
|
||||
status_t result;
|
||||
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
|
||||
@@ -571,7 +570,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
|
||||
&delegation);
|
||||
delegation);
|
||||
|
||||
FileHandle handle;
|
||||
reply.GetFH(&handle);
|
||||
@@ -587,9 +586,6 @@ NFS4Inode::OpenFile(OpenState* state, int mode)
|
||||
if (confirm)
|
||||
return ConfirmOpen(fInfo.fHandle, state);
|
||||
|
||||
if (delegation.fType != OPEN_DELEGATE_NONE)
|
||||
dprintf("GOT A DELEGATION!\n");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ protected:
|
||||
status_t LookUp(const char* name, uint64* change, uint64* fileID,
|
||||
FileHandle* handle);
|
||||
|
||||
status_t Link(Inode* dir, const char* name,
|
||||
status_t Link(Inode* dir, const char* name,s
|
||||
ChangeInfo* changeInfo);
|
||||
|
||||
static status_t Rename(Inode* from, Inode* to, const char* fromName,
|
||||
@@ -47,7 +47,8 @@ protected:
|
||||
status_t CreateFile(const char* name, int mode, int perms,
|
||||
OpenState* state, ChangeInfo* changeInfo,
|
||||
uint64* fileID, FileHandle* handle);
|
||||
status_t OpenFile(OpenState* state, int mode);
|
||||
status_t OpenFile(OpenState* state, int mode,
|
||||
OpenDelegationData* delegation);
|
||||
|
||||
status_t ReadFile(OpenFileCookie* cookie, OpenState* state,
|
||||
uint64 position, uint32* length, void* buffer,
|
||||
|
||||
@@ -19,6 +19,9 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
||||
{
|
||||
uint32 leaseTime;
|
||||
|
||||
if (cookie != NULL)
|
||||
state = cookie->fOpenState;
|
||||
|
||||
switch (nfs4Error) {
|
||||
case NFS4_OK:
|
||||
return false;
|
||||
@@ -62,10 +65,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
||||
// server has rebooted, reclaim share and try again
|
||||
case NFS4ERR_STALE_CLIENTID:
|
||||
case NFS4ERR_STALE_STATEID:
|
||||
if (cookie != NULL) {
|
||||
fFileSystem->NFSServer()->ServerRebooted(cookie->fClientID);
|
||||
return true;
|
||||
} else if (state != NULL) {
|
||||
if (state != NULL) {
|
||||
fFileSystem->NFSServer()->ServerRebooted(state->fClientID);
|
||||
return true;
|
||||
}
|
||||
@@ -85,10 +85,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
||||
|
||||
// lease has expired
|
||||
case NFS4ERR_EXPIRED:
|
||||
if (cookie != NULL) {
|
||||
fFileSystem->NFSServer()->ClientId(cookie->fClientID, true);
|
||||
return true;
|
||||
} else if (state != NULL) {
|
||||
if (state != NULL) {
|
||||
fFileSystem->NFSServer()->ClientId(state->fClientID, true);
|
||||
return true;
|
||||
}
|
||||
@@ -121,7 +118,7 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state)
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (HandleErrors(reply.NFS4Error(), serv))
|
||||
if (HandleErrors(reply.NFS4Error(), serv, NULL, state))
|
||||
continue;
|
||||
|
||||
fFileSystem->OpenOwnerSequenceUnlock();
|
||||
|
||||
@@ -59,7 +59,6 @@ NFS4Server::ServerRebooted(uint64 clientId)
|
||||
while (fs != NULL) {
|
||||
OpenFileCookie* current = fs->OpenFilesLock();
|
||||
while (current != NULL) {
|
||||
current->fClientID = fClientId;
|
||||
_ReclaimOpen(current);
|
||||
_ReclaimLocks(current);
|
||||
current = current->fNext;
|
||||
@@ -75,10 +74,8 @@ NFS4Server::ServerRebooted(uint64 clientId)
|
||||
status_t
|
||||
NFS4Server::_ReclaimOpen(OpenFileCookie* cookie)
|
||||
{
|
||||
if (cookie->fWriteState != NULL)
|
||||
cookie->fWriteState->Reclaim(fClientId);
|
||||
if (cookie->fReadState != NULL)
|
||||
cookie->fReadState->Reclaim(fClientId);
|
||||
if (cookie->fOpenState != NULL)
|
||||
cookie->fOpenState->Reclaim(fClientId);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -100,10 +97,7 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie)
|
||||
Request request(fServer);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
if (cookie->fWriteState != NULL)
|
||||
req.PutFH(cookie->fWriteState->fInfo.fHandle);
|
||||
else
|
||||
req.PutFH(cookie->fReadState->fInfo.fHandle);
|
||||
req.PutFH(cookie->fOpenState->fInfo.fHandle);
|
||||
req.Lock(cookie, linfo, true);
|
||||
|
||||
status_t result = request.Send();
|
||||
|
||||
@@ -298,6 +298,10 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm,
|
||||
|
||||
// delegation info
|
||||
uint32 delegation = fReply->Stream().GetUInt();
|
||||
OpenDelegationData data;
|
||||
if (delegData == NULL)
|
||||
delegData = &data;
|
||||
|
||||
if (delegation == OPEN_DELEGATE_NONE) {
|
||||
delegData->fType = OPEN_DELEGATE_NONE;
|
||||
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
|
||||
|
||||
@@ -173,14 +173,11 @@ void
|
||||
RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream,
|
||||
OpenFileCookie* cookie, LockOwner* owner)
|
||||
{
|
||||
stream.AddUHyper(cookie->fClientID);
|
||||
stream.AddUHyper(cookie->fOpenState->fClientID);
|
||||
|
||||
uint64 lockOwner[2];
|
||||
lockOwner[0] = owner->fOwner;
|
||||
if (cookie->fWriteState != NULL)
|
||||
lockOwner[1] = cookie->fWriteState->fInfo.fFileId;
|
||||
else
|
||||
lockOwner[1] = cookie->fReadState->fInfo.fFileId;
|
||||
lockOwner[1] = cookie->fOpenState->fInfo.fFileId;
|
||||
stream.AddOpaque(lockOwner, sizeof(lockOwner));
|
||||
}
|
||||
|
||||
@@ -208,11 +205,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, uint32 sequence,
|
||||
fRequest->Stream().AddBoolean(true); // new lock owner
|
||||
|
||||
// open seq stateid
|
||||
OpenState* state;
|
||||
if (lock->fType == READ_LT || lock->fType == READW_LT)
|
||||
state = cookie->fReadState;
|
||||
else
|
||||
state = cookie->fWriteState;
|
||||
OpenState* state = cookie->fOpenState;
|
||||
|
||||
fRequest->Stream().AddUInt(sequence);
|
||||
fRequest->Stream().AddUInt(state->fStateSeq);
|
||||
@@ -258,7 +251,7 @@ RequestBuilder::LockT(LockType type, uint64 pos, uint64 len,
|
||||
fRequest->Stream().AddUHyper(pos);
|
||||
fRequest->Stream().AddUHyper(len);
|
||||
|
||||
fRequest->Stream().AddUHyper(cookie->fClientID);
|
||||
fRequest->Stream().AddUHyper(cookie->fOpenState->fClientID);
|
||||
|
||||
uint32 owner = find_thread(NULL);
|
||||
fRequest->Stream().AddOpaque(&owner, sizeof(owner));
|
||||
|
||||
@@ -400,10 +400,24 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode,
|
||||
return result;
|
||||
}
|
||||
|
||||
void* ptr;
|
||||
result = get_vnode(volume, *_newVnodeID, &ptr);
|
||||
if (result != B_OK)
|
||||
delete cookie;
|
||||
Inode* child;
|
||||
result = get_vnode(volume, *_newVnodeID, reinterpret_cast<void**>(&child));
|
||||
if (result != B_OK) {
|
||||
result = inode->GetFileSystem()->GetInode(*_newVnodeID, &child);
|
||||
if (result != B_OK) {
|
||||
delete cookie;
|
||||
return result;
|
||||
}
|
||||
|
||||
result = new_vnode(volume, *_newVnodeID, child, &gNFSv4VnodeOps);
|
||||
if (result != B_OK) {
|
||||
delete child;
|
||||
delete cookie;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
child->SetOpenState(cookie->fOpenState);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user