nfs4: Basic data cache implementation
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fs_cache.h>
|
||||
#include <NodeMonitor.h>
|
||||
|
||||
#include "IdMap.h"
|
||||
@@ -22,7 +23,8 @@
|
||||
Inode::Inode()
|
||||
:
|
||||
fAttrCacheExpire(0),
|
||||
fCache(NULL)
|
||||
fCache(NULL),
|
||||
fFileCache(NULL)
|
||||
{
|
||||
mutex_init(&fAttrCacheLock, NULL);
|
||||
}
|
||||
@@ -43,6 +45,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
|
||||
inode->fInfo = fi;
|
||||
inode->fFileSystem = fs;
|
||||
|
||||
uint64 size;
|
||||
do {
|
||||
RPC::Server* serv = fs->Server();
|
||||
Request request(serv);
|
||||
@@ -50,7 +53,8 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
|
||||
|
||||
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));
|
||||
|
||||
status_t result = request.Send();
|
||||
@@ -67,14 +71,14 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
result = reply.GetAttr(&values, &count);
|
||||
if (result != B_OK || count < 2)
|
||||
if (result != B_OK || count < 3)
|
||||
return result;
|
||||
|
||||
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();
|
||||
else
|
||||
inode->fInfo.fFileId = values[2].fData.fValue64;
|
||||
inode->fInfo.fFileId = values[3].fData.fValue64;
|
||||
} else
|
||||
inode->fInfo.fFileId = fi.fFileId;
|
||||
|
||||
@@ -84,9 +88,12 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
|
||||
if (inode->fType == NF4DIR)
|
||||
inode->fCache = new DirectoryCache(inode);
|
||||
|
||||
// FATTR4_SIZE is mandatory
|
||||
size = values[1].fData.fValue64;
|
||||
|
||||
// FATTR4_FSID is mandatory
|
||||
FileSystemId* fsid =
|
||||
reinterpret_cast<FileSystemId*>(values[1].fData.fPointer);
|
||||
reinterpret_cast<FileSystemId*>(values[2].fData.fPointer);
|
||||
if (*fsid != fs->FsId()) {
|
||||
delete[] values;
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
@@ -96,13 +103,21 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode)
|
||||
|
||||
*_inode = inode;
|
||||
|
||||
return B_OK;
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
if (inode->fType == NF4REG)
|
||||
inode->fFileCache = file_cache_create(fs->DevId(), inode->ID(), size);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
Inode::~Inode()
|
||||
{
|
||||
if (fFileCache != NULL)
|
||||
file_cache_delete(fFileCache);
|
||||
|
||||
delete fCache;
|
||||
mutex_destroy(&fAttrCacheLock);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ public:
|
||||
inline const char* Name() const;
|
||||
inline FileSystem* GetFileSystem() const;
|
||||
|
||||
inline void* FileCache();
|
||||
|
||||
status_t GetChangeInfo(uint64* change);
|
||||
|
||||
status_t LookUp(const char* name, ino_t* id);
|
||||
@@ -52,7 +54,7 @@ public:
|
||||
status_t Open(int mode, OpenFileCookie* cookie);
|
||||
status_t Close(OpenFileCookie* cookie);
|
||||
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,
|
||||
const void* buffer, size_t *_length);
|
||||
|
||||
@@ -111,6 +113,7 @@ protected:
|
||||
FileSystem* fFileSystem;
|
||||
|
||||
DirectoryCache* fCache;
|
||||
void* fFileCache;
|
||||
};
|
||||
|
||||
|
||||
@@ -153,5 +156,12 @@ Inode::GetFileSystem() const
|
||||
}
|
||||
|
||||
|
||||
inline void*
|
||||
Inode::FileCache()
|
||||
{
|
||||
return fFileCache;
|
||||
}
|
||||
|
||||
|
||||
#endif // INODE_H
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <fs_cache.h>
|
||||
#include <NodeMonitor.h>
|
||||
|
||||
#include "IdMap.h"
|
||||
@@ -330,13 +331,14 @@ Inode::Close(OpenFileCookie* cookie)
|
||||
|
||||
|
||||
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 len = 0;
|
||||
|
||||
while (size < *_length && !eof) {
|
||||
while (size < *_length && !*eof) {
|
||||
do {
|
||||
RPC::Server* serv = fFileSystem->Server();
|
||||
Request request(serv);
|
||||
@@ -357,7 +359,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Read(reinterpret_cast<char*>(buffer) + size, &len,
|
||||
&eof);
|
||||
eof);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
RootInode::RootInode()
|
||||
:
|
||||
fInfoCacheExpire(0)
|
||||
fInfoCacheExpire(0),
|
||||
fIOSize(0)
|
||||
{
|
||||
mutex_init(&fInfoCacheLock, NULL);
|
||||
}
|
||||
@@ -90,29 +91,30 @@ RootInode::_UpdateInfo(bool force)
|
||||
next++;
|
||||
}
|
||||
|
||||
uint64 io_size = LONGLONG_MAX;
|
||||
uint64 ioSize = LONGLONG_MAX;
|
||||
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++;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
if (io_size == LONGLONG_MAX)
|
||||
io_size = 32768;
|
||||
fInfoCache.io_size = io_size;
|
||||
fInfoCache.block_size = io_size;
|
||||
if (ioSize == LONGLONG_MAX)
|
||||
ioSize = 32768;
|
||||
fInfoCache.io_size = ioSize;
|
||||
fInfoCache.block_size = ioSize;
|
||||
fIOSize = ioSize;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
status_t ReadInfo(struct fs_info* info);
|
||||
inline void MakeInfoInvalid();
|
||||
|
||||
inline uint32 IOSize();
|
||||
|
||||
bool ProbeMigration();
|
||||
status_t GetLocations(AttrValue** attr);
|
||||
|
||||
@@ -30,6 +32,8 @@ private:
|
||||
mutex fInfoCacheLock;
|
||||
time_t fInfoCacheExpire;
|
||||
|
||||
uint32 fIOSize;
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fs_cache.h>
|
||||
#include <fs_interface.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
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -378,7 +432,7 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie)
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
|
||||
|
||||
return inode->Read(cookie, pos, buffer, length);
|
||||
return file_cache_read(inode->FileCache(), cookie, pos, buffer, length);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
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);
|
||||
|
||||
@@ -409,7 +461,40 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
|
||||
|
||||
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 */
|
||||
NULL, // can_page()
|
||||
NULL, // read_pages()
|
||||
NULL, // write_pages()
|
||||
nfs4_read_pages,
|
||||
nfs4_write_pages,
|
||||
|
||||
NULL, // io()
|
||||
nfs4_io,
|
||||
NULL, // cancel_io()
|
||||
|
||||
NULL, // get_file_map()
|
||||
nfs4_get_file_map,
|
||||
|
||||
NULL, // ioctl()
|
||||
nfs4_set_flags,
|
||||
|
||||
Reference in New Issue
Block a user