diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index dbb10f0c50..2e571664e3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -175,7 +175,77 @@ DirectoryCache::Revalidate() return B_OK; } + DirectoryCacheSnapshot* oldSnapshot = fDirectoryCache; + oldSnapshot->AcquireReference(); + Trash(); - return B_ERROR; + + DirectoryCacheSnapshot* newSnapshot; + status_t result = fInode->GetDirSnapshot(&newSnapshot, NULL, &fChange); + if (result != B_OK) { + oldSnapshot->ReleaseReference(); + return B_OK; + } + newSnapshot->AcquireReference(); + + SetSnapshot(newSnapshot); + fExpireTime = system_time() + kExpirationTime; + fTrashed = false; + + NotifyChanges(oldSnapshot, newSnapshot); + oldSnapshot->ReleaseReference(); + newSnapshot->ReleaseReference(); + + return B_OK; +} + + +void +DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, + DirectoryCacheSnapshot* newSnapshot) +{ + MutexLocker _(newSnapshot->fLock); + + SinglyLinkedList::Iterator oldIt + = oldSnapshot->fEntries.GetIterator(); + NameCacheEntry* oldCurrent; + + SinglyLinkedList::Iterator newIt + = newSnapshot->fEntries.GetIterator(); + NameCacheEntry* newCurrent = newIt.Next(); + while (newCurrent != NULL) { + oldIt = oldSnapshot->fEntries.GetIterator(); + oldCurrent = oldIt.Next(); + + bool found = false; + NameCacheEntry* prev = NULL; + while (oldCurrent != NULL) { + if (oldCurrent->fNode == newCurrent->fNode && + strcmp(oldCurrent->fName, newCurrent->fName) == 0) { + found = true; + break; + } + + prev = oldCurrent; + oldCurrent = oldIt.Next(); + } + + if (!found) { + notify_entry_created(fInode->GetFileSystem()->DevId(), + fInode->ID(), newCurrent->fName, newCurrent->fNode); + } else + oldSnapshot->fEntries.Remove(prev, oldCurrent); + + newCurrent = newIt.Next(); + } + + oldIt = oldSnapshot->fEntries.GetIterator(); + oldCurrent = oldIt.Next(); + + while (oldCurrent != NULL) { + notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(), + oldCurrent->fName, oldCurrent->fNode); + oldCurrent = oldIt.Next(); + } } diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index e558b166e9..3f22e47c4b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -65,6 +65,10 @@ public: inline time_t ExpireTime(); static const bigtime_t kExpirationTime = 15000000; +protected: + void NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, + DirectoryCacheSnapshot* newSnapshot); + private: SinglyLinkedList fNameCache; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index c86d104c2d..be97c45558 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -22,6 +22,7 @@ Inode::Inode() : + fMetaCache(this), fCache(NULL), fDelegation(NULL), fFileCache(NULL), @@ -248,6 +249,8 @@ Inode::Link(Inode* dir, const char* name) dir->fCache->Unlock(); } + notify_entry_created(fFileSystem->DevId(), dir->ID(), name, ID()); + return B_OK; } @@ -256,7 +259,8 @@ status_t Inode::Remove(const char* name, FileType type) { ChangeInfo changeInfo; - status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo); + uint64 fileID; + status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID); if (result != B_OK) return result; @@ -272,6 +276,9 @@ Inode::Remove(const char* name, FileType type) fFileSystem->Root()->MakeInfoInvalid(); + notify_entry_removed(fFileSystem->DevId(), ID(), name, + FileIdToInoT(fileID)); + return B_OK; } @@ -311,6 +318,9 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) to->fCache->Unlock(); } + notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName, + to->ID(), toName, FileIdToInoT(fileID)); + return B_OK; } @@ -349,6 +359,9 @@ Inode::CreateObject(const char* name, const char* path, int mode, FileType type) fCache->Unlock(); } + notify_entry_created(fFileSystem->DevId(), ID(), name, + FileIdToInoT(fileID)); + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index b30f33f1a9..35dc4d8bbe 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -90,6 +90,10 @@ public: const struct flock* lock); status_t ReleaseAllLocks(OpenFileCookie* cookie); + status_t GetDirSnapshot(DirectoryCacheSnapshot** + _snapshot, OpenDirCookie* cookie, + uint64* _change); + protected: Inode(); @@ -105,9 +109,6 @@ protected: uint32 size); status_t FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, uint32 size); - status_t GetDirSnapshot(DirectoryCacheSnapshot** - _snapshot, OpenDirCookie* cookie, - uint64* _change); status_t ChildAdded(const char* name, uint64 fileID, const FileHandle& fileHandle); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index a4f69678c3..7bad21a6f5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -90,6 +90,8 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, fFileSystem->AddOpenFile(state); fFileSystem->Root()->MakeInfoInvalid(); + notify_entry_created(fFileSystem->DevId(), ID(), name, *id); + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index 058ce243c2..901021c47a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -9,11 +9,17 @@ #include "MetadataCache.h" +#include -MetadataCache::MetadataCache() +#include "Inode.h" + + +MetadataCache::MetadataCache(Inode* inode) : fExpire(0), - fForceValid(false) + fForceValid(false), + fInode(inode), + fInited(false) { mutex_init(&fLock, NULL); } @@ -52,8 +58,12 @@ void MetadataCache::SetStat(const struct stat& st) { MutexLocker _(fLock); + if (fInited) + NotifyChanges(&fStatCache, &st); + fStatCache = st; fExpire = time(NULL) + kExpirationTime; + fInited = true; } @@ -121,3 +131,35 @@ MetadataCache::UnlockValid() } +void +MetadataCache::NotifyChanges(const struct stat* oldStat, + const struct stat* newStat) +{ + uint32 flags = 0; + if (oldStat->st_size != newStat->st_size) + flags |= B_STAT_SIZE; + if (oldStat->st_mode != newStat->st_mode) + flags |= B_STAT_MODE; + if (oldStat->st_uid != newStat->st_uid) + flags |= B_STAT_UID; + if (oldStat->st_gid != newStat->st_gid) + flags |= B_STAT_GID; + + if (memcmp(&oldStat->st_atim, &newStat->st_atim, + sizeof(struct timespec) == 0)) + flags |= B_STAT_ACCESS_TIME; + + if (memcmp(&oldStat->st_ctim, &newStat->st_ctim, + sizeof(struct timespec) == 0)) + flags |= B_STAT_CHANGE_TIME; + + if (memcmp(&oldStat->st_crtim, &newStat->st_crtim, + sizeof(struct timespec) == 0)) + flags |= B_STAT_CREATION_TIME; + + if (memcmp(&oldStat->st_mtim, &newStat->st_mtim, + sizeof(struct timespec) == 0)) + flags |= B_STAT_MODIFICATION_TIME; + + notify_stat_changed(fInode->GetFileSystem()->DevId(), fInode->ID(), flags); +} diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h index 4622c9e7dd..26a5e971f1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h @@ -9,12 +9,15 @@ #define METADATACACHE_H +#include #include #include #include #include +class Inode; + struct AccessEntry { time_t fExpire; uint32 fAllowed; @@ -22,7 +25,7 @@ struct AccessEntry { class MetadataCache { public: - MetadataCache(); + MetadataCache(Inode* inode); ~MetadataCache(); status_t GetStat(struct stat* st); @@ -41,11 +44,19 @@ public: inline void Invalidate(); static const time_t kExpirationTime = 60; + +protected: + void NotifyChanges(const struct stat* oldStat, + const struct stat* newStat); + private: struct stat fStatCache; time_t fExpire; bool fForceValid; + Inode* fInode; + bool fInited; + AVLTreeMap fAccessCache; mutex fLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index a424350b29..24bb38d269 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -736,7 +736,8 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode, status_t -NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo) +NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, + uint64* fileID) { do { RPC::Server* serv = fFileSystem->Server(); @@ -755,6 +756,10 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo) req.Nverify(&attr, 1); req.PutFH(fInfo.fHandle); + + Attribute idAttr[] = { FATTR4_FILEID }; + req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute)); + req.Remove(name); status_t result = request.Send(); @@ -785,6 +790,18 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo) reply.PutFH(); + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + if (count == 0) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; + delete[] values; + return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter, changeInfo->fAtomic); } while (true); @@ -831,8 +848,7 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, return result; } - result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, - count, eof); + result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, count, eof); if (result != B_OK) { delete[] before; return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index 3e1bedb429..f340a42b3c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -62,7 +62,7 @@ protected: int mode, FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle); status_t RemoveObject(const char* name, FileType type, - ChangeInfo* changeInfo); + ChangeInfo* changeInfo, uint64* fileID); status_t ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, bool* eof, uint64* change,