nfs4: Use one open state per inode

This commit is contained in:
Pawel Dziepak
2012-08-05 22:07:44 +02:00
parent 990922235b
commit 52aaad172f
14 changed files with 137 additions and 135 deletions
@@ -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();
+17 -2
View File
@@ -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);
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) {
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);
status_t result = OpenFile(state, mode, NULL);
if (result != B_OK)
return result;
fWriteState = state;
} else
fWriteState->AcquireReference();
cookie->fWriteState = fWriteState;
}
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;
}
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;
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;
fOpenState->fMode = O_RDWR;
}
fOpenState->AcquireReference();
}
fReadState = state;
} else
fReadState->AcquireReference();
cookie->fOpenState = fOpenState;
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)
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;
}