From 0bc98afd433d6b193773d937c06048b4ade01cd6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 27 Jul 2012 01:53:54 +0200 Subject: [PATCH] nfs4: Basic data cache implementation --- .../kernel/file_systems/nfs4/Inode.cpp | 29 +++-- src/add-ons/kernel/file_systems/nfs4/Inode.h | 12 +- .../kernel/file_systems/nfs4/InodeRegular.cpp | 10 +- .../kernel/file_systems/nfs4/RootInode.cpp | 22 ++-- .../kernel/file_systems/nfs4/RootInode.h | 13 +++ .../file_systems/nfs4/kernel_interface.cpp | 107 ++++++++++++++++-- 6 files changed, 160 insertions(+), 33 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index b87792ece7..607df773de 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #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(values[1].fData.fPointer); + reinterpret_cast(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); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 6a7a584bca..110efa83bf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index ace10fa343..f6718f1b1c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -11,6 +11,7 @@ #include +#include #include #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(buffer) + size, &len, - &eof); + eof); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 82a0340400..6d99f30812 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -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++; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.h b/src/add-ons/kernel/file_systems/nfs4/RootInode.h index 5b01b89ff5..864d49ddba 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.h +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index fdd79f3d11..391b57dc2a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -9,6 +9,7 @@ #include +#include #include #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(vnode->private_node); + OpenFileCookie* cookie = reinterpret_cast(_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(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(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(_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(vnode->private_node); @@ -409,7 +461,40 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, OpenFileCookie* cookie = reinterpret_cast(_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(_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,