nfs4: Basic data cache implementation

This commit is contained in:
Pawel Dziepak
2012-07-27 01:53:54 +02:00
parent b5162ff580
commit 0bc98afd43
6 changed files with 160 additions and 33 deletions
+22 -7
View File
@@ -12,6 +12,7 @@
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <fs_cache.h>
#include <NodeMonitor.h> #include <NodeMonitor.h>
#include "IdMap.h" #include "IdMap.h"
@@ -22,7 +23,8 @@
Inode::Inode() Inode::Inode()
: :
fAttrCacheExpire(0), fAttrCacheExpire(0),
fCache(NULL) fCache(NULL),
fFileCache(NULL)
{ {
mutex_init(&fAttrCacheLock, NULL); mutex_init(&fAttrCacheLock, NULL);
} }
@@ -43,6 +45,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
inode->fInfo = fi; inode->fInfo = fi;
inode->fFileSystem = fs; inode->fFileSystem = fs;
uint64 size;
do { do {
RPC::Server* serv = fs->Server(); RPC::Server* serv = fs->Server();
Request request(serv); Request request(serv);
@@ -50,7 +53,8 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
req.PutFH(inode->fInfo.fHandle); req.PutFH(inode->fInfo.fHandle);
Attribute attr[] = { FATTR4_TYPE, FATTR4_FSID, FATTR4_FILEID }; Attribute attr[] = { FATTR4_TYPE, FATTR4_SIZE, FATTR4_FSID,
FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
status_t result = request.Send(); status_t result = request.Send();
@@ -67,14 +71,14 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
AttrValue* values; AttrValue* values;
uint32 count; uint32 count;
result = reply.GetAttr(&values, &count); result = reply.GetAttr(&values, &count);
if (result != B_OK || count < 2) if (result != B_OK || count < 3)
return result; return result;
if (fi.fFileId == 0) { if (fi.fFileId == 0) {
if (count < 3 || values[2].fAttribute != FATTR4_FILEID) if (count < 4 || values[3].fAttribute != FATTR4_FILEID)
inode->fInfo.fFileId = fs->AllocFileId(); inode->fInfo.fFileId = fs->AllocFileId();
else else
inode->fInfo.fFileId = values[2].fData.fValue64; inode->fInfo.fFileId = values[3].fData.fValue64;
} else } else
inode->fInfo.fFileId = fi.fFileId; inode->fInfo.fFileId = fi.fFileId;
@@ -84,9 +88,12 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
if (inode->fType == NF4DIR) if (inode->fType == NF4DIR)
inode->fCache = new DirectoryCache(inode); inode->fCache = new DirectoryCache(inode);
// FATTR4_SIZE is mandatory
size = values[1].fData.fValue64;
// FATTR4_FSID is mandatory // FATTR4_FSID is mandatory
FileSystemId* fsid = FileSystemId* fsid =
reinterpret_cast<FileSystemId*>(values[1].fData.fPointer); reinterpret_cast<FileSystemId*>(values[2].fData.fPointer);
if (*fsid != fs->FsId()) { if (*fsid != fs->FsId()) {
delete[] values; delete[] values;
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
@@ -96,13 +103,21 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
*_inode = inode; *_inode = inode;
return B_OK; break;
} while (true); } while (true);
if (inode->fType == NF4REG)
inode->fFileCache = file_cache_create(fs->DevId(), inode->ID(), size);
return B_OK;
} }
Inode::~Inode() Inode::~Inode()
{ {
if (fFileCache != NULL)
file_cache_delete(fFileCache);
delete fCache; delete fCache;
mutex_destroy(&fAttrCacheLock); mutex_destroy(&fAttrCacheLock);
} }
+11 -1
View File
@@ -30,6 +30,8 @@ public:
inline const char* Name() const; inline const char* Name() const;
inline FileSystem* GetFileSystem() const; inline FileSystem* GetFileSystem() const;
inline void* FileCache();
status_t GetChangeInfo(uint64* change); status_t GetChangeInfo(uint64* change);
status_t LookUp(const char* name, ino_t* id); status_t LookUp(const char* name, ino_t* id);
@@ -52,7 +54,7 @@ public:
status_t Open(int mode, OpenFileCookie* cookie); status_t Open(int mode, OpenFileCookie* cookie);
status_t Close(OpenFileCookie* cookie); status_t Close(OpenFileCookie* cookie);
status_t Read(OpenFileCookie* cookie, off_t pos, status_t Read(OpenFileCookie* cookie, off_t pos,
void* buffer, size_t* length); void* buffer, size_t* length, bool* eof);
status_t Write(OpenFileCookie* cookie, off_t pos, status_t Write(OpenFileCookie* cookie, off_t pos,
const void* buffer, size_t *_length); const void* buffer, size_t *_length);
@@ -111,6 +113,7 @@ protected:
FileSystem* fFileSystem; FileSystem* fFileSystem;
DirectoryCache* fCache; DirectoryCache* fCache;
void* fFileCache;
}; };
@@ -153,5 +156,12 @@ Inode::GetFileSystem() const
} }
inline void*
Inode::FileCache()
{
return fFileCache;
}
#endif // INODE_H #endif // INODE_H
@@ -11,6 +11,7 @@
#include <string.h> #include <string.h>
#include <fs_cache.h>
#include <NodeMonitor.h> #include <NodeMonitor.h>
#include "IdMap.h" #include "IdMap.h"
@@ -330,13 +331,14 @@ Inode::Close(OpenFileCookie* cookie)
status_t status_t
Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length,
bool* eof)
{ {
bool eof = false; *eof = false;
uint32 size = 0; uint32 size = 0;
uint32 len = 0; uint32 len = 0;
while (size < *_length && !eof) { while (size < *_length && !*eof) {
do { do {
RPC::Server* serv = fFileSystem->Server(); RPC::Server* serv = fFileSystem->Server();
Request request(serv); Request request(serv);
@@ -357,7 +359,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
reply.PutFH(); reply.PutFH();
result = reply.Read(reinterpret_cast<char*>(buffer) + size, &len, result = reply.Read(reinterpret_cast<char*>(buffer) + size, &len,
&eof); eof);
if (result != B_OK) if (result != B_OK)
return result; return result;
@@ -16,7 +16,8 @@
RootInode::RootInode() RootInode::RootInode()
: :
fInfoCacheExpire(0) fInfoCacheExpire(0),
fIOSize(0)
{ {
mutex_init(&fInfoCacheLock, NULL); mutex_init(&fInfoCacheLock, NULL);
} }
@@ -90,29 +91,30 @@ RootInode::_UpdateInfo(bool force)
next++; next++;
} }
uint64 io_size = LONGLONG_MAX; uint64 ioSize = LONGLONG_MAX;
if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) { if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) {
io_size = min_c(io_size, values[next].fData.fValue64); ioSize = min_c(ioSize, values[next].fData.fValue64);
next++; next++;
} }
if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) { if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) {
io_size = min_c(io_size, values[next].fData.fValue64); ioSize = min_c(ioSize, values[next].fData.fValue64);
next++; next++;
} }
if (io_size == LONGLONG_MAX) if (ioSize == LONGLONG_MAX)
io_size = 32768; ioSize = 32768;
fInfoCache.io_size = io_size; fInfoCache.io_size = ioSize;
fInfoCache.block_size = io_size; fInfoCache.block_size = ioSize;
fIOSize = ioSize;
if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) { if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) {
fInfoCache.free_blocks = values[next].fData.fValue64 / io_size; fInfoCache.free_blocks = values[next].fData.fValue64 / ioSize;
next++; next++;
} }
if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) { if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) {
fInfoCache.total_blocks = values[next].fData.fValue64 / io_size; fInfoCache.total_blocks = values[next].fData.fValue64 / ioSize;
next++; next++;
} }
@@ -22,6 +22,8 @@ public:
status_t ReadInfo(struct fs_info* info); status_t ReadInfo(struct fs_info* info);
inline void MakeInfoInvalid(); inline void MakeInfoInvalid();
inline uint32 IOSize();
bool ProbeMigration(); bool ProbeMigration();
status_t GetLocations(AttrValue** attr); status_t GetLocations(AttrValue** attr);
@@ -30,6 +32,8 @@ private:
mutex fInfoCacheLock; mutex fInfoCacheLock;
time_t fInfoCacheExpire; time_t fInfoCacheExpire;
uint32 fIOSize;
status_t _UpdateInfo(bool force = false); status_t _UpdateInfo(bool force = false);
}; };
@@ -42,5 +46,14 @@ RootInode::MakeInfoInvalid()
} }
inline uint32
RootInode::IOSize()
{
if (fIOSize == 0)
_UpdateInfo(true);
return fIOSize;
}
#endif // ROOTINODE_H #endif // ROOTINODE_H
@@ -9,6 +9,7 @@
#include <stdio.h> #include <stdio.h>
#include <fs_cache.h>
#include <fs_interface.h> #include <fs_interface.h>
#include "Connection.h" #include "Connection.h"
@@ -212,6 +213,59 @@ nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
} }
static status_t
nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos,
const iovec* vecs, size_t count, size_t* _numBytes)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
status_t result;
bool eof = false;
for (size_t i = 0; i < count && !eof; i++) {
size_t bytesLeft = vecs[i].iov_len;
char* buffer = reinterpret_cast<char*>(vecs[i].iov_base);
do {
size_t bytesRead = bytesLeft;
result = inode->Read(cookie, pos, buffer, &bytesRead, &eof);
if (result != B_OK)
return result;
pos += bytesRead;
buffer += bytesRead;
bytesLeft -= bytesRead;
} while (bytesLeft > 0 && !eof);
}
return B_OK;
}
static status_t
nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos,
const iovec* vecs, size_t count, size_t* _numBytes)
{
return B_OK;
}
static status_t
nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request)
{
// no asynchronous calls yet
return B_UNSUPPORTED;
}
static status_t
nfs4_get_file_map(fs_volume* volume, fs_vnode* vnode, off_t _offset,
size_t size, struct file_io_vec* vecs, size_t* _count)
{
return B_ERROR;
}
static status_t static status_t
nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags)
{ {
@@ -224,7 +278,7 @@ nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags)
static status_t static status_t
nfs4_fsync(fs_volume* volume, fs_vnode* vnode) nfs4_fsync(fs_volume* volume, fs_vnode* vnode)
{ {
// Currently, there is no cache and all writes are FILE_SYNC4 // Currently all writes are FILE_SYNC4
return B_OK; return B_OK;
} }
@@ -378,7 +432,7 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie)
static status_t static status_t
nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, nfs4_read(fs_volume* volume, fs_vnode* vnode, void* cookie, off_t pos,
void* buffer, size_t* length) void* buffer, size_t* length)
{ {
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node); Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
@@ -389,15 +443,13 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
if (inode->Type() == S_IFLNK) if (inode->Type() == S_IFLNK)
return B_BAD_VALUE; return B_BAD_VALUE;
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); return file_cache_read(inode->FileCache(), cookie, pos, buffer, length);
return inode->Read(cookie, pos, buffer, length);
} }
static status_t static status_t
nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
const void* buffer, size_t* length) const void* _buffer, size_t* length)
{ {
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node); Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
@@ -409,7 +461,40 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie); OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
return inode->Write(cookie, pos, buffer, length); struct stat stat;
status_t result = inode->Stat(&stat);
if (result != B_OK)
return result;
uint64 fileSize = max_c(stat.st_size, pos + *length);
result = file_cache_set_size(inode->FileCache(), fileSize);
if (result != B_OK)
return result;
result = file_cache_write(inode->FileCache(), cookie, pos, _buffer,
length);
if (result != B_OK)
return result;
uint32 ioSize = inode->GetFileSystem()->Root()->IOSize();
size_t bytesLeft = *length;
const char* buffer = reinterpret_cast<const char*>(_buffer);
do {
size_t bytesWritten = min_c(ioSize, bytesLeft);
result = inode->Write(cookie, pos, buffer, &bytesWritten);
if (result != B_OK)
break;
bytesLeft -= bytesWritten;
pos += bytesWritten;
buffer += bytesWritten;
} while (bytesLeft > 0);
if (bytesLeft == *length)
return result;
*length = *length - bytesLeft;
return B_OK;
} }
@@ -582,13 +667,13 @@ fs_vnode_ops gNFSv4VnodeOps = {
/* VM file access */ /* VM file access */
NULL, // can_page() NULL, // can_page()
NULL, // read_pages() nfs4_read_pages,
NULL, // write_pages() nfs4_write_pages,
NULL, // io() nfs4_io,
NULL, // cancel_io() NULL, // cancel_io()
NULL, // get_file_map() nfs4_get_file_map,
NULL, // ioctl() NULL, // ioctl()
nfs4_set_flags, nfs4_set_flags,