added 6 changesets to branch 'refs/remotes/pdziepak-github/nfs4' old head: e2e5f06d6e736c019ed37c475ff4f68e3c4f401c new head: 224d602294491975618b856227b84120a5e1e0fc ---------------------------------------------------------------------------- 2c36184: nfs4: Support delegations of created files cde3994: nfs4: Return delegation before open upgrade f1fe25e: nfs4: Repair O_TRUNC support 4121741: nfs4: Add asynchronous work queue 0dff48c: nfs4: Recall all delegations when callback path is down 224d602: nfs4: Add support for CB_GETATTR [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 24 files changed, 614 insertions(+), 43 deletions(-) .../kernel/file_systems/nfs4/Connection.cpp | 2 +- .../kernel/file_systems/nfs4/Delegation.cpp | 5 +- src/add-ons/kernel/file_systems/nfs4/Delegation.h | 2 - .../kernel/file_systems/nfs4/FileSystem.cpp | 18 ++ src/add-ons/kernel/file_systems/nfs4/FileSystem.h | 3 + src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 30 ++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 26 ++- .../kernel/file_systems/nfs4/InodeRegular.cpp | 38 +++- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/MetadataCache.cpp | 28 ++- .../kernel/file_systems/nfs4/MetadataCache.h | 4 + src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h | 5 + src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp | 18 +- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h | 3 +- .../kernel/file_systems/nfs4/NFS4Server.cpp | 83 ++++++- src/add-ons/kernel/file_systems/nfs4/NFS4Server.h | 4 + .../kernel/file_systems/nfs4/RPCCallbackServer.cpp | 4 +- .../kernel/file_systems/nfs4/ReplyBuilder.cpp | 34 +++ .../kernel/file_systems/nfs4/ReplyBuilder.h | 2 + .../file_systems/nfs4/RequestInterpreter.cpp | 34 +++ .../kernel/file_systems/nfs4/RequestInterpreter.h | 1 + src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp | 184 ++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/WorkQueue.h | 82 +++++++ .../kernel/file_systems/nfs4/kernel_interface.cpp | 46 +++- ############################################################################ Commit: 2c36184f198a0511e54da85e20b5bf1379503660 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Aug 6 14:41:34 2012 UTC nfs4: Support delegations of created files ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index e5d90c2..68928bf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -59,7 +59,8 @@ public: status_t WriteStat(const struct stat* st, uint32 mask); status_t Create(const char* name, int mode, int perms, - OpenFileCookie* cookie, ino_t* id); + OpenFileCookie* cookie, + OpenDelegationData* data, ino_t* id); status_t Open(int mode, OpenFileCookie* cookie); status_t Close(OpenFileCookie* cookie); status_t Read(OpenFileCookie* cookie, off_t pos, @@ -89,7 +90,8 @@ protected: Inode(); status_t CreateState(const char* name, int mode, - int perms, OpenState* state); + int perms, OpenState* state, + OpenDelegationData* data); status_t ReadDirUp(struct dirent* de, uint32 pos, uint32 size); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 0056512..4526487 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -20,13 +20,14 @@ status_t -Inode::CreateState(const char* name, int mode, int perms, OpenState* state) { +Inode::CreateState(const char* name, int mode, int perms, OpenState* state, + OpenDelegationData* delegationData) { uint64 fileID; FileHandle handle; ChangeInfo changeInfo; status_t result = CreateFile(name, mode, perms, state, &changeInfo, - &fileID, &handle); + &fileID, &handle, delegationData); if (result != B_OK) return result; @@ -64,7 +65,7 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state) { status_t Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, - ino_t* id) + OpenDelegationData* data, ino_t* id) { cookie->fMode = mode; cookie->fLocks = NULL; @@ -72,7 +73,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, MutexLocker _(fStateLock); OpenState* state = new OpenState; - status_t result = CreateState(name, mode, perms, state); + status_t result = CreateState(name, mode, perms, state, data); if (result != B_OK) return result; @@ -99,6 +100,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) OpenDelegationData data; data.fType = OPEN_DELEGATE_NONE; if (fOpenState == NULL) { + // TODO: revalidate cache + OpenState* state = new OpenState; if (state == NULL) return B_NO_MEMORY; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index e45f08f..67649d9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -381,15 +381,14 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, status_t -NFS4Inode::CreateFile(const char* name, int mode, int perms, - OpenState* state, ChangeInfo* changeInfo, uint64* fileID, - FileHandle* handle) +NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, + ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle, + OpenDelegationData* delegation) { bool confirm; status_t result; bool badOwner = false; - OpenDelegationData delegation; uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { state->fClientID = fFileSystem->NFSServer()->ClientId(); @@ -461,7 +460,7 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, reply.PutFH(); result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, - &delegation, changeInfo); + delegation, changeInfo); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index 968e670..3e1bedb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -46,7 +46,8 @@ protected: status_t CreateFile(const char* name, int mode, int perms, OpenState* state, ChangeInfo* changeInfo, - uint64* fileID, FileHandle* handle); + uint64* fileID, FileHandle* handle, + OpenDelegationData* delegation); status_t OpenFile(OpenState* state, int mode, OpenDelegationData* delegation); 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 6da6cd1..9a9f8b9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -392,7 +392,10 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, *_cookie = cookie; Inode* inode = reinterpret_cast<Inode*>(dir->private_node); - status_t result = inode->Create(name, openMode, perms, cookie, _newVnodeID); + + OpenDelegationData data; + status_t result = inode->Create(name, openMode, perms, cookie, &data, + _newVnodeID); if (result != B_OK) { delete cookie; return result; @@ -417,6 +420,17 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, child->SetOpenState(cookie->fOpenState); + if (data.fType != OPEN_DELEGATE_NONE) { + Delegation* delegation + = new(std::nothrow) Delegation(data, child, + cookie->fOpenState->fClientID); + if (delegation != NULL) { + delegation->fInfo = cookie->fOpenState->fInfo; + delegation->fFileSystem = child->GetFileSystem(); + child->SetDelegation(delegation); + } + } + return result; } ############################################################################ Commit: cde3994e6907eaa3324ce4918b259b65da290c84 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Aug 6 16:14:55 2012 UTC nfs4: Return delegation before open upgrade ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp index 7d64adb..80aeb43 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp @@ -26,12 +26,9 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode, status_t Delegation::GiveUp(bool truncate) { - if (!truncate) { + if (!truncate) fInode->SyncAndCommit(true); - // TODO: claim locks - } - ReturnDelegation(); return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h b/src/add-ons/kernel/file_systems/nfs4/Delegation.h index 9d67afb..19afcfb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h @@ -23,8 +23,6 @@ public: Delegation(const OpenDelegationData& data, Inode* inode, uint64 clientID); - // TODO: locks - status_t GiveUp(bool truncate = false); inline Inode* GetInode(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index e2362da..1121a6e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -139,6 +139,9 @@ Inode::~Inode() status_t Inode::RevalidateFileCache() { + if (fDelegation != NULL) + return B_OK; + uint64 change; status_t result = GetChangeInfo(&change); if (result != B_OK) @@ -153,8 +156,7 @@ Inode::RevalidateFileCache() if (result != B_OK) return result; - file_cache_sync(fFileCache); - Commit(); + SyncAndCommit(true); file_cache_delete(fFileCache); fFileCache = file_cache_create(fFileSystem->DevId(), ID(), st.st_size); @@ -760,6 +762,12 @@ void Inode::SetDelegation(Delegation* delegation) { WriteLocker _(fDelegationLock); + + fMetaCache.InvalidateStat(); + struct stat st; + Stat(&st); + fMetaCache.LockValid(); + fDelegation = delegation; fOpenState->AcquireReference(); fOpenState->fDelegation = delegation; @@ -773,6 +781,24 @@ Inode::RecallDelegation(bool truncate) WriteLocker _(fDelegationLock); if (fDelegation == NULL) return; + ReturnDelegation(truncate); +} + + +void +Inode::RecallReadDelegation() +{ + WriteLocker _(fDelegationLock); + if (fDelegation == NULL || fDelegation->Type() != OPEN_DELEGATE_READ) + return; + ReturnDelegation(false); +} + + +void +Inode::ReturnDelegation(bool truncate) +{ + fMetaCache.UnlockValid(); fDelegation->GiveUp(truncate); fFileSystem->RemoveDelegation(fDelegation); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 68928bf..d2bafcf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -36,6 +36,7 @@ public: void SetDelegation(Delegation* delegation); void RecallDelegation(bool truncate = false); + void RecallReadDelegation(); status_t LookUp(const char* name, ino_t* id); @@ -93,6 +94,8 @@ protected: int perms, OpenState* state, OpenDelegationData* data); + void ReturnDelegation(bool truncate); + status_t ReadDirUp(struct dirent* de, uint32 pos, uint32 size); status_t FillDirEntry(struct dirent* de, ino_t id, diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 4526487..cc53d1d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -95,12 +95,12 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, status_t Inode::Open(int mode, OpenFileCookie* cookie) { - MutexLocker _(fStateLock); + MutexLocker locker(fStateLock); OpenDelegationData data; data.fType = OPEN_DELEGATE_NONE; if (fOpenState == NULL) { - // TODO: revalidate cache + RevalidateFileCache(); OpenState* state = new OpenState; if (state == NULL) @@ -114,16 +114,28 @@ Inode::Open(int mode, OpenFileCookie* cookie) fFileSystem->AddOpenFile(state); fOpenState = state; + locker.Unlock(); } else { + fOpenState->AcquireReference(); + locker.Unlock(); + int newMode = mode & O_RWMASK; int oldMode = fOpenState->fMode & O_RWMASK; if (oldMode != newMode && oldMode != O_RDWR) { + if (oldMode == O_RDONLY) + RecallReadDelegation(); + status_t result = OpenFile(fOpenState, O_RDWR, &data); - if (result != B_OK) + if (result != B_OK) { + locker.Lock(); + if (fOpenState->ReleaseReference() == 1) { + fFileSystem->RemoveOpenFile(fOpenState); + fOpenState = NULL; + } return result; + } fOpenState->fMode = O_RDWR; } - fOpenState->AcquireReference(); } cookie->fOpenState = fOpenState; diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index d8ba4be..058ce24 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -12,7 +12,8 @@ MetadataCache::MetadataCache() : - fExpire(0) + fExpire(0), + fForceValid(false) { mutex_init(&fLock, NULL); } @@ -28,7 +29,7 @@ status_t MetadataCache::GetStat(struct stat* st) { MutexLocker _(fLock); - if (fExpire > time(NULL)) { + if (fForceValid || fExpire > time(NULL)) { // Do not touch other members of struct stat st->st_size = fStatCache.st_size; st->st_mode = fStatCache.st_mode; @@ -97,3 +98,26 @@ MetadataCache::SetAccess(uid_t uid, uint32 allowed) fAccessCache.Insert(uid, entry); } + +status_t +MetadataCache::LockValid() +{ + MutexLocker _(fLock); + if (fForceValid || fExpire > time(NULL)) { + fForceValid = true; + return B_OK; + } + + return B_ERROR; +} + + +void +MetadataCache::UnlockValid() +{ + MutexLocker _(fLock); + fExpire = time(NULL) + kExpirationTime; + fForceValid = false; +} + + diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h index ecf12e7..4622c9e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h @@ -32,6 +32,9 @@ public: status_t GetAccess(uid_t uid, uint32* allowed); void SetAccess(uid_t uid, uint32 allowed); + status_t LockValid(); + void UnlockValid(); + inline void InvalidateStat(); inline void InvalidateAccess(); @@ -41,6 +44,7 @@ public: private: struct stat fStatCache; time_t fExpire; + bool fForceValid; AVLTreeMap<uid_t, AccessEntry> fAccessCache; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 05c8503..274ac6a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -332,6 +332,7 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) delegation->GetInode()->RecallDelegation(truncate); reply->Recall(B_OK); + return B_OK; } ############################################################################ Commit: f1fe25e50864bd85cf8443b891d29dfa190b8c32 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Aug 6 16:30:02 2012 UTC nfs4: Repair O_TRUNC support ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index cc53d1d..f132762 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -138,6 +138,13 @@ Inode::Open(int mode, OpenFileCookie* cookie) } } + if ((mode & O_TRUNC) == O_TRUNC) { + struct stat st; + st.st_size = 0; + WriteStat(&st, B_STAT_SIZE); + file_cache_set_size(fFileCache, 0); + } + cookie->fOpenState = fOpenState; cookie->fFileSystem = fFileSystem; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 67649d9..a424350 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -526,15 +526,6 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) } req.PutFH(fInfo.fParent); - if ((mode & O_TRUNC) == O_TRUNC) { - AttrValue attr; - attr.fAttribute = FATTR4_SIZE; - attr.fFreePointer = false; - attr.fData.fValue64 = 0; - req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), - state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(), - fInfo.fName, &attr, 1, false); - } else req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID, OPEN4_NOCREATE, fFileSystem->OpenOwner(), fInfo.fName); req.GetFH(); ############################################################################ Commit: 412174162e796c3208a93041f33b7de45425c847 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Aug 6 20:41:20 2012 UTC nfs4: Add asynchronous work queue ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index cc4611b..322ef47 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -163,7 +163,7 @@ ServerAddress::InAddr() const status_t ServerAddress::ResolveName(const char* name, ServerAddress* address) { - address->fProtocol = IPPROTO_TCP; + address->fProtocol = IPPROTO_UDP; // getaddrinfo() is very expensive when called from kernel, so we do not // want to call it unless there is no other choice. diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index a3a4194..246ba99 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -35,6 +35,7 @@ KernelAddon nfs4 : RPCCallbackServer.cpp RPCReply.cpp RPCServer.cpp + WorkQueue.cpp XDR.cpp ; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 274ac6a..9ea450b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -11,6 +11,7 @@ #include "Inode.h" #include "NFS4Server.h" #include "Request.h" +#include "WorkQueue.h" NFS4Server::NFS4Server(RPC::Server* serv) @@ -247,6 +248,9 @@ NFS4Server::_Renewal() request.Send(); switch (request.Reply().NFS4Error()) { + case NFS4ERR_CB_PATH_DOWN: + RecallAll(); + break; case NFS4ERR_STALE_CLIENTID: ServerRebooted(clientId); break; @@ -328,11 +332,40 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) return B_FILE_NOT_FOUND; } - // TODO: should be asynchronous - delegation->GetInode()->RecallDelegation(truncate); + DelegationRecallArgs* args = new(std::nothrow) DelegationRecallArgs; + args->fDelegation = delegation; + args->fTruncate = truncate; + gWorkQueue->EnqueueJob(DelegationRecall, args); reply->Recall(B_OK); return B_OK; } + +status_t +NFS4Server::RecallAll() +{ +#if 0 + MutexLocker locker(fFSLock); + + Delegation* delegation = NULL; + FileSystem* current = fFileSystems; + while (current != NULL) { + delegation = current->GetDelegation(handle); + if (delegation != NULL) + break; + + current = current->fNext; + } + locker.Unlock(); + + DelegationRecallArgs args = new(std::nothrow) DelegationRecallArgs; + DelegationRecallArgs* args; + args->fDelegation = delegation; + args->fTruncate = truncate; + gWorkQueue->EnqueueJob(DelegationRecall, args); +#endif + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index d312018..fe159b3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -42,6 +42,7 @@ public: status_t CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply); + status_t RecallAll(); private: status_t _GetLeaseTime(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp index b007a3b..54fd3d3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -26,7 +26,7 @@ CallbackServer::CallbackServer() fConnectionList(NULL), fListener(NULL), fThreadRunning(false), - //fCallbackArray(NULL), + fCallbackArray(NULL), fArraySize(0), fFreeSlot(-1) { @@ -40,7 +40,7 @@ CallbackServer::~CallbackServer() { StopServer(); - //free(fCallbackArray); + free(fCallbackArray); rw_lock_destroy(&fArrayLock); mutex_destroy(&fThreadLock); mutex_destroy(&fConnectionLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp new file mode 100644 index 0000000..9d38724 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp @@ -0,0 +1,184 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@xxxxxxxxxxx + */ + + +#include "WorkQueue.h" + +#include <io_requests.h> + + +WorkQueue* gWorkQueue = NULL; + + +WorkQueue::WorkQueue() + : + fQueueSemaphore(create_sem(0, NULL)), + fThreadCancel(create_sem(0, NULL)) +{ + mutex_init(&fQueueLock, NULL); + + fThread = spawn_kernel_thread(&WorkQueue::LaunchWorkingThread, + "NFSv4 Work Queue", B_NORMAL_PRIORITY, this); + if (fThread < B_OK) { + fInitError = fThread; + return; + } + + status_t result = resume_thread(fThread); + if (result != B_OK) { + kill_thread(fThread); + fInitError = result; + return; + } + + fInitError = B_OK; +} + + +WorkQueue::~WorkQueue() +{ + release_sem(fThreadCancel); + + status_t result; + wait_for_thread(fThread, &result); + + mutex_destroy(&fQueueLock); + delete_sem(fThreadCancel); + delete_sem(fQueueSemaphore); +} + + +status_t +WorkQueue::EnqueueJob(JobType type, void* args) +{ + WorkQueueEntry* entry = new(std::nothrow) WorkQueueEntry; + if (entry == NULL) + return B_NO_MEMORY; + + entry->fType = type; + entry->fArguments = args; + MutexLocker locker(fQueueLock); + fQueue.InsertAfter(fQueue.Tail(), entry); + locker.Unlock(); + + release_sem(fQueueSemaphore); + return B_OK; +} + + +status_t +WorkQueue::LaunchWorkingThread(void* object) +{ + WorkQueue* queue = reinterpret_cast<WorkQueue*>(object); + return queue->WorkingThread(); +} + + +status_t +WorkQueue::WorkingThread() +{ + while (true) { + object_wait_info object[2]; + object[0].object = fThreadCancel; + object[0].type = B_OBJECT_TYPE_SEMAPHORE; + object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; + + object[1].object = fQueueSemaphore; + object[1].type = B_OBJECT_TYPE_SEMAPHORE; + object[1].events = B_EVENT_ACQUIRE_SEMAPHORE; + + status_t result = wait_for_objects(object, 2); + + if (result < B_OK || + (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { + return result; + } else if ((object[1].events & B_EVENT_ACQUIRE_SEMAPHORE) == 0) + continue; + + acquire_sem(fQueueSemaphore); + + DequeueJob(); + } + + return B_OK; +} + + +void +WorkQueue::DequeueJob() +{ + MutexLocker locker(fQueueLock); + + WorkQueueEntry* entry = fQueue.RemoveHead(); + + void* args = entry->fArguments; + switch (entry->fType) { + case DelegationRecall: + JobRecall(reinterpret_cast<DelegationRecallArgs*>(args)); + break; + case IORequest: + JobIO(reinterpret_cast<IORequestArgs*>(args)); + break; + } + + delete entry; +} + + +void +WorkQueue::JobRecall(DelegationRecallArgs* args) +{ + args->fDelegation->GetInode()->RecallDelegation(args->fTruncate); +} + + +void +WorkQueue::JobIO(IORequestArgs* args) +{ + uint64 offset = io_request_offset(args->fRequest); + uint64 length = io_request_length(args->fRequest); + + char* buffer = reinterpret_cast<char*>(malloc(length)); + if (buffer == NULL) { + notify_io_request(args->fRequest, B_NO_MEMORY); + return; + } + + bool eof = false; + uint64 size = 0; + status_t result; + if (io_request_is_write(args->fRequest)) { + result = read_from_io_request(args->fRequest, buffer, length); + + do { + size_t bytesWritten = length - size; + result = args->fInode->WriteDirect(NULL, offset + size, + buffer + size, &bytesWritten); + size += bytesWritten; + } while (size < length && result == B_OK); + } else { + do { + size_t bytesRead = length - size; + result = args->fInode->ReadDirect(NULL, offset + size, buffer, + &bytesRead, &eof); + if (result != B_OK) + break; + + result = write_to_io_request(args->fRequest, buffer, bytesRead); + if (result != B_OK) + break; + + size += bytesRead; + } while (size < length && result == B_OK && !eof); + + } + free(buffer); + + notify_io_request(args->fRequest, result); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.h b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.h new file mode 100644 index 0000000..954d011 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.h @@ -0,0 +1,82 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@xxxxxxxxxxx + */ +#ifndef WORKQUEUE_H +#define WORKQUEUE_H + + +#include <io_requests.h> +#include <lock.h> +#include <SupportDefs.h> +#include <util/DoublyLinkedList.h> + +#include "Delegation.h" +#include "Inode.h" + + +enum JobType { + DelegationRecall, + IORequest +}; + +struct DelegationRecallArgs { + Delegation* fDelegation; + bool fTruncate; +}; + +struct IORequestArgs { + io_request* fRequest; + Inode* fInode; +}; + +struct WorkQueueEntry : public DoublyLinkedListLinkImpl<WorkQueueEntry> { + JobType fType; + void* fArguments; +}; + +class WorkQueue { +public: + WorkQueue(); + ~WorkQueue(); + + inline status_t InitStatus(); + + status_t EnqueueJob(JobType type, void* args); + +protected: + static status_t LaunchWorkingThread(void* object); + status_t WorkingThread(); + + void DequeueJob(); + + void JobRecall(DelegationRecallArgs* args); + void JobIO(IORequestArgs* args); + +private: + status_t fInitError; + + sem_id fQueueSemaphore; + mutex fQueueLock; + DoublyLinkedList<WorkQueueEntry> fQueue; + + sem_id fThreadCancel; + thread_id fThread; +}; + + +inline status_t +WorkQueue::InitStatus() +{ + return fInitError; +} + + +extern WorkQueue* gWorkQueue; + + +#endif // WORKQUEUE_H + 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 9a9f8b9..f396be2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -22,6 +22,7 @@ #include "RootInode.h" #include "RPCCallbackServer.h" #include "RPCServer.h" +#include "WorkQueue.h" extern fs_volume_ops gNFSv4VolumeOps; @@ -282,8 +283,21 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, static status_t nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request) { - // no asynchronous calls yet - return B_UNSUPPORTED; + Inode* inode = reinterpret_cast<Inode*>(vnode->private_node); + + IORequestArgs* args = new(std::nothrow) IORequestArgs; + if (args == NULL) { + notify_io_request(request, B_NO_MEMORY); + return B_NO_MEMORY; + } + args->fRequest = request; + args->fInode = inode; + + status_t result = gWorkQueue->EnqueueJob(IORequest, args); + if (result != B_OK) + notify_io_request(request, result); + + return result; } @@ -651,10 +665,19 @@ nfs4_init() return B_NO_MEMORY; } + gWorkQueue = new(std::nothrow) WorkQueue; + if (gWorkQueue == NULL || gWorkQueue->InitStatus() != B_OK) { + delete gWorkQueue; + delete gIdMapper; + delete gRPCServerManager; + return B_NO_MEMORY; + } + gRPCCallbackServer = new(std::nothrow) RPC::CallbackServer; if (gRPCCallbackServer == NULL) { - delete gRPCServerManager; delete gIdMapper; + delete gWorkQueue; + delete gRPCServerManager; return B_NO_MEMORY; } @@ -669,6 +692,7 @@ nfs4_uninit() delete gRPCCallbackServer; delete gIdMapper; + delete gWorkQueue; delete gRPCServerManager; return B_OK; ############################################################################ Commit: 0dff48c7ea15e3ee52598682f5da108558987c20 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Aug 6 20:52:35 2012 UTC nfs4: Recall all delegations when callback path is down ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 9379f3e..ecc56b2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -311,11 +311,28 @@ FileSystem::RemoveOpenFile(OpenState* state) } +DoublyLinkedList<Delegation>& +FileSystem::DelegationsLock() +{ + mutex_lock(&fDelegationLock); + return fDelegationList; +} + + +void +FileSystem::DelegationsUnlock() +{ + mutex_unlock(&fDelegationLock); +} + + void FileSystem::AddDelegation(Delegation* delegation) { MutexLocker _(fDelegationLock); + fDelegationList.InsertBefore(fDelegationList.Head(), delegation); + fHandleToDelegation.Remove(delegation->fInfo.fHandle); fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation); @@ -328,6 +345,7 @@ FileSystem::RemoveDelegation(Delegation* delegation) { MutexLocker _(fDelegationLock); + fDelegationList.Remove(delegation); fHandleToDelegation.Remove(delegation->fInfo.fHandle); NFSServer()->DecUsage(); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 0bd634d..adfea0a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -36,6 +36,8 @@ public: void AddOpenFile(OpenState* state); void RemoveOpenFile(OpenState* state); + DoublyLinkedList<Delegation>& DelegationsLock(); + void DelegationsUnlock(); void AddDelegation(Delegation* delegation); void RemoveDelegation(Delegation* delegation); Delegation* GetDelegation(const FileHandle& handle); @@ -68,6 +70,7 @@ private: CacheRevalidator fCacheRevalidator; mutex fDelegationLock; + DoublyLinkedList<Delegation> fDelegationList; AVLTreeMap<FileHandle, Delegation*> fHandleToDelegation; OpenState* fOpenFiles; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 9ea450b..9dea65c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -346,26 +346,26 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) status_t NFS4Server::RecallAll() { -#if 0 - MutexLocker locker(fFSLock); + MutexLocker _(fFSLock); + FileSystem* fs = fFileSystems; + while (fs != NULL) { + DoublyLinkedList<Delegation>& list = fs->DelegationsLock(); + DoublyLinkedList<Delegation>::Iterator iterator = list.GetIterator(); - Delegation* delegation = NULL; - FileSystem* current = fFileSystems; - while (current != NULL) { - delegation = current->GetDelegation(handle); - if (delegation != NULL) - break; + Delegation* current = iterator.Next(); + while (current != NULL) { + DelegationRecallArgs* args = new(std::nothrow) DelegationRecallArgs; + args->fDelegation = current; + args->fTruncate = false; + gWorkQueue->EnqueueJob(DelegationRecall, args); - current = current->fNext; + current = iterator.Next(); + } + fs->DelegationsUnlock(); + + fs = fs->fNext; } - locker.Unlock(); - DelegationRecallArgs args = new(std::nothrow) DelegationRecallArgs; - DelegationRecallArgs* args; - args->fDelegation = delegation; - args->fTruncate = truncate; - gWorkQueue->EnqueueJob(DelegationRecall, args); -#endif return B_OK; } ############################################################################ Commit: 224d602294491975618b856227b84120a5e1e0fc Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Aug 6 21:26:37 2012 UTC nfs4: Add support for CB_GETATTR ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index d2bafcf..6dce7ba 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -34,6 +34,9 @@ public: inline uint64 MaxFileSize(); + inline uint64 Change(); + inline bool Dirty(); + void SetDelegation(Delegation* delegation); void RecallDelegation(bool truncate = false); void RecallReadDelegation(); @@ -195,5 +198,19 @@ Inode::MaxFileSize() } +inline uint64 +Inode::Change() +{ + return fChange; +} + + +inline bool +Inode::Dirty() +{ + return fWriteDirty; +} + + #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 f132762..a4dcd76 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -31,6 +31,8 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, if (result != B_OK) return result; + RevalidateFileCache(); + FileInfo fi; fi.fFileId = fileID; fi.fHandle = handle; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c162462..e60b45c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -26,6 +26,7 @@ enum CallbackProcedure { }; enum CallbackOpcode { + OpCallbackGetAttr = 3, OpCallbackRecall = 4 }; @@ -135,6 +136,10 @@ enum Attribute { FATTR4_MAXIMUM_ATTR_ID }; +enum CallbackAttr { + CallbackAttrSize = 1, + CallbackAttrChange = 2 +}; static inline bool sIsAttrSet(Attribute attr, const uint32* bitmap, uint32 count) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 9dea65c..07acb75 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -284,6 +284,9 @@ NFS4Server::ProcessCallback(RPC::CallbackRequest* request, for (uint32 i = 0; i < count; i++) { switch (req.Operation()) { + case OpCallbackGetAttr: + result = CallbackGetAttr(&req, &reply); + break; case OpCallbackRecall: result = CallbackRecall(&req, &reply); break; @@ -344,6 +347,48 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) status_t +NFS4Server::CallbackGetAttr(RequestInterpreter* request, ReplyBuilder* reply) +{ + FileHandle handle; + int mask; + + status_t result = request->GetAttr(&handle, &mask); + if (result != B_OK) + return result; + return B_OK; + + MutexLocker locker(fFSLock); + + Delegation* delegation = NULL; + FileSystem* current = fFileSystems; + while (current != NULL) { + delegation = current->GetDelegation(handle); + if (delegation != NULL) + break; + + current = current->fNext; + } + locker.Unlock(); + + if (delegation == NULL) { + reply->GetAttr(B_FILE_NOT_FOUND, 0, 0, 0); + return B_FILE_NOT_FOUND; + } + + struct stat st; + delegation->GetInode()->Stat(&st); + + uint64 change; + change = delegation->GetInode()->Change(); + if (delegation->GetInode()->Dirty()) + change++; + reply->GetAttr(B_OK, mask, st.st_size, change); + + return B_OK; +} + + +status_t NFS4Server::RecallAll() { MutexLocker _(fFSLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index fe159b3..4fe2dcc 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -43,6 +43,9 @@ public: status_t CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply); status_t RecallAll(); + + status_t CallbackGetAttr(RequestInterpreter* request, + ReplyBuilder* reply); private: status_t _GetLeaseTime(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp index e18a4a6..152d5de 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp @@ -57,6 +57,40 @@ ReplyBuilder::Reply() status_t +ReplyBuilder::GetAttr(status_t status, int mask, uint64 size, uint64 change) +{ + if (fStatus != B_OK) + return B_ERROR; + + fReply->Stream().AddUInt(OpCallbackGetAttr); + fReply->Stream().AddUInt(_HaikuErrorToNFS4(fStatus)); + fStatus = status; + + if (status == B_OK) { + uint32 bitmap = 0; + if ((mask & CallbackAttrChange) != 0) + bitmap |= 1 << FATTR4_CHANGE; + if ((mask & CallbackAttrSize) != 0) + bitmap |= 1 << FATTR4_SIZE; + fReply->Stream().AddUInt(1); + fReply->Stream().AddUInt(bitmap); + + XDR::WriteStream str; + if ((mask & CallbackAttrChange) != 0) + str.AddUHyper(change); + + if ((mask & CallbackAttrSize) != 0) + str.AddUHyper(size); + fReply->Stream().AddOpaque(str); + } + + fOpCount++; + + return B_OK; +} + + +status_t ReplyBuilder::Recall(status_t status) { if (fStatus != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h index be85416..2a12a0d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h @@ -22,6 +22,8 @@ public: RPC::CallbackReply* Reply(); + status_t GetAttr(status_t status, int mask, + uint64 size, uint64 change); status_t Recall(status_t status); private: diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp index c129cde..11ca0a2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp @@ -29,6 +29,40 @@ RequestInterpreter::~RequestInterpreter() status_t +RequestInterpreter::GetAttr(FileHandle* handle, int* _mask) +{ + if (fLastOperation != OpCallbackGetAttr) + return B_BAD_VALUE; + + uint32 size; + const void* ptr = fRequest->Stream().GetOpaque(&size); + handle->fSize = size; + memcpy(handle->fData, ptr, size); + + uint32 count = fRequest->Stream().GetUInt(); + if (count < 1) { + *_mask = 0; + return fRequest->Stream().IsEOF() ? B_BAD_VALUE : B_OK; + } + + uint32 bitmap = fRequest->Stream().GetUInt(); + uint32 mask = 0; + + if ((bitmap & (1 << FATTR4_CHANGE)) != 0) + mask |= CallbackAttrChange; + if ((bitmap & (1 << FATTR4_SIZE)) != 0) + mask |= CallbackAttrSize; + + *_mask = mask; + + for (uint32 i = 1; i < count; i++) + fRequest->Stream().GetUInt(); + + return fRequest->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + +status_t RequestInterpreter::Recall(FileHandle* handle, bool& truncate, uint32* stateSeq, uint32* stateID) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h index 5febb48..a17f2ce 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h @@ -24,6 +24,7 @@ public: inline uint32 OperationCount(); inline uint32 Operation(); + status_t GetAttr(FileHandle* handle, int* mask); status_t Recall(FileHandle* handle, bool& truncate, uint32* stateSeq, uint32* stateID);