diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index 9e880f67ff..e558b166e9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -64,7 +64,7 @@ public: inline Inode* GetInode(); inline time_t ExpireTime(); - static const bigtime_t kExpirationTime = 5000000; + static const bigtime_t kExpirationTime = 15000000; private: SinglyLinkedList fNameCache; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 53394cd8f5..5c28b4bbe2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -22,13 +22,11 @@ Inode::Inode() : - fAttrCacheExpire(0), fCache(NULL), fFileCache(NULL), fWriteCookie(NULL), fWriteDirty(false) { - mutex_init(&fAttrCacheLock, NULL); mutex_init(&fFileCacheLock, NULL); } @@ -126,7 +124,6 @@ Inode::~Inode() delete fCache; mutex_destroy(&fFileCacheLock); - mutex_destroy(&fAttrCacheLock); } @@ -142,7 +139,8 @@ Inode::RevalidateFileCache() if (change == fChange) return B_OK; - result = UpdateAttrCache(true); + struct stat st; + result = Stat(&st); if (result != B_OK) return result; @@ -150,8 +148,7 @@ Inode::RevalidateFileCache() Commit(); file_cache_delete(fFileCache); - fFileCache = file_cache_create(fFileSystem->DevId(), ID(), - fAttrCache.st_size); + fFileCache = file_cache_create(fFileSystem->DevId(), ID(), st.st_size); change = fChange; return B_OK; @@ -351,9 +348,13 @@ Inode::Access(int mode) int acc = 0; uint32 allowed; - status_t result = NFS4Inode::Access(&allowed); - if (result != B_OK) - return result; + status_t result = fMetaCache.GetAccess(geteuid(), &allowed); + if (result != B_OK) { + result = NFS4Inode::Access(&allowed); + if (result != B_OK) + return result; + fMetaCache.SetAccess(geteuid(), allowed); + } if ((allowed & ACCESS4_READ) != 0) acc |= R_OK; @@ -377,39 +378,26 @@ Inode::Access(int mode) status_t Inode::Stat(struct stat* st) { - status_t result = UpdateAttrCache(); - if (result != B_OK) - return result; - - // Do not touch other members of struct stat - st->st_size = fAttrCache.st_size; - st->st_mode = fAttrCache.st_mode; - st->st_nlink = fAttrCache.st_nlink; - st->st_uid = fAttrCache.st_uid; - st->st_gid = fAttrCache.st_gid; - st->st_atim = fAttrCache.st_atim; - st->st_ctim = fAttrCache.st_ctim; - st->st_crtim = fAttrCache.st_crtim; - st->st_mtim = fAttrCache.st_mtim; + status_t result = fMetaCache.GetStat(st); + if (result != B_OK) { + struct stat temp; + result = GetStat(&temp); + if (result != B_OK) + return result; + fMetaCache.SetStat(temp); + fMetaCache.GetStat(st); + } return B_OK; } status_t -Inode::UpdateAttrCache(bool force) +Inode::GetStat(struct stat* st) { - if (!force && fAttrCacheExpire > time(NULL)) - return B_OK; - - MutexLocker _(fAttrCacheLock); - - if (fAttrCacheExpire > time(NULL)) - return B_OK; - AttrValue* values; uint32 count; - status_t result = GetStat(&values, &count); + status_t result = NFS4Inode::GetStat(&values, &count); if (result != B_OK) return result; @@ -418,73 +406,71 @@ Inode::UpdateAttrCache(bool force) delete[] values; return B_BAD_VALUE; } - fAttrCache.st_size = values[0].fData.fValue64; + st->st_size = values[0].fData.fValue64; uint32 next = 1; - fAttrCache.st_mode = Type(); + st->st_mode = Type(); if (count >= next && values[next].fAttribute == FATTR4_MODE) { - fAttrCache.st_mode |= values[next].fData.fValue32; + st->st_mode |= values[next].fData.fValue32; next++; } else - fAttrCache.st_mode = 777; + st->st_mode = 777; if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { - fAttrCache.st_nlink = values[next].fData.fValue32; + st->st_nlink = values[next].fData.fValue32; next++; } else - fAttrCache.st_nlink = 1; + st->st_nlink = 1; if (count >= next && values[next].fAttribute == FATTR4_OWNER) { char* owner = reinterpret_cast(values[next].fData.fPointer); if (owner != NULL && isdigit(owner[0])) - fAttrCache.st_uid = atoi(owner); + st->st_uid = atoi(owner); else - fAttrCache.st_uid = gIdMapper->GetUserId(owner); + st->st_uid = gIdMapper->GetUserId(owner); next++; } else - fAttrCache.st_uid = 0; + st->st_uid = 0; if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { char* group = reinterpret_cast(values[next].fData.fPointer); if (group != NULL && isdigit(group[0])) - fAttrCache.st_gid = atoi(group); + st->st_gid = atoi(group); else - fAttrCache.st_gid = gIdMapper->GetGroupId(group); + st->st_gid = gIdMapper->GetGroupId(group); next++; } else - fAttrCache.st_gid = 0; + st->st_gid = 0; if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { - memcpy(&fAttrCache.st_atim, values[next].fData.fPointer, + memcpy(&st->st_atim, values[next].fData.fPointer, sizeof(timespec)); next++; } else - memset(&fAttrCache.st_atim, 0, sizeof(timespec)); + memset(&st->st_atim, 0, sizeof(timespec)); if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { - memcpy(&fAttrCache.st_crtim, values[next].fData.fPointer, + memcpy(&st->st_crtim, values[next].fData.fPointer, sizeof(timespec)); next++; } else - memset(&fAttrCache.st_crtim, 0, sizeof(timespec)); + memset(&st->st_crtim, 0, sizeof(timespec)); if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { - memcpy(&fAttrCache.st_ctim, values[next].fData.fPointer, + memcpy(&st->st_ctim, values[next].fData.fPointer, sizeof(timespec)); next++; } else - memset(&fAttrCache.st_ctim, 0, sizeof(timespec)); + memset(&st->st_ctim, 0, sizeof(timespec)); if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { - memcpy(&fAttrCache.st_mtim, values[next].fData.fPointer, + memcpy(&st->st_mtim, values[next].fData.fPointer, sizeof(timespec)); next++; } else - memset(&fAttrCache.st_mtim, 0, sizeof(timespec)); + memset(&st->st_mtim, 0, sizeof(timespec)); delete[] values; - fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime; - return B_OK; } @@ -559,7 +545,11 @@ Inode::WriteStat(const struct stat* st, uint32 mask) delete cookie; } - UpdateAttrCache(true); + fMetaCache.InvalidateStat(); + if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0 + || (mask & B_STAT_GID) != 0) { + fMetaCache.InvalidateAccess(); + } return result; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 0581251f8f..43892f9195 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -9,6 +9,7 @@ #define INODE_H +#include "MetadataCache.h" #include "NFS4Inode.h" @@ -85,7 +86,7 @@ protected: status_t ChildAdded(const char* name, uint64 fileID, const FileHandle& fileHandle); - status_t UpdateAttrCache(bool force = false); + status_t GetStat(struct stat* st); static inline status_t CheckLockType(short ltype, uint32 mode); @@ -93,11 +94,7 @@ protected: uint32 fType; - struct stat fAttrCache; - mutex fAttrCacheLock; - time_t fAttrCacheExpire; - static const time_t kAttrCacheExpirationTime = 60; - + MetadataCache fMetaCache; DirectoryCache* fCache; uint64 fChange; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index d9da7c2b9b..75b71dbef2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -151,7 +151,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, *_length = size; - fAttrCache.st_size = max_c(fAttrCache.st_size, *_length + pos); + fMetaCache.GrowFile(size + pos); fFileSystem->Root()->MakeInfoInvalid(); return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 13e62e81c1..a7c16d505d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -15,6 +15,7 @@ KernelAddon nfs4 : InodeDir.cpp InodeRegular.cpp kernel_interface.cpp + MetadataCache.cpp NFS4Inode.cpp NFS4Object.cpp NFS4Server.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp new file mode 100644 index 0000000000..d8ba4bec3d --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "MetadataCache.h" + + +MetadataCache::MetadataCache() + : + fExpire(0) +{ + mutex_init(&fLock, NULL); +} + + +MetadataCache::~MetadataCache() +{ + mutex_destroy(&fLock); +} + + +status_t +MetadataCache::GetStat(struct stat* st) +{ + MutexLocker _(fLock); + if (fExpire > time(NULL)) { + // Do not touch other members of struct stat + st->st_size = fStatCache.st_size; + st->st_mode = fStatCache.st_mode; + st->st_nlink = fStatCache.st_nlink; + st->st_uid = fStatCache.st_uid; + st->st_gid = fStatCache.st_gid; + st->st_atim = fStatCache.st_atim; + st->st_ctim = fStatCache.st_ctim; + st->st_crtim = fStatCache.st_crtim; + st->st_mtim = fStatCache.st_mtim; + + return B_OK; + } + + return B_ERROR; +} + + +void +MetadataCache::SetStat(const struct stat& st) +{ + MutexLocker _(fLock); + fStatCache = st; + fExpire = time(NULL) + kExpirationTime; +} + + +void +MetadataCache::GrowFile(size_t newSize) +{ + MutexLocker _(fLock); + fStatCache.st_size = max_c(newSize, fStatCache.st_size); +} + + +status_t +MetadataCache::GetAccess(uid_t uid, uint32* allowed) +{ + MutexLocker _(fLock); + AVLTreeMap::Iterator it = fAccessCache.Find(uid); + if (!it.HasCurrent()) + return B_ENTRY_NOT_FOUND; + + if (it.Current().fExpire < time(NULL)) { + it.Remove(); + return B_ERROR; + } + + *allowed = it.Current().fAllowed; + + return B_OK; +} + + +void +MetadataCache::SetAccess(uid_t uid, uint32 allowed) +{ + MutexLocker _(fLock); + AVLTreeMap::Iterator it = fAccessCache.Find(uid); + if (it.HasCurrent()) + it.Remove(); + + AccessEntry entry; + entry.fAllowed = allowed; + entry.fExpire = time(NULL) + kExpirationTime; + fAccessCache.Insert(uid, entry); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h new file mode 100644 index 0000000000..ecf12e70e2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h @@ -0,0 +1,76 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef METADATACACHE_H +#define METADATACACHE_H + + +#include +#include +#include +#include + + +struct AccessEntry { + time_t fExpire; + uint32 fAllowed; +}; + +class MetadataCache { +public: + MetadataCache(); + ~MetadataCache(); + + status_t GetStat(struct stat* st); + void SetStat(const struct stat& st); + void GrowFile(size_t newSize); + + status_t GetAccess(uid_t uid, uint32* allowed); + void SetAccess(uid_t uid, uint32 allowed); + + inline void InvalidateStat(); + inline void InvalidateAccess(); + + inline void Invalidate(); + + static const time_t kExpirationTime = 60; +private: + struct stat fStatCache; + time_t fExpire; + + AVLTreeMap fAccessCache; + + mutex fLock; +}; + + +inline void +MetadataCache::InvalidateStat() +{ + MutexLocker _(fLock); + fExpire = 0; +} + + +inline void +MetadataCache::InvalidateAccess() +{ + MutexLocker _(fLock); + fAccessCache.MakeEmpty(); +} + + +inline void +MetadataCache::Invalidate() +{ + InvalidateStat(); + InvalidateAccess(); +} + + +#endif // METADATACACHE_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index efb372a6d4..1369d2fe2d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -11,6 +11,7 @@ #include +#include "MetadataCache.h" #include "Request.h" @@ -126,7 +127,7 @@ RootInode::_UpdateInfo(bool force) fInfoCache.flags = 0; strncpy(fInfoCache.volume_name, fInfo.fName, B_FILE_NAME_LENGTH); - fInfoCacheExpire = time(NULL) + kAttrCacheExpirationTime; + fInfoCacheExpire = time(NULL) + MetadataCache::kExpirationTime; return B_OK; }