nfs4: Cache file attributes and filesystem info

This commit is contained in:
Pawel Dziepak
2012-07-10 20:57:52 +02:00
parent 00a8558cc7
commit 78fc85a6ba
7 changed files with 164 additions and 44 deletions
@@ -24,7 +24,7 @@ public:
~FileSystem(); ~FileSystem();
status_t GetInode(ino_t id, Inode** inode); status_t GetInode(ino_t id, Inode** inode);
inline Inode* Root(); inline RootInode* Root();
status_t Migrate(const RPC::Server* serv); status_t Migrate(const RPC::Server* serv);
@@ -74,10 +74,10 @@ private:
}; };
inline Inode* inline RootInode*
FileSystem::Root() FileSystem::Root()
{ {
return reinterpret_cast<Inode*>(fRoot); return fRoot;
} }
+83 -30
View File
@@ -20,7 +20,10 @@
Inode::Inode() Inode::Inode()
:
fAttrCacheExpire(0)
{ {
mutex_init(&fAttrCacheLock, NULL);
} }
@@ -96,6 +99,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
Inode::~Inode() Inode::~Inode()
{ {
mutex_destroy(&fAttrCacheLock);
} }
@@ -288,7 +292,11 @@ Inode::Remove(const char* name, FileType type)
return result; return result;
reply.PutFH(); reply.PutFH();
return reply.Remove(); result = reply.Remove();
fFileSystem->Root()->MakeInfoInvalid();
return result;
} while (true); } while (true);
} }
@@ -391,7 +399,11 @@ Inode::CreateLink(const char* name, const char* path, int mode)
reply.PutFH(); reply.PutFH();
return reply.Create(); result = reply.Create();
fFileSystem->Root()->MakeInfoInvalid();
return result;
} while (true); } while (true);
} }
@@ -481,6 +493,36 @@ Inode::Access(int mode)
status_t status_t
Inode::Stat(struct stat* st) 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;
return B_OK;
}
status_t
Inode::_UpdateAttrCache(bool force)
{
if (!force && fAttrCacheExpire > time(NULL))
return B_OK;
MutexLocker _(fAttrCacheLock);
if (fAttrCacheExpire > time(NULL))
return B_OK;
do { do {
RPC::Server* serv = fFileSystem->Server(); RPC::Server* serv = fFileSystem->Server();
Request request(serv); Request request(serv);
@@ -516,12 +558,12 @@ Inode::Stat(struct stat* st)
delete[] values; delete[] values;
return B_BAD_VALUE; return B_BAD_VALUE;
} }
st->st_size = values[0].fData.fValue64; fAttrCache.st_size = values[0].fData.fValue64;
uint32 next = 1; uint32 next = 1;
st->st_mode = Type(); fAttrCache.st_mode = Type();
if (count >= next && values[next].fAttribute == FATTR4_MODE) { if (count >= next && values[next].fAttribute == FATTR4_MODE) {
st->st_mode |= values[next].fData.fValue32; fAttrCache.st_mode |= values[next].fData.fValue32;
next++; next++;
} else { } else {
// Try to guess using ACCESS request // Try to guess using ACCESS request
@@ -538,70 +580,76 @@ Inode::Stat(struct stat* st)
return result; return result;
if ((prvl & ACCESS4_READ) != 0) if ((prvl & ACCESS4_READ) != 0)
st->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; fAttrCache.st_mode |= S_IRUSR | S_IRGRP | S_IROTH;
if ((prvl & ACCESS4_MODIFY) != 0) if ((prvl & ACCESS4_MODIFY) != 0)
st->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; fAttrCache.st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
if (fType == NF4DIR && (prvl & ACCESS4_LOOKUP) != 0) if (fType == NF4DIR && (prvl & ACCESS4_LOOKUP) != 0)
st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; fAttrCache.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
if (fType != NF4DIR && (prvl & ACCESS4_EXECUTE) != 0) if (fType != NF4DIR && (prvl & ACCESS4_EXECUTE) != 0)
st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; fAttrCache.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
} }
if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) {
st->st_nlink = values[next].fData.fValue32; fAttrCache.st_nlink = values[next].fData.fValue32;
next++; next++;
} else } else
st->st_nlink = 1; fAttrCache.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]))
st->st_uid = atoi(owner); fAttrCache.st_uid = atoi(owner);
else else
st->st_uid = gIdMapper->GetUserId(owner); fAttrCache.st_uid = gIdMapper->GetUserId(owner);
next++; next++;
} else } else
st->st_uid = 0; fAttrCache.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]))
st->st_gid = atoi(group); fAttrCache.st_gid = atoi(group);
else else
st->st_gid = gIdMapper->GetGroupId(group); fAttrCache.st_gid = gIdMapper->GetGroupId(group);
next++; next++;
} else } else
st->st_gid = 0; fAttrCache.st_gid = 0;
if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) {
memcpy(&st->st_atim, values[next].fData.fPointer, sizeof(timespec)); memcpy(&fAttrCache.st_atim, values[next].fData.fPointer,
next++;
} else
memset(&st->st_atim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) {
memcpy(&st->st_crtim, values[next].fData.fPointer,
sizeof(timespec)); sizeof(timespec));
next++; next++;
} else } else
memset(&st->st_crtim, 0, sizeof(timespec)); memset(&fAttrCache.st_atim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) {
memcpy(&fAttrCache.st_crtim, values[next].fData.fPointer,
sizeof(timespec));
next++;
} else
memset(&fAttrCache.st_crtim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) {
memcpy(&st->st_ctim, values[next].fData.fPointer, sizeof(timespec)); memcpy(&fAttrCache.st_ctim, values[next].fData.fPointer,
sizeof(timespec));
next++; next++;
} else } else
memset(&st->st_ctim, 0, sizeof(timespec)); memset(&fAttrCache.st_ctim, 0, sizeof(timespec));
if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) {
memcpy(&st->st_mtim, values[next].fData.fPointer, sizeof(timespec)); memcpy(&fAttrCache.st_mtim, values[next].fData.fPointer,
sizeof(timespec));
next++; next++;
} else } else
memset(&st->st_mtim, 0, sizeof(timespec)); memset(&fAttrCache.st_mtim, 0, sizeof(timespec));
delete[] values; delete[] values;
fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime;
return B_OK; return B_OK;
} while (true); } while (true);
} }
@@ -701,9 +749,14 @@ Inode::WriteStat(const struct stat* st, uint32 mask)
delete cookie; delete cookie;
} }
return result; if (result != B_OK)
return result;
break;
} while (true); } while (true);
_UpdateAttrCache(true);
return B_OK; return B_OK;
} }
@@ -89,6 +89,12 @@ protected:
static inline ino_t _FileIdToInoT(uint64 fileid); static inline ino_t _FileIdToInoT(uint64 fileid);
struct stat fAttrCache;
mutex fAttrCacheLock;
time_t fAttrCacheExpire;
static const time_t kAttrCacheExpirationTime = 60;
status_t _UpdateAttrCache(bool force = false);
uint32 fType; uint32 fType;
FileInfo fInfo; FileInfo fInfo;
@@ -109,6 +109,8 @@ Inode::OpenDir(OpenDirCookie* cookie)
cookie->fCookie = 0; cookie->fCookie = 0;
cookie->fCookieVerf = 2; cookie->fCookieVerf = 2;
fFileSystem->Root()->MakeInfoInvalid();
return B_OK; return B_OK;
} while (true); } while (true);
} }
@@ -15,6 +15,7 @@
#include "IdMap.h" #include "IdMap.h"
#include "Request.h" #include "Request.h"
#include "RootInode.h"
status_t status_t
@@ -172,6 +173,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
} while (true); } while (true);
fFileSystem->AddOpenFile(cookie); fFileSystem->AddOpenFile(cookie);
fFileSystem->Root()->MakeInfoInvalid();
if (confirm) if (confirm)
return _ConfirmOpen(fh, cookie); return _ConfirmOpen(fh, cookie);
@@ -430,6 +432,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
*_length = size; *_length = size;
fFileSystem->Root()->MakeInfoInvalid();
return B_OK; return B_OK;
} }
@@ -14,9 +14,44 @@
#include "Request.h" #include "Request.h"
RootInode::RootInode()
:
fInfoCacheExpire(0)
{
mutex_init(&fInfoCacheLock, NULL);
}
RootInode::~RootInode()
{
mutex_destroy(&fInfoCacheLock);
}
status_t status_t
RootInode::ReadInfo(struct fs_info* info) RootInode::ReadInfo(struct fs_info* info)
{ {
status_t result = _UpdateInfo();
if (result != B_OK)
return result;
memcpy(info, &fInfoCache, sizeof(struct fs_info));
return B_OK;
}
status_t
RootInode::_UpdateInfo(bool force)
{
if (!force && fInfoCacheExpire > time(NULL))
return B_OK;
MutexLocker _(fInfoCacheLock);
if (fInfoCacheExpire > time(NULL))
return B_OK;
do { do {
RPC::Server* serv = fFileSystem->Server(); RPC::Server* serv = fFileSystem->Server();
Request request(serv); Request request(serv);
@@ -46,12 +81,12 @@ RootInode::ReadInfo(struct fs_info* info)
return result; return result;
if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) { if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) {
info->free_nodes = values[next].fData.fValue64; fInfoCache.free_nodes = values[next].fData.fValue64;
next++; next++;
} }
if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) { if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) {
info->total_nodes = values[next].fData.fValue64; fInfoCache.total_nodes = values[next].fData.fValue64;
next++; next++;
} }
@@ -68,16 +103,16 @@ RootInode::ReadInfo(struct fs_info* info)
if (io_size == LONGLONG_MAX) if (io_size == LONGLONG_MAX)
io_size = 32768; io_size = 32768;
info->io_size = io_size; fInfoCache.io_size = io_size;
info->block_size = io_size; fInfoCache.block_size = io_size;
if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) { if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) {
info->free_blocks = values[next].fData.fValue64 / io_size; fInfoCache.free_blocks = values[next].fData.fValue64 / io_size;
next++; next++;
} }
if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) { if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) {
info->total_blocks = values[next].fData.fValue64 / io_size; fInfoCache.total_blocks = values[next].fData.fValue64 / io_size;
next++; next++;
} }
@@ -86,8 +121,10 @@ RootInode::ReadInfo(struct fs_info* info)
break; break;
} while (true); } while (true);
info->flags = 0; fInfoCache.flags = 0;
strncpy(info->volume_name, fInfo.fName, B_FILE_NAME_LENGTH); strncpy(fInfoCache.volume_name, fInfo.fName, B_FILE_NAME_LENGTH);
fInfoCacheExpire = time(NULL) + kAttrCacheExpirationTime;
return B_OK; return B_OK;
} }
@@ -16,13 +16,31 @@
class RootInode : public Inode { class RootInode : public Inode {
public: public:
status_t ReadInfo(struct fs_info* info); RootInode();
~RootInode();
bool ProbeMigration(); status_t ReadInfo(struct fs_info* info);
status_t GetLocations(AttrValue** attr); inline void MakeInfoInvalid();
bool ProbeMigration();
status_t GetLocations(AttrValue** attr);
private:
struct fs_info fInfoCache;
mutex fInfoCacheLock;
time_t fInfoCacheExpire;
status_t _UpdateInfo(bool force = false);
}; };
inline void
RootInode::MakeInfoInvalid()
{
fInfoCacheExpire = 0;
}
#endif // ROOTINODE_H #endif // ROOTINODE_H