added 1 changeset to branch 'refs/remotes/pdziepak-github/nfs4' old head: aec9dfc921c4624711e9636fb76e0a75d839c1ee new head: eed5b716d0d47b766659295406c54f910dc1a092 overview: https://github.com/pdziepak/Haiku/compare/aec9dfc...eed5b71 ---------------------------------------------------------------------------- eed5b71: nfs4: Fix problems with reading directory entries * Inode::ReadDir missed an entry when given buffer was too small * Each OpenDirCookie now has its own copy of directory snapshot what would prevent Inode::ReadDir from accessing freed memory when removing files and reading directory entries simultaneously * Several minor issues fixed [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- Commit: eed5b716d0d47b766659295406c54f910dc1a092 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Wed Dec 19 07:12:39 2012 UTC ---------------------------------------------------------------------------- 7 files changed, 51 insertions(+), 18 deletions(-) .../kernel/file_systems/nfs4/DirectoryCache.cpp | 28 ++++++++++++++++++++ .../kernel/file_systems/nfs4/DirectoryCache.h | 11 +++++--- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 4 +-- .../kernel/file_systems/nfs4/InodeDir.cpp | 16 ++++++----- .../kernel/file_systems/nfs4/InodeRegular.cpp | 2 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 5 +--- .../file_systems/nfs4/kernel_interface.cpp | 3 +++ ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 8585f81..923ae53 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -25,6 +25,14 @@ NameCacheEntry::NameCacheEntry(const char* name, ino_t node) } +NameCacheEntry::NameCacheEntry(const NameCacheEntry& entry) + : + fNode(entry.fNode), + fName(strdup(entry.fName)) +{ +} + + NameCacheEntry::~NameCacheEntry() { free(const_cast<char*>(fName)); @@ -37,6 +45,26 @@ DirectoryCacheSnapshot::DirectoryCacheSnapshot() } +DirectoryCacheSnapshot::DirectoryCacheSnapshot( + const DirectoryCacheSnapshot& snapshot) +{ + mutex_init(&fLock, NULL); + + MutexLocker _(snapshot.fLock); + NameCacheEntry* entry = snapshot.fEntries.Head(); + NameCacheEntry* new_entry; + while (entry) { + new_entry = new NameCacheEntry(*entry); + if (new_entry == NULL) + break; + + fEntries.Add(new_entry); + + entry = snapshot.fEntries.GetNext(entry); + } +} + + DirectoryCacheSnapshot::~DirectoryCacheSnapshot() { while (!fEntries.IsEmpty()) { diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index 45b7bf3..5cc6854 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -24,15 +24,18 @@ struct NameCacheEntry : const char* fName; NameCacheEntry(const char* name, ino_t node); + NameCacheEntry(const NameCacheEntry& entry); ~NameCacheEntry(); }; struct DirectoryCacheSnapshot : public KernelReferenceable { - SinglyLinkedList<NameCacheEntry> fEntries; - mutex fLock; + SinglyLinkedList<NameCacheEntry> fEntries; + mutable mutex fLock; - DirectoryCacheSnapshot(); - ~DirectoryCacheSnapshot(); + DirectoryCacheSnapshot(); + DirectoryCacheSnapshot( + const DirectoryCacheSnapshot& snapshot); + ~DirectoryCacheSnapshot(); }; class DirectoryCache : public DoublyLinkedListLinkImpl<DirectoryCache> { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 600a15d..be79b53 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -250,7 +250,7 @@ Inode::Link(Inode* dir, const char* name) && dir->fCache->ChangeInfo() == changeInfo.fBefore) { dir->fCache->AddEntry(name, fInfo.fFileId, true); dir->fCache->SetChangeInfo(changeInfo.fAfter); - } else if (dir->fCache->ChangeInfo() != changeInfo.fBefore) + } else dir->fCache->Trash(); } dir->fCache->Unlock(); @@ -428,7 +428,7 @@ Inode::CreateObject(const char* name, const char* path, int mode, FileType type, if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(changeInfo.fAfter); - } else if (fCache->ChangeInfo() != changeInfo.fBefore) + } else fCache->Trash(); } fCache->Unlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 508b5c8..2b71dce 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -123,7 +123,7 @@ Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, ASSERT(de != NULL); ASSERT(name != NULL); - uint32 nameSize = strlen(name); + uint32 nameSize = strlen(name) + 1; const uint32 entSize = sizeof(struct dirent); if (pos + entSize + nameSize > size) @@ -282,7 +282,7 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, free(const_cast<char*>(name)); if (entry == NULL || entry->fName == NULL) { - if (entry->fName == NULL) + if (entry != NULL) delete entry; delete snapshot; delete[] dirents; @@ -324,10 +324,10 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, else fFileSystem->Revalidator().RemoveDirectory(cache); - cookie->fSnapshot = cache->GetSnapshot(); - if (cookie->fSnapshot == NULL) { + DirectoryCacheSnapshot* snapshot = cache->GetSnapshot(); + if (snapshot == NULL) { uint64 change; - result = GetDirSnapshot(&cookie->fSnapshot, cookie, &change, + result = GetDirSnapshot(&snapshot, cookie, &change, cookie->fAttrDir); if (result != B_OK) { cache->Unlock(); @@ -335,9 +335,9 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, return result; } cache->ValidateChangeInfo(change); - cache->SetSnapshot(cookie->fSnapshot); + cache->SetSnapshot(snapshot); } - cookie->fSnapshot->AcquireReference(); + cookie->fSnapshot = new DirectoryCacheSnapshot(*snapshot); fFileSystem->Revalidator().AddDirectory(cache); cache->Unlock(); fFileSystem->Revalidator().Unlock(); @@ -387,6 +387,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, MutexLocker _(cookie->fSnapshot->fLock); for (; !overflow && i < *_count; i++) { struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); + NameCacheEntry* temp = cookie->fCurrent; if (cookie->fCurrent == NULL) cookie->fCurrent = cookie->fSnapshot->fEntries.Head(); @@ -402,6 +403,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, if (FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName, pos, size) == B_BUFFER_OVERFLOW) { + cookie->fCurrent = temp; overflow = true; break; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index d5fa76d..7533b86 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -52,7 +52,7 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, && fCache->ChangeInfo() == changeInfo.fBefore) { fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(changeInfo.fAfter); - } else if (fCache->ChangeInfo() != changeInfo.fBefore) + } else fCache->Trash(); } fCache->Unlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 14b8df8..271cabb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -421,10 +421,7 @@ ReplyInterpreter::ReadDir(uint64* cookie, uint64* cookieVerf, isNext = fReply->Stream().GetBoolean(); } - if (!isNext) - *eof = fReply->Stream().GetBoolean(); - else - *eof = false; + *eof = fReply->Stream().GetBoolean(); *_count = count; *dirents = entries; 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 7641ac9..546aa02 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -1039,6 +1039,9 @@ nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) OpenDirCookie* cookie = reinterpret_cast<OpenDirCookie*>(_cookie); cookie->fSpecial = 0; + if (cookie->fSnapshot != NULL) + cookie->fSnapshot->ReleaseReference(); + cookie->fSnapshot = NULL; cookie->fCurrent = NULL; cookie->fEOF = false;