nfs4: Add ACCESS cache
This commit is contained in:
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
if (result != B_OK) {
|
||||||
return result;
|
result = NFS4Inode::Access(&allowed);
|
||||||
|
if (result != B_OK)
|
||||||
|
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)
|
if (result != B_OK) {
|
||||||
return result;
|
struct stat temp;
|
||||||
|
result = GetStat(&temp);
|
||||||
// Do not touch other members of struct stat
|
if (result != B_OK)
|
||||||
st->st_size = fAttrCache.st_size;
|
return result;
|
||||||
st->st_mode = fAttrCache.st_mode;
|
fMetaCache.SetStat(temp);
|
||||||
st->st_nlink = fAttrCache.st_nlink;
|
fMetaCache.GetStat(st);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user