nfs4: Basic data cache implementation
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user