diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 016d107a20..83d0336a8b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -13,9 +13,6 @@ #include "Request.h" -vint64 OpenFileCookie::fLastOwnerId = 0; - - LockOwner::LockOwner(uint32 owner) : fSequence(0), @@ -164,7 +161,7 @@ OpenFileCookie::GetLockOwner(uint32 owner) if (current == NULL) return NULL; - current->fClientId = fClientId; + current->fClientId = fClientID; current->fNext = fLockOwners; if (fLockOwners != NULL) fLockOwners->fPrev = current; diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index c5b0528ce4..baeca6706d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -12,6 +12,7 @@ #include #include "FileSystem.h" +#include "OpenState.h" struct LockOwner { @@ -70,19 +71,13 @@ struct Cookie { }; struct OpenFileCookie : public Cookie { - uint64 fClientId; + uint64 fClientID; + + OpenState* fReadState; + OpenState* fWriteState; uint32 fMode; - FileInfo fInfo; - uint32 fStateId[3]; - uint32 fStateSeq; - - uint32 fSequence; - - uint64 fOwnerId; - static vint64 fLastOwnerId; - LockInfo* fLocks; mutex fLocksLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 5c28b4bbe2..007890e310 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -24,9 +24,11 @@ Inode::Inode() : fCache(NULL), fFileCache(NULL), - fWriteCookie(NULL), + fWriteState(NULL), + fReadState(NULL), fWriteDirty(false) { + mutex_init(&fStateLock, NULL); mutex_init(&fFileCacheLock, NULL); } @@ -123,6 +125,7 @@ Inode::~Inode() file_cache_delete(fFileCache); delete fCache; + mutex_destroy(&fStateLock); mutex_destroy(&fFileCacheLock); } @@ -479,22 +482,10 @@ status_t Inode::WriteStat(const struct stat* st, uint32 mask) { status_t result; - OpenFileCookie* cookie = NULL; AttrValue attr[6]; uint32 i = 0; if ((mask & B_STAT_SIZE) != 0) { - delete cookie; - cookie = new OpenFileCookie; - if (cookie == NULL) - return B_NO_MEMORY; - - result = Open(O_WRONLY, cookie); - if (result != B_OK) { - delete cookie; - return result; - } - attr[i].fAttribute = FATTR4_SIZE; attr[i].fFreePointer = false; attr[i].fData.fValue64 = st->st_size; @@ -538,12 +529,9 @@ Inode::WriteStat(const struct stat* st, uint32 mask) i++; } - result = NFS4Inode::WriteStat(cookie, attr, i); - - if ((mask & B_STAT_SIZE) != 0) { - Close(cookie); - delete cookie; - } + MutexLocker stateLocker(fStateLock); + result = NFS4Inode::WriteStat(fWriteState, attr, i); + stateLocker.Unlock(); fMetaCache.InvalidateStat(); if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0 @@ -689,7 +677,6 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) MutexLocker _(cookie->fLocksLock); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { - MutexLocker ownerLocker(linfo->fOwner->fLock); NFS4Inode::ReleaseLock(cookie, linfo); cookie->RemoveLock(linfo, NULL); cookie->DeleteLock(linfo); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 43892f9195..e4bfa9ac6b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -11,6 +11,7 @@ #include "MetadataCache.h" #include "NFS4Inode.h" +#include "OpenState.h" class Inode : public NFS4Inode { @@ -27,9 +28,6 @@ public: inline void* FileCache(); status_t RevalidateFileCache(); - inline OpenFileCookie* WriteCookie(); - inline void SetWriteCookie(OpenFileCookie* cookie); - status_t LookUp(const char* name, ino_t* id); status_t Access(int mode); @@ -75,6 +73,9 @@ public: protected: Inode(); + status_t CreateState(const char* name, int mode, + int perms, OpenState* state); + status_t ReadDirUp(struct dirent* de, uint32 pos, uint32 size); status_t FillDirEntry(struct dirent* de, ino_t id, @@ -99,9 +100,12 @@ protected: uint64 fChange; void* fFileCache; - OpenFileCookie* fWriteCookie; mutex fFileCacheLock; + OpenState* fWriteState; + OpenState* fReadState; + mutex fStateLock; + bool fWriteDirty; }; @@ -152,19 +156,5 @@ Inode::FileCache() } -inline OpenFileCookie* -Inode::WriteCookie() -{ - return fWriteCookie; -} - - -inline void -Inode::SetWriteCookie(OpenFileCookie* cookie) -{ - fWriteCookie = cookie; -} - - #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 75b71dbef2..51d41229c9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -20,23 +20,16 @@ status_t -Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, - ino_t* id) -{ - cookie->fMode = mode; - cookie->fSequence = 0; - cookie->fLocks = NULL; - +Inode::CreateState(const char* name, int mode, int perms, OpenState* state) { uint64 fileID; FileHandle handle; ChangeInfo changeInfo; - status_t result = CreateFile(name, mode, perms, cookie, &changeInfo, + + status_t result = CreateFile(name, mode, perms, state, &changeInfo, &fileID, &handle); if (result != B_OK) return result; - *id = FileIdToInoT(fileID); - FileInfo fi; fi.fFileId = fileID; fi.fHandle = handle; @@ -50,7 +43,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, strcat(path, name); fi.fPath = path; - fFileSystem->InoIdMap()->AddEntry(fi, *id); + fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); if (fCache->Lock() == B_OK) { if (changeInfo.fAtomic @@ -62,8 +55,59 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, fCache->Unlock(); } + state->fFileSystem = fFileSystem; + state->fInfo = fi; + + return B_OK; +} + + +status_t +Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, + ino_t* id) +{ + cookie->fMode = mode; + 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; + + fWriteState = state; + *id = FileIdToInoT(cookie->fWriteState->fInfo.fFileId); + cookie->fWriteState = fWriteState; + } + + 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; + } + cookie->fFileSystem = fFileSystem; - cookie->fInfo = fi; + cookie->fClientID = fFileSystem->NFSServer()->ClientId(); fFileSystem->AddOpenFile(cookie); fFileSystem->Root()->MakeInfoInvalid(); @@ -75,15 +119,59 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, status_t Inode::Open(int mode, OpenFileCookie* cookie) { - cookie->fFileSystem = fFileSystem; - cookie->fInfo = fInfo; - cookie->fMode = mode; - cookie->fSequence = 0; - cookie->fLocks = NULL; + MutexLocker _(fStateLock); + int openMode = mode & O_RWMASK; - status_t result = OpenFile(cookie, mode); - if (result != B_OK) - return result; + if (openMode == O_WRONLY || openMode == O_RDWR) { + if (fWriteState == 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); + 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; + return result; + } + + fReadState = state; + } else + fReadState->AcquireReference(); + + cookie->fReadState = fReadState; + } + + cookie->fClientID = fFileSystem->NFSServer()->ClientId(); + cookie->fFileSystem = fFileSystem; + cookie->fMode = mode; + cookie->fLocks = NULL; fFileSystem->AddOpenFile(cookie); @@ -95,7 +183,17 @@ status_t Inode::Close(OpenFileCookie* cookie) { fFileSystem->RemoveOpenFile(cookie); - return CloseFile(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; + + return B_OK; } @@ -109,7 +207,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, pos + size, &len, + result = ReadFile(cookie, fReadState, pos + size, &len, reinterpret_cast(buffer) + size, eof); if (result != B_OK) { if (size == 0) @@ -138,7 +236,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, while (size < *_length) { uint32 len = *_length - size; - status_t result = WriteFile(cookie, pos + size, &len, buffer + size); + status_t result = WriteFile(cookie, fWriteState, pos + size, &len, + buffer + size); if (result != B_OK) { if (size == 0) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index a7c16d505d..16a0306a88 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -19,6 +19,7 @@ KernelAddon nfs4 : NFS4Inode.cpp NFS4Object.cpp NFS4Server.cpp + OpenState.cpp ReplyInterpreter.cpp Request.cpp RequestBuilder.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 564690c19b..a95c3b9700 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -244,38 +244,6 @@ NFS4Inode::ReadLink(void* buffer, size_t* length) } -status_t -NFS4Inode::ConfirmOpen(const FileHandle& fh, OpenFileCookie* cookie) -{ - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - - RequestBuilder& req = request.Builder(); - - req.PutFH(fh); - req.OpenConfirm(cookie->fSequence++, cookie->fStateId, - cookie->fStateSeq); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - result = reply.OpenConfirm(&cookie->fStateSeq); - if (result != B_OK) - return result; - - return B_OK; - } while (true); -} - - status_t NFS4Inode::GetStat(AttrValue** values, uint32* count) { @@ -309,7 +277,7 @@ NFS4Inode::GetStat(AttrValue** values, uint32* count) status_t -NFS4Inode::WriteStat(OpenFileCookie* cookie, AttrValue* attrs, uint32 attrCount) +NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) { do { RPC::Server* serv = fFileSystem->Server(); @@ -317,8 +285,8 @@ NFS4Inode::WriteStat(OpenFileCookie* cookie, AttrValue* attrs, uint32 attrCount) RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - if (cookie != NULL) - req.SetAttr(cookie->fStateId, cookie->fStateSeq, attrs, attrCount); + if (state != NULL) + req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount); else req.SetAttr(NULL, 0, attrs, attrCount); @@ -414,7 +382,7 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, status_t NFS4Inode::CreateFile(const char* name, int mode, int perms, - OpenFileCookie* cookie, ChangeInfo* changeInfo, uint64* fileID, + OpenState* state, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle) { bool confirm; @@ -422,13 +390,13 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, bool badOwner = false; do { - cookie->fClientId = fFileSystem->NFSServer()->ClientId(); + state->fClientID = fFileSystem->NFSServer()->ClientId(); RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); + state->fOwnerID = atomic_add64(&state->fLastOwnerID, 1); req.PutFH(fInfo.fHandle); @@ -459,8 +427,8 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, i++; } - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr, + req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode), + state->fClientID, OPEN4_CREATE, state->fOwnerID, name, cattr, i, (mode & O_EXCL) == O_EXCL); req.GetFH(); @@ -485,7 +453,7 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, reply.PutFH(); - result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm, + result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, &changeInfo->fBefore, &changeInfo->fAfter, &changeInfo->fAtomic); if (result != B_OK) return result; @@ -508,26 +476,28 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, break; } while (true); + state->fOpened = true; + if (confirm) - return ConfirmOpen(*handle, cookie); + return ConfirmOpen(*handle, state); return B_OK; } status_t -NFS4Inode::OpenFile(OpenFileCookie* cookie, int mode) +NFS4Inode::OpenFile(OpenState* state, int mode) { bool confirm; status_t result; do { - cookie->fClientId = fFileSystem->NFSServer()->ClientId(); + state->fClientID = fFileSystem->NFSServer()->ClientId(); RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); + state->fOwnerID = atomic_add64(&state->fLastOwnerID, 1); // Since we are opening the file using a pair (parentFH, name) we // need to check for race conditions. @@ -556,12 +526,12 @@ NFS4Inode::OpenFile(OpenFileCookie* cookie, int mode) attr.fAttribute = FATTR4_SIZE; attr.fFreePointer = false; attr.fData.fValue64 = 0; - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, fInfo.fName, + req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode), + state->fClientID, OPEN4_CREATE, state->fOwnerID, fInfo.fName, &attr, 1, false); } else - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fInfo.fName); + req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode), + state->fClientID, OPEN4_NOCREATE, state->fOwnerID, fInfo.fName); result = request.Send(); if (result != B_OK) @@ -588,22 +558,25 @@ NFS4Inode::OpenFile(OpenFileCookie* cookie, int mode) } reply.PutFH(); - result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); + result = reply.Open(state->fStateID, &state->fStateSeq, &confirm); if (result != B_OK) return result; break; } while (true); + state->fOpened = true; + if (confirm) - return ConfirmOpen(fInfo.fHandle, cookie); + return ConfirmOpen(fInfo.fHandle, state); return B_OK; } status_t -NFS4Inode::CloseFile(OpenFileCookie* cookie) +NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, + uint32* length, void* buffer, bool* eof) { do { RPC::Server* serv = fFileSystem->Server(); @@ -611,34 +584,7 @@ NFS4Inode::CloseFile(OpenFileCookie* cookie) RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - req.Close(cookie->fSequence++, cookie->fStateId, cookie->fStateSeq); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - reply.PutFH(); - return reply.Close(); - } while (true); -} - - -status_t -NFS4Inode::ReadFile(OpenFileCookie* cookie, uint64 position, uint32* length, - void* buffer, bool* eof) -{ - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.Read(cookie->fStateId, cookie->fStateSeq, position, *length); + req.Read(state->fStateID, state->fStateSeq, position, *length); status_t result = request.Send(cookie); if (result != B_OK) @@ -660,9 +606,10 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, uint64 position, uint32* length, status_t -NFS4Inode::WriteFile(OpenFileCookie* cookie, uint64 position, uint32* length, - const void* buffer) +NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position, + uint32* length, const void* buffer) { + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); @@ -670,8 +617,7 @@ NFS4Inode::WriteFile(OpenFileCookie* cookie, uint64 position, uint32* length, req.PutFH(fInfo.fHandle); - req.Write(cookie->fStateId, cookie->fStateSeq, buffer, position, - *length); + req.Write(state->fStateID, state->fStateSeq, buffer, position, *length); status_t result = request.Send(cookie); if (result != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index 4d5a6221db..027f6a4917 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -13,6 +13,9 @@ #include +#include "Cookie.h" +#include "FileInfo.h" +#include "FileSystem.h" #include "NFS4Object.h" #include "ReplyInterpreter.h" @@ -38,19 +41,20 @@ protected: ChangeInfo* toChange, uint64* fileID); status_t GetStat(AttrValue** values, uint32* count); - status_t WriteStat(OpenFileCookie* cookie, AttrValue* attrs, + status_t WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount); status_t CreateFile(const char* name, int mode, int perms, - OpenFileCookie* cookie, ChangeInfo* changeInfo, + OpenState* state, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle); - status_t OpenFile(OpenFileCookie* cookie, int mode); - status_t CloseFile(OpenFileCookie* cookie); + status_t OpenFile(OpenState* state, int mode); - status_t ReadFile(OpenFileCookie* cookie, uint64 position, - uint32* length, void* buffer, bool* eof); - status_t WriteFile(OpenFileCookie* cookie, uint64 position, - uint32* length, const void* buffer); + status_t ReadFile(OpenFileCookie* cookie, OpenState* state, + uint64 position, uint32* length, void* buffer, + bool* eof); + status_t WriteFile(OpenFileCookie* cookie, OpenState* state, + uint64 position, uint32* length, + const void* buffer); status_t CreateObject(const char* name, const char* path, int mode, FileType type, ChangeInfo* changeInfo, @@ -67,10 +71,6 @@ protected: status_t AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait); status_t ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo); - - status_t ConfirmOpen(const FileHandle& fileHandle, - OpenFileCookie* cookie); - }; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index ba08e77c7c..e5db3e618c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -7,7 +7,10 @@ */ +#include "Cookie.h" +#include "FileSystem.h" #include "NFS4Object.h" +#include "Request.h" bool @@ -59,7 +62,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server has rebooted, reclaim share and try again case NFS4ERR_STALE_CLIENTID: case NFS4ERR_STALE_STATEID: - fFileSystem->NFSServer()->ServerRebooted(cookie->fClientId); + fFileSystem->NFSServer()->ServerRebooted(cookie->fClientID); return true; // FileHandle has expired @@ -77,7 +80,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, // lease has expired case NFS4ERR_EXPIRED: if (cookie != NULL) { - fFileSystem->NFSServer()->ClientId(cookie->fClientId, true); + fFileSystem->NFSServer()->ClientId(cookie->fClientID, true); return true; } return false; @@ -87,3 +90,34 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, } } + +status_t +NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + + RequestBuilder& req = request.Builder(); + + req.PutFH(fh); + req.OpenConfirm(state->fSequence++, state->fStateID, state->fStateSeq); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.OpenConfirm(&state->fStateSeq); + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h index 49b4ecf466..7ffcf4b9a1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -8,18 +8,21 @@ #ifndef NFS4OBJECT_H #define NFS4OBJECT_H - -#include "Cookie.h" -#include "FileSystem.h" +#include "FileInfo.h" #include "NFS4Defs.h" +#include "RPCServer.h" +class OpenFileCookie; +class OpenState; + class NFS4Object { public: bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, OpenFileCookie* cookie = NULL); -protected: + status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state); + FileInfo fInfo; FileSystem* fFileSystem; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index f3ea764525..412a653866 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -59,6 +59,7 @@ NFS4Server::ServerRebooted(uint64 clientId) while (fs != NULL) { OpenFileCookie* current = fs->OpenFilesLock(); while (current != NULL) { + current->fClientID = fClientId; _ReclaimOpen(current); _ReclaimLocks(current); current = current->fNext; @@ -74,47 +75,10 @@ NFS4Server::ServerRebooted(uint64 clientId) status_t NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) { - if (cookie->fClientId == fClientId) - return B_OK; - - cookie->fClientId = fClientId; - - Request request(fServer); - RequestBuilder& req = request.Builder(); - - req.PutFH(cookie->fInfo.fHandle); - req.Open(CLAIM_PREVIOUS, cookie->fSequence++, sModeToAccess(cookie->fMode), - cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, NULL); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - reply.PutFH(); - - bool confirm; - result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); - if (result != B_OK) - return result; - - if (confirm) { - request.Reset(); - - req.PutFH(cookie->fInfo.fHandle); - req.OpenConfirm(cookie->fSequence++, cookie->fStateId, - cookie->fStateSeq); - - result = request.Send(); - if (result != B_OK) - return result; - - reply.PutFH(); - result = reply.OpenConfirm(&cookie->fStateSeq); - if (result != B_OK) - return result; - } + if (cookie->fWriteState != NULL) + cookie->fWriteState->Reclaim(fClientId); + if (cookie->fReadState != NULL) + cookie->fReadState->Reclaim(fClientId); return B_OK; } @@ -136,7 +100,10 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) Request request(fServer); RequestBuilder& req = request.Builder(); - req.PutFH(cookie->fInfo.fHandle); + if (cookie->fWriteState != NULL) + req.PutFH(cookie->fWriteState->fInfo.fHandle); + else + req.PutFH(cookie->fReadState->fInfo.fHandle); req.Lock(cookie, linfo, true); status_t result = request.Send(); diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp new file mode 100644 index 0000000000..26a4df52e5 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "OpenState.h" + +#include + +#include "FileSystem.h" +#include "Request.h" + + +vint64 OpenState::fLastOwnerID = 0; + +OpenState::OpenState() + : + fSequence(0), + fOpened(false) +{ + mutex_init(&fLock, NULL); +} + + +OpenState::~OpenState() +{ + Close(); + mutex_destroy(&fLock); +} + + +status_t +OpenState::Reclaim(uint64 newClientID) +{ + if (!fOpened) + return B_OK; + + MutexLocker _(fLock); + + if (fClientID == newClientID) + return B_OK; + fClientID = newClientID; + + bool confirm; + do { + RPC::Server* server = fFileSystem->Server(); + Request request(server); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Open(CLAIM_PREVIOUS, fSequence++, sModeToAccess(fMode), newClientID, + OPEN4_NOCREATE, fOwnerID, NULL); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), server)) + continue; + + reply.PutFH(); + + result = reply.Open(fStateID, &fStateSeq, &confirm); + if (result != B_OK) + return result; + } while (true); + + if (confirm) + return ConfirmOpen(fInfo.fHandle, this); + + return B_OK; +} + + +status_t +OpenState::Close() +{ + if (!fOpened) + return B_OK; + + MutexLocker _(fLock); + fOpened = false; + + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Close(fSequence++, fStateID, fStateSeq); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + return reply.Close(); + } while (true); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.h b/src/add-ons/kernel/file_systems/nfs4/OpenState.h new file mode 100644 index 0000000000..00da687bd2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.h @@ -0,0 +1,46 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef OPENSTATE_H +#define OPENSTATE_H + + +#include +#include +#include + +#include "NFS4Object.h" + + +struct OpenState : public NFS4Object, public KernelReferenceable { + OpenState(); + ~OpenState(); + + uint64 fClientID; + + int fMode; + mutex fLock; + + uint32 fStateID[3]; + uint32 fStateSeq; + + uint32 fSequence; + + uint64 fOwnerID; + static vint64 fLastOwnerID; + + bool fOpened; + + + status_t Reclaim(uint64 newClientID); + + status_t Close(); +}; + + +#endif // OPENSTATE_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index d4b676cf00..3833faf66a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -171,11 +171,14 @@ void RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream, OpenFileCookie* cookie, LockOwner* owner) { - stream.AddUHyper(cookie->fClientId); + stream.AddUHyper(cookie->fClientID); uint64 lockOwner[2]; lockOwner[0] = owner->fOwner; - lockOwner[1] = cookie->fInfo.fFileId; + if (cookie->fWriteState != NULL) + lockOwner[1] = cookie->fWriteState->fInfo.fFileId; + else + lockOwner[1] = cookie->fReadState->fInfo.fFileId; stream.AddOpaque(lockOwner, sizeof(lockOwner)); } @@ -202,11 +205,17 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim) fRequest->Stream().AddBoolean(true); // new lock owner // open seq stateid - fRequest->Stream().AddUInt(cookie->fSequence++); - fRequest->Stream().AddUInt(cookie->fStateSeq); - fRequest->Stream().AddUInt(cookie->fStateId[0]); - fRequest->Stream().AddUInt(cookie->fStateId[1]); - fRequest->Stream().AddUInt(cookie->fStateId[2]); + OpenState* state; + if (lock->fType == READ_LT || lock->fType == READW_LT) + state = cookie->fReadState; + else + state = cookie->fWriteState; + + fRequest->Stream().AddUInt(state->fSequence++); + fRequest->Stream().AddUInt(state->fStateSeq); + fRequest->Stream().AddUInt(state->fStateID[0]); + fRequest->Stream().AddUInt(state->fStateID[1]); + fRequest->Stream().AddUInt(state->fStateID[2]); // lock seq owner fRequest->Stream().AddUInt(lock->fOwner->fSequence++); @@ -246,7 +255,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->fClientID); uint32 owner = find_thread(NULL); fRequest->Stream().AddOpaque(&owner, sizeof(owner)); diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index 560a7a9355..cc58c5593b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -253,12 +253,6 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, Inode* inode = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); - if (cookie == NULL) { - cookie = inode->WriteCookie(); - if (cookie == NULL) - return B_BAD_VALUE; - } - status_t result; uint32 ioSize = inode->GetFileSystem()->Root()->IOSize(); for (size_t i = 0; i < count; i++) { @@ -462,9 +456,6 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) file_cache_sync(inode->FileCache()); inode->Commit(); - if (inode->WriteCookie() == cookie) - inode->SetWriteCookie(NULL); - inode->Close(cookie); delete cookie; @@ -512,7 +503,6 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, if (result != B_OK) return result; - inode->SetWriteCookie(cookie); return file_cache_write(inode->FileCache(), cookie, pos, _buffer, length); }