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,