diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 68ed4e775d..039da2d1c4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -29,6 +29,7 @@ Inode::Inode() fWriteDirty(false) { mutex_init(&fAttrCacheLock, NULL); + mutex_init(&fFileCacheLock, NULL); } @@ -55,8 +56,8 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) req.PutFH(inode->fInfo.fHandle); - Attribute attr[] = { FATTR4_TYPE, FATTR4_SIZE, FATTR4_FSID, - FATTR4_FILEID }; + Attribute attr[] = { FATTR4_TYPE, FATTR4_CHANGE, FATTR4_SIZE, + FATTR4_FSID, FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -73,14 +74,14 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 3) + if (result != B_OK || count < 4) return result; if (fi.fFileId == 0) { - if (count < 4 || values[3].fAttribute != FATTR4_FILEID) + if (count < 5 || values[4].fAttribute != FATTR4_FILEID) inode->fInfo.fFileId = fs->AllocFileId(); else - inode->fInfo.fFileId = values[3].fData.fValue64; + inode->fInfo.fFileId = values[4].fData.fValue64; } else inode->fInfo.fFileId = fi.fFileId; @@ -90,12 +91,15 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) if (inode->fType == NF4DIR) inode->fCache = new DirectoryCache(inode); + // FATTR4_CHANGE is mandatory + inode->fChange = values[1].fData.fValue64; + // FATTR4_SIZE is mandatory - size = values[1].fData.fValue64; + size = values[2].fData.fValue64; // FATTR4_FSID is mandatory FileSystemId* fsid = - reinterpret_cast(values[2].fData.fPointer); + reinterpret_cast(values[3].fData.fPointer); if (*fsid != fs->FsId()) { delete[] values; return B_ENTRY_NOT_FOUND; @@ -121,10 +125,39 @@ Inode::~Inode() file_cache_delete(fFileCache); delete fCache; + mutex_destroy(&fFileCacheLock); mutex_destroy(&fAttrCacheLock); } +status_t +Inode::RevalidateFileCache() +{ + uint64 change; + status_t result = GetChangeInfo(&change); + if (result != B_OK) + return result; + + MutexLocker _(fFileCacheLock); + if (change == fChange) + return B_OK; + + result = _UpdateAttrCache(true); + if (result != B_OK) + return result; + + file_cache_sync(fFileCache); + Commit(); + file_cache_delete(fFileCache); + + fFileCache = file_cache_create(fFileSystem->DevId(), ID(), + fAttrCache.st_size); + + change = fChange; + return B_OK; +} + + status_t Inode::GetChangeInfo(uint64* change) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 30e0623d6e..2385063bff 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -31,6 +31,8 @@ public: inline FileSystem* GetFileSystem() const; inline void* FileCache(); + status_t RevalidateFileCache(); + inline OpenFileCookie* WriteCookie(); inline void SetWriteCookie(OpenFileCookie* cookie); @@ -117,8 +119,11 @@ protected: FileSystem* fFileSystem; DirectoryCache* fCache; + + uint64 fChange; void* fFileCache; OpenFileCookie* fWriteCookie; + mutex fFileCacheLock; bool fWriteDirty; }; 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 fd0307b282..560a7a9355 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -429,7 +429,6 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) return B_NO_MEMORY; *_cookie = cookie; - status_t result = inode->Open(openMode, cookie); if (result != B_OK) delete cookie; @@ -605,6 +604,9 @@ nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, { Inode* inode = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); + + inode->RevalidateFileCache(); + return inode->AcquireLock(cookie, lock, wait); } @@ -619,6 +621,10 @@ nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, return B_OK; OpenFileCookie* cookie = reinterpret_cast(_cookie); + + file_cache_sync(inode->FileCache()); + inode->Commit(); + if (lock != NULL) return inode->ReleaseLock(cookie, lock); else