nfs4: Add ACCESS cache

This commit is contained in:
Pawel Dziepak
2012-08-04 00:47:13 +02:00
parent 0dbff36172
commit 7efb4c9b49
8 changed files with 229 additions and 65 deletions
@@ -64,7 +64,7 @@ public:
inline Inode* GetInode(); inline Inode* GetInode();
inline time_t ExpireTime(); inline time_t ExpireTime();
static const bigtime_t kExpirationTime = 5000000; static const bigtime_t kExpirationTime = 15000000;
private: private:
SinglyLinkedList<NameCacheEntry> fNameCache; SinglyLinkedList<NameCacheEntry> fNameCache;
+42 -52
View File
@@ -22,13 +22,11 @@
Inode::Inode() Inode::Inode()
: :
fAttrCacheExpire(0),
fCache(NULL), fCache(NULL),
fFileCache(NULL), fFileCache(NULL),
fWriteCookie(NULL), fWriteCookie(NULL),
fWriteDirty(false) fWriteDirty(false)
{ {
mutex_init(&fAttrCacheLock, NULL);
mutex_init(&fFileCacheLock, NULL); mutex_init(&fFileCacheLock, NULL);
} }
@@ -126,7 +124,6 @@ Inode::~Inode()
delete fCache; delete fCache;
mutex_destroy(&fFileCacheLock); mutex_destroy(&fFileCacheLock);
mutex_destroy(&fAttrCacheLock);
} }
@@ -142,7 +139,8 @@ Inode::RevalidateFileCache()
if (change == fChange) if (change == fChange)
return B_OK; return B_OK;
result = UpdateAttrCache(true); struct stat st;
result = Stat(&st);
if (result != B_OK) if (result != B_OK)
return result; return result;
@@ -150,8 +148,7 @@ Inode::RevalidateFileCache()
Commit(); Commit();
file_cache_delete(fFileCache); file_cache_delete(fFileCache);
fFileCache = file_cache_create(fFileSystem->DevId(), ID(), fFileCache = file_cache_create(fFileSystem->DevId(), ID(), st.st_size);
fAttrCache.st_size);
change = fChange; change = fChange;
return B_OK; return B_OK;
@@ -351,9 +348,13 @@ Inode::Access(int mode)
int acc = 0; int acc = 0;
uint32 allowed; uint32 allowed;
status_t result = NFS4Inode::Access(&allowed); status_t result = fMetaCache.GetAccess(geteuid(), &allowed);
if (result != B_OK) {
result = NFS4Inode::Access(&allowed);
if (result != B_OK) if (result != B_OK)
return result; return result;
fMetaCache.SetAccess(geteuid(), allowed);
}
if ((allowed & ACCESS4_READ) != 0) if ((allowed & ACCESS4_READ) != 0)
acc |= R_OK; acc |= R_OK;
@@ -377,39 +378,26 @@ Inode::Access(int mode)
status_t status_t
Inode::Stat(struct stat* st) Inode::Stat(struct stat* st)
{ {
status_t result = UpdateAttrCache(); status_t result = fMetaCache.GetStat(st);
if (result != B_OK) {
struct stat temp;
result = GetStat(&temp);
if (result != B_OK) if (result != B_OK)
return result; return result;
fMetaCache.SetStat(temp);
// Do not touch other members of struct stat fMetaCache.GetStat(st);
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;
return B_OK; return B_OK;
} }
status_t 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; AttrValue* values;
uint32 count; uint32 count;
status_t result = GetStat(&values, &count); status_t result = NFS4Inode::GetStat(&values, &count);
if (result != B_OK) if (result != B_OK)
return result; return result;
@@ -418,73 +406,71 @@ Inode::UpdateAttrCache(bool force)
delete[] values; delete[] values;
return B_BAD_VALUE; return B_BAD_VALUE;
} }
fAttrCache.st_size = values[0].fData.fValue64; st->st_size = values[0].fData.fValue64;
uint32 next = 1; uint32 next = 1;
fAttrCache.st_mode = Type(); st->st_mode = Type();
if (count >= next && values[next].fAttribute == FATTR4_MODE) { if (count >= next && values[next].fAttribute == FATTR4_MODE) {
fAttrCache.st_mode |= values[next].fData.fValue32; st->st_mode |= values[next].fData.fValue32;
next++; next++;
} else } else
fAttrCache.st_mode = 777; st->st_mode = 777;
if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) {
fAttrCache.st_nlink = values[next].fData.fValue32; st->st_nlink = values[next].fData.fValue32;
next++; next++;
} else } else
fAttrCache.st_nlink = 1; st->st_nlink = 1;
if (count >= next && values[next].fAttribute == FATTR4_OWNER) { if (count >= next && values[next].fAttribute == FATTR4_OWNER) {
char* owner = reinterpret_cast<char*>(values[next].fData.fPointer); char* owner = reinterpret_cast<char*>(values[next].fData.fPointer);
if (owner != NULL && isdigit(owner[0])) if (owner != NULL && isdigit(owner[0]))
fAttrCache.st_uid = atoi(owner); st->st_uid = atoi(owner);
else else
fAttrCache.st_uid = gIdMapper->GetUserId(owner); st->st_uid = gIdMapper->GetUserId(owner);
next++; next++;
} else } else
fAttrCache.st_uid = 0; st->st_uid = 0;
if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) {
char* group = reinterpret_cast<char*>(values[next].fData.fPointer); char* group = reinterpret_cast<char*>(values[next].fData.fPointer);
if (group != NULL && isdigit(group[0])) if (group != NULL && isdigit(group[0]))
fAttrCache.st_gid = atoi(group); st->st_gid = atoi(group);
else else
fAttrCache.st_gid = gIdMapper->GetGroupId(group); st->st_gid = gIdMapper->GetGroupId(group);
next++; next++;
} else } else
fAttrCache.st_gid = 0; st->st_gid = 0;
if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { 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)); sizeof(timespec));
next++; next++;
} else } else
memset(&fAttrCache.st_atim, 0, sizeof(timespec)); memset(&st->st_atim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { 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)); sizeof(timespec));
next++; next++;
} else } else
memset(&fAttrCache.st_crtim, 0, sizeof(timespec)); memset(&st->st_crtim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { 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)); sizeof(timespec));
next++; next++;
} else } else
memset(&fAttrCache.st_ctim, 0, sizeof(timespec)); memset(&st->st_ctim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { 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)); sizeof(timespec));
next++; next++;
} else } else
memset(&fAttrCache.st_mtim, 0, sizeof(timespec)); memset(&st->st_mtim, 0, sizeof(timespec));
delete[] values; delete[] values;
fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime;
return B_OK; return B_OK;
} }
@@ -559,7 +545,11 @@ Inode::WriteStat(const struct stat* st, uint32 mask)
delete cookie; 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; return result;
} }
+3 -6
View File
@@ -9,6 +9,7 @@
#define INODE_H #define INODE_H
#include "MetadataCache.h"
#include "NFS4Inode.h" #include "NFS4Inode.h"
@@ -85,7 +86,7 @@ protected:
status_t ChildAdded(const char* name, uint64 fileID, status_t ChildAdded(const char* name, uint64 fileID,
const FileHandle& fileHandle); const FileHandle& fileHandle);
status_t UpdateAttrCache(bool force = false); status_t GetStat(struct stat* st);
static inline status_t CheckLockType(short ltype, uint32 mode); static inline status_t CheckLockType(short ltype, uint32 mode);
@@ -93,11 +94,7 @@ protected:
uint32 fType; uint32 fType;
struct stat fAttrCache; MetadataCache fMetaCache;
mutex fAttrCacheLock;
time_t fAttrCacheExpire;
static const time_t kAttrCacheExpirationTime = 60;
DirectoryCache* fCache; DirectoryCache* fCache;
uint64 fChange; uint64 fChange;
@@ -151,7 +151,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
*_length = size; *_length = size;
fAttrCache.st_size = max_c(fAttrCache.st_size, *_length + pos); fMetaCache.GrowFile(size + pos);
fFileSystem->Root()->MakeInfoInvalid(); fFileSystem->Root()->MakeInfoInvalid();
return B_OK; return B_OK;
@@ -15,6 +15,7 @@ KernelAddon nfs4 :
InodeDir.cpp InodeDir.cpp
InodeRegular.cpp InodeRegular.cpp
kernel_interface.cpp kernel_interface.cpp
MetadataCache.cpp
NFS4Inode.cpp NFS4Inode.cpp
NFS4Object.cpp NFS4Object.cpp
NFS4Server.cpp NFS4Server.cpp
@@ -0,0 +1,99 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#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<uid_t, AccessEntry>::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<uid_t, AccessEntry>::Iterator it = fAccessCache.Find(uid);
if (it.HasCurrent())
it.Remove();
AccessEntry entry;
entry.fAllowed = allowed;
entry.fExpire = time(NULL) + kExpirationTime;
fAccessCache.Insert(uid, entry);
}
@@ -0,0 +1,76 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#ifndef METADATACACHE_H
#define METADATACACHE_H
#include <lock.h>
#include <SupportDefs.h>
#include <util/AutoLock.h>
#include <util/AVLTreeMap.h>
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<uid_t, AccessEntry> 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
@@ -11,6 +11,7 @@
#include <string.h> #include <string.h>
#include "MetadataCache.h"
#include "Request.h" #include "Request.h"
@@ -126,7 +127,7 @@ RootInode::_UpdateInfo(bool force)
fInfoCache.flags = 0; fInfoCache.flags = 0;
strncpy(fInfoCache.volume_name, fInfo.fName, B_FILE_NAME_LENGTH); strncpy(fInfoCache.volume_name, fInfo.fName, B_FILE_NAME_LENGTH);
fInfoCacheExpire = time(NULL) + kAttrCacheExpirationTime; fInfoCacheExpire = time(NULL) + MetadataCache::kExpirationTime;
return B_OK; return B_OK;
} }