nfs4: Cache file attributes and filesystem info
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user