nfs4: Cache file attributes and filesystem info
This commit is contained in:
@@ -24,7 +24,7 @@ public:
|
||||
~FileSystem();
|
||||
|
||||
status_t GetInode(ino_t id, Inode** inode);
|
||||
inline Inode* Root();
|
||||
inline RootInode* Root();
|
||||
|
||||
status_t Migrate(const RPC::Server* serv);
|
||||
|
||||
@@ -74,10 +74,10 @@ private:
|
||||
};
|
||||
|
||||
|
||||
inline Inode*
|
||||
inline RootInode*
|
||||
FileSystem::Root()
|
||||
{
|
||||
return reinterpret_cast<Inode*>(fRoot);
|
||||
return fRoot;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,10 @@
|
||||
|
||||
|
||||
Inode::Inode()
|
||||
:
|
||||
fAttrCacheExpire(0)
|
||||
{
|
||||
mutex_init(&fAttrCacheLock, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +99,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
|
||||
|
||||
Inode::~Inode()
|
||||
{
|
||||
mutex_destroy(&fAttrCacheLock);
|
||||
}
|
||||
|
||||
|
||||
@@ -288,7 +292,11 @@ Inode::Remove(const char* name, FileType type)
|
||||
return result;
|
||||
|
||||
reply.PutFH();
|
||||
return reply.Remove();
|
||||
result = reply.Remove();
|
||||
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
return result;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@@ -391,7 +399,11 @@ Inode::CreateLink(const char* name, const char* path, int mode)
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
return reply.Create();
|
||||
result = reply.Create();
|
||||
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
return result;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@@ -481,6 +493,36 @@ 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;
|
||||
|
||||
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 {
|
||||
RPC::Server* serv = fFileSystem->Server();
|
||||
Request request(serv);
|
||||
@@ -516,12 +558,12 @@ Inode::Stat(struct stat* st)
|
||||
delete[] values;
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
st->st_size = values[0].fData.fValue64;
|
||||
fAttrCache.st_size = values[0].fData.fValue64;
|
||||
|
||||
uint32 next = 1;
|
||||
st->st_mode = Type();
|
||||
fAttrCache.st_mode = Type();
|
||||
if (count >= next && values[next].fAttribute == FATTR4_MODE) {
|
||||
st->st_mode |= values[next].fData.fValue32;
|
||||
fAttrCache.st_mode |= values[next].fData.fValue32;
|
||||
next++;
|
||||
} else {
|
||||
// Try to guess using ACCESS request
|
||||
@@ -538,70 +580,76 @@ Inode::Stat(struct stat* st)
|
||||
return result;
|
||||
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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) {
|
||||
st->st_nlink = values[next].fData.fValue32;
|
||||
fAttrCache.st_nlink = values[next].fData.fValue32;
|
||||
next++;
|
||||
} else
|
||||
st->st_nlink = 1;
|
||||
fAttrCache.st_nlink = 1;
|
||||
|
||||
if (count >= next && values[next].fAttribute == FATTR4_OWNER) {
|
||||
char* owner = reinterpret_cast<char*>(values[next].fData.fPointer);
|
||||
if (owner != NULL && isdigit(owner[0]))
|
||||
st->st_uid = atoi(owner);
|
||||
fAttrCache.st_uid = atoi(owner);
|
||||
else
|
||||
st->st_uid = gIdMapper->GetUserId(owner);
|
||||
fAttrCache.st_uid = gIdMapper->GetUserId(owner);
|
||||
next++;
|
||||
} else
|
||||
st->st_uid = 0;
|
||||
fAttrCache.st_uid = 0;
|
||||
|
||||
if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) {
|
||||
char* group = reinterpret_cast<char*>(values[next].fData.fPointer);
|
||||
if (group != NULL && isdigit(group[0]))
|
||||
st->st_gid = atoi(group);
|
||||
fAttrCache.st_gid = atoi(group);
|
||||
else
|
||||
st->st_gid = gIdMapper->GetGroupId(group);
|
||||
fAttrCache.st_gid = gIdMapper->GetGroupId(group);
|
||||
next++;
|
||||
} else
|
||||
st->st_gid = 0;
|
||||
fAttrCache.st_gid = 0;
|
||||
|
||||
if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) {
|
||||
memcpy(&st->st_atim, values[next].fData.fPointer, sizeof(timespec));
|
||||
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,
|
||||
memcpy(&fAttrCache.st_atim, values[next].fData.fPointer,
|
||||
sizeof(timespec));
|
||||
next++;
|
||||
} 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) {
|
||||
memcpy(&st->st_ctim, values[next].fData.fPointer, sizeof(timespec));
|
||||
memcpy(&fAttrCache.st_ctim, values[next].fData.fPointer,
|
||||
sizeof(timespec));
|
||||
next++;
|
||||
} else
|
||||
memset(&st->st_ctim, 0, sizeof(timespec));
|
||||
memset(&fAttrCache.st_ctim, 0, sizeof(timespec));
|
||||
|
||||
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++;
|
||||
} else
|
||||
memset(&st->st_mtim, 0, sizeof(timespec));
|
||||
memset(&fAttrCache.st_mtim, 0, sizeof(timespec));
|
||||
|
||||
delete[] values;
|
||||
|
||||
fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime;
|
||||
|
||||
return B_OK;
|
||||
} while (true);
|
||||
}
|
||||
@@ -701,9 +749,14 @@ Inode::WriteStat(const struct stat* st, uint32 mask)
|
||||
delete cookie;
|
||||
}
|
||||
|
||||
return result;
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
_UpdateAttrCache(true);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,12 @@ protected:
|
||||
|
||||
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;
|
||||
|
||||
FileInfo fInfo;
|
||||
|
||||
@@ -109,6 +109,8 @@ Inode::OpenDir(OpenDirCookie* cookie)
|
||||
cookie->fCookie = 0;
|
||||
cookie->fCookieVerf = 2;
|
||||
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
return B_OK;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "IdMap.h"
|
||||
#include "Request.h"
|
||||
#include "RootInode.h"
|
||||
|
||||
|
||||
status_t
|
||||
@@ -172,6 +173,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
|
||||
} while (true);
|
||||
|
||||
fFileSystem->AddOpenFile(cookie);
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
if (confirm)
|
||||
return _ConfirmOpen(fh, cookie);
|
||||
@@ -430,6 +432,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
|
||||
*_length = size;
|
||||
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,44 @@
|
||||
#include "Request.h"
|
||||
|
||||
|
||||
RootInode::RootInode()
|
||||
:
|
||||
fInfoCacheExpire(0)
|
||||
{
|
||||
mutex_init(&fInfoCacheLock, NULL);
|
||||
}
|
||||
|
||||
|
||||
RootInode::~RootInode()
|
||||
{
|
||||
mutex_destroy(&fInfoCacheLock);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
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 {
|
||||
RPC::Server* serv = fFileSystem->Server();
|
||||
Request request(serv);
|
||||
@@ -46,12 +81,12 @@ RootInode::ReadInfo(struct fs_info* info)
|
||||
return result;
|
||||
|
||||
if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) {
|
||||
info->free_nodes = values[next].fData.fValue64;
|
||||
fInfoCache.free_nodes = values[next].fData.fValue64;
|
||||
next++;
|
||||
}
|
||||
|
||||
if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) {
|
||||
info->total_nodes = values[next].fData.fValue64;
|
||||
fInfoCache.total_nodes = values[next].fData.fValue64;
|
||||
next++;
|
||||
}
|
||||
|
||||
@@ -68,16 +103,16 @@ RootInode::ReadInfo(struct fs_info* info)
|
||||
|
||||
if (io_size == LONGLONG_MAX)
|
||||
io_size = 32768;
|
||||
info->io_size = io_size;
|
||||
info->block_size = io_size;
|
||||
fInfoCache.io_size = io_size;
|
||||
fInfoCache.block_size = io_size;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
@@ -86,8 +121,10 @@ RootInode::ReadInfo(struct fs_info* info)
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
info->flags = 0;
|
||||
strncpy(info->volume_name, fInfo.fName, B_FILE_NAME_LENGTH);
|
||||
fInfoCache.flags = 0;
|
||||
strncpy(fInfoCache.volume_name, fInfo.fName, B_FILE_NAME_LENGTH);
|
||||
|
||||
fInfoCacheExpire = time(NULL) + kAttrCacheExpirationTime;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -16,13 +16,31 @@
|
||||
|
||||
class RootInode : public Inode {
|
||||
public:
|
||||
status_t ReadInfo(struct fs_info* info);
|
||||
RootInode();
|
||||
~RootInode();
|
||||
|
||||
bool ProbeMigration();
|
||||
status_t GetLocations(AttrValue** attr);
|
||||
status_t ReadInfo(struct fs_info* info);
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user