diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp index 7d64adba61..80aeb4330a 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 9d67afb371..19afcfb450 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 e2362da7fb..1121a6e765 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 68928bf941..d2bafcf5db 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 452648779a..cc53d1d070 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 d8ba4bec3d..058ce243c2 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 ecf12e70e2..4622c9e7dd 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 fAccessCache; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 05c85035f5..274ac6a3ce 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; }