From 469f13fdfe886f0eca9cc9204ad2e3da7377f7ba Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Mar 2013 02:31:31 +0100 Subject: [PATCH] nfs4: support hard links properly The main purpose of this patch is to prevent VFS from removing a vnode to early what might have happened if the NFS client knew it had more than one name but then one of them was deleted. Moreover, all discovered and still valid names are stored what may be useful in proper file handle recovery when they are volatile. This patch fixes both #9558 and #9561. --- .../file_systems/nfs4/DirectoryCache.cpp | 13 -- .../kernel/file_systems/nfs4/FileInfo.cpp | 216 +++++++++++------- .../kernel/file_systems/nfs4/FileInfo.h | 102 ++++----- .../kernel/file_systems/nfs4/FileSystem.cpp | 142 +++++++++--- .../kernel/file_systems/nfs4/FileSystem.h | 9 +- .../kernel/file_systems/nfs4/Inode.cpp | 19 +- .../kernel/file_systems/nfs4/InodeIdMap.cpp | 81 +++++++ .../kernel/file_systems/nfs4/InodeIdMap.h | 91 +------- .../kernel/file_systems/nfs4/InodeRegular.cpp | 15 +- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/NFS4Inode.cpp | 25 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 56 +++-- .../file_systems/nfs4/ReplyInterpreter.h | 8 +- .../kernel/file_systems/nfs4/VnodeToInode.cpp | 26 ++- .../kernel/file_systems/nfs4/VnodeToInode.h | 11 +- .../file_systems/nfs4/kernel_interface.cpp | 45 ++-- 16 files changed, 487 insertions(+), 373 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/InodeIdMap.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 321e73d8d7..168f54ccdf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -308,19 +308,6 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, } else { notify_entry_created(fInode->GetFileSystem()->DevId(), fInode->ID(), newCurrent->fName, newCurrent->fNode); - - do { - FileInfo fi; - fi.fFileId = newCurrent->fNode; - fi.fParent = fInode->fInfo.fHandle; - status_t result = fi.CreateName(fInode->fInfo.fPath, - newCurrent->fName); - if (result != B_OK) - break; - - fInode->GetFileSystem()->InoIdMap()->AddEntry(fi, - Inode::FileIdToInoT(newCurrent->fNode), true); - } while (false); } } else oldSnapshot->fEntries.Remove(prev, oldCurrent); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index 8bcadcc9b8..d620481c77 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -13,80 +13,122 @@ #include "Request.h" -status_t -FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path, - bool getFileHandle) +InodeName::InodeName(InodeNames* parent, const char* name) + : + fParent(parent), + fName(strdup(name)) { - ASSERT(_path != NULL); + if (fParent != NULL) + fParent->AcquireReference(); +} - char* path = strdup(_path); - if (path == NULL) - return B_NO_MEMORY; - char* pathStart = path; - char* pathEnd; +InodeName::~InodeName() +{ + if (fParent != NULL) + fParent->ReleaseReference(); + free(const_cast(fName)); +} - while (pathStart != NULL) { - pathEnd = strchr(pathStart, '/'); - if (pathEnd != NULL) - *pathEnd = '\0'; - if (pathEnd != pathStart) { - if (!strcmp(pathStart, "..")) { - req.LookUpUp(); - count++; - } else if (strcmp(pathStart, ".")) { - req.LookUp(pathStart); - if (getFileHandle) - req.GetFH(); - count++; - } - } +InodeNames::InodeNames() +{ + mutex_init(&fLock, NULL); +} - if (pathEnd != NULL && pathEnd[1] != '\0') - pathStart = pathEnd + 1; - else - pathStart = NULL; - } - free(path); - return B_OK; +InodeNames::~InodeNames() +{ + while (!fNames.IsEmpty()) + delete fNames.RemoveHead(); + mutex_destroy(&fLock); } status_t -FileInfo::CreateName(const char* dirPath, const char* name) +InodeNames::AddName(InodeNames* parent, const char* name) { - ASSERT(name != NULL); + MutexLocker _(fLock); - free(const_cast(fName)); - fName = strdup(name); - if (fName == NULL) + InodeName* current = fNames.Head(); + while (current != NULL) { + if (current->fParent == parent && !strcmp(current->fName, name)) + return B_OK; + current = fNames.GetNext(current); + } + + InodeName* newName = new InodeName(parent, name); + if (newName == NULL) return B_NO_MEMORY; - - free(const_cast(fPath)); - fPath = NULL; - if (dirPath != NULL) { - char* path = reinterpret_cast(malloc(strlen(name) + 2 - + strlen(dirPath))); - if (path == NULL) - return B_NO_MEMORY; - - strcpy(path, dirPath); - strcat(path, "/"); - strcat(path, name); - - fPath = path; - } else - fPath = strdup(name); - - if (fPath == NULL) - return B_NO_MEMORY; - + fNames.Add(newName); return B_OK; } +bool +InodeNames::RemoveName(InodeNames* parent, const char* name) +{ + MutexLocker _(fLock); + + InodeName* previous = NULL; + InodeName* current = fNames.Head(); + while (current != NULL) { + if (current->fParent == parent && !strcmp(current->fName, name)) { + fNames.Remove(previous, current); + delete current; + break; + } + + previous = current; + current = fNames.GetNext(current); + } + + return fNames.IsEmpty(); +} + + +FileInfo::FileInfo() + : + fFileId(0), + fNames(NULL) +{ +} + + +FileInfo::~FileInfo() +{ + if (fNames != NULL) + fNames->ReleaseReference(); +} + + +FileInfo::FileInfo(const FileInfo& fi) + : + fFileId(fi.fFileId), + fHandle(fi.fHandle), + fNames(fi.fNames) +{ + if (fNames != NULL) + fNames->AcquireReference(); +} + + +FileInfo& +FileInfo::operator=(const FileInfo& fi) +{ + fFileId = fi.fFileId; + fHandle = fi.fHandle; + + if (fNames != NULL) + fNames->ReleaseReference(); + fNames = fi.fNames; + if (fNames != NULL) + fNames->AcquireReference(); + + return *this; +} + + status_t FileInfo::UpdateFileHandles(FileSystem* fs) { @@ -96,16 +138,41 @@ FileInfo::UpdateFileHandles(FileSystem* fs) RequestBuilder& req = request.Builder(); req.PutRootFH(); - req.GetFH(); uint32 lookupCount = 0; - status_t result = ParsePath(req, lookupCount, fs->Path(), true); - if (result != B_OK) - return result; + const char** path = fs->Path(); + if (path != NULL) { + for (; path[lookupCount] != NULL; lookupCount++) + req.LookUp(path[lookupCount]); + } - result = ParsePath(req, lookupCount, fPath, true); - if (result != B_OK) - return result; + uint32 i; + InodeNames* names = fNames; + for (i = 0; names != NULL; i++) + names = names->fNames.Head()->fParent; + + if (i > 0) { + names = fNames; + InodeNames** pathNames = new InodeNames*[i]; + if (pathNames == NULL) + return B_NO_MEMORY; + + for (i = 0; names != NULL; i++) { + pathNames[i] = names; + names = names->fNames.Head()->fParent; + } + + for (; i > 0; i--) { + if (!strcmp(pathNames[i - 1]->fNames.Head()->fName, "")) + continue; + + req.LookUp(pathNames[i - 1]->fNames.Head()->fName); + lookupCount++; + } + delete[] pathNames; + } + + req.GetFH(); if (fs->IsAttrSupported(FATTR4_FILEID)) { AttrValue attr; @@ -115,25 +182,20 @@ FileInfo::UpdateFileHandles(FileSystem* fs) req.Verify(&attr, 1); } - result = request.Send(); + status_t result = request.Send(); if (result != B_OK) return result; ReplyInterpreter& reply = request.Reply(); - FileHandle parent; - FileHandle child; - reply.PutRootFH(); - reply.GetFH(&child); - parent = child; - for (uint32 i = 0; i < lookupCount; i++) { + for (uint32 i = 0; i < lookupCount; i++) reply.LookUp(); - parent = child; - result = reply.GetFH(&child); - if (result != B_OK) - return result; - } + + FileHandle handle; + result = reply.GetFH(&handle); + if (result != B_OK) + return result; if (fs->IsAttrSupported(FATTR4_FILEID)) { result = reply.Verify(); @@ -141,8 +203,8 @@ FileInfo::UpdateFileHandles(FileSystem* fs) return result; } - fHandle = child; - fParent = parent; + fHandle = handle; + fNames->fHandle = handle; return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h index ca2fbb5bef..d98574817b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h @@ -12,7 +12,9 @@ #include #include +#include #include +#include #define NFS4_FHSIZE 128 @@ -26,11 +28,34 @@ struct FileHandle { inline FileHandle& operator=(const FileHandle& fh); + inline bool operator==(const FileHandle& handle) const; inline bool operator!=(const FileHandle& handle) const; inline bool operator>(const FileHandle& handle) const; inline bool operator<(const FileHandle& handle) const; }; +class InodeNames; + +struct InodeName : public SinglyLinkedListLinkImpl { + InodeName(InodeNames* parent, const char* name); + ~InodeName(); + + InodeNames* fParent; + const char* fName; +}; + +struct InodeNames : public KernelReferenceable { + InodeNames(); + ~InodeNames(); + + status_t AddName(InodeNames* parent, const char* name); + bool RemoveName(InodeNames* parent, + const char* name); + + mutex fLock; + SinglyLinkedList fNames; + FileHandle fHandle; +}; class FileSystem; class RequestBuilder; @@ -42,23 +67,16 @@ struct FileInfo { uint64 fFileId; FileHandle fHandle; - FileHandle fParent; - const char* fName; - const char* fPath; + InodeNames* fNames; FileHandle fAttrDir; - inline FileInfo(); - inline ~FileInfo(); - inline FileInfo(const FileInfo& fi); - inline FileInfo& operator=(const FileInfo& fi); + FileInfo(); + ~FileInfo(); + FileInfo(const FileInfo& fi); + FileInfo& operator=(const FileInfo& fi); status_t UpdateFileHandles(FileSystem* fs); - - static status_t ParsePath(RequestBuilder& req, uint32& count, - const char* _path, bool getFileHandle = false); - - status_t CreateName(const char* dirPath, const char* name); }; struct FileSystemId { @@ -97,11 +115,18 @@ FileHandle::operator=(const FileHandle& fh) inline bool -FileHandle::operator!=(const FileHandle& handle) const +FileHandle::operator==(const FileHandle& handle) const { if (fSize != handle.fSize) - return true; - return memcmp(fData, handle.fData, fSize) != 0; + return false; + return memcmp(fData, handle.fData, fSize) == 0; +} + + +inline bool +FileHandle::operator!=(const FileHandle& handle) const +{ + return !operator==(handle); } @@ -123,53 +148,6 @@ FileHandle::operator<(const FileHandle& handle) const } -inline -FileInfo::FileInfo() - : - fFileId(0), - fName(NULL), - fPath(NULL) -{ -} - - -inline -FileInfo::~FileInfo() -{ - free(const_cast(fName)); - free(const_cast(fPath)); -} - - -inline -FileInfo::FileInfo(const FileInfo& fi) - : - fFileId(fi.fFileId), - fHandle(fi.fHandle), - fParent(fi.fParent), - fName(strdup(fi.fName)), - fPath(strdup(fi.fPath)) -{ -} - - -inline FileInfo& -FileInfo::operator=(const FileInfo& fi) -{ - fFileId = fi.fFileId; - fHandle = fi.fHandle; - fParent = fi.fParent; - - free(const_cast(fName)); - fName = strdup(fi.fName); - - free(const_cast(fPath)); - fPath = strdup(fi.fPath); - - return *this; -} - - inline bool FileSystemId::operator==(const FileSystemId& fsid) const { diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 309f572d28..c1a5a7b9ad 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -54,33 +54,74 @@ FileSystem::~FileSystem() mutex_destroy(&fOpenOwnerLock); mutex_destroy(&fCreateFileLock); - free(const_cast(fPath)); + if (fPath != NULL) { + for (uint32 i = 0; fPath[i] != NULL; i++) + free(const_cast(fPath[i])); + } + delete[] fPath; + delete fRoot; } -static const char* -GetPath(const char* root, const char* path) +static InodeNames* +GetInodeNames(const char** root, const char* _path) { - ASSERT(path != NULL); + ASSERT(_path != NULL); - int slash = 0; int i; - for (i = 0; path[i] != '\0'; i++) { - if (path[i] == '/') - slash = i; + char* path = strdup(_path); + if (path == NULL) + return NULL; + MemoryDeleter _(path); - if (root == NULL) - break; + if (root != NULL) { + for (i = 0; root[i] != NULL; i++) { + char* pathEnd = strchr(path, '/'); + if (pathEnd == path) { + path++; + i--; + continue; + } - if (path[i] != root[i] || root[i] == '\0') - break; + if (pathEnd == NULL) { + path = NULL; + break; + } else + path = pathEnd + 1; + } } - if (path[i] == '\0') - return NULL; + InodeNames* names = NULL; + if (path == NULL) { + names = new InodeNames; + if (names == NULL) + return NULL; - return path + slash; + names->AddName(NULL, ""); + return names; + } + + do { + char* pathEnd = strchr(path, '/'); + if (pathEnd != NULL) + *pathEnd = '\0'; + + InodeNames* name = new InodeNames; + if (name == NULL) { + delete names; + return NULL; + } + + name->AddName(names, path); + names = name; + if (pathEnd == NULL) + break; + + path = pathEnd + 1; + } while (*path != '\0'); + + return names; } @@ -103,7 +144,7 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath, req.PutRootFH(); uint32 lookupCount = 0; - status_t result = FileInfo::ParsePath(req, lookupCount, fsPath); + status_t result = _ParsePath(req, lookupCount, fsPath); if (result != B_OK) return result; @@ -156,30 +197,25 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath, FSLocations* locs = reinterpret_cast(values[3].fData.fLocations); - fs->fPath = strdup(locs->fRootPath); + fs->fPath = locs->fRootPath; + locs->fRootPath = NULL; } else fs->fPath = NULL; FileInfo fi; - const char* name; - if (fsPath != NULL && fsPath[0] == '/') - fsPath++; fs->fServer = serv; fs->fDevId = id; fs->fFsId = *fsid; fi.fHandle = fh; - fi.fParent = fh; - fi.fPath = strdup(GetPath(fs->fPath, fsPath)); - if (fi.fPath != NULL) { - name = strrchr(fi.fPath, '/'); - if (name != NULL) { - name++; - fi.fName = strdup(name); - } + fi.fNames = GetInodeNames(fs->fPath, fsPath); + if (fi.fNames == NULL) { + delete[] values; + return B_NO_MEMORY; } + fi.fNames->fHandle = fh; delete[] values; @@ -188,7 +224,7 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath, if (result != B_OK) return result; - name = strrchr(fsPath, '/'); + char* name = strrchr(fsPath, '/'); if (name != NULL) { name++; reinterpret_cast(inode)->SetName(name); @@ -263,8 +299,14 @@ FileSystem::Migrate(const RPC::Server* serv) if (gRPCServerManager->Acquire(&fServer, &resolver, CreateNFS4Server) == B_OK) { - free(const_cast(fPath)); - fPath = strdup(locs->fLocations[i].fRootPath); + if (fPath != NULL) { + for (uint32 i = 0; fPath[i] != NULL; i++) + free(const_cast(fPath[i])); + } + delete[] fPath; + + fPath = locs->fLocations[i].fRootPath; + locs->fLocations[i].fRootPath = NULL; if (fPath == NULL) { gRPCServerManager->Release(fServer); @@ -391,3 +433,41 @@ FileSystem::GetDelegation(const FileHandle& handle) return it.Current(); } + +status_t +FileSystem::_ParsePath(RequestBuilder& req, uint32& count, const char* _path) +{ + ASSERT(_path != NULL); + + char* path = strdup(_path); + if (path == NULL) + return B_NO_MEMORY; + + char* pathStart = path; + char* pathEnd; + + while (pathStart != NULL) { + pathEnd = strchr(pathStart, '/'); + if (pathEnd != NULL) + *pathEnd = '\0'; + + if (pathEnd != pathStart) { + if (!strcmp(pathStart, "..")) { + req.LookUpUp(); + count++; + } else if (strcmp(pathStart, ".")) { + req.LookUp(pathStart); + count++; + } + } + + if (pathEnd != NULL && pathEnd[1] != '\0') + pathStart = pathEnd + 1; + else + pathStart = NULL; + } + free(path); + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index d9b4ae3d27..5d16d8d477 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -59,7 +59,7 @@ public: inline RPC::Server* Server(); inline NFS4Server* NFSServer(); - inline const char* Path() const; + inline const char** Path() const; inline const FileSystemId& FsId() const; inline uint64 AllocFileId(); @@ -80,6 +80,9 @@ public: private: FileSystem(const MountConfiguration& config); + static status_t _ParsePath(RequestBuilder& req, uint32& count, + const char* _path); + mutex fCreateFileLock; mutex fDelegationLock; @@ -99,7 +102,7 @@ private: bool fNamedAttrs; FileSystemId fFsId; - const char* fPath; + const char** fPath; RootInode* fRoot; @@ -158,7 +161,7 @@ FileSystem::NFSServer() } -inline const char* +inline const char** FileSystem::Path() const { ASSERT(fPath != NULL); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index e62aaffb4d..6afceaafc1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -232,14 +232,7 @@ Inode::Link(Inode* dir, const char* name) return result; fFileSystem->Root()->MakeInfoInvalid(); - - FileInfo fi = fInfo; - fi.fParent = dir->fInfo.fHandle; - result = fi.CreateName(fInfo.fPath, name); - if (result != B_OK) - return result; - - fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId); + fInfo.fNames->AddName(dir->fInfo.fNames, name); dir->fCache->Lock(); if (dir->fCache->Valid()) { @@ -875,19 +868,17 @@ Inode::ChildAdded(const char* name, uint64 fileID, FileInfo fi; fi.fFileId = fileID; fi.fHandle = fileHandle; - fi.fParent = fInfo.fHandle; - status_t result = fi.CreateName(fInfo.fPath, name); - if (result != B_OK) - return result; - return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); + return fFileSystem->InoIdMap()->AddName(fi, fInfo.fNames, name, + FileIdToInoT(fileID)); } const char* Inode::Name() const { - return fInfo.fName; + ASSERT(fInfo.fNames->fNames.Head() != NULL); + return fInfo.fNames->fNames.Head()->fName; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.cpp new file mode 100644 index 0000000000..7f1ca2c529 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.cpp @@ -0,0 +1,81 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "InodeIdMap.h" + + +status_t +InodeIdMap::AddName(FileInfo& fileInfo, InodeNames* parent, + const char* name, ino_t id) +{ + MutexLocker _(fLock); + AVLTreeMap::Iterator iterator = fMap.Find(id); + if (iterator.HasCurrent()) { + if (fileInfo.fHandle == iterator.Current().fHandle) { + return iterator.CurrentValuePointer()->fNames->AddName(parent, + name); + } + } + + fMap.Remove(id); + fileInfo.fNames = new InodeNames; + if (fileInfo.fNames == NULL) + return B_NO_MEMORY; + + fileInfo.fNames->fHandle = fileInfo.fHandle; + status_t result = fileInfo.fNames->AddName(parent, name); + if (result != B_OK) { + delete fileInfo.fNames; + return result; + } + + return fMap.Insert(id, fileInfo); +} + + +bool +InodeIdMap::RemoveName(ino_t id, InodeNames* parent, const char* name) +{ + ASSERT(name != NULL); + + MutexLocker _(fLock); + AVLTreeMap::Iterator iterator = fMap.Find(id); + if (!iterator.HasCurrent()) + return true; + + FileInfo* fileInfo = iterator.CurrentValuePointer(); + + return fileInfo->fNames->RemoveName(parent, name); +} + + +status_t +InodeIdMap::RemoveEntry(ino_t id) +{ + MutexLocker _(fLock); + return fMap.Remove(id); +} + + +status_t +InodeIdMap::GetFileInfo(FileInfo* fileInfo, ino_t id) +{ + ASSERT(fileInfo != NULL); + + MutexLocker _(fLock); + AVLTreeMap::Iterator iterator = fMap.Find(id); + if (!iterator.HasCurrent()) + return B_ENTRY_NOT_FOUND; + + *fileInfo = iterator.Current(); + if (fileInfo->fNames->fNames.IsEmpty()) + return B_ENTRY_NOT_FOUND; + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index 43ae7994b2..a375c7702d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -1,5 +1,5 @@ /* - * Copyright 2012 Haiku, Inc. All rights reserved. + * Copyright 2012,2013 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -16,27 +16,24 @@ #include "FileInfo.h" -struct InodeIdMapEntry { - FileInfo fFileInfo; - bool fRemoved; -}; class InodeIdMap { public: inline InodeIdMap(); inline ~InodeIdMap(); - inline status_t AddEntry(const FileInfo& fi, - ino_t id, bool weak = false); - inline status_t MarkRemoved(ino_t id); - inline status_t RemoveEntry(ino_t id); - inline status_t GetFileInfo(FileInfo* fi, ino_t id); - -protected: - inline bool _IsEntryRemoved(ino_t id); + status_t AddName(FileInfo& fileInfo, + InodeNames* parent, + const char* name, ino_t id); + bool RemoveName(ino_t id, + InodeNames* parent, + const char* name); + status_t RemoveEntry(ino_t id); + status_t GetFileInfo(FileInfo* fileInfo, + ino_t id); private: - AVLTreeMap fMap; + AVLTreeMap fMap; mutex fLock; }; @@ -56,71 +53,5 @@ InodeIdMap::~InodeIdMap() } -inline status_t -InodeIdMap::AddEntry(const FileInfo& fi, ino_t id, bool weak) -{ - InodeIdMapEntry entry; - - MutexLocker _(fLock); - if (!weak || _IsEntryRemoved(id)) - fMap.Remove(id); - - entry.fFileInfo = fi; - entry.fRemoved = false; - - return fMap.Insert(id, entry); -} - - -inline status_t -InodeIdMap::MarkRemoved(ino_t id) -{ - MutexLocker _(fLock); - AVLTreeMap::Iterator it = fMap.Find(id); - if (!it.HasCurrent()) - return B_ENTRY_NOT_FOUND; - - it.CurrentValuePointer()->fRemoved = true; - return B_OK; -} - - -inline status_t -InodeIdMap::RemoveEntry(ino_t id) -{ - MutexLocker _(fLock); - if (_IsEntryRemoved(id)) - return fMap.Remove(id); - return B_OK; -} - - -inline status_t -InodeIdMap::GetFileInfo(FileInfo* fi, ino_t id) -{ - ASSERT(fi != NULL); - - MutexLocker _(fLock); - AVLTreeMap::Iterator it = fMap.Find(id); - if (!it.HasCurrent()) - return B_ENTRY_NOT_FOUND; - - *fi = it.Current().fFileInfo; - return B_OK; -} - - -// Caller must hold fLock -inline bool -InodeIdMap::_IsEntryRemoved(ino_t id) -{ - AVLTreeMap::Iterator it = fMap.Find(id); - if (!it.HasCurrent()) - return true; - - return it.Current().fRemoved; -} - - #endif // INODEIDMAP_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 4eb1d49db9..d61907429d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -36,13 +36,12 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, if (result != B_OK) return result; - FileInfo fi; - fi.fFileId = fileID; - fi.fHandle = handle; - fi.fParent = fInfo.fHandle; - fi.CreateName(fInfo.fPath, name); + FileInfo fileInfo; + fileInfo.fFileId = fileID; + fileInfo.fHandle = handle; - fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); + fFileSystem->InoIdMap()->AddName(fileInfo, fInfo.fNames, name, + FileIdToInoT(fileID)); fCache->Lock(); if (fCache->Valid()) { @@ -56,7 +55,7 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, fCache->Unlock(); state->fFileSystem = fFileSystem; - state->fInfo = fi; + state->fInfo = fileInfo; state->fMode = mode & O_RWMASK; return B_OK; @@ -253,8 +252,6 @@ Inode::OpenAttr(const char* _name, int mode, OpenAttrCookie* cookie, if (state == NULL) return B_NO_MEMORY; - state->fInfo.fName = strdup(name); - state->fInfo.fParent = fInfo.fAttrDir; state->fFileSystem = fFileSystem; result = NFS4Inode::OpenAttr(state, name, mode, &data, create); if (result != B_OK) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 3d678a9001..da8f82eb75 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -12,6 +12,7 @@ KernelAddon nfs4 : FileSystem.cpp IdMap.cpp Inode.cpp + InodeIdMap.cpp InodeDir.cpp InodeRegular.cpp kernel_interface.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 4d86e0e98f..a3519792ef 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -125,10 +125,8 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); - if (parent) - req.PutFH(fInfo.fParent); - else - req.PutFH(fInfo.fHandle); + (void)parent; // TODO: add support for named attributes + req.PutFH(fInfo.fHandle); if (change != NULL) { Attribute dirAttr[] = { FATTR4_CHANGE }; @@ -562,16 +560,16 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) // Since we are opening the file using a pair (parentFH, name) we // need to check for race conditions. if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { - req.PutFH(fInfo.fParent); - req.LookUp(fInfo.fName); + req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle); + req.LookUp(fInfo.fNames->fNames.Head()->fName); AttrValue attr; attr.fAttribute = FATTR4_FILEID; attr.fFreePointer = false; attr.fData.fValue64 = fInfo.fFileId; req.Verify(&attr, 1); } else if (fFileSystem->ExpireType() == FH4_PERSISTENT) { - req.PutFH(fInfo.fParent); - req.LookUp(fInfo.fName); + req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle); + req.LookUp(fInfo.fNames->fNames.Head()->fName); AttrValue attr; attr.fAttribute = FATTR4_FILEHANDLE; attr.fFreePointer = true; @@ -580,9 +578,10 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) req.Verify(&attr, 1); } - req.PutFH(fInfo.fParent); + req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle); req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID, - OPEN4_NOCREATE, fFileSystem->OpenOwner(), fInfo.fName); + OPEN4_NOCREATE, fFileSystem->OpenOwner(), + fInfo.fNames->fNames.Head()->fName); req.GetFH(); result = request.Send(); @@ -796,10 +795,8 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode, Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); - if (parent) - req.PutFH(fInfo.fParent); - else - req.PutFH(fInfo.fHandle); + (void)parent; // TODO: support named attributes + req.PutFH(fInfo.fHandle); uint32 i = 0; AttrValue cattr[1]; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index d078e4bc18..a965b9e8cd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -19,7 +19,12 @@ FSLocation::~FSLocation() { - free(const_cast(fRootPath)); + if (fRootPath != NULL) { + for (uint32 i = 0; fRootPath[i] != NULL; i++) + free(const_cast(fRootPath[i])); + } + delete[] fRootPath; + for (uint32 i = 0; i < fCount; i++) free(const_cast(fLocations[i])); delete[] fLocations; @@ -28,7 +33,12 @@ FSLocation::~FSLocation() FSLocations::~FSLocations() { - free(const_cast(fRootPath)); + if (fRootPath != NULL) { + for (uint32 i = 0; fRootPath[i] != NULL; i++) + free(const_cast(fRootPath[i])); + } + delete[] fRootPath; + delete[] fLocations; } @@ -528,27 +538,29 @@ ReplyInterpreter::Write(uint32* size) } -const char* -ReplyInterpreter::_FlattenPathname(XDR::ReadStream& stream) +const char** +ReplyInterpreter::_GetPath(XDR::ReadStream& stream) { uint32 count = stream.GetUInt(); - char* pathname = NULL; - uint32 size = 0; - for (uint32 i = 0; i < count; i++) { - const char* path = stream.GetString(); - size += strlen(path) + 1; - if (pathname == NULL) { - pathname = reinterpret_cast(malloc(strlen(path) + 1)); - pathname[0] = '\0'; - } else { - *pathname++ = '/'; - pathname = reinterpret_cast(realloc(pathname, size)); - } - strcat(pathname, path); - free(const_cast(path)); - } + char** path = new char*[count + 1]; + if (path == NULL) + return NULL; - return pathname; + uint32 i; + for (i = 0; i < count; i++) { + path[i] = stream.GetString(); + if (path[i] == NULL) + goto out; + } + path[count] = NULL; + + return const_cast(path); + +out: + for (uint32 j = 0; j < i; j++) + free(path[i]); + delete[] path; + return NULL; } @@ -662,11 +674,11 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, values[current].fAttribute = FATTR4_FS_LOCATIONS; FSLocations* locs = new FSLocations; - locs->fRootPath = _FlattenPathname(stream); + locs->fRootPath = _GetPath(stream); locs->fCount = stream.GetUInt(); locs->fLocations = new FSLocation[locs->fCount]; for (uint32 i = 0; i < locs->fCount; i++) { - locs->fLocations[i].fRootPath = _FlattenPathname(stream); + locs->fLocations[i].fRootPath = _GetPath(stream); locs->fLocations[i].fCount = stream.GetUInt(); locs->fLocations[i].fLocations = new const char*[locs->fLocations[i].fCount]; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 654963ad4e..819cce4955 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -17,7 +17,8 @@ struct FSLocation { - const char* fRootPath; + const char** fRootPath; + const char** fLocations; uint32 fCount; @@ -25,7 +26,8 @@ struct FSLocation { }; struct FSLocations { - const char* fRootPath; + const char** fRootPath; + FSLocation* fLocations; uint32 fCount; @@ -108,7 +110,7 @@ public: private: void _ParseHeader(); - static const char* _FlattenPathname(XDR::ReadStream& stream); + static const char** _GetPath(XDR::ReadStream& stream); status_t _DecodeAttrs(XDR::ReadStream& stream, AttrValue** attrs, uint32* count); diff --git a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp index b77feae8f4..2e20cfc22b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp @@ -27,15 +27,27 @@ void VnodeToInode::Replace(Inode* newInode) { WriteLocker _(fLock); - if (fInode != NULL && !IsRoot()) { - fInode->GetFileSystem()->InoIdMap()->MarkRemoved(fID); + if (fInode != NULL && !IsRoot()) delete fInode; - } fInode = newInode; - if (fInode != NULL) { - ASSERT(fFileSystem == fInode->GetFileSystem()); - fInode->GetFileSystem()->InoIdMap()->AddEntry(fInode->fInfo, fID); - } +} + + +bool +VnodeToInode::Unlink(InodeNames* parent, const char* name) +{ + WriteLocker _(fLock); + if (fInode != NULL && !IsRoot()) { + bool removed = fInode->GetFileSystem()->InoIdMap()->RemoveName(fID, + parent, name); + if (removed) { + delete fInode; + fInode = NULL; + } + return removed; + } + + return false; } diff --git a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h index 302457a721..b75528aaea 100644 --- a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h +++ b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h @@ -28,7 +28,7 @@ public: Inode* Get(); void Replace(Inode* newInode); - inline void Remove(); + bool Unlink(InodeNames* parent, const char* name); inline void Clear(); inline ino_t ID() const; @@ -72,7 +72,7 @@ VnodeToInode::VnodeToInode(ino_t id, FileSystem* fileSystem) inline VnodeToInode::~VnodeToInode() { - Remove(); + Replace(NULL); if (fFileSystem != NULL && !IsRoot()) fFileSystem->InoIdMap()->RemoveEntry(fID); rw_lock_destroy(&fLock); @@ -93,13 +93,6 @@ VnodeToInode::Unlock() } -inline void -VnodeToInode::Remove() -{ - Replace(NULL); -} - - inline void VnodeToInode::Clear() { 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 74663cf721..2672ae0b2a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -321,23 +321,6 @@ nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) } -static status_t -nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer, - size_t bufferSize) -{ - VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID()); - - VnodeToInodeLocker _(vti); - Inode* inode = vti->Get(); - if (inode == NULL) - return B_ENTRY_NOT_FOUND; - - strncpy(buffer, inode->Name(), bufferSize); - return B_OK; -} - - static status_t nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { @@ -606,11 +589,12 @@ nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) if (result == B_OK) { result = get_vnode(volume, id, reinterpret_cast(&vti)); ASSERT(result == B_OK); - vti->Remove(); - put_vnode(volume, id); - remove_vnode(volume, id); + + if (vti->Unlink(inode->fInfo.fNames, name)) + remove_vnode(volume, id); put_vnode(volume, id); + put_vnode(volume, id); } return B_OK; @@ -654,9 +638,10 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, if (result == B_OK) { result = get_vnode(volume, oldID, reinterpret_cast(&vti)); ASSERT(result == B_OK); - vti->Remove(); + if (vti->Unlink(toInode->fInfo.fNames, toName)) + remove_vnode(volume, oldID); + put_vnode(volume, oldID); - remove_vnode(volume, oldID); put_vnode(volume, oldID); } } @@ -670,8 +655,8 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, } unremove_vnode(volume, id); - child->fInfo.fParent = toInode->fInfo.fHandle; - child->fInfo.CreateName(toInode->fInfo.fPath, toName); + child->fInfo.fNames->RemoveName(fromInode->fInfo.fNames, fromName); + child->fInfo.fNames->AddName(toInode->fInfo.fNames, toName); put_vnode(volume, id); } @@ -998,11 +983,13 @@ nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) result = acquire_vnode(volume, id); if (result == B_OK) { - ASSERT(get_vnode(volume, id, reinterpret_cast(&vti)) == B_OK); - vti->Remove(); - put_vnode(volume, id); - remove_vnode(volume, id); + result = get_vnode(volume, id, reinterpret_cast(&vti)); + ASSERT(result == B_OK); + if (vti->Unlink(inode->fInfo.fNames, name)) + remove_vnode(volume, id); + + put_vnode(volume, id); put_vnode(volume, id); } @@ -1444,7 +1431,7 @@ fs_volume_ops gNFSv4VolumeOps = { fs_vnode_ops gNFSv4VnodeOps = { nfs4_lookup, - nfs4_get_vnode_name, + NULL, // get_vnode_name() nfs4_put_vnode, nfs4_remove_vnode,